@ottimis/jack-provider-sdk 0.1.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.
@@ -0,0 +1,651 @@
1
+ /**
2
+ * JackProvider — plugin contract for an AI provider integration.
3
+ *
4
+ * A provider package (in-tree `providers/claude/`, future external
5
+ * `jack-codex`, `jack-gemini`, …) registers a single `JackProvider` object
6
+ * that wires up everything the host needs to drive that AI:
7
+ *
8
+ * - one or more {@link BackendDescriptor}s (the wire-protocol implementations)
9
+ * - a {@link CapabilityMatrix} so the UI knows what features to show
10
+ * - a {@link ToolDescriptor} catalog so the renderer can map provider-native
11
+ * tool names to canonical Jack shapes
12
+ * - a {@link JackProvider.detect} probe so the gate UI can warn when the
13
+ * host lacks a usable installation
14
+ *
15
+ * This file is the boundary between Jack core and a provider package — keep
16
+ * it free of provider-specific imports.
17
+ */
18
+ import type { AgentBackend, AgentQueryOptions } from './backend';
19
+ import type { ClientToolHandler, NormalizedMessage, NormalizedToolRef, ProviderUserContentPolicy, ToolShape } from '@ottimis/jack-chat-core';
20
+ export type ProviderId = string;
21
+ /**
22
+ * Slash-command definition surfaced by a provider. Different providers
23
+ * source these differently — Claude scans `.claude/commands/` and
24
+ * declares a fixed list of CLI builtins; Codex / Gemini have their own
25
+ * conventions or none at all. The rendered shape is the same.
26
+ */
27
+ export type SlashCommandDef = {
28
+ name: string;
29
+ scope: 'user' | 'project' | 'builtin';
30
+ description?: string;
31
+ argumentHint?: string;
32
+ body: string;
33
+ filePath: string;
34
+ };
35
+ /**
36
+ * Parsed envelope a provider's CLI may wrap slash commands in when it logs
37
+ * them into the session transcript. Claude uses
38
+ * `<command-name>foo</command-name><command-args>bar</command-args>` plus
39
+ * an optional `<local-command-stdout>...</local-command-stdout>`.
40
+ */
41
+ export type ParsedSlashEnvelope = {
42
+ commandName: string;
43
+ commandArgs?: string;
44
+ commandStdout?: string;
45
+ };
46
+ /**
47
+ * Provider-declared slash-command support. Every field is optional so a
48
+ * partial implementation degrades gracefully — e.g. a provider with
49
+ * builtin commands but no envelope detection just declares
50
+ * `builtins` and the host skips the envelope hook.
51
+ */
52
+ export type SlashCommandSupport = {
53
+ /** Static catalog of builtins the runtime intercepts. */
54
+ builtins: SlashCommandDef[];
55
+ /**
56
+ * Scan host filesystem for user/project file-based commands. Returns
57
+ * the catalog of file-based defs the user has authored locally. Empty
58
+ * array when the provider doesn't support file-based commands.
59
+ */
60
+ scanCommands?(projectPath?: string): Promise<SlashCommandDef[]>;
61
+ /**
62
+ * Detect the provider's slash envelope inside a user message text.
63
+ * Return null when the text doesn't match — caller renders it as a
64
+ * normal user bubble. Plumbed through `ReduceContext.parseSlashEnvelope`
65
+ * to chat-core's reducer.
66
+ */
67
+ parseEnvelope?(text: string): ParsedSlashEnvelope | null;
68
+ /**
69
+ * True when the message body is only CLI markers (e.g. Claude's
70
+ * `<local-command-stdout>...</local-command-stdout>` blobs that show
71
+ * up between turns). Used by `loadHistory` to drop noise from the
72
+ * transcript. Plumbed through `ReduceContext.isCliMarkerOnly`.
73
+ */
74
+ isCliMarkerOnly?(text: string): boolean;
75
+ /**
76
+ * Substitute the provider's argument placeholders in a file-based
77
+ * command body. Claude uses `$N` (positional) and `$ARGUMENTS` (full
78
+ * raw args). Other providers with file-based commands declare their
79
+ * own substitution rule.
80
+ */
81
+ expandBody?(def: SlashCommandDef, rawArgs: string): string;
82
+ /**
83
+ * Subscribe to wire-sourced slash command updates. Used by providers
84
+ * that surface their command catalog dynamically over the wire instead
85
+ * of (or in addition to) on-disk files — Gemini ACP emits a
86
+ * `session/update { sessionUpdate: 'available_commands_update' }`
87
+ * notification per session with the runtime command list.
88
+ *
89
+ * Contract:
90
+ * - The provider invokes the callback whenever the wire publishes a
91
+ * new catalog. The callback receives the FULL set (not a delta) so
92
+ * the host's command store can replace verbatim.
93
+ * - Returns an unsubscribe function. The host calls it on session
94
+ * close.
95
+ * - Optional. Providers without wire-driven commands (Claude file-
96
+ * based, Codex no-commands) leave it undefined and the host falls
97
+ * back to {@link builtins} + {@link scanCommands}.
98
+ *
99
+ * Wire-sourced commands COEXIST with `builtins` and `scanCommands` —
100
+ * the host merges the three sets (wire takes precedence on name
101
+ * collisions, since it reflects the agent's actual runtime state).
102
+ */
103
+ subscribeToWireCommands?(sessionId: string, callback: (commands: SlashCommandDef[]) => void): () => void;
104
+ };
105
+ /**
106
+ * Options for {@link JackProvider.readSessionTranscript}. Provider-neutral
107
+ * superset of what each backend supports — providers ignore fields they
108
+ * can't honor (e.g. a remote-only provider with no on-disk replay).
109
+ */
110
+ export type ReadSessionTranscriptOptions = {
111
+ /** Provider-side conversation id (the value persisted in `sessions.provider_session_id`). REQUIRED. */
112
+ providerSessionId: string;
113
+ /** cwd hint Claude needs to find the right `~/.claude/projects/<encoded>` dir. */
114
+ cwd?: string;
115
+ /** Cap on the number of messages returned (caller decides head vs tail). */
116
+ limit?: number;
117
+ /** Skip ahead N messages before reading (caller-driven pagination). */
118
+ offset?: number;
119
+ /**
120
+ * When true, include host-injected `system` rows (init, etc.). Default
121
+ * false matches the existing behavior of the Claude SDK loader and the
122
+ * current consumers.
123
+ */
124
+ includeSystemMessages?: boolean;
125
+ };
126
+ /**
127
+ * Provider-declared model identifiers used by host one-shot tasks. These
128
+ * are the bits of "we need to ask the model something cheap and quick"
129
+ * (session-name suggestion, agent-def suggestion, shared-template hint)
130
+ * that previously hardcoded `claude-haiku-4-5` everywhere. Each provider
131
+ * picks its own cheapest acceptable model.
132
+ */
133
+ export type ProviderModelDefaults = {
134
+ /**
135
+ * Cheapest model the host should use for one-shot suggester tasks.
136
+ * MUST be available on every account that has the provider installed —
137
+ * suggesters degrade if the user can't access it.
138
+ */
139
+ oneShot: string;
140
+ };
141
+ /**
142
+ * One entry of the inline model dropdown rendered under the chat composer.
143
+ * `value` is what gets passed to the provider's `/model` slash handler;
144
+ * `label` is the short human display (e.g. `Sonnet`, `Pro`, `Flash`).
145
+ */
146
+ export type ProviderModelOption = {
147
+ value: string;
148
+ label: string;
149
+ };
150
+ /**
151
+ * Declarative rules a provider hands the host so the host knows *how* to
152
+ * handle the provider's content — chat sanitization, future system-prompt
153
+ * injection strategy, future tool-name detection hints.
154
+ *
155
+ * Today only `userContent` is wired; new namespaces are added as additional
156
+ * optional fields without breaking external provider packages. The host
157
+ * forwards the relevant slice to its consumer:
158
+ * - `userContent` → `provider.readSessionTranscript` (on-disk replay) +
159
+ * chat-core `ReduceContext.userContentPolicy` (live wire + history).
160
+ *
161
+ * Empty / undefined fields are no-ops.
162
+ */
163
+ export type ProviderPolicies = {
164
+ userContent?: ProviderUserContentPolicy;
165
+ };
166
+ /**
167
+ * Capabilities the UI gates on. Honest declaration > aspirational —
168
+ * a provider that lies here will produce dead UI affordances.
169
+ *
170
+ * When you add a feature to Jack that depends on a provider primitive,
171
+ * add a flag here so the corresponding renderer can opt out for providers
172
+ * that don't support it.
173
+ */
174
+ export type CapabilityMatrix = {
175
+ /** Token-by-token assistant streaming (Claude `stream_event`). */
176
+ partialMessages: boolean;
177
+ /** Hook events the provider can emit. */
178
+ hooks: {
179
+ PreToolUse: boolean;
180
+ PostToolUse: boolean;
181
+ };
182
+ /** Native plan-mode primitive (Claude `ExitPlanMode`). */
183
+ planMode: boolean;
184
+ /** Native question primitive (Claude `AskUserQuestion`). */
185
+ askUserQuestion: boolean;
186
+ /** Subagent spawn: 'native' = provider has it, 'polyfill' = simulated, 'none' = absent. */
187
+ subagents: 'native' | 'polyfill' | 'none';
188
+ /** MCP (Model Context Protocol) server support. */
189
+ mcp: boolean;
190
+ /** Claude-style structuredPatch in PostToolUse for fs.edit/fs.write. */
191
+ structuredPatch: boolean;
192
+ /** Resume an existing session by id (preserves chat history across spawns). */
193
+ resumeSession: boolean;
194
+ /** Switch model live without respawn (Claude control request `set_model`). */
195
+ liveModelSwitch: boolean;
196
+ /** Switch permission mode live without respawn. */
197
+ livePermissionModeSwitch: boolean;
198
+ /**
199
+ * Permission flow granularity.
200
+ *
201
+ * - `'callback'` — the provider exposes a per-call canUseTool callback:
202
+ * each tool invocation can be blocked, modified, or auto-allowed
203
+ * before it fires (Claude). The renderer subscribes to the channel
204
+ * and the user sees every request.
205
+ * - `'sandbox-only'` — no per-call callback. The sandbox / approval
206
+ * policy is set at spawn time and the sandbox blocks violations as
207
+ * runtime errors; the model reads the error and self-corrects
208
+ * (Codex). The PermissionCard has no channel to subscribe to: the
209
+ * renderer hides it and only shows the post-fact audit log.
210
+ */
211
+ permissionGranularity: 'callback' | 'sandbox-only';
212
+ };
213
+ /**
214
+ * Re-exports of canonical wire-shape types from chat-core so consumers of
215
+ * this SDK get them at the same import path. Keeps `JackProvider` type
216
+ * definitions self-contained in this package.
217
+ */
218
+ export type { ToolShape };
219
+ export type { ClientToolHandler, ClientToolHandlerContext, ClientFsHandler, ClientTerminalHandler, ClientToolsHandler, TerminalSpec, TerminalHandle, TerminalOutput, RegisteredTool, ToolCallResult } from '@ottimis/jack-chat-core';
220
+ export type ToolDescriptor = {
221
+ /** Name as the provider emits it on the wire (e.g. 'Edit', 'apply_patch'). */
222
+ providerToolName: string;
223
+ /** Canonical shape — the renderer keys off this. */
224
+ shape: ToolShape;
225
+ /**
226
+ * Hint for renderer / analytics card classification:
227
+ *
228
+ * - `'bespoke'`: the renderer has a dedicated React card (Read,
229
+ * Write, Edit, Bash, apply_patch, …).
230
+ * - `'schema'`: the renderer uses SmartGenericRegistry to build a
231
+ * data-driven card (CronCreate, Skill, EnterPlanMode, …).
232
+ * - omitted = `'generic'` fallback (JSON renderer).
233
+ *
234
+ * MCP tools (`mcp__<slug>__<name>`) are classified separately via
235
+ * `parseToolName` → kind=mcp and don't need this flag.
236
+ */
237
+ cardStyle?: 'bespoke' | 'schema';
238
+ };
239
+ /**
240
+ * Probe result for {@link JackProvider.detect}. Used by the bootstrap
241
+ * gate UI (`ProviderGate`) to decide whether to render the rest of the
242
+ * app and, when missing or unauthenticated, what affordance to show
243
+ * (install command, sign-in flow, docs link).
244
+ *
245
+ * On the `installed: true` branch, `authenticated` is an OPTIONAL
246
+ * three-state signal:
247
+ * - `true` → credentials present and probably valid
248
+ * - `false` → binary present, credentials missing or expired
249
+ * - omitted → provider doesn't model auth (e.g. SDK that's self-contained,
250
+ * or auth is implicit via the same install)
251
+ */
252
+ export type ProviderDetectResult = {
253
+ installed: true;
254
+ /** Tri-state: true = creds present, false = creds missing/expired, undefined = N/A. */
255
+ authenticated?: boolean;
256
+ /** Human-readable reason when `authenticated: false` (e.g. "OAuth token expired"). */
257
+ authReason?: string;
258
+ /** Single-line command that authenticates (e.g. `claude login` / `codex login` / `gemini auth login`). */
259
+ signInCommand?: string;
260
+ /** External docs URL for the auth flow when distinct from install docs. */
261
+ authDocsUrl?: string;
262
+ details?: Record<string, unknown>;
263
+ } | {
264
+ installed: false;
265
+ reason: string;
266
+ probedPaths?: string[];
267
+ /** Single-line shell command that installs the missing runtime. */
268
+ installCommand?: string;
269
+ /** External docs URL pointing at the canonical install guide. */
270
+ docsUrl?: string;
271
+ };
272
+ /**
273
+ * One backend = one wire-protocol implementation. A provider can ship
274
+ * several (Claude: `sdk` bundles cli.js inside the asar, `cli` calls the
275
+ * user's locally installed binary). Selection happens via
276
+ * `JACK_AGENT_BACKEND` env var; default is `JackProvider.defaultBackendId`.
277
+ *
278
+ * `factory` is lazy so unused backends pay zero cost at boot.
279
+ */
280
+ export type BackendDescriptor = {
281
+ id: string;
282
+ label: string;
283
+ factory: () => AgentBackend;
284
+ /**
285
+ * True when the backend ships its own runtime and doesn't depend on a
286
+ * host install (e.g. Claude's `sdk` backend embeds `cli.js` inside the
287
+ * asar). The bootstrap gate skips the install-missing screen when the
288
+ * active backend is self-contained, regardless of `detect()` result.
289
+ * Defaults to `false` for backends that drive a host-installed binary.
290
+ */
291
+ selfContained?: boolean;
292
+ /**
293
+ * Backend-level capability overrides. When present, these take precedence
294
+ * over the provider-level {@link CapabilityMatrix} for sessions running
295
+ * on this backend. Provider-level remains the default for backends that
296
+ * don't override.
297
+ *
298
+ * Use case: Gemini ships `cli` (stream-json) and `acp` (JSON-RPC)
299
+ * transports with **different** feature sets — ACP exposes structured
300
+ * plan, live model switch, callback-style permission gating; stream-json
301
+ * has none. The provider declares the LCD at provider-level and ACP
302
+ * overrides the deltas. Pattern A providers (Claude SDK/CLI are wire-
303
+ * identical) typically don't need this and leave it undefined.
304
+ */
305
+ capabilities?: Partial<CapabilityMatrix>;
306
+ };
307
+ /**
308
+ * Context the host hands to {@link JackProvider.prepareSpawnOptions} so the
309
+ * provider can decide what to wire (e.g. asar-unpacked CLI path in packaged
310
+ * builds vs. a no-op in dev). Kept narrow on purpose — providers that need
311
+ * more state should read it themselves.
312
+ */
313
+ export type PrepareSpawnContext = {
314
+ /** True in packaged builds (Electron `app.isPackaged`). */
315
+ isPackaged: boolean;
316
+ };
317
+ /**
318
+ * MCP server registration in canonical Anthropic spec shape. Used by
319
+ * {@link KnowledgeContext.mcpServers} as the cross-provider exchange format
320
+ * for `kind=mcp` knowledge sources. Each provider's
321
+ * {@link JackProvider.applyKnowledgeContext} translates this into whatever
322
+ * its native runtime expects (Claude SDK `mcpServers` map; Codex
323
+ * `mcp_servers.toml`; …).
324
+ */
325
+ export type KnowledgeMcpResolution = {
326
+ type: 'stdio';
327
+ command: string;
328
+ args?: string[];
329
+ env?: Record<string, string>;
330
+ } | {
331
+ type: 'http';
332
+ url: string;
333
+ headers?: Record<string, string>;
334
+ } | {
335
+ type: 'sse';
336
+ url: string;
337
+ headers?: Record<string, string>;
338
+ };
339
+ /**
340
+ * Provider-neutral container for everything the host has computed about the
341
+ * agent's working context: the system prompt addendum (markdown), the extra
342
+ * working directories, and any MCP server registrations resolved from
343
+ * `kind=mcp` knowledge sources.
344
+ *
345
+ * The host merges multiple KnowledgeContexts (workspace context +
346
+ * AgentDefinition knowledge + per-instance overrides) into one before
347
+ * handing it to {@link JackProvider.applyKnowledgeContext}, which folds it
348
+ * into the provider's native {@link AgentQueryOptions} shape.
349
+ */
350
+ export type KnowledgeContext = {
351
+ /**
352
+ * Markdown block to append to the agent's system prompt. Already formatted
353
+ * — providers can either embed it verbatim (Claude `systemPrompt.append`)
354
+ * or split it across system / first-user message (other providers).
355
+ */
356
+ systemPromptAppend: string;
357
+ /** Absolute paths the agent should treat as part of its working set. */
358
+ directories: string[];
359
+ /** Resolved MCP server registrations keyed by slug. */
360
+ mcpServers: Record<string, KnowledgeMcpResolution>;
361
+ };
362
+ /**
363
+ * Visual identity declared by each provider. The host surfaces it in the
364
+ * chat composer + sidebar so the user sees which provider is driving a
365
+ * session at a glance.
366
+ *
367
+ * Lightweight by design — providers shouldn't need to ship images or
368
+ * elaborate themes. Renderer treats `accentColor` as a CSS color (any
369
+ * format CSS accepts) and `iconKey` as an enum of curated lucide icon
370
+ * names the renderer maps to React components. Providers that don't
371
+ * declare branding fall back to neutral defaults.
372
+ */
373
+ export type ProviderBranding = {
374
+ /**
375
+ * Primary accent color. Used as a subtle border on the chat composer +
376
+ * a small dot/icon next to the provider name in sidebar entries.
377
+ * Format: any valid CSS color (`#ff6b6b`, `oklch(...)`).
378
+ *
379
+ * Choose a color with enough contrast on both light + dark themes
380
+ * (~50% lightness works). The renderer applies it at low opacity for
381
+ * borders so vivid hex codes are fine.
382
+ */
383
+ accentColor: string;
384
+ /**
385
+ * Curated icon key — one of the names the renderer maps to a lucide
386
+ * component. Keeping this an enum (instead of free-form SVG/asset)
387
+ * means providers don't ship rendering assets and the host stays in
388
+ * control of what shapes can land in the UI.
389
+ */
390
+ iconKey?: string;
391
+ };
392
+ export type JackProvider = {
393
+ id: ProviderId;
394
+ label: string;
395
+ /**
396
+ * Visual identity (accent color + icon) the renderer can use to mark
397
+ * which provider drives a session. Optional; renderer falls back to
398
+ * neutral host theme when absent.
399
+ */
400
+ branding?: ProviderBranding;
401
+ /**
402
+ * Probe the host to see if the provider is usable (binary installed,
403
+ * credentials present, …). Surface result in the bootstrap gate.
404
+ */
405
+ detect(): Promise<ProviderDetectResult>;
406
+ backends: BackendDescriptor[];
407
+ /** Must match one of `backends[].id`. Used when no env override is set. */
408
+ defaultBackendId: string;
409
+ capabilities: CapabilityMatrix;
410
+ /**
411
+ * Declarative rules that tell the host how to interpret this provider's
412
+ * data. Distinct from {@link CapabilityMatrix} (what the provider CAN do
413
+ * — drives UI gating) — `policies` say *how* the host should handle
414
+ * content the provider emits or persists. Provider authors declare them
415
+ * statically; the host consumes them at well-defined entry points
416
+ * (`readSessionTranscript`, chat-core reducer via ReduceContext, …).
417
+ *
418
+ * Optional everywhere: a provider that doesn't need any rule simply
419
+ * omits the field. New rule namespaces grow {@link ProviderPolicies}
420
+ * without breaking existing providers.
421
+ */
422
+ policies?: ProviderPolicies;
423
+ /**
424
+ * Default model identifiers for host one-shot tasks. Read by suggester
425
+ * call sites (session naming, agent-def hint, shared-template hint) so
426
+ * they don't hardcode a Claude-specific model.
427
+ */
428
+ modelDefaults: ProviderModelDefaults;
429
+ /**
430
+ * Options surfaced in the inline Model dropdown under the chat composer.
431
+ * Empty / omitted = no Model dropdown rendered (regardless of
432
+ * `liveModelSwitch`). Selection fires the provider's `/model <value>`
433
+ * slash handler. Hardcoded list is fine for providers with a fixed
434
+ * family (Claude: opus/sonnet/haiku); providers whose available models
435
+ * are dynamic per-session (Gemini's `availableModels[]`) leave this
436
+ * empty until a per-session push lands.
437
+ */
438
+ modelOptions?: readonly ProviderModelOption[];
439
+ /**
440
+ * Reasoning-effort tiers surfaced in the inline Effort dropdown.
441
+ * Empty / omitted = no Effort dropdown rendered. Selection fires the
442
+ * provider's `/effort <value>` slash handler. Only Claude exposes
443
+ * effort tiers as a live switch; other providers (Codex via
444
+ * spawn-time, Gemini not at all) leave this empty.
445
+ */
446
+ effortLevels?: readonly string[];
447
+ /**
448
+ * Tools the provider surfaces in `tool_use` messages, with their
449
+ * canonical shape. Tools not listed fall back to the generic renderer.
450
+ * The `mcp__` prefixed tools are dynamic and resolved at runtime, not
451
+ * declared here.
452
+ */
453
+ toolCatalog: ToolDescriptor[];
454
+ /**
455
+ * Optional hook called by the host right before each `backend.query()`
456
+ * so the provider can wire packaging-specific spawn details (e.g.
457
+ * Claude's SDK backend pointing at an asar-unpacked `cli.js` and the
458
+ * macOS Electron Helper). Mutate `options` in place. Called once per
459
+ * spawn, after the host has already populated `cwd`, `mcpServers`,
460
+ * knowledge context, and any sandbox `spawner`. No-op for providers
461
+ * that don't need it (CLI-only, dev-only, …).
462
+ */
463
+ prepareSpawnOptions?(options: AgentQueryOptions, ctx: PrepareSpawnContext): void;
464
+ /**
465
+ * Parse a wire tool name into a {@link NormalizedToolRef}. Each provider
466
+ * owns its own naming convention (Claude: `mcp__<slug>__<tool>` for MCP,
467
+ * literal name for native; Codex: `apply_patch` style; …). The host
468
+ * calls this whenever it needs to reason about a tool name without
469
+ * committing to a specific provider's format — e.g. detecting Jack's
470
+ * own MCP tools, MCP card classification, audit logs.
471
+ */
472
+ parseToolName(rawName: string): NormalizedToolRef;
473
+ /**
474
+ * Optional slash-command support. Providers that surface a `/command`
475
+ * UX (Claude's `.claude/commands/`, the `<command-name>` envelope in
476
+ * transcripts, etc.) declare it here; providers without any slash
477
+ * convention (Codex, Gemini, …) leave it undefined and the renderer
478
+ * hides the slash autocomplete + skips envelope detection.
479
+ */
480
+ slashCommands?: SlashCommandSupport;
481
+ /**
482
+ * Fold a provider-neutral {@link KnowledgeContext} into the provider's
483
+ * native {@link AgentQueryOptions} shape. Mutates `options` in place.
484
+ *
485
+ * Claude maps the three fields onto SDK options:
486
+ * - `systemPromptAppend` → `systemPrompt.append`
487
+ * - `directories` → `additionalDirectories`
488
+ * - `mcpServers` → `mcpServers`
489
+ *
490
+ * Other providers may package the same data differently (e.g. Codex
491
+ * inlines MCP into a config TOML and treats `directories` as sandbox
492
+ * mount points). Called once per spawn, after the host has merged
493
+ * workspace context + AgentDefinition knowledge + per-instance
494
+ * overrides into a single {@link KnowledgeContext}.
495
+ */
496
+ applyKnowledgeContext(context: KnowledgeContext, options: AgentQueryOptions): void;
497
+ /**
498
+ * Read a session's persisted transcript and return it as
499
+ * {@link NormalizedMessage}[]. Replaces direct `getSessionMessages`
500
+ * calls sprinkled across the host (indexer, mobile routes, IPC, name
501
+ * suggester) — those used to import from the Claude SDK and would
502
+ * crash for any other provider. Now they go through this hook.
503
+ *
504
+ * Implementations MUST:
505
+ * - return rows in chronological order (oldest first)
506
+ * - populate `messageId` on every message that has one in the source
507
+ * (Claude JSONL `uuid` → top-level `messageId`)
508
+ * - preserve `raw` verbatim (lossless)
509
+ *
510
+ * Returns an empty array when the session has no transcript yet (e.g.
511
+ * fresh row, never sent a turn).
512
+ */
513
+ readSessionTranscript(opts: ReadSessionTranscriptOptions): Promise<NormalizedMessage[]>;
514
+ /**
515
+ * Attach an in-process MCP server to the spawn options. Used by the
516
+ * host to expose Jack-specific tools to the agent (e.g. partner
517
+ * transcript reader for reviewer/tester slots in pair mode) without
518
+ * going through an external MCP process.
519
+ *
520
+ * Provider-neutral spec: the host hands name/version + tool list, the
521
+ * provider wraps them into whatever shape its SDK accepts. Optional —
522
+ * providers without an in-process MCP API simply omit this method, and
523
+ * the host quietly degrades (the agent doesn't get the Jack tools).
524
+ *
525
+ * Claude wraps via `createSdkMcpServer` + `tool` from the agent SDK.
526
+ * Codex SDK has no in-process MCP — global `codex mcp add` only — so
527
+ * `codexProvider` leaves this undefined and pair-mode reviewers
528
+ * running on Codex don't get `get_partner_transcript`. Documented
529
+ * limitation.
530
+ */
531
+ attachInProcessMcpServer?(options: AgentQueryOptions, spec: InProcessMcpServerSpec): void;
532
+ /**
533
+ * Pattern B (ACP-speaking providers like jack-gemini): the host injects
534
+ * a {@link ClientToolHandler} the provider invokes for fs/terminal/tools
535
+ * execution requested by the agent over JSON-RPC. The provider stores
536
+ * the reference and routes ACP `fs/*`, `terminal/*`, `tools/*` requests
537
+ * through it instead of calling `node:fs` / `node-pty` directly.
538
+ *
539
+ * Pattern A providers (Claude, Codex) leave this undefined; the host
540
+ * detects the pattern by absence and skips wiring.
541
+ *
542
+ * `ctx` carries the host's correlation ids the provider may want to
543
+ * bridge to wire-driven side channels (e.g. mapping
544
+ * `available_commands_update` notifications back to the renderer's
545
+ * slash command store via the host's session id). Optional for
546
+ * providers that don't need it.
547
+ */
548
+ attachClientToolHandler?(handler: ClientToolHandler, ctx?: {
549
+ jackSessionId?: string;
550
+ }): void;
551
+ /**
552
+ * Persisted permission rules manager. The host's
553
+ * `permissions:{list,add,remove}` IPC dispatches through this — providers
554
+ * that don't persist permission rules (sandbox-only models like Codex)
555
+ * leave it undefined and the host returns empty snapshots.
556
+ */
557
+ persistedPermissions?: PersistedPermissionsApi;
558
+ };
559
+ /**
560
+ * Provider-neutral spec for an in-process MCP server the host wants to
561
+ * expose to the agent. Each tool carries a zod schema for argument
562
+ * validation + an async handler that produces MCP `content` blocks.
563
+ *
564
+ * Mirrors the surface of Claude's `tool()` factory but stays SDK-free
565
+ * here so non-Claude providers can implement
566
+ * {@link JackProvider.attachInProcessMcpServer} without dragging in
567
+ * `@anthropic-ai/claude-agent-sdk`.
568
+ */
569
+ export type InProcessMcpServerSpec = {
570
+ name: string;
571
+ version: string;
572
+ tools: InProcessMcpToolSpec[];
573
+ };
574
+ /**
575
+ * Behaviour token the provider persists alongside each rule. Mirror of
576
+ * Claude's `permissions.{allow,deny,ask}` arrays — providers with a
577
+ * different vocabulary translate to/from this enum at their boundary.
578
+ */
579
+ export type PermissionBehavior = 'allow' | 'deny' | 'ask';
580
+ /**
581
+ * Layer the rule lives in. The four-way split mirrors Claude's
582
+ * user/userLocal/project/projectLocal settings cascade. Providers that
583
+ * persist fewer layers populate only the relevant blocks; consumers see
584
+ * empty arrays for the rest.
585
+ */
586
+ export type PermissionSource = 'user' | 'userLocal' | 'project' | 'projectLocal';
587
+ /**
588
+ * One persisted rule as the provider stores it. `tool` + `pattern` are a
589
+ * convenience parse — `raw` is the source of truth for round-trip writes
590
+ * (remove/add use the raw string verbatim).
591
+ */
592
+ export type PermissionRule = {
593
+ /** Tool name (e.g. `Bash`, `Edit`, `mcp__figma__authenticate`). */
594
+ tool: string;
595
+ /** Content inside the parens (the glob / pattern), or null if the rule has no parens. */
596
+ pattern: string | null;
597
+ /** Original string as stored in the settings file — source of truth for round-trip writes. */
598
+ raw: string;
599
+ };
600
+ export type PermissionsSourceBlock = {
601
+ source: PermissionSource;
602
+ /** Absolute path of the settings file (null if no project context was provided). */
603
+ path: string | null;
604
+ /** True if the file currently exists on disk. */
605
+ exists: boolean;
606
+ allow: PermissionRule[];
607
+ deny: PermissionRule[];
608
+ ask: PermissionRule[];
609
+ };
610
+ export type PermissionsSnapshot = {
611
+ user: PermissionsSourceBlock;
612
+ userLocal: PermissionsSourceBlock;
613
+ project: PermissionsSourceBlock;
614
+ projectLocal: PermissionsSourceBlock;
615
+ };
616
+ /**
617
+ * Persisted permission rules manager — provider-declared, optional. The
618
+ * host's `permissions:list/add/remove` IPC dispatches through the active
619
+ * provider's implementation. Providers without a persisted permissions
620
+ * model leave this undefined and the host returns empty snapshots.
621
+ *
622
+ * The neutral shape (four sources × three behaviours × `tool(pattern)`
623
+ * rules) was generalised from Claude's `.claude/settings*.json` cascade
624
+ * but stays generic enough for other providers' approval-policy stores.
625
+ * A provider with a different vocabulary (e.g. Codex `approval_policy`
626
+ * keyed by command prefix) translates inside this method.
627
+ */
628
+ export type PersistedPermissionsApi = {
629
+ list(projectPath?: string): PermissionsSnapshot;
630
+ remove(source: PermissionSource, behavior: PermissionBehavior, rawRule: string, projectPath?: string): boolean;
631
+ add(source: PermissionSource, behavior: PermissionBehavior, rawRule: string, projectPath?: string): boolean;
632
+ };
633
+ export type InProcessMcpToolSpec = {
634
+ name: string;
635
+ description: string;
636
+ /**
637
+ * Zod schema for the tool arguments. Providers that don't speak zod
638
+ * natively can call `.shape` to inspect fields. We keep zod here
639
+ * instead of JSON Schema because the host already uses it everywhere
640
+ * (one source of truth for tool shapes).
641
+ */
642
+ schema: Record<string, unknown>;
643
+ handler: (args: Record<string, unknown>) => Promise<{
644
+ content: Array<{
645
+ type: 'text';
646
+ text: string;
647
+ }>;
648
+ isError?: boolean;
649
+ }>;
650
+ };
651
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}