@ottimis/jack-provider-sdk 0.10.0 → 0.13.0

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.
package/src/sandbox.ts CHANGED
@@ -31,36 +31,36 @@
31
31
  */
32
32
 
33
33
  /**
34
- * Mount a provider-side config artifact (directory or file) into the
35
- * container. Most providers persist auth + sessions + per-user settings in
36
- * a dotfile dir under `$HOME` (Claude `~/.claude`, Codex `~/.codex`,
37
- * Gemini `~/.gemini`); some additionally need a sibling config file
38
- * mounted alongside (Claude `~/.claude.json` is a good example — the CLI
39
- * reads it as the "main config" separate from the dotfile dir). The host
40
- * mounts each entry into the container at {@link containerPath} so the CLI
41
- * inside the container has access to the same state as the host.
34
+ * Mount a named Docker volume into the container at {@link containerPath}.
35
+ * The pattern Anthropic recommends for CLI config dirs (see
36
+ * https://code.claude.com/docs/en/devcontainer#persist-authentication-and-settings-across-rebuilds):
37
+ * the volume is auto-created on demand, persists across container
38
+ * restarts, and isolates writes from the host filesystem entirely.
39
+ * Best fit for `~/.claude`, `~/.codex`, `~/.gemini` since they hold auth
40
+ * tokens, session JSONLs, and CLI-mutated settings.
42
41
  *
43
- * Read-only is recommended whenever the provider's CLI doesn't genuinely
44
- * need to mutate state. Set `readOnly: false` when the CLI writes back —
45
- * Claude writes session-env, project history, MCP additions; Codex appends
46
- * thread JSONL; etc. The trade-off when RW is enabled: sandbox sessions
47
- * share the same on-disk state as the host CLI (history, project state,
48
- * MCP edits). If you need credential isolation, build a copy-on-write
49
- * scratch volume — the {@link SandboxApi} contract doesn't impose one.
42
+ * Read-only is recommended whenever the CLI doesn't genuinely need to
43
+ * mutate state. Set `readOnly: false` when the CLI writes back — Claude
44
+ * writes session-env, project history, MCP additions; Codex appends
45
+ * thread JSONL; etc.
50
46
  */
51
47
  export type SandboxConfigMount = {
52
48
  /**
53
- * Absolute host path. Provider implementations resolve this lazily call
54
- * `os.homedir()` + `path.join(...)` at the time `configMounts` is read,
55
- * not at module-load time, so test environments and per-process HOME
56
- * overrides work correctly. May point to either a directory or a single
57
- * file — Docker's bind mount accepts both.
49
+ * Docker volume name. The host auto-creates the volume if missing
50
+ * (via `docker volume create <name>`). Use a stable, namespaced name
51
+ * like `jack-sandbox-<provider>-config` so volumes can be inspected
52
+ * / pruned predictably from the Docker CLI.
53
+ *
54
+ * Volumes are NOT scoped per session by default — sharing one volume
55
+ * across sandbox sessions of the same provider is the common case
56
+ * and matches Anthropic's reference. If you need per-session
57
+ * isolation, embed the session id in the name.
58
58
  */
59
- hostPath: string
59
+ readonly volumeName: string
60
60
  /** Absolute container path. */
61
- containerPath: string
61
+ readonly containerPath: string
62
62
  /** When `true`, the host adds `:ro` to the bind. */
63
- readOnly: boolean
63
+ readonly readOnly: boolean
64
64
  }
65
65
 
66
66
  /**
@@ -117,4 +117,54 @@ export interface SandboxApi {
117
117
  * sandbox even when the user has it on globally.
118
118
  */
119
119
  envExtras?(): Record<string, string>
120
+
121
+ /**
122
+ * Optional spawn-time setup hook. Runs once on the host before the
123
+ * container starts and lets the provider produce per-session artifacts
124
+ * (e.g. a sanitized `settings.json` with hooks stripped, a generated
125
+ * MCP manifest) and mount them into the container alongside the static
126
+ * {@link configMounts}.
127
+ *
128
+ * Returned `extraMounts` are appended to {@link configMounts} in
129
+ * declaration order. The `cleanup` callback (if provided) is invoked
130
+ * after the container exits so the provider can unlink temp files.
131
+ *
132
+ * Errors thrown here propagate as spawn failures — keep the work fast
133
+ * and synchronous-friendly (file I/O, not network calls).
134
+ */
135
+ prepareSpawn?(
136
+ ctx: SandboxSpawnContext
137
+ ): SandboxSpawnSetup | Promise<SandboxSpawnSetup>
138
+ }
139
+
140
+ /**
141
+ * Context passed to {@link SandboxApi.prepareSpawn}. Identifies the Jack
142
+ * session and the project root being mounted at `/workspace`. Providers
143
+ * use these to namespace temp files (one settings overlay per session)
144
+ * and avoid collisions across concurrent sandbox sessions.
145
+ */
146
+ export interface SandboxSpawnContext {
147
+ /** Stable per-session id. Safe to embed in temp filenames. */
148
+ readonly sessionId: string
149
+ /** Absolute host path mounted at `/workspace` inside the container. */
150
+ readonly projectPath: string
151
+ }
152
+
153
+ /**
154
+ * Return value of {@link SandboxApi.prepareSpawn}. Both fields optional —
155
+ * a no-op setup just returns `{}`.
156
+ */
157
+ export interface SandboxSpawnSetup {
158
+ /**
159
+ * Mounts to merge with the provider's static {@link configMounts}.
160
+ * Useful for overlaying generated files (e.g. a sanitized settings.json
161
+ * mounted on top of a config-dir mount shadows the original entry).
162
+ */
163
+ readonly extraMounts?: readonly SandboxConfigMount[]
164
+ /**
165
+ * Optional teardown. Invoked once after the container exits, even if
166
+ * the spawn fails after `prepareSpawn` resolved. Errors are logged but
167
+ * not propagated — cleanup is best-effort.
168
+ */
169
+ cleanup?(): void | Promise<void>
120
170
  }