@ikenga/contract 0.3.0 → 0.4.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/engine.d.ts +509 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +79 -1
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/manifest.d.ts +829 -0
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +10 -0
- package/dist/manifest.js.map +1 -1
- package/package.json +10 -10
- package/src/engine.test.ts +205 -0
- package/src/engine.ts +428 -0
- package/src/index.ts +1 -1
- package/src/manifest.ts +12 -0
package/src/engine.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
// - engine-aider (future)
|
|
5
5
|
// - engine-noop (testing / shell-without-AI mode)
|
|
6
6
|
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
7
9
|
export interface SessionOpts {
|
|
8
10
|
cwd?: string;
|
|
9
11
|
systemPrompt?: string;
|
|
@@ -33,6 +35,94 @@ export interface McpServerSpec {
|
|
|
33
35
|
env?: Record<string, string>;
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
// ---------- Capabilities (single source of truth) ----------
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Capability flags every engine adapter advertises. This is the canonical
|
|
42
|
+
* shape consumed by both the shell-side ChatAdapter layer and any pkg that
|
|
43
|
+
* needs to reason about adapter features (wizard, settings UI, telemetry).
|
|
44
|
+
*
|
|
45
|
+
* Fields are intentionally a *superset* of what any single adapter
|
|
46
|
+
* supports — an adapter sets the ones it implements to `true` and the
|
|
47
|
+
* rest to `false`. Adding a new flag is a non-breaking schema change so
|
|
48
|
+
* long as adapters default it to `false` until they implement it.
|
|
49
|
+
*/
|
|
50
|
+
export const AgentCapabilitiesSchema = z.object({
|
|
51
|
+
/** Streams partial responses as they arrive (vs. all-at-once). */
|
|
52
|
+
streaming: z.boolean(),
|
|
53
|
+
/** Invokes external tools / function calls during a turn. */
|
|
54
|
+
toolUse: z.boolean(),
|
|
55
|
+
/** Emits an extended-thinking / reasoning channel separate from output. */
|
|
56
|
+
thinking: z.boolean(),
|
|
57
|
+
/** Produces structured artifacts (code blocks, files, images) the host renders. */
|
|
58
|
+
artifacts: z.boolean(),
|
|
59
|
+
/** Accepts file attachments as part of an input. */
|
|
60
|
+
fileAttachments: z.boolean(),
|
|
61
|
+
/** Accepts image input (vision). */
|
|
62
|
+
imageInput: z.boolean(),
|
|
63
|
+
/** Recognises a `/slash` command vocabulary. */
|
|
64
|
+
slashCommands: z.boolean(),
|
|
65
|
+
/** Lets the user switch models mid-thread. */
|
|
66
|
+
modelSwitching: z.boolean(),
|
|
67
|
+
/** Uses prompt-caching for repeated context (Anthropic-specific today). */
|
|
68
|
+
promptCaching: z.boolean(),
|
|
69
|
+
/** Runs agentic tools (recursive sub-agents, long-running loops). */
|
|
70
|
+
agenticTools: z.boolean(),
|
|
71
|
+
/** Speaks MCP — can register and route through MCP servers. */
|
|
72
|
+
mcp: z.boolean(),
|
|
73
|
+
/** Can resume a prior session by id. */
|
|
74
|
+
sessionResume: z.boolean(),
|
|
75
|
+
});
|
|
76
|
+
export type AgentCapabilities = z.infer<typeof AgentCapabilitiesSchema>;
|
|
77
|
+
|
|
78
|
+
// ---------- Engine pkg manifest "engine" block ----------
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Per-adapter onboarding requirements surfaced in the first-run wizard.
|
|
82
|
+
* The wizard composes these instead of hardcoding per-agent forms —
|
|
83
|
+
* every engine pkg owns its own setup story.
|
|
84
|
+
*/
|
|
85
|
+
export const EngineOnboardingSchema = z.object({
|
|
86
|
+
/** Stronghold-vault keys this adapter needs at runtime (e.g. `ANTHROPIC_API_KEY`). */
|
|
87
|
+
requiredVaultKeys: z.array(z.string()).default([]),
|
|
88
|
+
/** Plain env-vars the adapter expects on the host shell. */
|
|
89
|
+
requiredEnvVars: z.array(z.string()).default([]),
|
|
90
|
+
/**
|
|
91
|
+
* CLI command the user can run to authenticate. The wizard surfaces this
|
|
92
|
+
* as a copy-to-clipboard hint — it never shells out on the user's behalf.
|
|
93
|
+
*/
|
|
94
|
+
authCommand: z.string().optional(),
|
|
95
|
+
/** Docs URL for setting up this adapter. */
|
|
96
|
+
docsUrl: z.string().url().optional(),
|
|
97
|
+
});
|
|
98
|
+
export type EngineOnboarding = z.infer<typeof EngineOnboardingSchema>;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Manifest block declared by engine-* pkgs. Read by the shell's
|
|
102
|
+
* `AdapterLoader` at pkg-discovery time; consumed by the wizard to compose
|
|
103
|
+
* adapter-specific onboarding hints.
|
|
104
|
+
*/
|
|
105
|
+
export const EngineProvidesSchema = z.object({
|
|
106
|
+
/**
|
|
107
|
+
* Stable id — matches the detection-side agent id (e.g. `claude-code`,
|
|
108
|
+
* `codex`, `aider`, `noop`). The wizard's `selected_agent_id` is matched
|
|
109
|
+
* against this field at adapter-resolve time.
|
|
110
|
+
*/
|
|
111
|
+
agentId: z.string().min(1),
|
|
112
|
+
/** Display name; overrides any detection-side display if both present. */
|
|
113
|
+
display: z.string().optional(),
|
|
114
|
+
/** Snapshot of what this adapter implements. */
|
|
115
|
+
capabilities: AgentCapabilitiesSchema,
|
|
116
|
+
/** Onboarding requirements composed by the wizard. */
|
|
117
|
+
onboarding: EngineOnboardingSchema.default({
|
|
118
|
+
requiredVaultKeys: [],
|
|
119
|
+
requiredEnvVars: [],
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
export type EngineProvides = z.infer<typeof EngineProvidesSchema>;
|
|
123
|
+
|
|
124
|
+
// ---------- Engine adapter runtime contract ----------
|
|
125
|
+
|
|
36
126
|
export interface Engine {
|
|
37
127
|
/** Stable identifier — matches the pkg id of the engine adapter. */
|
|
38
128
|
readonly id: string;
|
|
@@ -40,6 +130,19 @@ export interface Engine {
|
|
|
40
130
|
/** Human-readable adapter version. */
|
|
41
131
|
readonly version: string;
|
|
42
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Static metadata copied from the loading manifest's `engine` block.
|
|
135
|
+
* Required: every adapter must surface its agentId / display / capabilities
|
|
136
|
+
* / onboarding so the shell and wizard can introspect without re-parsing
|
|
137
|
+
* the manifest.
|
|
138
|
+
*/
|
|
139
|
+
readonly metadata: {
|
|
140
|
+
agentId: string;
|
|
141
|
+
display: string;
|
|
142
|
+
capabilities: AgentCapabilities;
|
|
143
|
+
onboarding: EngineOnboarding;
|
|
144
|
+
};
|
|
145
|
+
|
|
43
146
|
/** Open a new session. Sessions are cheap; create one per pkg invocation. */
|
|
44
147
|
startSession(opts: SessionOpts): Promise<Session>;
|
|
45
148
|
|
|
@@ -55,3 +158,328 @@ export interface Engine {
|
|
|
55
158
|
/** Health check — used by the kernel before routing pkg requests. */
|
|
56
159
|
healthCheck(): Promise<{ ok: boolean; reason?: string }>;
|
|
57
160
|
}
|
|
161
|
+
|
|
162
|
+
// ---------- Adapter loader contract ----------
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Loader the shell uses to bring engine-* pkgs online at boot, tear them
|
|
166
|
+
* down on removal, and gracefully fall back when the user's
|
|
167
|
+
* `selected_agent_id` has no installed adapter.
|
|
168
|
+
*
|
|
169
|
+
* Implementation lives shell-side (post-Phase-7); this interface lets
|
|
170
|
+
* the contract pin the shape so engine pkgs and the shell agree on the
|
|
171
|
+
* load lifecycle.
|
|
172
|
+
*/
|
|
173
|
+
export interface AdapterLoader {
|
|
174
|
+
/**
|
|
175
|
+
* Load + register the engine for a given pkg manifest. The manifest must
|
|
176
|
+
* carry an `engine` block (see `EngineProvidesSchema`); the loader
|
|
177
|
+
* resolves the adapter implementation and threads the manifest's
|
|
178
|
+
* metadata into the returned `Engine.metadata`.
|
|
179
|
+
*/
|
|
180
|
+
load(manifest: { id: string; engine: EngineProvides }): Promise<Engine>;
|
|
181
|
+
|
|
182
|
+
/** Unload — used on pkg removal. After this resolves the agentId is unregistered. */
|
|
183
|
+
unload(agentId: string): Promise<void>;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Fallback returned when the requested agentId has no registered loader.
|
|
187
|
+
* Implementations MUST return a working `engine-noop` (or equivalent
|
|
188
|
+
* inert) adapter so the chat surface never dead-ends.
|
|
189
|
+
*/
|
|
190
|
+
fallback(): Engine;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ─── ACP (Agent Client Protocol) shapes ───────────────────────────────────────
|
|
194
|
+
//
|
|
195
|
+
// Phase 10: a second, ACP-shaped contract sits alongside the legacy `Engine`
|
|
196
|
+
// interface above. The two coexist while Phase 11 retires the legacy
|
|
197
|
+
// adapter. New engines (in-process Rust ACP, Node ACP sidecars, etc.) target
|
|
198
|
+
// `AcpEngine`; existing consumers keep the `Engine` shape until they migrate.
|
|
199
|
+
//
|
|
200
|
+
// The names mirror ACP's method names verbatim so the wire layer and the
|
|
201
|
+
// adapter layer share vocabulary — `newSession`, `prompt`, `cancel`,
|
|
202
|
+
// `setMode`, `loadSession`, `forkSession`, `requestPermission`.
|
|
203
|
+
|
|
204
|
+
/** ACP `ProtocolVersion`. Numeric. V1 = 1. */
|
|
205
|
+
export type AcpProtocolVersion = number;
|
|
206
|
+
|
|
207
|
+
export interface AcpInitializeRequest {
|
|
208
|
+
protocolVersion: AcpProtocolVersion;
|
|
209
|
+
/** Optional `_meta` passthrough; the in-process shell ignores it. */
|
|
210
|
+
_meta?: Record<string, unknown>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface AcpPromptCapabilities {
|
|
214
|
+
image: boolean;
|
|
215
|
+
audio: boolean;
|
|
216
|
+
embeddedContext: boolean;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface AcpMcpCapabilities {
|
|
220
|
+
http: boolean;
|
|
221
|
+
sse: boolean;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface AcpAgentCapabilities {
|
|
225
|
+
loadSession: boolean;
|
|
226
|
+
promptCapabilities: AcpPromptCapabilities;
|
|
227
|
+
mcpCapabilities: AcpMcpCapabilities;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface AcpInitializeResponse {
|
|
231
|
+
protocolVersion: AcpProtocolVersion;
|
|
232
|
+
agentCapabilities: AcpAgentCapabilities;
|
|
233
|
+
/** Authentication methods the agent supports — opaque structure passed
|
|
234
|
+
* through to the wizard. */
|
|
235
|
+
authMethods?: unknown[];
|
|
236
|
+
_meta?: Record<string, unknown>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface AcpTextContentBlock {
|
|
240
|
+
type: 'text';
|
|
241
|
+
text: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** ACP `ContentBlock::Image`. `data` is raw base64 with NO `data:` URI prefix. */
|
|
245
|
+
export interface AcpImageContentBlock {
|
|
246
|
+
type: 'image';
|
|
247
|
+
data: string;
|
|
248
|
+
mimeType: string;
|
|
249
|
+
uri?: string;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export type AcpContentBlock =
|
|
253
|
+
| AcpTextContentBlock
|
|
254
|
+
| AcpImageContentBlock
|
|
255
|
+
| { type: 'audio'; data: string; mimeType: string }
|
|
256
|
+
| { type: 'resource_link'; name: string; uri: string }
|
|
257
|
+
| { type: 'resource'; resource: unknown };
|
|
258
|
+
|
|
259
|
+
export interface AcpNewSessionRequest {
|
|
260
|
+
cwd: string;
|
|
261
|
+
mcpServers: McpServerSpec[];
|
|
262
|
+
_meta?: Record<string, unknown>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** The four canonical ACP session modes the Rust ACP server advertises. */
|
|
266
|
+
export type AcpSessionModeId = 'plan' | 'default' | 'auto' | 'bypassPermissions';
|
|
267
|
+
|
|
268
|
+
export interface AcpSessionMode {
|
|
269
|
+
id: AcpSessionModeId;
|
|
270
|
+
name: string;
|
|
271
|
+
description?: string;
|
|
272
|
+
_meta?: Record<string, unknown>;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export interface AcpSessionModes {
|
|
276
|
+
currentModeId: AcpSessionModeId;
|
|
277
|
+
availableModes: AcpSessionMode[];
|
|
278
|
+
_meta?: Record<string, unknown>;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface AcpNewSessionResponse {
|
|
282
|
+
sessionId: string;
|
|
283
|
+
modes?: AcpSessionModes;
|
|
284
|
+
models?: unknown;
|
|
285
|
+
configOptions?: unknown[];
|
|
286
|
+
_meta?: Record<string, unknown>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export interface AcpPromptRequest {
|
|
290
|
+
sessionId: string;
|
|
291
|
+
prompt: AcpContentBlock[];
|
|
292
|
+
messageId?: string;
|
|
293
|
+
_meta?: Record<string, unknown>;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export type AcpStopReason =
|
|
297
|
+
| 'end_turn'
|
|
298
|
+
| 'max_tokens'
|
|
299
|
+
| 'max_turn_requests'
|
|
300
|
+
| 'refusal'
|
|
301
|
+
| 'cancelled';
|
|
302
|
+
|
|
303
|
+
export interface AcpPromptResponse {
|
|
304
|
+
stopReason: AcpStopReason;
|
|
305
|
+
userMessageId?: string;
|
|
306
|
+
usage?: unknown;
|
|
307
|
+
_meta?: Record<string, unknown>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** ACP `SessionUpdate` discriminated union. Open-ended on the `string` tail
|
|
311
|
+
* so adapter-specific extensions don't break TS consumers. */
|
|
312
|
+
export type AcpSessionUpdate =
|
|
313
|
+
| { sessionUpdate: 'agent_message_chunk'; content: AcpContentBlock; messageId?: string }
|
|
314
|
+
| { sessionUpdate: 'agent_thought_chunk'; content: AcpContentBlock; messageId?: string }
|
|
315
|
+
| { sessionUpdate: 'user_message_chunk'; content: AcpContentBlock }
|
|
316
|
+
| {
|
|
317
|
+
sessionUpdate: 'tool_call';
|
|
318
|
+
toolCallId: string;
|
|
319
|
+
title: string;
|
|
320
|
+
kind?: string;
|
|
321
|
+
status?: string;
|
|
322
|
+
content?: unknown[];
|
|
323
|
+
rawInput?: unknown;
|
|
324
|
+
_meta?: Record<string, unknown>;
|
|
325
|
+
}
|
|
326
|
+
| {
|
|
327
|
+
sessionUpdate: 'tool_call_update';
|
|
328
|
+
toolCallId: string;
|
|
329
|
+
fields: {
|
|
330
|
+
status?: string;
|
|
331
|
+
content?: unknown[];
|
|
332
|
+
rawOutput?: unknown;
|
|
333
|
+
};
|
|
334
|
+
_meta?: Record<string, unknown>;
|
|
335
|
+
}
|
|
336
|
+
| { sessionUpdate: 'current_mode_update'; currentModeId: AcpSessionModeId }
|
|
337
|
+
| { sessionUpdate: 'plan_update'; plan: unknown }
|
|
338
|
+
| { sessionUpdate: string; [k: string]: unknown };
|
|
339
|
+
|
|
340
|
+
export interface AcpSessionNotification {
|
|
341
|
+
sessionId: string;
|
|
342
|
+
update: AcpSessionUpdate;
|
|
343
|
+
_meta?: Record<string, unknown>;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// ── Permission round-trip (Phase 4) ───────────────────────────────────────────
|
|
347
|
+
|
|
348
|
+
export type AcpPermissionOptionKind =
|
|
349
|
+
| 'allow_once'
|
|
350
|
+
| 'allow_always'
|
|
351
|
+
| 'reject_once'
|
|
352
|
+
| 'reject_always';
|
|
353
|
+
|
|
354
|
+
export interface AcpPermissionOption {
|
|
355
|
+
optionId: string;
|
|
356
|
+
name: string;
|
|
357
|
+
kind: AcpPermissionOptionKind;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
export interface AcpToolCallSummary {
|
|
361
|
+
toolCallId: string;
|
|
362
|
+
title?: string;
|
|
363
|
+
kind?: string;
|
|
364
|
+
status?: string;
|
|
365
|
+
content?: unknown[];
|
|
366
|
+
rawInput?: unknown;
|
|
367
|
+
rawOutput?: unknown;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export interface AcpRequestPermissionRequest {
|
|
371
|
+
sessionId: string;
|
|
372
|
+
toolCall: AcpToolCallSummary;
|
|
373
|
+
options: AcpPermissionOption[];
|
|
374
|
+
_meta?: Record<string, unknown>;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export type AcpRequestPermissionOutcome =
|
|
378
|
+
| { outcome: 'cancelled' }
|
|
379
|
+
| { outcome: 'selected'; optionId: string };
|
|
380
|
+
|
|
381
|
+
export interface AcpRequestPermissionResponse {
|
|
382
|
+
outcome: AcpRequestPermissionOutcome;
|
|
383
|
+
_meta?: Record<string, unknown>;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/** Wire envelope: pairs a `requestId` with the request body so the client
|
|
387
|
+
* reply can address the parked Rust-side oneshot. */
|
|
388
|
+
export interface AcpPermissionRequestEnvelope {
|
|
389
|
+
requestId: string;
|
|
390
|
+
request: AcpRequestPermissionRequest;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ── Session load + fork (Phase 8) ─────────────────────────────────────────────
|
|
394
|
+
|
|
395
|
+
export interface AcpLoadSessionResponse {
|
|
396
|
+
/** Optional mode advertisement so the picker can hydrate without paying
|
|
397
|
+
* the cold-spawn cost of `newSession`. */
|
|
398
|
+
modes?: AcpSessionModes;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface AcpForkResult {
|
|
402
|
+
newThreadId: string;
|
|
403
|
+
sourceThreadId: string;
|
|
404
|
+
branchedFromTurn?: number;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface AcpForkOpts {
|
|
408
|
+
upToTurn?: number;
|
|
409
|
+
label?: string;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// ── OS-attention notify (Phase 9) ─────────────────────────────────────────────
|
|
413
|
+
|
|
414
|
+
export type AcpNotifyKind = 'notification' | 'permissionRequest';
|
|
415
|
+
|
|
416
|
+
export interface AcpNotifyPayload {
|
|
417
|
+
threadId: string;
|
|
418
|
+
title: string;
|
|
419
|
+
body: string;
|
|
420
|
+
kind: AcpNotifyKind;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ── Engine adapter (ACP-shaped) ───────────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* ACP-shaped engine adapter. Implementations:
|
|
427
|
+
* - `pkgs/engine-claude-code` — wraps the in-process Rust ACP server.
|
|
428
|
+
* - future: `pkgs/engine-codex`, `pkgs/engine-aider` — each speaking the
|
|
429
|
+
* same wire shapes.
|
|
430
|
+
*
|
|
431
|
+
* Method names mirror ACP verbatim (`newSession`, `prompt`, `cancel`,
|
|
432
|
+
* `setMode`, `loadSession`, `forkSession`, `respondPermission`) so the wire
|
|
433
|
+
* layer, adapter layer, and host shell share one vocabulary.
|
|
434
|
+
*
|
|
435
|
+
* Subscriptions return a synchronous `() => void` unsubscribe — the
|
|
436
|
+
* implementation may resolve the underlying tauri-listener asynchronously
|
|
437
|
+
* but the caller can drop the registration immediately on unmount.
|
|
438
|
+
*/
|
|
439
|
+
export interface AcpEngine {
|
|
440
|
+
initialize(req: AcpInitializeRequest): Promise<AcpInitializeResponse>;
|
|
441
|
+
|
|
442
|
+
/** Mint a new session. The agent may lazily spawn its child on the first
|
|
443
|
+
* `prompt` rather than during `newSession` itself. */
|
|
444
|
+
newSession(req: AcpNewSessionRequest): Promise<AcpNewSessionResponse>;
|
|
445
|
+
|
|
446
|
+
/** Send a turn. Resolves when the turn ends; in-progress events flow via
|
|
447
|
+
* `onSessionUpdate`. */
|
|
448
|
+
prompt(req: AcpPromptRequest): Promise<AcpPromptResponse>;
|
|
449
|
+
|
|
450
|
+
/** Clean interrupt. Preserves the transcript and keeps the child alive
|
|
451
|
+
* for the next turn. */
|
|
452
|
+
cancel(sessionId: string): Promise<void>;
|
|
453
|
+
|
|
454
|
+
/** Switch the session's permission mode. */
|
|
455
|
+
setMode(sessionId: string, modeId: AcpSessionModeId): Promise<void>;
|
|
456
|
+
|
|
457
|
+
/** Re-attach to an existing session by id. The child stays lazy. */
|
|
458
|
+
loadSession(sessionId: string): Promise<AcpLoadSessionResponse>;
|
|
459
|
+
|
|
460
|
+
/** Clone a session from a chosen turn. The new thread inherits the source's
|
|
461
|
+
* on-disk transcript so the first prompt resumes from the cutoff. */
|
|
462
|
+
forkSession(sourceSessionId: string, opts?: AcpForkOpts): Promise<AcpForkResult>;
|
|
463
|
+
|
|
464
|
+
/** Subscribe to session updates. Returns a sync unsubscribe. */
|
|
465
|
+
onSessionUpdate(
|
|
466
|
+
sessionId: string,
|
|
467
|
+
callback: (update: AcpSessionUpdate) => void,
|
|
468
|
+
): () => void;
|
|
469
|
+
|
|
470
|
+
/** Subscribe to permission requests for this session. Reply via
|
|
471
|
+
* `respondPermission`. Returns a sync unsubscribe. */
|
|
472
|
+
onPermissionRequest(
|
|
473
|
+
sessionId: string,
|
|
474
|
+
callback: (envelope: AcpPermissionRequestEnvelope) => void,
|
|
475
|
+
): () => void;
|
|
476
|
+
|
|
477
|
+
/** Reply to a parked permission request. */
|
|
478
|
+
respondPermission(
|
|
479
|
+
requestId: string,
|
|
480
|
+
response: AcpRequestPermissionResponse,
|
|
481
|
+
): Promise<void>;
|
|
482
|
+
|
|
483
|
+
/** Subscribe to OS-attention notifications. Returns a sync unsubscribe. */
|
|
484
|
+
onNotify(callback: (payload: AcpNotifyPayload) => void): () => void;
|
|
485
|
+
}
|
package/src/index.ts
CHANGED
package/src/manifest.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// On disk: `<pkg-root>/manifest.json` (JSON, not TOML).
|
|
10
10
|
|
|
11
11
|
import { z } from 'zod';
|
|
12
|
+
import { EngineProvidesSchema } from './engine.js';
|
|
12
13
|
|
|
13
14
|
export const IKENGA_API_VERSION = 1 as const;
|
|
14
15
|
export const IKENGA_API_MIN_SUPPORTED = 1 as const;
|
|
@@ -162,9 +163,20 @@ export const ManifestSchema = z.object({
|
|
|
162
163
|
cron: z.array(CronEntrySchema).default([]),
|
|
163
164
|
window: WindowBlockSchema.optional(),
|
|
164
165
|
queries: QueriesBlockSchema.optional(),
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Engine-adapter manifest block. Present iff this pkg is an engine-*
|
|
169
|
+
* adapter. Declares the agent id, display name, capability snapshot,
|
|
170
|
+
* and onboarding hints surfaced by the first-run wizard.
|
|
171
|
+
* See `@ikenga/contract/engine` for the source-of-truth schema.
|
|
172
|
+
*/
|
|
173
|
+
engine: EngineProvidesSchema.optional(),
|
|
165
174
|
});
|
|
166
175
|
|
|
167
176
|
export type Manifest = z.infer<typeof ManifestSchema>;
|
|
177
|
+
/** Alias retained for symmetry with the Rust side / external consumers. */
|
|
178
|
+
export const PkgManifestSchema = ManifestSchema;
|
|
179
|
+
export type PkgManifest = Manifest;
|
|
168
180
|
|
|
169
181
|
// ---------- Helpers ----------
|
|
170
182
|
|