@tanstack/ai-sandbox 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +15 -5
  2. package/dist/esm/agents-file.d.ts +15 -0
  3. package/dist/esm/agents-file.js +47 -1
  4. package/dist/esm/agents-file.js.map +1 -1
  5. package/dist/esm/bootstrap.js +2 -1
  6. package/dist/esm/bootstrap.js.map +1 -1
  7. package/dist/esm/contracts.d.ts +12 -8
  8. package/dist/esm/git-exec.js +2 -0
  9. package/dist/esm/git-exec.js.map +1 -1
  10. package/dist/esm/index.d.ts +2 -1
  11. package/dist/esm/index.js +3 -3
  12. package/dist/esm/journal-sweep.js +3 -2
  13. package/dist/esm/journal-sweep.js.map +1 -1
  14. package/dist/esm/middleware.js +5 -2
  15. package/dist/esm/middleware.js.map +1 -1
  16. package/dist/esm/reap.js +2 -1
  17. package/dist/esm/reap.js.map +1 -1
  18. package/dist/esm/sandbox.d.ts +2 -0
  19. package/dist/esm/sandbox.js +19 -2
  20. package/dist/esm/sandbox.js.map +1 -1
  21. package/dist/esm/shell.js +5 -4
  22. package/dist/esm/shell.js.map +1 -1
  23. package/dist/esm/testkit/conformance.js +4 -2
  24. package/dist/esm/testkit/conformance.js.map +1 -1
  25. package/dist/esm/testkit/journal-conformance.js +6 -3
  26. package/dist/esm/testkit/journal-conformance.js.map +1 -1
  27. package/dist/esm/testkit/reaper-conformance.js +13 -8
  28. package/dist/esm/testkit/reaper-conformance.js.map +1 -1
  29. package/dist/esm/testkit/takeover-conformance.js +4 -3
  30. package/dist/esm/testkit/takeover-conformance.js.map +1 -1
  31. package/dist/esm/tool-bridge.js +1 -1
  32. package/dist/esm/tool-bridge.js.map +1 -1
  33. package/package.json +14 -4
  34. package/skills/ai-sandbox/SKILL.md +13 -8
  35. package/src/agents-file.ts +65 -0
  36. package/src/bootstrap.ts +5 -1
  37. package/src/contracts.ts +12 -8
  38. package/src/git-exec.ts +7 -0
  39. package/src/index.ts +2 -0
  40. package/src/middleware.ts +4 -1
  41. package/src/sandbox.ts +23 -0
  42. package/src/tool-bridge.ts +3 -1
package/src/middleware.ts CHANGED
@@ -48,6 +48,7 @@ import {
48
48
  } from './tool-history'
49
49
  import { watchWorkspace } from './watch'
50
50
  import { DEFAULT_WORKSPACE_ROOT } from './bootstrap'
51
+ import { resolveHarnessCwd } from './harness-cwd'
51
52
  import type { InternalLogger } from '@tanstack/ai/adapter-internals'
52
53
  import type { LockStore } from '@tanstack/ai/locks'
53
54
  import type {
@@ -293,6 +294,7 @@ function buildEnsureCtx(
293
294
  locks: options?.locks ?? ctx.getOptional(LocksCapability),
294
295
  tenant: tenantFrom(ctx.context),
295
296
  signal: ctx.signal,
297
+ adapterName: ctx.provider,
296
298
  }
297
299
  }
298
300
 
@@ -570,7 +572,8 @@ export function withSandbox<TOffset extends string = string>(
570
572
 
571
573
  const workspace = definition.workspace
572
574
  if (workspace !== undefined) {
573
- const root = workspace.root ?? DEFAULT_WORKSPACE_ROOT
575
+ const virtualRoot = workspace.root ?? DEFAULT_WORKSPACE_ROOT
576
+ const root = resolveHarnessCwd(handle, virtualRoot)
574
577
  const workspaceHash = computeWorkspaceHash(workspace)
575
578
  const secrets = workspace.secrets
576
579
  provideWorkspaceProjection(ctx, {
package/src/sandbox.ts CHANGED
@@ -76,6 +76,8 @@ export interface SandboxEnsureContext {
76
76
  locks?: LockStore
77
77
  tenant?: { userId?: string; orgId?: string }
78
78
  signal?: AbortSignal
79
+ /** Harness adapter name (`grok-build`, `claude-code`, `codex`, `opencode`). Optional. */
80
+ adapterName?: string
79
81
  }
80
82
 
81
83
  export interface SandboxDefinition {
@@ -123,6 +125,24 @@ const DESTROY_TIMEOUT_MS = 60 * 1000
123
125
  const fallbackStore = new InMemorySandboxInstanceStore()
124
126
  const fallbackLocks = new InMemoryLockStore()
125
127
 
128
+ /**
129
+ * Put workspace secrets onto a live handle. Resume and snapshot restore skip
130
+ * bootstrap, so this is the only path that re-injects them after reconnect.
131
+ * Create injects secrets via `provider.create({ env })`, but resume/restore
132
+ * return a handle whose process env is empty unless we set it here. sbx in
133
+ * particular has no Docker Env on resume, so this is the only way secrets
134
+ * come back for that provider.
135
+ */
136
+ async function applyWorkspaceSecrets(
137
+ handle: SandboxHandle,
138
+ workspace: WorkspaceDefinition | undefined,
139
+ ): Promise<void> {
140
+ if (workspace?.secrets === undefined) return
141
+ const resolved = resolveAllSecrets(workspace.secrets)
142
+ if (Object.keys(resolved).length === 0) return
143
+ await handle.env.set(resolved)
144
+ }
145
+
126
146
  export function defineSandbox(config: SandboxConfig): SandboxDefinition {
127
147
  const keyInputFor = (ctx: SandboxEnsureContext): SandboxKeyInput => ({
128
148
  threadId:
@@ -160,6 +180,7 @@ export function defineSandbox(config: SandboxConfig): SandboxDefinition {
160
180
  signal: ctx.signal,
161
181
  })
162
182
  if (resumed) {
183
+ await applyWorkspaceSecrets(resumed, config.workspace)
163
184
  await store.upsert({
164
185
  ...existing,
165
186
  latestRunId: ctx.runId,
@@ -183,6 +204,7 @@ export function defineSandbox(config: SandboxConfig): SandboxDefinition {
183
204
  : undefined,
184
205
  signal: ctx.signal,
185
206
  })
207
+ await applyWorkspaceSecrets(restored, config.workspace)
186
208
  await store.upsert({
187
209
  ...existing,
188
210
  providerSandboxId: restored.id,
@@ -208,6 +230,7 @@ export function defineSandbox(config: SandboxConfig): SandboxDefinition {
208
230
  ? resolveAllSecrets(config.workspace.secrets)
209
231
  : undefined,
210
232
  signal: ctx.signal,
233
+ adapterName: ctx.adapterName,
211
234
  })
212
235
 
213
236
  if (config.workspace) {
@@ -38,7 +38,9 @@ export const BRIDGED_MCP_SERVER_NAME = 'tanstack'
38
38
 
39
39
  /** Hostname the sandbox uses to reach the bridge endpoint, per provider. */
40
40
  export function hostForSandbox(provider: string): string {
41
- return provider === 'docker' ? 'host.docker.internal' : '127.0.0.1'
41
+ return provider === 'docker' || provider === 'sbx'
42
+ ? 'host.docker.internal'
43
+ : '127.0.0.1'
42
44
  }
43
45
 
44
46
  /** Result of a permission decision returned to the harness's prompt tool. */