fix: mock agent process, React 18/19 types, release version refs

- Add hidden `mock-agent-process` CLI subcommand implementing a stdio
  JSON-RPC echo agent (ported from examples/mock-acp-agent)
- Update write_mock_agent_process_launcher() to exec the new subcommand
  instead of exiting with error
- Update sdks/react to support React 18 and 19 peer dependencies
- Update @types/react to v19 across workspace (pnpm override + inspector)
- Fix RefObject<T | null> compatibility for React 19 useRef() signatures
- Add version reference replacement logic to release update_version.ts
  covering all docs, examples, and code files listed in CLAUDE.md
- Add missing files to CLAUDE.md Install Version References list
  (architecture.mdx, boxlite, modal, computesdk docs and examples)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nathan Flurry 2026-03-15 22:36:48 -07:00
parent 2f9f25ae54
commit bf543d225d
14 changed files with 296 additions and 100 deletions

View file

@ -93,15 +93,21 @@ When adding a new agent, update all of the following:
- `docs/sdk-overview.mdx`
- `docs/react-components.mdx`
- `docs/session-persistence.mdx`
- `docs/architecture.mdx`
- `docs/deploy/local.mdx`
- `docs/deploy/cloudflare.mdx`
- `docs/deploy/vercel.mdx`
- `docs/deploy/daytona.mdx`
- `docs/deploy/e2b.mdx`
- `docs/deploy/docker.mdx`
- `docs/deploy/boxlite.mdx`
- `docs/deploy/modal.mdx`
- `docs/deploy/computesdk.mdx`
- `frontend/packages/website/src/components/GetStarted.tsx`
- `.claude/commands/post-release-testing.md`
- `examples/cloudflare/Dockerfile`
- `examples/boxlite/Dockerfile`
- `examples/boxlite-python/Dockerfile`
- `examples/daytona/src/index.ts`
- `examples/shared/src/docker.ts`
- `examples/docker/src/index.ts`

View file

@ -1,8 +1,19 @@
import { AgentTranscript as AgentTranscript_, type AgentTranscriptClassNames, type TranscriptEntry } from "@sandbox-agent/react";
// Cast to work around React 18/19 type incompatibility between @sandbox-agent/react and foundry
const AgentTranscript = AgentTranscript_ as unknown as (props: Record<string, unknown>) => JSX.Element;
import { memo, useEffect, useMemo, type MutableRefObject, type RefObject } from "react";
// Cast needed: tsup-generated .d.ts returns react_jsx_runtime.JSX.Element which
// doesn't unify with the consumer's JSX.Element under Bundler moduleResolution.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const AgentTranscript = AgentTranscript_ as any as React.FC<{
entries: TranscriptEntry[];
classNames?: Partial<AgentTranscriptClassNames>;
scrollRef?: RefObject<HTMLDivElement | null>;
scrollToEntryId?: string | null;
virtualize?: boolean;
isThinking?: boolean;
renderMessageText?: (entry: TranscriptEntry) => React.ReactNode;
renderThinkingState?: () => React.ReactNode;
}>;
import { useStyletron } from "baseui";
import { LabelSmall, LabelXSmall } from "baseui/typography";
import { Copy } from "lucide-react";
@ -156,7 +167,7 @@ export const MessageList = memo(function MessageList({
pendingMessage,
}: {
session: AgentSession | null | undefined;
scrollRef: RefObject<HTMLDivElement>;
scrollRef: RefObject<HTMLDivElement | null>;
messageRefs: MutableRefObject<Map<string, HTMLDivElement>>;
historyEvents: HistoryEvent[];
onSelectHistoryEvent: (event: HistoryEvent) => void;

View file

@ -14,8 +14,8 @@
"devDependencies": {
"@sandbox-agent/react": "workspace:*",
"sandbox-agent": "workspace:*",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.3.1",
"fake-indexeddb": "^6.2.4",
"typescript": "^5.7.3",

View file

@ -71,7 +71,7 @@ const ChatPanel = ({
agents: AgentInfo[];
agentsLoading: boolean;
agentsError: string | null;
scrollRef: RefObject<HTMLDivElement>;
scrollRef: RefObject<HTMLDivElement | null>;
agentLabel: string;
modelLabel?: string | null;
currentAgentVersion?: string | null;

View file

@ -84,7 +84,7 @@ export interface InspectorConversationProps {
entries: TranscriptEntry[];
sessionError: string | null;
eventError?: string | null;
scrollRef: RefObject<HTMLDivElement>;
scrollRef: RefObject<HTMLDivElement | null>;
onEventClick?: (eventId: string) => void;
isThinking?: boolean;
agentId?: string;

View file

@ -20,8 +20,8 @@
},
"pnpm": {
"overrides": {
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0"
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.6"
}
}
}

158
pnpm-lock.yaml generated
View file

@ -5,8 +5,8 @@ settings:
excludeLinksFromLockfile: false
overrides:
'@types/react': ^18.3.3
'@types/react-dom': ^18.3.0
'@types/react': ^19.1.12
'@types/react-dom': ^19.1.6
importers:
@ -78,11 +78,11 @@ importers:
specifier: latest
version: 25.5.0
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
'@types/react-dom':
specifier: ^18.3.0
version: 18.3.7(@types/react@18.3.27)
specifier: ^19.1.6
version: 19.2.3(@types/react@19.1.12)
'@vitejs/plugin-react':
specifier: ^4.5.0
version: 4.7.0(vite@6.4.1(@types/node@25.5.0)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))
@ -549,8 +549,8 @@ importers:
version: link:../../../sdks/typescript
devDependencies:
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
tsup:
specifier: ^8.5.0
version: 8.5.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
@ -577,7 +577,7 @@ importers:
version: 3.13.22(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
baseui:
specifier: ^16.1.1
version: 16.1.1(@types/react@18.3.27)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styletron-react@6.1.1(react@19.2.4))
version: 16.1.1(@types/react@19.1.12)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styletron-react@6.1.1(react@19.2.4))
lucide-react:
specifier: ^0.542.0
version: 0.542.0(react@19.2.4)
@ -599,19 +599,19 @@ importers:
devDependencies:
'@react-grab/mcp':
specifier: ^0.1.13
version: 0.1.27(@types/react@18.3.27)(react@19.2.4)
version: 0.1.27(@types/react@19.1.12)(react@19.2.4)
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
'@types/react-dom':
specifier: ^18.3.0
version: 18.3.7(@types/react@18.3.27)
specifier: ^19.1.6
version: 19.2.3(@types/react@19.1.12)
'@vitejs/plugin-react':
specifier: ^5.0.3
version: 5.1.4(vite@7.3.1(@types/node@25.5.0)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))
react-grab:
specifier: ^0.1.13
version: 0.1.27(@types/react@18.3.27)(react@19.2.4)
version: 0.1.27(@types/react@19.1.12)(react@19.2.4)
tsup:
specifier: ^8.5.0
version: 8.5.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2)
@ -651,11 +651,11 @@ importers:
specifier: workspace:*
version: link:../../../sdks/react
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
'@types/react-dom':
specifier: ^18.3.0
version: 18.3.7(@types/react@18.3.27)
specifier: ^19.1.6
version: 19.2.3(@types/react@19.1.12)
'@vitejs/plugin-react':
specifier: ^4.3.1
version: 4.7.0(vite@5.4.21(@types/node@25.5.0))
@ -679,7 +679,7 @@ importers:
dependencies:
'@astrojs/react':
specifier: ^4.2.0
version: 4.4.2(@types/node@25.5.0)(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(jiti@1.21.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.2)
version: 4.4.2(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.1.12))(@types/react@19.1.12)(jiti@1.21.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.2)
'@astrojs/sitemap':
specifier: ^3.2.0
version: 3.7.0
@ -706,11 +706,11 @@ importers:
version: 3.4.19(tsx@4.21.0)(yaml@2.8.2)
devDependencies:
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
'@types/react-dom':
specifier: ^18.3.0
version: 18.3.7(@types/react@18.3.27)
specifier: ^19.1.6
version: 19.2.3(@types/react@19.1.12)
typescript:
specifier: ^5.7.0
version: 5.9.3
@ -942,17 +942,17 @@ importers:
dependencies:
'@tanstack/react-virtual':
specifier: ^3.13.22
version: 3.13.22(react-dom@19.2.4(react@18.3.1))(react@18.3.1)
version: 3.13.22(react-dom@19.2.4(react@19.1.1))(react@19.1.1)
ghostty-web:
specifier: ^0.4.0
version: 0.4.0
devDependencies:
'@types/react':
specifier: ^18.3.3
version: 18.3.27
specifier: ^19.1.12
version: 19.1.12
react:
specifier: ^18.3.1
version: 18.3.1
specifier: ^19.1.1
version: 19.1.1
sandbox-agent:
specifier: workspace:*
version: link:../typescript
@ -1083,8 +1083,8 @@ packages:
resolution: {integrity: sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ==}
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
peerDependencies:
'@types/react': ^18.3.3
'@types/react-dom': ^18.3.0
'@types/react': ^19.1.12
'@types/react-dom': ^19.1.6
react: ^17.0.2 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.2 || ^18.0.0 || ^19.0.0
@ -3588,21 +3588,18 @@ packages:
'@types/pg@8.18.0':
resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==}
'@types/prop-types@15.7.15':
resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
'@types/react-dom@18.3.7':
resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==}
'@types/react-dom@19.2.3':
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
'@types/react-reconciler@0.28.9':
resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
'@types/react@18.3.27':
resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==}
'@types/react@19.1.12':
resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==}
'@types/retry@0.12.2':
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
@ -6076,7 +6073,7 @@ packages:
react-focus-lock@2.13.7:
resolution: {integrity: sha512-20lpZHEQrXPb+pp1tzd4ULL6DyO5D2KnR0G69tTDdydrmNhU7pdFmbQUYVyHUgp+xN29IuFR0PVuhOmvaZL9Og==}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
@ -6145,7 +6142,7 @@ packages:
resolution: {integrity: sha512-tsPZ77GR0pISGYmpCLHAbZTabKXZ7zBniKPVqVMMfnXFyo39zq5g/psIlD5vLTKkjQEhWOO8JhqcHnxkwNu6eA==}
engines: {node: '>=8.5.0'}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
react: ^16.8.0
peerDependenciesMeta:
'@types/react':
@ -6175,6 +6172,10 @@ packages:
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
engines: {node: '>=0.10.0'}
react@19.1.1:
resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==}
engines: {node: '>=0.10.0'}
react@19.2.4:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
@ -6980,7 +6981,7 @@ packages:
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
@ -6990,7 +6991,7 @@ packages:
resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^18.3.3
'@types/react': ^19.1.12
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
@ -7413,10 +7414,10 @@ snapshots:
dependencies:
prismjs: 1.30.0
'@astrojs/react@4.4.2(@types/node@25.5.0)(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(jiti@1.21.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.2)':
'@astrojs/react@4.4.2(@types/node@25.5.0)(@types/react-dom@19.2.3(@types/react@19.1.12))(@types/react@19.1.12)(jiti@1.21.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(tsx@4.21.0)(yaml@2.8.2)':
dependencies:
'@types/react': 18.3.27
'@types/react-dom': 18.3.7(@types/react@18.3.27)
'@types/react': 19.1.12
'@types/react-dom': 19.2.3(@types/react@19.1.12)
'@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@25.5.0)(jiti@1.21.7)(tsx@4.21.0)(yaml@2.8.2))
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
@ -9416,11 +9417,11 @@ snapshots:
prompts: 2.4.2
smol-toml: 1.6.0
'@react-grab/mcp@0.1.27(@types/react@18.3.27)(react@19.2.4)':
'@react-grab/mcp@0.1.27(@types/react@19.1.12)(react@19.2.4)':
dependencies:
'@modelcontextprotocol/sdk': 1.27.1(zod@3.25.76)
fkill: 9.0.0
react-grab: 0.1.27(@types/react@18.3.27)(react@19.2.4)
react-grab: 0.1.27(@types/react@19.1.12)(react@19.2.4)
zod: 3.25.76
transitivePeerDependencies:
- '@cfworker/json-schema'
@ -10033,11 +10034,11 @@ snapshots:
react-dom: 19.2.4(react@19.2.4)
use-sync-external-store: 1.6.0(react@19.2.4)
'@tanstack/react-virtual@3.13.22(react-dom@19.2.4(react@18.3.1))(react@18.3.1)':
'@tanstack/react-virtual@3.13.22(react-dom@19.2.4(react@19.1.1))(react@19.1.1)':
dependencies:
'@tanstack/virtual-core': 3.13.22
react: 18.3.1
react-dom: 19.2.4(react@18.3.1)
react: 19.1.1
react-dom: 19.2.4(react@19.1.1)
'@tanstack/react-virtual@3.13.22(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
@ -10154,19 +10155,16 @@ snapshots:
pg-protocol: 1.11.0
pg-types: 2.2.0
'@types/prop-types@15.7.15': {}
'@types/react-dom@18.3.7(@types/react@18.3.27)':
'@types/react-dom@19.2.3(@types/react@19.1.12)':
dependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
'@types/react-reconciler@0.28.9(@types/react@18.3.27)':
'@types/react-reconciler@0.28.9(@types/react@19.1.12)':
dependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
'@types/react@18.3.27':
'@types/react@19.1.12':
dependencies:
'@types/prop-types': 15.7.15
csstype: 3.2.3
'@types/retry@0.12.2': {}
@ -10523,7 +10521,7 @@ snapshots:
baseline-browser-mapping@2.9.18: {}
baseui@16.1.1(@types/react@18.3.27)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styletron-react@6.1.1(react@19.2.4)):
baseui@16.1.1(@types/react@19.1.12)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(styletron-react@6.1.1(react@19.2.4)):
dependencies:
'@date-io/date-fns': 2.17.0(date-fns@2.30.0)
'@date-io/moment': 2.17.0(moment@2.30.1)
@ -10543,7 +10541,7 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
react-dropzone: 9.0.0(react@19.2.4)
react-focus-lock: 2.13.7(@types/react@18.3.27)(react@19.2.4)
react-focus-lock: 2.13.7(@types/react@19.1.12)(react@19.2.4)
react-hook-form: 7.71.2(react@19.2.4)
react-input-mask: 2.0.4(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-is: 17.0.2
@ -10551,7 +10549,7 @@ snapshots:
react-movable: 3.4.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-multi-ref: 1.0.2
react-range: 1.10.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-uid: 2.3.0(@types/react@18.3.27)(react@19.2.4)
react-uid: 2.3.0(@types/react@19.1.12)(react@19.2.4)
react-virtualized: 9.22.6(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-virtualized-auto-sizer: 1.0.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react-window: 1.8.5(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@ -10615,9 +10613,9 @@ snapshots:
dependencies:
file-uri-to-path: 1.0.0
bippy@0.5.32(@types/react@18.3.27)(react@19.2.4):
bippy@0.5.32(@types/react@19.1.12)(react@19.2.4):
dependencies:
'@types/react-reconciler': 0.28.9(@types/react@18.3.27)
'@types/react-reconciler': 0.28.9(@types/react@19.1.12)
react: 19.2.4
transitivePeerDependencies:
- '@types/react'
@ -13009,9 +13007,9 @@ snapshots:
react: 18.3.1
scheduler: 0.23.2
react-dom@19.2.4(react@18.3.1):
react-dom@19.2.4(react@19.1.1):
dependencies:
react: 18.3.1
react: 19.1.1
scheduler: 0.27.0
react-dom@19.2.4(react@19.2.4):
@ -13027,23 +13025,23 @@ snapshots:
prop-types-extra: 1.1.1(react@19.2.4)
react: 19.2.4
react-focus-lock@2.13.7(@types/react@18.3.27)(react@19.2.4):
react-focus-lock@2.13.7(@types/react@19.1.12)(react@19.2.4):
dependencies:
'@babel/runtime': 7.28.6
focus-lock: 1.3.6
prop-types: 15.8.1
react: 19.2.4
react-clientside-effect: 1.2.8(react@19.2.4)
use-callback-ref: 1.3.3(@types/react@18.3.27)(react@19.2.4)
use-sidecar: 1.1.3(@types/react@18.3.27)(react@19.2.4)
use-callback-ref: 1.3.3(@types/react@19.1.12)(react@19.2.4)
use-sidecar: 1.1.3(@types/react@19.1.12)(react@19.2.4)
optionalDependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
react-grab@0.1.27(@types/react@18.3.27)(react@19.2.4):
react-grab@0.1.27(@types/react@19.1.12)(react@19.2.4):
dependencies:
'@medv/finder': 4.0.2
'@react-grab/cli': 0.1.27
bippy: 0.5.32(@types/react@18.3.27)(react@19.2.4)
bippy: 0.5.32(@types/react@19.1.12)(react@19.2.4)
solid-js: 1.9.11
optionalDependencies:
react: 19.2.4
@ -13097,12 +13095,12 @@ snapshots:
react-refresh@0.18.0: {}
react-uid@2.3.0(@types/react@18.3.27)(react@19.2.4):
react-uid@2.3.0(@types/react@19.1.12)(react@19.2.4):
dependencies:
react: 19.2.4
tslib: 1.14.1
optionalDependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
react-virtualized-auto-sizer@1.0.2(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
@ -13131,6 +13129,8 @@ snapshots:
dependencies:
loose-envify: 1.4.0
react@19.1.1: {}
react@19.2.4: {}
read-cache@1.0.0:
@ -14068,20 +14068,20 @@ snapshots:
escalade: 3.2.0
picocolors: 1.1.1
use-callback-ref@1.3.3(@types/react@18.3.27)(react@19.2.4):
use-callback-ref@1.3.3(@types/react@19.1.12)(react@19.2.4):
dependencies:
react: 19.2.4
tslib: 2.8.1
optionalDependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
use-sidecar@1.1.3(@types/react@18.3.27)(react@19.2.4):
use-sidecar@1.1.3(@types/react@19.1.12)(react@19.2.4):
dependencies:
detect-node-es: 1.1.0
react: 19.2.4
tslib: 2.8.1
optionalDependencies:
'@types/react': 18.3.27
'@types/react': 19.1.12
use-sync-external-store@1.6.0(react@19.2.4):
dependencies:

View file

@ -2,6 +2,7 @@ import * as fs from "node:fs/promises";
import { join } from "node:path";
import { $ } from "execa";
import { glob } from "glob";
import * as semver from "semver";
import type { ReleaseOpts } from "./main";
function assert(condition: any, message?: string): asserts condition {
@ -10,13 +11,56 @@ function assert(condition: any, message?: string): asserts condition {
}
}
// Files containing version references that need channel/image tag updates.
// Keep in sync with CLAUDE.md "Install Version References" section.
const VERSION_REFERENCE_FILES = [
"README.md",
"docs/acp-http-client.mdx",
"docs/cli.mdx",
"docs/quickstart.mdx",
"docs/sdk-overview.mdx",
"docs/react-components.mdx",
"docs/session-persistence.mdx",
"docs/architecture.mdx",
"docs/deploy/local.mdx",
"docs/deploy/cloudflare.mdx",
"docs/deploy/vercel.mdx",
"docs/deploy/daytona.mdx",
"docs/deploy/e2b.mdx",
"docs/deploy/docker.mdx",
"docs/deploy/boxlite.mdx",
"docs/deploy/modal.mdx",
"docs/deploy/computesdk.mdx",
"frontend/packages/website/src/components/GetStarted.tsx",
".claude/commands/post-release-testing.md",
"examples/cloudflare/Dockerfile",
"examples/boxlite/Dockerfile",
"examples/boxlite-python/Dockerfile",
"examples/daytona/src/index.ts",
"examples/shared/src/docker.ts",
"examples/docker/src/index.ts",
"examples/e2b/src/index.ts",
"examples/vercel/src/index.ts",
"sdks/typescript/src/providers/shared.ts",
"scripts/release/main.ts",
"scripts/release/promote-artifacts.ts",
"scripts/release/sdk.ts",
"scripts/sandbox-testing/test-sandbox.ts",
];
export async function updateVersion(opts: ReleaseOpts) {
// 1. Update workspace version and internal crate versions in root Cargo.toml
// 1. Read current version from Cargo.toml before overwriting
const cargoTomlPath = join(opts.root, "Cargo.toml");
let cargoContent = await fs.readFile(cargoTomlPath, "utf-8");
const oldVersionMatch = cargoContent.match(/\[workspace\.package\]\nversion = "([^"]+)"/);
assert(oldVersionMatch, "Could not find workspace.package version in Cargo.toml");
const oldVersion = oldVersionMatch[1];
const oldParsed = semver.parse(oldVersion);
assert(oldParsed, `Could not parse old version: ${oldVersion}`);
const oldMinorChannel = `${oldParsed.major}.${oldParsed.minor}.x`;
// Update [workspace.package] version
assert(/\[workspace\.package\]\nversion = ".*"/.test(cargoContent), "Could not find workspace.package version in Cargo.toml");
cargoContent = cargoContent.replace(/\[workspace\.package\]\nversion = ".*"/, `[workspace.package]\nversion = "${opts.version}"`);
// Discover internal crates from [workspace.dependencies] by matching
@ -69,4 +113,70 @@ export async function updateVersion(opts: ReleaseOpts) {
await fs.writeFile(fullPath, updated);
await $({ cwd: opts.root })`git add ${relPath}`;
}
// 3. Update version references across docs, examples, and code
await updateVersionReferences(opts, oldVersion, oldMinorChannel);
}
async function updateVersionReferences(opts: ReleaseOpts, oldVersion: string, oldMinorChannel: string) {
const newMinorChannel = opts.minorVersionChannel;
// Find old Docker image tags by scanning for rivetdev/sandbox-agent:<version>-full patterns
// The old version might be a different patch or RC, so we match any version-full tag
const oldDockerTagPattern = /rivetdev\/sandbox-agent:([0-9]+\.[0-9]+\.[0-9]+(?:-[a-zA-Z0-9.]+)?)-full/;
console.log(`\nUpdating version references:`);
console.log(` Old minor channel: ${oldMinorChannel}`);
console.log(` New minor channel: ${newMinorChannel}`);
console.log(` New Docker tag: ${opts.version}-full`);
const modifiedFiles: string[] = [];
for (const relPath of VERSION_REFERENCE_FILES) {
const fullPath = join(opts.root, relPath);
let content: string;
try {
content = await fs.readFile(fullPath, "utf-8");
} catch (err: any) {
if (err.code === "ENOENT") {
console.log(` ⚠️ Skipping ${relPath} (file not found)`);
continue;
}
throw err;
}
const original = content;
// Replace minor channel references (e.g. sandbox-agent@0.3.x -> sandbox-agent@0.4.x)
content = content.replaceAll(`sandbox-agent@${oldMinorChannel}`, `sandbox-agent@${newMinorChannel}`);
content = content.replaceAll(`@sandbox-agent/cli@${oldMinorChannel}`, `@sandbox-agent/cli@${newMinorChannel}`);
content = content.replaceAll(`@sandbox-agent/react@${oldMinorChannel}`, `@sandbox-agent/react@${newMinorChannel}`);
// Replace install script URL channel
content = content.replaceAll(`releases.rivet.dev/sandbox-agent/${oldMinorChannel}/`, `releases.rivet.dev/sandbox-agent/${newMinorChannel}/`);
// Replace Docker image tags (rivetdev/sandbox-agent:<anything>-full -> rivetdev/sandbox-agent:<version>-full)
content = content.replaceAll(
new RegExp(`rivetdev/sandbox-agent:[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.]+)?-full`, "g"),
`rivetdev/sandbox-agent:${opts.version}-full`,
);
// Replace standalone version-full references in prose (e.g. "The `0.3.2-full` tag pins...")
// Match backtick-wrapped version-full patterns
content = content.replaceAll(new RegExp("`[0-9]+\\.[0-9]+\\.[0-9]+(?:-[a-zA-Z0-9.]+)?-full`", "g"), `\`${opts.version}-full\``);
if (content !== original) {
await fs.writeFile(fullPath, content);
modifiedFiles.push(relPath);
console.log(`${relPath}`);
}
}
if (modifiedFiles.length > 0) {
await $({ cwd: opts.root })`git add ${modifiedFiles}`;
console.log(`\nUpdated ${modifiedFiles.length} files with version references.`);
} else {
console.log(`\nNo version reference files needed updates.`);
}
}

View file

@ -24,7 +24,7 @@
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"react": "^18.3.1",
"react": "^18.3.1 || ^19.0.0",
"sandbox-agent": "^0.2.2"
},
"dependencies": {
@ -32,8 +32,8 @@
"ghostty-web": "^0.4.0"
},
"devDependencies": {
"@types/react": "^18.3.3",
"react": "^18.3.1",
"@types/react": "^19.1.12",
"react": "^19.1.1",
"sandbox-agent": "workspace:*",
"tsup": "^8.0.0",
"typescript": "^5.7.0"

View file

@ -18,7 +18,7 @@ export interface AgentConversationProps {
emptyState?: ReactNode;
transcriptClassName?: string;
transcriptClassNames?: Partial<AgentTranscriptClassNames>;
scrollRef?: RefObject<HTMLDivElement>;
scrollRef?: RefObject<HTMLDivElement | null>;
composerClassName?: string;
composerClassNames?: Partial<ChatComposerClassNames>;
transcriptProps?: Omit<AgentTranscriptProps, "entries" | "className" | "classNames" | "scrollRef">;

View file

@ -98,8 +98,8 @@ export interface AgentTranscriptProps {
entries: TranscriptEntry[];
className?: string;
classNames?: Partial<AgentTranscriptClassNames>;
endRef?: RefObject<HTMLDivElement>;
scrollRef?: RefObject<HTMLDivElement>;
endRef?: RefObject<HTMLDivElement | null>;
scrollRef?: RefObject<HTMLDivElement | null>;
scrollToEntryId?: string | null;
sessionError?: string | null;
eventError?: string | null;

View file

@ -4,7 +4,7 @@ import type { RefObject } from "react";
import { useEffect, useRef } from "react";
import { useVirtualizer } from "@tanstack/react-virtual";
export function useTranscriptVirtualizer<T>(items: T[], scrollElementRef?: RefObject<HTMLDivElement>, onAtBottomChange?: (atBottom: boolean) => void) {
export function useTranscriptVirtualizer<T>(items: T[], scrollElementRef?: RefObject<HTMLDivElement | null>, onAtBottomChange?: (atBottom: boolean) => void) {
const isFollowingRef = useRef(true);
const virtualizer = useVirtualizer({

View file

@ -1090,9 +1090,9 @@ fn write_mock_agent_process_launcher(path: &Path) -> Result<(), AgentError> {
fs::create_dir_all(parent)?;
}
let script = if cfg!(windows) {
"@echo off\r\necho mock agent process is in-process in sandbox-agent\r\nexit /b 1\r\n"
"@echo off\r\nsandbox-agent mock-agent-process %*\r\n"
} else {
"#!/usr/bin/env sh\necho 'mock agent process is in-process in sandbox-agent'\nexit 1\n"
"#!/usr/bin/env sh\nexec sandbox-agent mock-agent-process \"$@\"\n"
};
write_text_file(path, script)
}

View file

@ -83,6 +83,9 @@ pub enum Command {
InstallAgent(InstallAgentArgs),
/// Inspect locally discovered credentials.
Credentials(CredentialsArgs),
/// Internal: stdio JSON-RPC echo agent for the mock agent process.
#[command(hide = true)]
MockAgentProcess,
}
#[derive(Args, Debug)]
@ -406,6 +409,7 @@ pub fn run_command(command: &Command, cli: &CliConfig) -> Result<(), CliError> {
Command::Daemon(subcommand) => run_daemon(&subcommand.command, cli),
Command::InstallAgent(args) => install_agent_local(args),
Command::Credentials(subcommand) => run_credentials(&subcommand.command),
Command::MockAgentProcess => run_mock_agent_process(),
}
}
@ -929,6 +933,71 @@ fn run_credentials(command: &CredentialsCommand) -> Result<(), CliError> {
}
}
fn run_mock_agent_process() -> Result<(), CliError> {
use std::io::BufRead;
let stdin = std::io::stdin();
let reader = stdin.lock();
for line in reader.lines() {
let line = line.map_err(|e| CliError::Server(format!("stdin read error: {}", e)))?;
if line.trim().is_empty() {
continue;
}
let msg: Value = match serde_json::from_str(&line) {
Ok(v) => v,
Err(e) => {
let err_notification = json!({
"jsonrpc": "2.0",
"method": "mock/parse_error",
"params": {
"error": e.to_string(),
"raw": line,
}
});
write_stdout_line(&serde_json::to_string(&err_notification)?)?;
continue;
}
};
// Echo notification for every message
let echo = json!({
"jsonrpc": "2.0",
"method": "mock/echo",
"params": { "message": msg }
});
write_stdout_line(&serde_json::to_string(&echo)?)?;
let has_method = msg.get("method").and_then(|v| v.as_str()).is_some();
let has_id = msg.get("id").is_some();
if has_method && has_id {
// Request -> respond with echo result
let response = json!({
"jsonrpc": "2.0",
"id": msg["id"],
"result": { "echoed": msg }
});
write_stdout_line(&serde_json::to_string(&response)?)?;
} else if !has_method && has_id {
// Client response
let notification = json!({
"jsonrpc": "2.0",
"method": "mock/client_response",
"params": {
"id": msg["id"],
"result": msg.get("result").unwrap_or(&Value::Null),
"error": msg.get("error").unwrap_or(&Value::Null),
}
});
write_stdout_line(&serde_json::to_string(&notification)?)?;
}
}
Ok(())
}
fn load_json_payload(
json_inline: Option<&str>,
json_file: Option<&std::path::Path>,