@ottimis/jack-provider-sdk 0.9.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/dist/cjs/defaults.js +46 -0
- package/dist/cjs/defaults.js.map +1 -0
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/oneshot.js +3 -0
- package/dist/cjs/oneshot.js.map +1 -0
- package/dist/defaults.d.ts +126 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +45 -0
- package/dist/defaults.js.map +1 -0
- package/dist/host.d.ts +17 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/oneshot.d.ts +81 -0
- package/dist/oneshot.d.ts.map +1 -0
- package/dist/oneshot.js +2 -0
- package/dist/oneshot.js.map +1 -0
- package/dist/provider.d.ts +151 -2
- package/dist/provider.d.ts.map +1 -1
- package/dist/sandbox.d.ts +79 -22
- package/dist/sandbox.d.ts.map +1 -1
- package/package.json +12 -7
- package/src/defaults.ts +130 -0
- package/src/host.ts +17 -0
- package/src/index.ts +2 -0
- package/src/oneshot.ts +81 -0
- package/src/provider.ts +151 -2
- package/src/sandbox.ts +84 -22
package/src/provider.ts
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { AgentBackend, AgentPermissionMode, AgentQueryOptions, McpServerSpec } from './backend'
|
|
20
|
+
import type { ProviderDefaultsApi } from './defaults'
|
|
20
21
|
import type { HostServices } from './host'
|
|
22
|
+
import type { OneshotApi } from './oneshot'
|
|
21
23
|
import type { ProfilesApi } from './profiles'
|
|
22
24
|
import type { SandboxApi } from './sandbox'
|
|
23
25
|
import type { UsageApi } from './usage'
|
|
@@ -38,7 +40,13 @@ export type ProviderId = string
|
|
|
38
40
|
* commands carry `body` + `filePath`, builtin and wire-sourced ones
|
|
39
41
|
* don't (they don't *have* a markdown file behind them).
|
|
40
42
|
*/
|
|
41
|
-
export type SlashCommandScope =
|
|
43
|
+
export type SlashCommandScope =
|
|
44
|
+
| 'builtin'
|
|
45
|
+
| 'wire'
|
|
46
|
+
| 'user'
|
|
47
|
+
| 'project'
|
|
48
|
+
| 'jack-builtin'
|
|
49
|
+
| (string & {})
|
|
42
50
|
|
|
43
51
|
/**
|
|
44
52
|
* Common surface every slash command def carries regardless of source.
|
|
@@ -51,7 +59,7 @@ type SlashCommandDefBase = {
|
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
/**
|
|
54
|
-
* Slash-command definition surfaced by a provider.
|
|
62
|
+
* Slash-command definition surfaced by a provider. Four sources can
|
|
55
63
|
* coexist (see {@link SlashCommandSupport}):
|
|
56
64
|
*
|
|
57
65
|
* - `'builtin'` — static catalog the runtime intercepts. The renderer
|
|
@@ -64,6 +72,14 @@ type SlashCommandDefBase = {
|
|
|
64
72
|
* `filePath` + `body` are required so the renderer can offer "open
|
|
65
73
|
* in editor" affordances and the host can expand `$ARGUMENTS` /
|
|
66
74
|
* `$N` placeholders.
|
|
75
|
+
* - `'jack-builtin'` — host-shipped slash command pack distributed
|
|
76
|
+
* inside the Jack app bundle (e.g. `/changelog-turn`,
|
|
77
|
+
* `/save-decision` for the user-data-tables feature). Read-only
|
|
78
|
+
* for the user (no edit/delete), expanded the same way as
|
|
79
|
+
* `'user'/'project'` (`$ARGUMENTS` + `$N` substitution). The body
|
|
80
|
+
* comes from `resources/slash-commands/builtin/<name>.md`; the
|
|
81
|
+
* renderer treats the catalog like any file-sourced command but
|
|
82
|
+
* hides authoring affordances behind the `readonly` flag.
|
|
67
83
|
*
|
|
68
84
|
* Discriminated by `scope` so consumers narrow before reading the
|
|
69
85
|
* file-only fields. Replaces the legacy uniform shape that forced
|
|
@@ -74,6 +90,31 @@ export type SlashCommandDef =
|
|
|
74
90
|
| (SlashCommandDefBase & { scope: 'builtin' })
|
|
75
91
|
| (SlashCommandDefBase & { scope: 'wire' })
|
|
76
92
|
| (SlashCommandDefBase & { scope: 'user' | 'project'; body: string; filePath: string })
|
|
93
|
+
| (SlashCommandDefBase & { scope: 'jack-builtin'; body: string; readonly: true })
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Input shape for {@link SlashCommandSupport.createCommand}. The host
|
|
97
|
+
* collects these fields from a dialog form and hands them verbatim to
|
|
98
|
+
* the provider, which writes the markdown file in its native layout
|
|
99
|
+
* (Claude: `~/.claude/commands/<name>.md` for user scope,
|
|
100
|
+
* `<projectPath>/.claude/commands/<name>.md` for project).
|
|
101
|
+
*
|
|
102
|
+
* `name` may include subdirectory namespacing via `:` — e.g.
|
|
103
|
+
* `git:review` → file at `git/review.md` under the scope root.
|
|
104
|
+
* Provider validates the name (regex `[a-z][a-z0-9:-]*` typically) and
|
|
105
|
+
* rejects with an error when the file already exists (caller decides
|
|
106
|
+
* whether to retry with `overwrite`, omitted in v1 to avoid
|
|
107
|
+
* accidental clobbering).
|
|
108
|
+
*/
|
|
109
|
+
export type CreateSlashCommandInput = {
|
|
110
|
+
name: string
|
|
111
|
+
scope: 'user' | 'project'
|
|
112
|
+
description?: string
|
|
113
|
+
argumentHint?: string
|
|
114
|
+
body: string
|
|
115
|
+
/** Required when `scope === 'project'`. */
|
|
116
|
+
projectPath?: string
|
|
117
|
+
}
|
|
77
118
|
|
|
78
119
|
/**
|
|
79
120
|
* Parsed envelope a provider's CLI may wrap slash commands in when it logs
|
|
@@ -148,6 +189,71 @@ export type SlashCommandSupport = {
|
|
|
148
189
|
sessionId: string,
|
|
149
190
|
callback: (commands: SlashCommandDef[]) => void
|
|
150
191
|
): () => void
|
|
192
|
+
/**
|
|
193
|
+
* Authoring: create a new file-sourced slash command on disk. Only
|
|
194
|
+
* meaningful for providers that surface file-based commands (Claude
|
|
195
|
+
* `.claude/commands/*.md`); providers without an on-disk format leave
|
|
196
|
+
* this undefined and the host hides the "+ New" affordance.
|
|
197
|
+
*
|
|
198
|
+
* Contract:
|
|
199
|
+
* - Validates `input.name` against the provider's naming convention
|
|
200
|
+
* (typical regex: `[a-z][a-z0-9:-]*` with `:` for subdirectory
|
|
201
|
+
* namespacing).
|
|
202
|
+
* - Resolves the target file path under the scope root, creating
|
|
203
|
+
* intermediate directories as needed.
|
|
204
|
+
* - Refuses overwrite when the file already exists (throws an
|
|
205
|
+
* error with a stable code so the host can render a clear
|
|
206
|
+
* conflict message).
|
|
207
|
+
* - Writes frontmatter (`description`, `argument-hint`) plus the
|
|
208
|
+
* body verbatim. Returns the absolute file path.
|
|
209
|
+
*
|
|
210
|
+
* The host calls this from `provider:slash-commands:create` IPC and
|
|
211
|
+
* the new file is picked up by {@link subscribeFsChanges} so the
|
|
212
|
+
* renderer's palette refreshes without a manual reload.
|
|
213
|
+
*/
|
|
214
|
+
createCommand?(input: CreateSlashCommandInput): Promise<{ filePath: string }>
|
|
215
|
+
/**
|
|
216
|
+
* Authoring: delete a file-sourced slash command. The host passes the
|
|
217
|
+
* absolute `filePath` previously returned in a {@link SlashCommandDef}.
|
|
218
|
+
* `projectPath` (when provided) lets the provider validate
|
|
219
|
+
* project-scoped deletes too — without it, only files inside the user
|
|
220
|
+
* root are accepted (delete-by-path on a project file requires the
|
|
221
|
+
* caller to thread the project path through, which the host knows
|
|
222
|
+
* from the active session's cwd).
|
|
223
|
+
*
|
|
224
|
+
* Contract:
|
|
225
|
+
* - Verifies that `filePath` is contained inside one of the provider's
|
|
226
|
+
* known scope roots (path normalisation + `path.relative()` check)
|
|
227
|
+
* to prevent the host from accidentally requesting deletion of a
|
|
228
|
+
* file outside the slash-commands tree.
|
|
229
|
+
* - Deletes the file. Idempotent: a missing file is treated as a
|
|
230
|
+
* successful no-op (no `ENOENT` thrown).
|
|
231
|
+
*
|
|
232
|
+
* Like {@link createCommand}, omitting this field hides the "Delete"
|
|
233
|
+
* affordance for file-sourced rows in the renderer.
|
|
234
|
+
*/
|
|
235
|
+
deleteCommand?(filePath: string, projectPath?: string): Promise<{ ok: true }>
|
|
236
|
+
/**
|
|
237
|
+
* Subscribe to filesystem changes in the provider's user/project
|
|
238
|
+
* command roots. Distinct from {@link subscribeToWireCommands}: this
|
|
239
|
+
* is fs-driven (markdown files added/edited/deleted on disk),
|
|
240
|
+
* whereas the wire variant is provider-pushed runtime state.
|
|
241
|
+
*
|
|
242
|
+
* Contract:
|
|
243
|
+
* - The provider invokes the callback whenever a `.md` file under
|
|
244
|
+
* a known root is added, modified, or deleted (debounce is the
|
|
245
|
+
* provider's concern; the host treats the callback as "your
|
|
246
|
+
* cached list is stale, refetch").
|
|
247
|
+
* - The callback receives no payload — it's a stale-flag, not a
|
|
248
|
+
* diff. The host responds by re-running `scanCommands` and
|
|
249
|
+
* emitting `slashCommands:changed` to its renderers.
|
|
250
|
+
* - Returns an unsubscribe function. The host calls it on shutdown
|
|
251
|
+
* or provider switch.
|
|
252
|
+
* - Optional. Providers without a file-based source (Codex,
|
|
253
|
+
* Gemini today) leave this undefined and the host's cache is
|
|
254
|
+
* invalidated only on session boundary events.
|
|
255
|
+
*/
|
|
256
|
+
subscribeFsChanges?(callback: () => void): () => void
|
|
151
257
|
}
|
|
152
258
|
|
|
153
259
|
/**
|
|
@@ -170,6 +276,19 @@ export type ReadSessionTranscriptOptions = {
|
|
|
170
276
|
* current consumers.
|
|
171
277
|
*/
|
|
172
278
|
includeSystemMessages?: boolean
|
|
279
|
+
/**
|
|
280
|
+
* Provider-config root for transcript lookup (Claude `CLAUDE_CONFIG_DIR`,
|
|
281
|
+
* Codex `CODEX_HOME`, …). When set, the provider reads transcripts from
|
|
282
|
+
* `<configDir>/<provider-native-subpath>` instead of its implicit default
|
|
283
|
+
* — required when the session was spawned under a non-default
|
|
284
|
+
* {@link ProviderProfile} so the JSONL/rollout file resolves correctly.
|
|
285
|
+
*
|
|
286
|
+
* The host resolves this from the session's pinned `profile_id` and
|
|
287
|
+
* passes it verbatim. Providers without a profile concept ignore the
|
|
288
|
+
* field; providers with profiles MUST treat it as authoritative when
|
|
289
|
+
* present.
|
|
290
|
+
*/
|
|
291
|
+
configDir?: string
|
|
173
292
|
}
|
|
174
293
|
|
|
175
294
|
/**
|
|
@@ -298,6 +417,15 @@ export type CapabilityMatrix = {
|
|
|
298
417
|
* sandbox request returns a clear error.
|
|
299
418
|
*/
|
|
300
419
|
sandbox: boolean
|
|
420
|
+
/**
|
|
421
|
+
* Provider exposes a non-agentic single-shot completion via
|
|
422
|
+
* {@link JackProvider.oneshot}. When `false` the host hides any UI
|
|
423
|
+
* affordance that depends on it (e.g. CommitComposer's "AI commit
|
|
424
|
+
* message" button is disabled with an explanatory tooltip).
|
|
425
|
+
*
|
|
426
|
+
* When `true`, {@link JackProvider.oneshot} MUST be defined.
|
|
427
|
+
*/
|
|
428
|
+
oneshot: boolean
|
|
301
429
|
/**
|
|
302
430
|
* Permission modes the provider actually supports. Drives the
|
|
303
431
|
* Shift-Tab cycle in the renderer (`MessageInputBar`) and any
|
|
@@ -736,6 +864,27 @@ export type JackProvider = {
|
|
|
736
864
|
* mode for this provider's sessions.
|
|
737
865
|
*/
|
|
738
866
|
sandbox?: SandboxApi
|
|
867
|
+
/**
|
|
868
|
+
* One-shot completion capability — non-agentic, no tools, no session.
|
|
869
|
+
* See {@link OneshotApi}. Optional; when undefined `capabilities.oneshot`
|
|
870
|
+
* MUST be `false` and the host disables any UI affordance that relies
|
|
871
|
+
* on this primitive (e.g. CommitComposer's AI commit message button).
|
|
872
|
+
*/
|
|
873
|
+
oneshot?: OneshotApi
|
|
874
|
+
/**
|
|
875
|
+
* User-configurable defaults applied to newly-created sessions —
|
|
876
|
+
* which model, reasoning-effort tier, and permission mode the host
|
|
877
|
+
* should pre-fill on the session row when the user spawns a new
|
|
878
|
+
* session against this provider. See {@link ProviderDefaultsApi}.
|
|
879
|
+
*
|
|
880
|
+
* Optional + presence-based. A provider that omits the field doesn't
|
|
881
|
+
* appear in `Settings → Provider defaults` and no pre-fill happens for
|
|
882
|
+
* its sessions (the runtime falls back to its built-in default model /
|
|
883
|
+
* effort / permission_mode at spawn time). Catalog-only contract: the
|
|
884
|
+
* provider declares the legal values, the host owns storage (kv) and
|
|
885
|
+
* resolution.
|
|
886
|
+
*/
|
|
887
|
+
defaults?: ProviderDefaultsApi
|
|
739
888
|
/**
|
|
740
889
|
* Optional one-shot activation hook. Called once by the host during
|
|
741
890
|
* registration with a {@link HostServices} bag scoped to this
|
package/src/sandbox.ts
CHANGED
|
@@ -31,30 +31,36 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
|
-
* Mount
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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.
|
|
40
41
|
*
|
|
41
|
-
* Read-only
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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.
|
|
45
46
|
*/
|
|
46
47
|
export type SandboxConfigMount = {
|
|
47
48
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
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.
|
|
52
58
|
*/
|
|
53
|
-
|
|
59
|
+
readonly volumeName: string
|
|
54
60
|
/** Absolute container path. */
|
|
55
|
-
containerPath: string
|
|
56
|
-
/** When `true`, the host adds `:ro` to the bind.
|
|
57
|
-
readOnly: boolean
|
|
61
|
+
readonly containerPath: string
|
|
62
|
+
/** When `true`, the host adds `:ro` to the bind. */
|
|
63
|
+
readonly readOnly: boolean
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
/**
|
|
@@ -87,11 +93,17 @@ export interface SandboxApi {
|
|
|
87
93
|
readonly binaryName: string
|
|
88
94
|
|
|
89
95
|
/**
|
|
90
|
-
* Mount
|
|
91
|
-
* Optional — providers that are stateless on the host
|
|
92
|
-
* leave this undefined.
|
|
96
|
+
* Mount provider-side config artifacts (directories and/or files) into
|
|
97
|
+
* the container. Optional — providers that are stateless on the host
|
|
98
|
+
* (none today) leave this undefined or pass an empty array.
|
|
99
|
+
*
|
|
100
|
+
* Multiple entries support providers whose CLI splits state across more
|
|
101
|
+
* than one path (e.g. Claude needs both `~/.claude/` for the dotfile dir
|
|
102
|
+
* and `~/.claude.json` for the main config file). Order is preserved
|
|
103
|
+
* but mounts are independent — if two entries overlap, Docker resolves
|
|
104
|
+
* them in declaration order.
|
|
93
105
|
*/
|
|
94
|
-
readonly
|
|
106
|
+
readonly configMounts?: readonly SandboxConfigMount[]
|
|
95
107
|
|
|
96
108
|
/**
|
|
97
109
|
* Optional environment extras to inject into the container. Layered AFTER
|
|
@@ -105,4 +117,54 @@ export interface SandboxApi {
|
|
|
105
117
|
* sandbox even when the user has it on globally.
|
|
106
118
|
*/
|
|
107
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>
|
|
108
170
|
}
|