@ordewell/core 0.7.2 → 0.8.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/README.md +5 -2
- package/dist/{IFileSystem-B5asBRDa.d.mts → IFileSystem-D96mT-bm.d.ts} +1 -1
- package/dist/{IFileSystem-CbCmUDBn.d.ts → IFileSystem-DXJCRw5x.d.mts} +1 -1
- package/dist/IRunner-CGCihlGQ.d.ts +1165 -0
- package/dist/IRunner-XVUddYVX.d.mts +1165 -0
- package/dist/{ModeResolver-DtfhWeVL.d.ts → ModeResolver-DE-o2lRF.d.mts} +2 -2
- package/dist/{ModeResolver-DcqAho4y.d.mts → ModeResolver-EWlpmVAy.d.ts} +2 -2
- package/dist/Task-1Q19y7sZ.d.mts +1122 -0
- package/dist/Task-1Q19y7sZ.d.ts +1122 -0
- package/dist/{chunk-OUIQWNS3.mjs → chunk-2M4X3VB7.mjs} +15 -5
- package/dist/chunk-2M4X3VB7.mjs.map +1 -0
- package/dist/{chunk-AJ5KDO6V.mjs → chunk-BLLIBCCS.mjs} +117 -198
- package/dist/chunk-BLLIBCCS.mjs.map +1 -0
- package/dist/{chunk-MZYZS7B3.mjs → chunk-UUU46PVQ.mjs} +68 -8
- package/dist/chunk-UUU46PVQ.mjs.map +1 -0
- package/dist/index.d.mts +516 -713
- package/dist/index.d.ts +516 -713
- package/dist/index.js +5012 -6370
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3275 -4589
- package/dist/index.mjs.map +1 -1
- package/dist/order-labels.d.mts +1 -4
- package/dist/order-labels.d.ts +1 -4
- package/dist/{parsing-COFGUEWx.d.ts → parsing-CZdp2p_n.d.ts} +5 -3
- package/dist/{parsing-D0uo-Icd.d.mts → parsing-GgUJoYKs.d.mts} +5 -3
- package/dist/parsing.d.mts +3 -6
- package/dist/parsing.d.ts +3 -6
- package/dist/parsing.js +25 -4
- package/dist/parsing.js.map +1 -1
- package/dist/parsing.mjs +2 -2
- package/dist/{plan-utils-CdW3mxt5.d.mts → plan-utils-BMayhGBj.d.mts} +89 -12
- package/dist/{plan-utils-D4Z8UyLL.d.ts → plan-utils-Cv48fe7r.d.ts} +89 -12
- package/dist/plan-utils.d.mts +4 -4
- package/dist/plan-utils.d.ts +4 -4
- package/dist/plan-utils.js +120 -65
- package/dist/plan-utils.js.map +1 -1
- package/dist/plan-utils.mjs +7 -3
- package/dist/testing.d.mts +12 -24
- package/dist/testing.d.ts +12 -24
- package/dist/testing.js +24 -28
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +17 -27
- package/dist/testing.mjs.map +1 -1
- package/package.json +1 -1
- package/skills/tdd/SKILL.md +19 -0
- package/dist/Task-BpzIbunq.d.mts +0 -2599
- package/dist/Task-BpzIbunq.d.ts +0 -2599
- package/dist/chunk-AJ5KDO6V.mjs.map +0 -1
- package/dist/chunk-MZYZS7B3.mjs.map +0 -1
- package/dist/chunk-OUIQWNS3.mjs.map +0 -1
|
@@ -0,0 +1,1165 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
import { ao as UsageRecord, a8 as SubagentOutcome, W as RunnerId, ag as TaskSkillSnapshot } from './Task-1Q19y7sZ.js';
|
|
3
|
+
import { z } from 'zod/v4';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The planner's single approval seam. Every capability that reaches beyond the
|
|
7
|
+
* default read-only, in-workspace envelope — a path outside the workspace root,
|
|
8
|
+
* a shell command outside the auto-allowed set, a URL fetch — routes through
|
|
9
|
+
* one `request()` so the policy has exactly one owner (the same "one repair
|
|
10
|
+
* owner" shape as PlanRepair).
|
|
11
|
+
*
|
|
12
|
+
* Surfaces supply the human channel. VS Code answers with a modal; the web
|
|
13
|
+
* server currently has no prompt UI, so it denies unless the scope was
|
|
14
|
+
* pre-approved through config. Denial is always a visible, actionable tool
|
|
15
|
+
* result — never a silent success.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `runner_tool` is a task runner's own tool request (ADR-0018, A1): it waits
|
|
19
|
+
* for an answer as long as it takes, and never passes through the planner's
|
|
20
|
+
* policy — the runner's mode already decided it needed asking.
|
|
21
|
+
*/
|
|
22
|
+
type ApprovalKind = 'external_path' | 'shell_command' | 'url_fetch' | 'runner_tool';
|
|
23
|
+
interface ApprovalRequest {
|
|
24
|
+
kind: ApprovalKind;
|
|
25
|
+
/** The concrete thing being asked about: an absolute path, a command line, a URL. */
|
|
26
|
+
subject: string;
|
|
27
|
+
/**
|
|
28
|
+
* What a grant covers. Approving remembers this, not `subject`, so reading a
|
|
29
|
+
* second file from an already-approved directory does not prompt again.
|
|
30
|
+
*/
|
|
31
|
+
scope: string;
|
|
32
|
+
/**
|
|
33
|
+
* Every scope one answer settles, when a command needs more than one — its
|
|
34
|
+
* own and each outside directory it touches — so it prompts once rather than
|
|
35
|
+
* once per scope. `scope` is the first. Absent means `scope` alone.
|
|
36
|
+
*/
|
|
37
|
+
scopes?: string[];
|
|
38
|
+
/** One-line context for the prompt. */
|
|
39
|
+
detail?: string;
|
|
40
|
+
/** The task whose runner asked; absent for the planner's own requests. */
|
|
41
|
+
taskId?: string;
|
|
42
|
+
/** "Allow for this task" can be offered: the runner proposed its own session-scoped grant. */
|
|
43
|
+
allowForTask?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* An answer, from whoever gives it — a person on any surface, or later the
|
|
47
|
+
* supervisor (#28). `allowForTask` is Allow plus the runner's own grant for
|
|
48
|
+
* the rest of the task; `note` goes back to the agent with a denial.
|
|
49
|
+
*/
|
|
50
|
+
type ApprovalDecision = {
|
|
51
|
+
decision: 'allow';
|
|
52
|
+
} | {
|
|
53
|
+
decision: 'allowForTask';
|
|
54
|
+
} | {
|
|
55
|
+
decision: 'deny';
|
|
56
|
+
note?: string;
|
|
57
|
+
};
|
|
58
|
+
/** What an answer may be given as: a planner prompt's yes/no still is one. */
|
|
59
|
+
type ApprovalAnswer = boolean | ApprovalDecision;
|
|
60
|
+
declare function toApprovalDecision(answer: ApprovalAnswer): ApprovalDecision;
|
|
61
|
+
declare function isGranted(decision: ApprovalDecision): boolean;
|
|
62
|
+
declare function approvalScopes(request: ApprovalRequest): string[];
|
|
63
|
+
declare function isRunnerApproval(request: ApprovalRequest): boolean;
|
|
64
|
+
interface IApproval {
|
|
65
|
+
request(req: ApprovalRequest): Promise<boolean>;
|
|
66
|
+
}
|
|
67
|
+
/** Denies everything. The safe default when a surface wires no approval channel. */
|
|
68
|
+
declare const DENY_ALL: IApproval;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The tools of the Ordewell MCP server, per token role (ADR-0022), and the
|
|
72
|
+
* handler interfaces the session side implements to answer them.
|
|
73
|
+
*
|
|
74
|
+
* Every handler method is optional so each tool can be wired on its own; one
|
|
75
|
+
* left unset answers its call with a "not available" error rather than
|
|
76
|
+
* disappearing from `tools/list`, so the list a runner sees never depends on
|
|
77
|
+
* how far the wiring has got.
|
|
78
|
+
*/
|
|
79
|
+
declare const taskCompleteInput: z.ZodObject<{
|
|
80
|
+
status: z.ZodEnum<{
|
|
81
|
+
failed: "failed";
|
|
82
|
+
blocked: "blocked";
|
|
83
|
+
done: "done";
|
|
84
|
+
}>;
|
|
85
|
+
summary: z.ZodString;
|
|
86
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
declare const checkpointInput: z.ZodObject<{
|
|
89
|
+
question: z.ZodString;
|
|
90
|
+
}, z.core.$strip>;
|
|
91
|
+
declare const listRunnersInput: z.ZodObject<{}, z.core.$strip>;
|
|
92
|
+
declare const listModelsInput: z.ZodObject<{
|
|
93
|
+
runner: z.ZodString;
|
|
94
|
+
}, z.core.$strip>;
|
|
95
|
+
declare const loadSkillInput: z.ZodObject<{
|
|
96
|
+
name: z.ZodString;
|
|
97
|
+
}, z.core.$strip>;
|
|
98
|
+
declare const submitPlanInput: z.ZodObject<{
|
|
99
|
+
tasks: z.ZodArray<z.ZodObject<{
|
|
100
|
+
id: z.ZodOptional<z.ZodString>;
|
|
101
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
102
|
+
title: z.ZodString;
|
|
103
|
+
description: z.ZodOptional<z.ZodString>;
|
|
104
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
105
|
+
ai: "ai";
|
|
106
|
+
user: "user";
|
|
107
|
+
}>>;
|
|
108
|
+
dependencies: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
109
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
110
|
+
userSteps: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
111
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
112
|
+
instruction: z.ZodString;
|
|
113
|
+
}, z.core.$loose>>>;
|
|
114
|
+
assignedRunner: z.ZodOptional<z.ZodString>;
|
|
115
|
+
assignedModel: z.ZodOptional<z.ZodObject<{
|
|
116
|
+
modelId: z.ZodString;
|
|
117
|
+
modelLabel: z.ZodOptional<z.ZodString>;
|
|
118
|
+
thinkingEffort: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, z.core.$loose>>;
|
|
120
|
+
taskMode: z.ZodOptional<z.ZodString>;
|
|
121
|
+
autonomy: z.ZodOptional<z.ZodEnum<{
|
|
122
|
+
AFK: "AFK";
|
|
123
|
+
HITL: "HITL";
|
|
124
|
+
}>>;
|
|
125
|
+
sliceType: z.ZodOptional<z.ZodEnum<{
|
|
126
|
+
AFK: "AFK";
|
|
127
|
+
HITL: "HITL";
|
|
128
|
+
}>>;
|
|
129
|
+
ops: z.ZodOptional<z.ZodBoolean>;
|
|
130
|
+
userStoriesCovered: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
131
|
+
skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
132
|
+
subtasks: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
|
|
133
|
+
}, z.core.$loose>>;
|
|
134
|
+
}, z.core.$strip>;
|
|
135
|
+
declare const editPlanInput: z.ZodObject<{
|
|
136
|
+
ops: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
137
|
+
op: z.ZodLiteral<"update">;
|
|
138
|
+
taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
139
|
+
changes: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
140
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
141
|
+
op: z.ZodLiteral<"add">;
|
|
142
|
+
task: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
143
|
+
handle: z.ZodOptional<z.ZodString>;
|
|
144
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
145
|
+
op: z.ZodLiteral<"remove">;
|
|
146
|
+
taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
147
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
148
|
+
op: z.ZodLiteral<"reorder">;
|
|
149
|
+
taskIds: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
150
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
151
|
+
op: z.ZodLiteral<"merge">;
|
|
152
|
+
taskIds: z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
|
|
153
|
+
merged: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
154
|
+
handle: z.ZodOptional<z.ZodString>;
|
|
155
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
156
|
+
op: z.ZodLiteral<"split">;
|
|
157
|
+
taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
158
|
+
parts: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
159
|
+
handle: z.ZodOptional<z.ZodString>;
|
|
160
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
161
|
+
op: z.ZodLiteral<"rearm">;
|
|
162
|
+
taskId: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
163
|
+
changes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
164
|
+
}, z.core.$strip>]>>;
|
|
165
|
+
}, z.core.$strip>;
|
|
166
|
+
declare const taskQueryInput: z.ZodObject<{
|
|
167
|
+
tasks: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
|
|
168
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
169
|
+
skills: "skills";
|
|
170
|
+
description: "description";
|
|
171
|
+
prompt: "prompt";
|
|
172
|
+
userSteps: "userSteps";
|
|
173
|
+
verdict: "verdict";
|
|
174
|
+
outputSummary: "outputSummary";
|
|
175
|
+
userStoriesCovered: "userStoriesCovered";
|
|
176
|
+
}>>>;
|
|
177
|
+
catalog: z.ZodOptional<z.ZodBoolean>;
|
|
178
|
+
}, z.core.$strip>;
|
|
179
|
+
declare const taskOutputInput: z.ZodObject<{
|
|
180
|
+
task: z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>;
|
|
181
|
+
lines: z.ZodOptional<z.ZodNumber>;
|
|
182
|
+
since: z.ZodOptional<z.ZodNumber>;
|
|
183
|
+
}, z.core.$strip>;
|
|
184
|
+
type TaskCompleteArgs = z.infer<typeof taskCompleteInput>;
|
|
185
|
+
type CheckpointArgs = z.infer<typeof checkpointInput>;
|
|
186
|
+
type ListRunnersArgs = z.infer<typeof listRunnersInput>;
|
|
187
|
+
type ListModelsArgs = z.infer<typeof listModelsInput>;
|
|
188
|
+
type LoadSkillArgs = z.infer<typeof loadSkillInput>;
|
|
189
|
+
type SubmitPlanArgs = z.infer<typeof submitPlanInput>;
|
|
190
|
+
type EditPlanArgs = z.infer<typeof editPlanInput>;
|
|
191
|
+
type TaskQueryArgs = z.infer<typeof taskQueryInput>;
|
|
192
|
+
type TaskOutputArgs = z.infer<typeof taskOutputInput>;
|
|
193
|
+
/** What a handler answers with. `isError` marks a refusal the caller should act on. */
|
|
194
|
+
interface McpToolReply {
|
|
195
|
+
text: string;
|
|
196
|
+
isError?: boolean;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* How a checkpoint call ended. `withdrawn` is the attempt going away under it
|
|
200
|
+
* (verdict, cancel, retry, stop) or the call being refused, not a verdict on
|
|
201
|
+
* the question.
|
|
202
|
+
*/
|
|
203
|
+
type CheckpointAnswer = {
|
|
204
|
+
kind: 'continue';
|
|
205
|
+
} | {
|
|
206
|
+
kind: 'rejected';
|
|
207
|
+
reason: string;
|
|
208
|
+
} | {
|
|
209
|
+
kind: 'withdrawn';
|
|
210
|
+
why: string;
|
|
211
|
+
};
|
|
212
|
+
interface McpToolContext {
|
|
213
|
+
/** Aborts when the token is revoked or the caller cancels — a waiting handler must stop. */
|
|
214
|
+
signal: AbortSignal;
|
|
215
|
+
}
|
|
216
|
+
type Run<A> = (args: A, context: McpToolContext) => Promise<McpToolReply>;
|
|
217
|
+
interface TaskToolHandler {
|
|
218
|
+
taskComplete?: Run<TaskCompleteArgs>;
|
|
219
|
+
checkpoint?: Run<CheckpointArgs>;
|
|
220
|
+
}
|
|
221
|
+
interface PlannerToolHandler {
|
|
222
|
+
loadSkill?: Run<LoadSkillArgs>;
|
|
223
|
+
listRunners?: Run<ListRunnersArgs>;
|
|
224
|
+
listModels?: Run<ListModelsArgs>;
|
|
225
|
+
submitPlan?: Run<SubmitPlanArgs>;
|
|
226
|
+
editPlan?: Run<EditPlanArgs>;
|
|
227
|
+
taskQuery?: Run<TaskQueryArgs>;
|
|
228
|
+
taskOutput?: Run<TaskOutputArgs>;
|
|
229
|
+
}
|
|
230
|
+
interface McpTool<H> {
|
|
231
|
+
name: string;
|
|
232
|
+
description: string;
|
|
233
|
+
inputSchema: {
|
|
234
|
+
type: 'object';
|
|
235
|
+
[key: string]: unknown;
|
|
236
|
+
};
|
|
237
|
+
annotations?: {
|
|
238
|
+
readOnlyHint: boolean;
|
|
239
|
+
};
|
|
240
|
+
/** Validate `args` and hand them to the handler's method for this tool. */
|
|
241
|
+
call(handler: H, args: unknown, context: McpToolContext): Promise<McpToolReply>;
|
|
242
|
+
}
|
|
243
|
+
/** The task tool whose call settles the attempt (ADR-0022, V1). */
|
|
244
|
+
declare const TASK_COMPLETE_TOOL = "task_complete";
|
|
245
|
+
declare const TASK_TOOLS: readonly McpTool<TaskToolHandler>[];
|
|
246
|
+
declare const PLANNER_TOOLS: readonly McpTool<PlannerToolHandler>[];
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* The Ordewell MCP server (ADR-0022): one loopback listener per process,
|
|
250
|
+
* shared by every session in it, where the caller's token alone decides which
|
|
251
|
+
* tools it sees and which session and task its calls reach.
|
|
252
|
+
*/
|
|
253
|
+
declare const ORDEWELL_MCP_PATH = "/mcp";
|
|
254
|
+
interface OrdewellMcpServerOptions {
|
|
255
|
+
/** How often a call that is still waiting tells its caller so. */
|
|
256
|
+
heartbeatMs?: number;
|
|
257
|
+
}
|
|
258
|
+
interface TaskTokenScope {
|
|
259
|
+
sessionId: string;
|
|
260
|
+
taskId: string;
|
|
261
|
+
/** The attempt generation the token is good for; a later attempt gets a new token. */
|
|
262
|
+
attempt: number;
|
|
263
|
+
}
|
|
264
|
+
interface PlannerTokenScope {
|
|
265
|
+
sessionId: string;
|
|
266
|
+
}
|
|
267
|
+
/** Where a runner reaches the server and what it presents there. Never put either half in a prompt. */
|
|
268
|
+
interface McpCredential {
|
|
269
|
+
url: string;
|
|
270
|
+
token: string;
|
|
271
|
+
}
|
|
272
|
+
declare class OrdewellMcpServer {
|
|
273
|
+
private readonly grants;
|
|
274
|
+
private http;
|
|
275
|
+
private listening;
|
|
276
|
+
private boundUrl;
|
|
277
|
+
private boundHost;
|
|
278
|
+
private readonly heartbeatMs;
|
|
279
|
+
constructor(options?: OrdewellMcpServerOptions);
|
|
280
|
+
/** The listener's URL, once the first token has started it. */
|
|
281
|
+
get url(): string | undefined;
|
|
282
|
+
issueTaskToken(scope: TaskTokenScope, handler?: TaskToolHandler): Promise<McpCredential>;
|
|
283
|
+
issuePlannerToken(scope: PlannerTokenScope, handler?: PlannerToolHandler): Promise<McpCredential>;
|
|
284
|
+
/** Refuse every later request carrying `token`, and abort the calls it has in flight. */
|
|
285
|
+
revoke(token: string): void;
|
|
286
|
+
dispose(): Promise<void>;
|
|
287
|
+
private issue;
|
|
288
|
+
private start;
|
|
289
|
+
private handle;
|
|
290
|
+
}
|
|
291
|
+
/** The process's one server, which the daemon and the extension host hand to every session they build. */
|
|
292
|
+
declare function sharedMcpServer(): OrdewellMcpServer;
|
|
293
|
+
|
|
294
|
+
/** The server's name in every runner's MCP configuration, and so in its tool names (`mcp__ordewell__*`). */
|
|
295
|
+
declare const ORDEWELL_MCP_SERVER_NAME = "ordewell";
|
|
296
|
+
interface McpClientConfig {
|
|
297
|
+
name: typeof ORDEWELL_MCP_SERVER_NAME;
|
|
298
|
+
url: string;
|
|
299
|
+
headers: Record<string, string>;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The one shape every runner adapter renders its own MCP configuration from.
|
|
303
|
+
* The token travels only in `headers`: the adapter writes it to an owner-only
|
|
304
|
+
* file or an environment variable, never a prompt or a process argument
|
|
305
|
+
* (ADR-0022, A4/A5).
|
|
306
|
+
*/
|
|
307
|
+
declare function mcpClientConfig(credential: McpCredential): McpClientConfig;
|
|
308
|
+
/** A runner's MCP configuration on disk, and the way to take it back off. */
|
|
309
|
+
interface OwnerOnlyFile {
|
|
310
|
+
path: string;
|
|
311
|
+
/** Delete the file. Idempotent. */
|
|
312
|
+
remove(): void;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Write a configuration that carries a token where only the user can read it,
|
|
316
|
+
* for a runner that takes its MCP servers from a file (ADR-0022, A5). The
|
|
317
|
+
* directory is private too, so the name cannot be raced before the mode lands.
|
|
318
|
+
*/
|
|
319
|
+
declare function ownerOnlyConfigFile(fileName: string, contents: string): OwnerOnlyFile;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* The harness-planner transport contract (ADR-0009).
|
|
323
|
+
*
|
|
324
|
+
* One adapter per coding agent, each speaking that agent's own programmatic
|
|
325
|
+
* protocol and normalizing it to the event union below. Everything above this
|
|
326
|
+
* line — reply classification, the repair loop, plan validation, the four
|
|
327
|
+
* surfaces — is already provider-agnostic, so an adapter is the entire cost of
|
|
328
|
+
* teaching Ordewell to plan with another agent.
|
|
329
|
+
*/
|
|
330
|
+
/**
|
|
331
|
+
* One normalized event from a running agent turn. Deliberately smaller than
|
|
332
|
+
* any single agent's native protocol: this is the intersection Ordewell can act
|
|
333
|
+
* on, not a lossless re-encoding. Event fidelity differs by agent — `thinking`
|
|
334
|
+
* is rich on Claude Code and absent elsewhere — so consumers must tolerate a
|
|
335
|
+
* turn that emits nothing but `assistant_text` and `turn_end`.
|
|
336
|
+
*/
|
|
337
|
+
type AgentEvent =
|
|
338
|
+
/**
|
|
339
|
+
* A complete run of the assistant's reply. Concatenated in order to form the
|
|
340
|
+
* turn's text. When the same run already streamed as `assistant_text_delta`,
|
|
341
|
+
* this is the authoritative copy of it — it replaces the deltas, it is not
|
|
342
|
+
* appended after them.
|
|
343
|
+
*/
|
|
344
|
+
{
|
|
345
|
+
type: 'assistant_text';
|
|
346
|
+
text: string;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* An incremental piece of the assistant's reply, for agents that stream
|
|
350
|
+
* partial messages. The planner's own text only: a subagent's words never
|
|
351
|
+
* arrive here, so they can never become the reply.
|
|
352
|
+
*/
|
|
353
|
+
| {
|
|
354
|
+
type: 'assistant_text_delta';
|
|
355
|
+
text: string;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Reasoning the agent chose to expose. Never contributes to the reply text.
|
|
359
|
+
* Like `assistant_text`, it supersedes deltas already streamed for it.
|
|
360
|
+
*/
|
|
361
|
+
| {
|
|
362
|
+
type: 'thinking';
|
|
363
|
+
text: string;
|
|
364
|
+
subagentId?: string;
|
|
365
|
+
} | {
|
|
366
|
+
type: 'thinking_delta';
|
|
367
|
+
text: string;
|
|
368
|
+
subagentId?: string;
|
|
369
|
+
}
|
|
370
|
+
/** `subagentId` marks a call made inside a subagent rather than by the planner itself. */
|
|
371
|
+
| {
|
|
372
|
+
type: 'tool_call';
|
|
373
|
+
id: string;
|
|
374
|
+
name: string;
|
|
375
|
+
args: Record<string, unknown>;
|
|
376
|
+
subagentId?: string;
|
|
377
|
+
} | {
|
|
378
|
+
type: 'tool_result';
|
|
379
|
+
id: string;
|
|
380
|
+
name: string;
|
|
381
|
+
output: string;
|
|
382
|
+
success: boolean;
|
|
383
|
+
subagentId?: string;
|
|
384
|
+
}
|
|
385
|
+
/** One model call's usage, as the agent reported it — never estimated. */
|
|
386
|
+
| {
|
|
387
|
+
type: 'usage';
|
|
388
|
+
record: UsageRecord;
|
|
389
|
+
}
|
|
390
|
+
/** The agent delegated `brief` to a subagent, whose events carry `subagentId` until it finishes. */
|
|
391
|
+
| {
|
|
392
|
+
type: 'subagent_started';
|
|
393
|
+
subagentId: string;
|
|
394
|
+
brief: string;
|
|
395
|
+
model?: string;
|
|
396
|
+
} | {
|
|
397
|
+
type: 'subagent_finished';
|
|
398
|
+
subagentId: string;
|
|
399
|
+
outcome: SubagentOutcome;
|
|
400
|
+
digest: string;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* The agent asked to do something its mode does not cover. A planner always
|
|
404
|
+
* auto-denies it (T1) — a planner that can mutate is not a planner — and the
|
|
405
|
+
* adapter answers so the turn does not hang. A task's request stays open
|
|
406
|
+
* until {@link TaskModeAgentAdapter.answerPermission} (ADR-0018, A1).
|
|
407
|
+
*
|
|
408
|
+
* `input` and `suggestions` are the raw request; `suggestions` are the
|
|
409
|
+
* agent's own session-scoped grants, what "Allow for this task" answers with.
|
|
410
|
+
* `decided` marks a request the task's mode already answered — the adapter
|
|
411
|
+
* replied as the manifest says that mode does — so it is shown, never asked.
|
|
412
|
+
*/
|
|
413
|
+
| {
|
|
414
|
+
type: 'permission_request';
|
|
415
|
+
id: string;
|
|
416
|
+
name: string;
|
|
417
|
+
detail: string;
|
|
418
|
+
input?: Record<string, unknown>;
|
|
419
|
+
suggestions?: unknown[];
|
|
420
|
+
toolUseId?: string;
|
|
421
|
+
decided?: ApprovalDecision;
|
|
422
|
+
}
|
|
423
|
+
/** The agent withdrew an open request — an interrupt cancels the call it was for. It takes no answer now. */
|
|
424
|
+
| {
|
|
425
|
+
type: 'permission_cancelled';
|
|
426
|
+
id: string;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* The agent delegated work to a subagent it left running in the background,
|
|
430
|
+
* and may end its turn before that work reports. Ordewell's conversation is
|
|
431
|
+
* request/response: a turn that ends hands control back to the user, and
|
|
432
|
+
* anything the agent says afterwards arrives with no turn open and is lost.
|
|
433
|
+
* Naming the launch is what lets the service ask for the results in time.
|
|
434
|
+
*/
|
|
435
|
+
| {
|
|
436
|
+
type: 'background_agent';
|
|
437
|
+
id: string;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* The agent finished its turn and is waiting for the next user message.
|
|
441
|
+
* `interrupted` marks a turn cut short by {@link TaskModeAgentAdapter.interrupt}
|
|
442
|
+
* rather than one the agent chose to end.
|
|
443
|
+
*/
|
|
444
|
+
| {
|
|
445
|
+
type: 'turn_end';
|
|
446
|
+
interrupted?: boolean;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The model has a message handed over by {@link TaskModeAgentAdapter.steer},
|
|
450
|
+
* by the runner's own account rather than because the write succeeded
|
|
451
|
+
* (ADR-0023, D3). With no turn open, the runner opened one for it.
|
|
452
|
+
*/
|
|
453
|
+
| {
|
|
454
|
+
type: 'message_delivered';
|
|
455
|
+
id: string;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* The runner let go of a message it accepted from `steer` without showing it
|
|
459
|
+
* to the model — Codex does, for one its turn ended before consuming. It is
|
|
460
|
+
* Ordewell's to send again (ADR-0023, D4).
|
|
461
|
+
*/
|
|
462
|
+
| {
|
|
463
|
+
type: 'message_dropped';
|
|
464
|
+
id: string;
|
|
465
|
+
}
|
|
466
|
+
/** The turn failed. Carries the agent's own words — never a Ordewell paraphrase. */
|
|
467
|
+
| {
|
|
468
|
+
type: 'error';
|
|
469
|
+
message: string;
|
|
470
|
+
};
|
|
471
|
+
interface AgentStartCommon {
|
|
472
|
+
/** Workspace root. The agent works from here and, in read-only mode, cannot leave it. */
|
|
473
|
+
cwd: string;
|
|
474
|
+
/** Model id from the runner's own discovery catalog. Omitted means the agent's default. */
|
|
475
|
+
model?: string;
|
|
476
|
+
/**
|
|
477
|
+
* The agent's own session id from a previous run. For the planner a hint
|
|
478
|
+
* only: Ordewell's transcript is the source of truth (T4), so a failed resume
|
|
479
|
+
* degrades to a fresh session seeded from the stored history, not an error.
|
|
480
|
+
*/
|
|
481
|
+
resumeSessionId?: string;
|
|
482
|
+
}
|
|
483
|
+
/** The read-only planner (ADR-0008/0009). The only start `CliAgentAiService` can express. */
|
|
484
|
+
interface PlannerStartOptions extends AgentStartCommon {
|
|
485
|
+
kind: 'planner';
|
|
486
|
+
/** The planner system prompt, in its harness variant. */
|
|
487
|
+
systemPrompt: string;
|
|
488
|
+
/** Variant / reasoning effort id from that model's `variants` list. */
|
|
489
|
+
effort?: string;
|
|
490
|
+
/** The Ordewell MCP server to inject, pre-authorized (ADR-0022). Only for an adapter with {@link AgentAdapter.mcpAttached}. */
|
|
491
|
+
mcp?: McpClientConfig;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* What a runner manifest says the task's mode and effort mean (ADR-0001),
|
|
495
|
+
* resolved from the runner manifest — see `resolveTaskRunnerFlags`.
|
|
496
|
+
* The adapter adds only its protocol flags around these.
|
|
497
|
+
*/
|
|
498
|
+
interface TaskRunnerFlags {
|
|
499
|
+
/** The runner's own permission-mode value for the task's mode. */
|
|
500
|
+
permissionMode: string;
|
|
501
|
+
/** The task's raw effort id, present only alongside a model. Each adapter maps it to its own protocol. */
|
|
502
|
+
effort?: string;
|
|
503
|
+
/** The manifest's further settings for the task's mode, by setting name — see `RunnerFeatures.modeSettings`. */
|
|
504
|
+
modeSettings: Record<string, string>;
|
|
505
|
+
}
|
|
506
|
+
/** A plan task driven over the runner's programmatic protocol (ADR-0018, C1). */
|
|
507
|
+
interface TaskStartOptions extends AgentStartCommon {
|
|
508
|
+
kind: 'task';
|
|
509
|
+
/** The task's runner mode id, as the plan names it. */
|
|
510
|
+
mode: string;
|
|
511
|
+
flags: TaskRunnerFlags;
|
|
512
|
+
/**
|
|
513
|
+
* The Ordewell MCP server and this attempt's token (ADR-0022), injected
|
|
514
|
+
* with its tools pre-approved. A task is never started without it: its
|
|
515
|
+
* `task_complete` call is how it reports it is done.
|
|
516
|
+
*/
|
|
517
|
+
mcp?: McpClientConfig;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* The explicit start switch. Discriminated so that a read-only planner and a
|
|
521
|
+
* mutating task can never be confused by a missing field: every caller names
|
|
522
|
+
* which one it is starting.
|
|
523
|
+
*/
|
|
524
|
+
type AgentStartOptions = PlannerStartOptions | TaskStartOptions;
|
|
525
|
+
/** A runner asked to start in task mode that has no task-mode connector yet. */
|
|
526
|
+
declare class TaskModeUnsupportedError extends Error {
|
|
527
|
+
readonly runner: string;
|
|
528
|
+
constructor(runner: string);
|
|
529
|
+
}
|
|
530
|
+
interface AgentAdapter {
|
|
531
|
+
/** The runner id this adapter drives — `claude-code`, `codex`, `opencode`. */
|
|
532
|
+
readonly agentId: string;
|
|
533
|
+
/** Spawn the agent — read-only for a planner, in the task's mode for a task — ready to receive messages. */
|
|
534
|
+
start(opts: AgentStartOptions): Promise<void>;
|
|
535
|
+
/**
|
|
536
|
+
* Send one user message and stream the turn's events until it ends. Resolves
|
|
537
|
+
* when the agent yields the floor; rejects only when the transport itself
|
|
538
|
+
* failed in a way no `error` event could describe.
|
|
539
|
+
*
|
|
540
|
+
* `onActivity`, when given, fires on raw transport traffic — every stdio
|
|
541
|
+
* line or stream chunk the process produces — independent of whether that
|
|
542
|
+
* traffic becomes an `AgentEvent`. An adapter may legitimately emit nothing
|
|
543
|
+
* for long stretches (a subagent's filtered output, most often); a caller
|
|
544
|
+
* using presence-of-events as a liveness signal would read that silence as
|
|
545
|
+
* a hang. `onActivity` is the seam that keeps liveness detection from being
|
|
546
|
+
* coupled to what each adapter chooses to surface.
|
|
547
|
+
*/
|
|
548
|
+
send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal, onActivity?: () => void): Promise<void>;
|
|
549
|
+
/** The agent's native session id once it has announced one. Resumption hint only. */
|
|
550
|
+
nativeSessionId(): string | null;
|
|
551
|
+
/** Kill the process and release its resources. Idempotent. */
|
|
552
|
+
dispose(): void;
|
|
553
|
+
/**
|
|
554
|
+
* Whether the Ordewell MCP server passed in the start options' `mcp` is
|
|
555
|
+
* connected, as the runner itself reports it (ADR-0022, S4). Absent on an
|
|
556
|
+
* adapter that cannot inject the server at all, which cannot run tasks.
|
|
557
|
+
*/
|
|
558
|
+
mcpAttached?(): Promise<boolean>;
|
|
559
|
+
}
|
|
560
|
+
/** What an adapter adds to run a task rather than a planner (ADR-0018). */
|
|
561
|
+
interface TaskModeAgentAdapter extends AgentAdapter {
|
|
562
|
+
mcpAttached(): Promise<boolean>;
|
|
563
|
+
/**
|
|
564
|
+
* Ask the running turn to stop, keeping the process and its session. Resolves
|
|
565
|
+
* true once the agent acknowledged it; the turn then ends with
|
|
566
|
+
* `turn_end { interrupted: true }`. False means the agent did not answer
|
|
567
|
+
* within `timeoutMs`, and the caller must fall back to killing it.
|
|
568
|
+
*/
|
|
569
|
+
interrupt(timeoutMs: number): Promise<boolean>;
|
|
570
|
+
/**
|
|
571
|
+
* Registers the listener for what the agent does after a turn has ended and
|
|
572
|
+
* before the next message — a turn it opens itself when background work
|
|
573
|
+
* finishes, most often. Without one that output is dropped, which is right
|
|
574
|
+
* for a planner and wrong for a task, which may report completion there.
|
|
575
|
+
*/
|
|
576
|
+
onOutOfTurn?(listener: (event: AgentEvent) => void): void;
|
|
577
|
+
/** Registers a listener for the process ending, for any reason. Fires at most once. */
|
|
578
|
+
onProcessExit(listener: (code: number) => void): void;
|
|
579
|
+
/**
|
|
580
|
+
* Hand a message to the running turn, for the runner to show the model at
|
|
581
|
+
* its next step boundary (ADR-0023, D1–D2). Resolves true once the runner
|
|
582
|
+
* accepted it: handed over, not yet delivered — the turn's events later
|
|
583
|
+
* carry `message_delivered` or `message_dropped` for `id`. False when the
|
|
584
|
+
* runner refused it or no turn is running; the caller keeps it for the
|
|
585
|
+
* turn's end. Absent on an adapter whose runner cannot take a message
|
|
586
|
+
* mid-turn.
|
|
587
|
+
*/
|
|
588
|
+
steer?(id: string, text: string): Promise<boolean>;
|
|
589
|
+
/**
|
|
590
|
+
* Answer an open `permission_request`. False when the id is not open — it
|
|
591
|
+
* was answered, cancelled, or never asked.
|
|
592
|
+
*/
|
|
593
|
+
answerPermission(id: string, decision: ApprovalDecision): boolean;
|
|
594
|
+
}
|
|
595
|
+
type SpawnFn = (command: string, args: string[], options: {
|
|
596
|
+
env: NodeJS.ProcessEnv;
|
|
597
|
+
stdio: Array<'pipe' | 'ignore'>;
|
|
598
|
+
cwd: string;
|
|
599
|
+
/** Set by the Windows batch route, where `args` is already a quoted command line. */
|
|
600
|
+
windowsVerbatimArguments?: boolean;
|
|
601
|
+
/** Set on POSIX so the runner leads its own process group (see `spawnInOwnGroup`). */
|
|
602
|
+
detached?: boolean;
|
|
603
|
+
}) => ChildProcess;
|
|
604
|
+
/**
|
|
605
|
+
* The single injected boundary between Ordewell and the operating system.
|
|
606
|
+
* Tests feed
|
|
607
|
+
* recorded agent output through `spawn` (and, for HTTP-transport agents,
|
|
608
|
+
* `fetch`) so one test exercises adapter parsing, event mapping, reply
|
|
609
|
+
* classification and the repair loop as a single observable behavior.
|
|
610
|
+
*/
|
|
611
|
+
interface AgentProcessDeps {
|
|
612
|
+
spawn: SpawnFn;
|
|
613
|
+
fetch: typeof globalThis.fetch;
|
|
614
|
+
/** Resolves the PATH agents are spawned under. Defaults to the augmented PATH. */
|
|
615
|
+
resolvePath?: () => Promise<string>;
|
|
616
|
+
/** Host platform. Defaults to the real one; injected so OS-specific behavior is testable anywhere. */
|
|
617
|
+
platform?: NodeJS.Platform;
|
|
618
|
+
/** True when `workspace` names an existing directory. Defaults to a real filesystem check. */
|
|
619
|
+
isDirectory?: (workspace: string) => boolean;
|
|
620
|
+
/** True when `candidate` names an existing, spawnable file. Defaults to a real filesystem check. */
|
|
621
|
+
exists?: (candidate: string) => boolean;
|
|
622
|
+
/** The workspace's own variables for a cwd (ADR-0016). Defaults to {@link resolveWorkspaceEnv}. */
|
|
623
|
+
workspaceEnv?: (cwd: string) => Promise<Record<string, string>>;
|
|
624
|
+
}
|
|
625
|
+
/** Builds the adapter for one runner id, or null when that runner cannot plan. */
|
|
626
|
+
type AgentAdapterFactory = (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;
|
|
627
|
+
/**
|
|
628
|
+
* Split a stream of chunks into complete lines. Every agent transport here is
|
|
629
|
+
* newline-delimited JSON of some shape, and a chunk boundary lands mid-object
|
|
630
|
+
* often enough that parsing per-chunk silently drops events.
|
|
631
|
+
*/
|
|
632
|
+
declare class LineBuffer {
|
|
633
|
+
private buffer;
|
|
634
|
+
push(chunk: string, onLine: (line: string) => void): void;
|
|
635
|
+
/** Anything left unterminated when the stream closed. */
|
|
636
|
+
flush(): string;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
interface RunnerManifest {
|
|
640
|
+
name: string;
|
|
641
|
+
displayName: string;
|
|
642
|
+
runner: {
|
|
643
|
+
command: string;
|
|
644
|
+
};
|
|
645
|
+
features: RunnerFeatures;
|
|
646
|
+
modelDiscovery: RunnerModelDiscovery;
|
|
647
|
+
contextFile?: string;
|
|
648
|
+
contextFileAltPath?: string;
|
|
649
|
+
modes?: RunnerMode[];
|
|
650
|
+
}
|
|
651
|
+
interface RunnerFeatures {
|
|
652
|
+
permissionModeValues?: Record<string, string>;
|
|
653
|
+
modeSettings?: Record<string, Record<string, string>>;
|
|
654
|
+
}
|
|
655
|
+
type ModelDiscoveryParser = 'claude-help' | 'opencode-models' | 'opencode-models-verbose' | 'anthropic-models' | 'line-by-line' | 'json' | 'json-table';
|
|
656
|
+
interface DiscoveryCommand {
|
|
657
|
+
command: string;
|
|
658
|
+
args: string[];
|
|
659
|
+
parser?: ModelDiscoveryParser;
|
|
660
|
+
}
|
|
661
|
+
type ApiAuthMethod = {
|
|
662
|
+
type: 'env';
|
|
663
|
+
varName: string;
|
|
664
|
+
header: string;
|
|
665
|
+
prefix?: string;
|
|
666
|
+
} | {
|
|
667
|
+
type: 'file';
|
|
668
|
+
path: string;
|
|
669
|
+
jsonPath: string;
|
|
670
|
+
header: string;
|
|
671
|
+
prefix?: string;
|
|
672
|
+
};
|
|
673
|
+
interface ApiDiscoveryConfig {
|
|
674
|
+
url: string;
|
|
675
|
+
headers?: Record<string, string>;
|
|
676
|
+
auth: ApiAuthMethod[];
|
|
677
|
+
parser: ModelDiscoveryParser;
|
|
678
|
+
}
|
|
679
|
+
interface RunnerModelDiscovery {
|
|
680
|
+
method: 'command' | 'hardcoded';
|
|
681
|
+
command?: string;
|
|
682
|
+
args?: string[];
|
|
683
|
+
parser?: ModelDiscoveryParser;
|
|
684
|
+
jsonPath?: string;
|
|
685
|
+
/**
|
|
686
|
+
* Stdio JSON-RPC discovery (Codex `app-server`): spawn the command, send
|
|
687
|
+
* `initialize` then `model/list`, and read the catalog from the response.
|
|
688
|
+
* Tried BEFORE apiDiscovery and command discovery. When the call fails,
|
|
689
|
+
* `cacheFile` (the runner's own on-disk catalog cache, `~` expanded) is
|
|
690
|
+
* read before falling through to the remaining discovery methods.
|
|
691
|
+
*/
|
|
692
|
+
appServer?: {
|
|
693
|
+
command: string;
|
|
694
|
+
args: string[];
|
|
695
|
+
cacheFile?: string;
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* Optional last-resort list for a CLI that cannot enumerate
|
|
699
|
+
* models. Used only when command discovery fails entirely or the CLI is
|
|
700
|
+
* unavailable. Built-in manifests must NOT use this: anything listed here is
|
|
701
|
+
* shown to the user as available even when it isn't.
|
|
702
|
+
*/
|
|
703
|
+
fallbackModels?: {
|
|
704
|
+
modelId: string;
|
|
705
|
+
modelLabel: string;
|
|
706
|
+
}[];
|
|
707
|
+
/**
|
|
708
|
+
* Stable `--model` aliases that the runner's CLI always accepts but its help
|
|
709
|
+
* text may omit (e.g. Claude's 'haiku'). Merged into successful discovery
|
|
710
|
+
* results to fill gaps — discovered models take precedence, missing aliases
|
|
711
|
+
* are appended — and used as the last resort when discovery fails entirely.
|
|
712
|
+
* Unlike `fallbackModels`, entries must be stable CLI-accepted aliases
|
|
713
|
+
* (contracts that always resolve), not arbitrary model IDs.
|
|
714
|
+
*/
|
|
715
|
+
canonicalAliases?: {
|
|
716
|
+
modelId: string;
|
|
717
|
+
modelLabel: string;
|
|
718
|
+
}[];
|
|
719
|
+
/**
|
|
720
|
+
* HTTP API discovery — tried BEFORE command discovery. When the runner's CLI
|
|
721
|
+
* has no model-listing subcommand (Claude Code), an API endpoint can serve as
|
|
722
|
+
* the authoritative source. Auth methods are tried in order; the first that
|
|
723
|
+
* yields a token is used. If no auth method yields a token or the request
|
|
724
|
+
* fails, discovery falls through to `discoveryCommands` + `canonicalAliases`.
|
|
725
|
+
*/
|
|
726
|
+
apiDiscovery?: ApiDiscoveryConfig;
|
|
727
|
+
preferredPatterns?: {
|
|
728
|
+
id: string;
|
|
729
|
+
label: string;
|
|
730
|
+
}[];
|
|
731
|
+
variants?: {
|
|
732
|
+
id: string;
|
|
733
|
+
label: string;
|
|
734
|
+
}[];
|
|
735
|
+
discoveryCommands?: DiscoveryCommand[];
|
|
736
|
+
}
|
|
737
|
+
interface RunnerMode {
|
|
738
|
+
id: string;
|
|
739
|
+
label: string;
|
|
740
|
+
description: string;
|
|
741
|
+
/** CLI value passed to the runner's permission/mode flag. Defaults to id if omitted. */
|
|
742
|
+
cliValue?: string;
|
|
743
|
+
/** Marks this mode as the runner's most permissive mode — the resolved default when autonomous mode is ON. */
|
|
744
|
+
autonomous?: boolean;
|
|
745
|
+
/** Marks this mode as the runner's conservative build mode — the resolved default when autonomous mode is OFF. */
|
|
746
|
+
safe?: boolean;
|
|
747
|
+
}
|
|
748
|
+
interface RunnerEntry {
|
|
749
|
+
manifest: RunnerManifest;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Decides whether one out-of-envelope capability may run, and remembers the
|
|
754
|
+
* answer for the rest of the session.
|
|
755
|
+
*
|
|
756
|
+
* Grants are keyed on {@link ApprovalRequest.scope}, never on the concrete
|
|
757
|
+
* subject: approving a read of `/tmp/foo/a.log` grants `/tmp/foo/*`, and
|
|
758
|
+
* approving `az group list` grants `az group`. Without that, a planner doing
|
|
759
|
+
* real research would prompt on every single call and the feature would be
|
|
760
|
+
* unusable.
|
|
761
|
+
*
|
|
762
|
+
* `mode` is the policy floor:
|
|
763
|
+
* ask consult the human channel; no channel means deny (headless, web)
|
|
764
|
+
* allow grant everything the tier system did not already refuse
|
|
765
|
+
* deny grant nothing beyond `preApproved`
|
|
766
|
+
*
|
|
767
|
+
* Note the ordering: `preApproved` is honored under every mode including
|
|
768
|
+
* `deny`, because it is an explicit operator decision rather than a default.
|
|
769
|
+
*/
|
|
770
|
+
type ApprovalMode = 'ask' | 'allow' | 'deny';
|
|
771
|
+
interface ApprovalPolicyOptions {
|
|
772
|
+
mode?: ApprovalMode;
|
|
773
|
+
/** Scopes granted up front from config. A trailing `*` matches by prefix. */
|
|
774
|
+
preApproved?: string[];
|
|
775
|
+
/** The human channel. Absent means there is nobody to ask. */
|
|
776
|
+
ask?: (req: ApprovalRequest) => Promise<boolean>;
|
|
777
|
+
/** Called whenever a decision is reached, for surfacing in a UI or a log. */
|
|
778
|
+
onDecision?: (req: ApprovalRequest, granted: boolean, source: ApprovalSource) => void;
|
|
779
|
+
}
|
|
780
|
+
type ApprovalSource = 'pre-approved' | 'remembered' | 'mode' | 'asked' | 'no-channel';
|
|
781
|
+
declare class ApprovalPolicy implements IApproval {
|
|
782
|
+
private readonly mode;
|
|
783
|
+
private readonly preApproved;
|
|
784
|
+
private readonly asker?;
|
|
785
|
+
private readonly onDecision?;
|
|
786
|
+
private readonly granted;
|
|
787
|
+
private readonly refused;
|
|
788
|
+
/** One in-flight ask per scope: a parallel tool round must not prompt twice for the same thing. */
|
|
789
|
+
private readonly inFlight;
|
|
790
|
+
private generation;
|
|
791
|
+
constructor(opts?: ApprovalPolicyOptions);
|
|
792
|
+
request(req: ApprovalRequest): Promise<boolean>;
|
|
793
|
+
/** Scopes the user has granted this session — for display and for persistence. */
|
|
794
|
+
grantedScopes(): string[];
|
|
795
|
+
/** Drop every session-scoped decision. Called on session reset. */
|
|
796
|
+
reset(): void;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
interface CatalogModel {
|
|
800
|
+
id: string;
|
|
801
|
+
name: string;
|
|
802
|
+
description: string;
|
|
803
|
+
pricing: {
|
|
804
|
+
prompt: string;
|
|
805
|
+
completion: string;
|
|
806
|
+
};
|
|
807
|
+
contextLength: number;
|
|
808
|
+
}
|
|
809
|
+
declare class ModelCatalog {
|
|
810
|
+
static fetchModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<CatalogModel[]>;
|
|
811
|
+
/**
|
|
812
|
+
* Delete the on-disk catalog cache for a base URL so the next fetch re-runs.
|
|
813
|
+
* Used by the resolver's `invalidate()` in production (no injected fetch);
|
|
814
|
+
* best-effort — a missing file or unreadable dir is a no-op.
|
|
815
|
+
*/
|
|
816
|
+
static clearCache(baseUrl?: string): void;
|
|
817
|
+
private static readCache;
|
|
818
|
+
private static writeCache;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
interface ModelShortcut {
|
|
822
|
+
label: string;
|
|
823
|
+
id: string;
|
|
824
|
+
provider: string;
|
|
825
|
+
description: string;
|
|
826
|
+
pricing?: string;
|
|
827
|
+
}
|
|
828
|
+
declare const ORCHESTRATOR_SHORTCUTS: ModelShortcut[];
|
|
829
|
+
declare function resolveModelShortcut(input: string, shortcuts: ModelShortcut[]): string | null;
|
|
830
|
+
/**
|
|
831
|
+
* Resolves a value to a model id ONLY when it is in the supplied catalog
|
|
832
|
+
* option list — either directly or via a shortcut label. Free-typed, unknown,
|
|
833
|
+
* or not-currently-available values return null, so callers never store an id
|
|
834
|
+
* the user couldn't have selected from the list. Keeps model-setting list-only.
|
|
835
|
+
*/
|
|
836
|
+
declare function knownModelId(value: string, optionIds: string[], shortcuts: ModelShortcut[]): string | null;
|
|
837
|
+
|
|
838
|
+
type ProviderModelLists = Record<string, string[]>;
|
|
839
|
+
interface OrchestratorOption {
|
|
840
|
+
id: string;
|
|
841
|
+
label: string;
|
|
842
|
+
provider: string;
|
|
843
|
+
apiProvider: AiProvider;
|
|
844
|
+
description?: string;
|
|
845
|
+
pricing?: string;
|
|
846
|
+
/** The model's context window when the catalog reports one (#49). */
|
|
847
|
+
contextWindow?: number;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
interface FetchAllProviderModelsOptions {
|
|
851
|
+
apiKeys: Record<string, string>;
|
|
852
|
+
baseUrls: Record<string, string>;
|
|
853
|
+
fetchImpl?: typeof fetch;
|
|
854
|
+
}
|
|
855
|
+
type AllProviderModels = Record<string, CatalogModel[]>;
|
|
856
|
+
/**
|
|
857
|
+
* Result of a picker-catalog fetch fan-out: the per-provider model lists plus
|
|
858
|
+
* the per-provider failures. `errors` is keyed by provider id and holds the
|
|
859
|
+
* failure message for any provider whose catalog fetch rejected — the seam the
|
|
860
|
+
* surfaces (CLI, VS Code) use to flag "this configured provider didn't work"
|
|
861
|
+
* rather than silently showing a short list.
|
|
862
|
+
*/
|
|
863
|
+
interface ProviderModelsResult {
|
|
864
|
+
models: AllProviderModels;
|
|
865
|
+
errors: Record<string, string>;
|
|
866
|
+
}
|
|
867
|
+
/** The provider config fields the discovery fan-out needs. */
|
|
868
|
+
interface ProviderCredentialSource {
|
|
869
|
+
getProviderApiKey(provider: AiProvider): string;
|
|
870
|
+
getProviderBaseUrl(provider: AiProvider): string;
|
|
871
|
+
openaiCompatibleBaseUrl: string;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Collect the API keys and base URLs the picker fan-out should probe, applying
|
|
875
|
+
* the single "configured" policy shared by every surface (CLI + VS Code):
|
|
876
|
+
* - a preset is discovered only when it has an API key (OpenRouter included —
|
|
877
|
+
* its public catalog is not probed keyless, matching the product rule that
|
|
878
|
+
* only key-configured providers appear);
|
|
879
|
+
* - `openai_compatible` is discovered only when an explicit endpoint is set
|
|
880
|
+
* (keyless local servers like ollama / LM Studio).
|
|
881
|
+
* Base URLs are handed through only for providers that pass the gate, so the
|
|
882
|
+
* fan-out never touches an unconfigured third-party endpoint.
|
|
883
|
+
*/
|
|
884
|
+
declare function collectProviderCredentials(config: ProviderCredentialSource): {
|
|
885
|
+
apiKeys: Record<string, string>;
|
|
886
|
+
baseUrls: Record<string, string>;
|
|
887
|
+
};
|
|
888
|
+
declare function fetchAllProviderModels(opts: FetchAllProviderModelsOptions): Promise<ProviderModelsResult>;
|
|
889
|
+
declare function resolveProvider(modelId: string, providerModelLists: Record<string, string[]>): AiProvider | null;
|
|
890
|
+
declare function toOrchestratorOptions(providerModels: AllProviderModels, shortcuts: ModelShortcut[]): OrchestratorOption[];
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* Who plans. Mostly LLM vendors reached over HTTP; the last three are *harness
|
|
894
|
+
* planners* (ADR-0009) — a coding agent CLI already installed on the machine,
|
|
895
|
+
* driven as the planner over its own programmatic transport and authenticated
|
|
896
|
+
* by the subscription the user already holds. They are runners in the provider
|
|
897
|
+
* axis, deliberately: "what plans for me?" is one question, and it belongs in
|
|
898
|
+
* one setting. `isCliProvider` is the single guard that tells the two kinds
|
|
899
|
+
* apart.
|
|
900
|
+
*/
|
|
901
|
+
type AiProvider = 'google' | 'openrouter' | 'openai_compatible' | 'openai' | 'xai' | 'groq' | 'deepseek' | 'together' | 'mistral' | 'anthropic' | 'fireworks' | 'perplexity' | 'zhipu' | 'kimi' | 'cerebras' | 'deepinfra' | 'doubao' | 'qwen' | 'hunyuan' | 'baichuan' | 'minimax' | 'yi' | 'stepfun' | 'siliconflow' | 'cohere' | 'novita' | 'claude-code' | 'codex' | 'opencode';
|
|
902
|
+
interface IConfig {
|
|
903
|
+
aiProvider: AiProvider;
|
|
904
|
+
apiKey: string;
|
|
905
|
+
planningModel: string;
|
|
906
|
+
enabledRunners: string[];
|
|
907
|
+
maxParallelSessions: number;
|
|
908
|
+
researchEnabled: boolean;
|
|
909
|
+
researchMaxSteps: number;
|
|
910
|
+
researchMaxFileSize: number;
|
|
911
|
+
openAiBaseUrl: string;
|
|
912
|
+
openAiApiKey: string;
|
|
913
|
+
/** Provider keys + base URL the ModelResolver uses to fetch the picker catalogs. */
|
|
914
|
+
openrouterKey: string;
|
|
915
|
+
geminiKey: string;
|
|
916
|
+
geminiBaseUrl?: string;
|
|
917
|
+
/** Base URL + API key for a user-provided OpenAI-compatible endpoint (ollama, vLLM, LM Studio, etc.). */
|
|
918
|
+
openaiCompatibleBaseUrl: string;
|
|
919
|
+
openaiCompatibleApiKey: string;
|
|
920
|
+
orchestratorModel: string;
|
|
921
|
+
geminiModel: string;
|
|
922
|
+
/** Model for research subagents (issue #34); defaults to the (cheap) planner model. */
|
|
923
|
+
researchSubagentModel: string;
|
|
924
|
+
/**
|
|
925
|
+
* Thinking effort / model variant for a harness planner (ADR-0009), chosen
|
|
926
|
+
* from the agent's own discovered variants. Separate from the per-task
|
|
927
|
+
* efforts the plan carries — this one is the planner's own dial.
|
|
928
|
+
*/
|
|
929
|
+
plannerThinkingEffort?: string;
|
|
930
|
+
planMapEnabled: boolean;
|
|
931
|
+
autonomousMode: boolean;
|
|
932
|
+
/**
|
|
933
|
+
* Run each AI task in its own git worktree and integrate the results on a
|
|
934
|
+
* per-run branch (ADR-0013). Non-git workspaces fall back to the shared
|
|
935
|
+
* workspace root regardless of this flag.
|
|
936
|
+
*/
|
|
937
|
+
worktreeIsolation: boolean;
|
|
938
|
+
/**
|
|
939
|
+
* Shell command run in a fresh task worktree instead of symlinking ignored
|
|
940
|
+
* artifacts from the main worktree — for repos where sharing `node_modules`
|
|
941
|
+
* or a virtualenv is wrong.
|
|
942
|
+
*/
|
|
943
|
+
worktreeSetupCommand?: string;
|
|
944
|
+
/**
|
|
945
|
+
* Repositories of the repo group listed by hand, relative to the workspace
|
|
946
|
+
* (ADR-0014). When non-empty the group is exactly these, replacing the
|
|
947
|
+
* repositories auto-detected directly inside the folder; needed for ones
|
|
948
|
+
* deeper than that, which are never auto-detected.
|
|
949
|
+
*/
|
|
950
|
+
workspaceRepos: string[];
|
|
951
|
+
/**
|
|
952
|
+
* Extra paths or globs, relative to each repo root, linked from the real repo
|
|
953
|
+
* into its task worktree where they exist — gitignored local state such as
|
|
954
|
+
* `*.tfstate` that a task must use, not a copy of.
|
|
955
|
+
*/
|
|
956
|
+
worktreeLinks: string[];
|
|
957
|
+
/**
|
|
958
|
+
* How many conflict repairs one task may go through before its conflict is
|
|
959
|
+
* left for a person (ADR-0015); 0 turns repair off.
|
|
960
|
+
*/
|
|
961
|
+
conflictRepairAttempts: number;
|
|
962
|
+
/**
|
|
963
|
+
* What to do when planner research reaches outside its default envelope — an
|
|
964
|
+
* out-of-workspace path, or a shell command beyond the auto-allowed read-only
|
|
965
|
+
* set. `ask` prompts the user (and denies where no surface can prompt, such as
|
|
966
|
+
* headless runs); `allow` and `deny` skip the prompt entirely.
|
|
967
|
+
*/
|
|
968
|
+
approvalMode: ApprovalMode;
|
|
969
|
+
/** Scopes granted up front, so CI and power users never see a prompt. Trailing `*` matches by prefix. */
|
|
970
|
+
approvalPreApproved: string[];
|
|
971
|
+
/** Get the base URL for an OpenAI-compatible provider. */
|
|
972
|
+
getProviderBaseUrl(provider: AiProvider): string;
|
|
973
|
+
/** Get the API key for a provider. */
|
|
974
|
+
getProviderApiKey(provider: AiProvider): string;
|
|
975
|
+
/**
|
|
976
|
+
* Push the canonical provider routing lists in (sole producer: ModelResolver).
|
|
977
|
+
* Config consumes them when resolving a chosen model id to its serving API.
|
|
978
|
+
*/
|
|
979
|
+
setProviderModelLists(lists: ProviderModelLists): void;
|
|
980
|
+
}
|
|
981
|
+
declare function enabledRunners(cfg: IConfig): RunnerId[];
|
|
982
|
+
|
|
983
|
+
declare class RunnerRegistry {
|
|
984
|
+
private readonly runners;
|
|
985
|
+
get(id: string): RunnerEntry | undefined;
|
|
986
|
+
getManifest(id: string): RunnerManifest | undefined;
|
|
987
|
+
list(): RunnerEntry[];
|
|
988
|
+
listEnabled(config: IConfig): RunnerEntry[];
|
|
989
|
+
listEnabledIds(config: IConfig): string[];
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
/** How a structured turn ended. `failed` carries the agent's own words in the preceding `error` event. */
|
|
993
|
+
type StructuredTurnEnd = 'completed' | 'interrupted' | 'failed';
|
|
994
|
+
/**
|
|
995
|
+
* One normalized event from a structured task (ADR-0018, O1b): the adapter's
|
|
996
|
+
* events, with the turn made explicit at both ends and the message queue (M1)
|
|
997
|
+
* alongside. Subagent work carries its `subagentId`. The source for the
|
|
998
|
+
* full-fidelity task log, never for verdicts.
|
|
999
|
+
*/
|
|
1000
|
+
type StructuredEvent = Exclude<AgentEvent, {
|
|
1001
|
+
type: 'turn_end' | 'permission_cancelled' | 'message_delivered' | 'message_dropped';
|
|
1002
|
+
}>
|
|
1003
|
+
/**
|
|
1004
|
+
* `text` is the user message the turn answers; `messageId` is set when it had
|
|
1005
|
+
* waited in the queue, `forced` when it was force sent (ADR-0023, Q2).
|
|
1006
|
+
*/
|
|
1007
|
+
| {
|
|
1008
|
+
type: 'turn_start';
|
|
1009
|
+
text: string;
|
|
1010
|
+
messageId?: string;
|
|
1011
|
+
forced?: boolean;
|
|
1012
|
+
} | {
|
|
1013
|
+
type: 'turn_end';
|
|
1014
|
+
reason: StructuredTurnEnd;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Waiting in Ordewell's queue — again, for a message the runner was handed
|
|
1018
|
+
* and let go of (ADR-0023, D4). `forced` puts it ahead of the rest, behind
|
|
1019
|
+
* earlier forced ones (F2); a message already listed moves there.
|
|
1020
|
+
*/
|
|
1021
|
+
| {
|
|
1022
|
+
type: 'message_queued';
|
|
1023
|
+
messageId: string;
|
|
1024
|
+
text: string;
|
|
1025
|
+
forced?: boolean;
|
|
1026
|
+
} | {
|
|
1027
|
+
type: 'message_removed';
|
|
1028
|
+
messageId: string;
|
|
1029
|
+
} | {
|
|
1030
|
+
type: 'message_undelivered';
|
|
1031
|
+
messageId: string;
|
|
1032
|
+
text: string;
|
|
1033
|
+
}
|
|
1034
|
+
/** The runner accepted the message into its running turn; it can no longer be taken back (ADR-0023, D3). */
|
|
1035
|
+
| {
|
|
1036
|
+
type: 'message_handed_over';
|
|
1037
|
+
messageId: string;
|
|
1038
|
+
}
|
|
1039
|
+
/** The model read the message inside the running turn, at this point of it (ADR-0023, Q2). */
|
|
1040
|
+
| {
|
|
1041
|
+
type: 'message_delivered';
|
|
1042
|
+
messageId: string;
|
|
1043
|
+
text: string;
|
|
1044
|
+
}
|
|
1045
|
+
/** An open `permission_request` was answered, by whoever answered it (ADR-0018, A1). */
|
|
1046
|
+
| {
|
|
1047
|
+
type: 'permission_decided';
|
|
1048
|
+
id: string;
|
|
1049
|
+
decision: ApprovalDecision;
|
|
1050
|
+
}
|
|
1051
|
+
/** An open `permission_request` can no longer be answered: the runner withdrew it, or its process is gone. */
|
|
1052
|
+
| {
|
|
1053
|
+
type: 'permission_withdrawn';
|
|
1054
|
+
id: string;
|
|
1055
|
+
};
|
|
1056
|
+
interface QueuedTaskMessage {
|
|
1057
|
+
id: string;
|
|
1058
|
+
text: string;
|
|
1059
|
+
/** The runner has it and owes a delivery, so it cannot be taken back (ADR-0023, Q1). */
|
|
1060
|
+
handedOver?: boolean;
|
|
1061
|
+
/** Force sent: it goes out as soon as the running turn is interrupted (ADR-0023, F1). */
|
|
1062
|
+
forced?: boolean;
|
|
1063
|
+
}
|
|
1064
|
+
interface IRunnerSession {
|
|
1065
|
+
id: string;
|
|
1066
|
+
taskId: string;
|
|
1067
|
+
onOutput(callback: (text: string) => void): void;
|
|
1068
|
+
onExit(callback: (code: number) => void): void;
|
|
1069
|
+
kill(): void;
|
|
1070
|
+
getOutput(): string;
|
|
1071
|
+
write(text: string): void;
|
|
1072
|
+
/** `working` while a turn runs; `idle` between turns, waiting for a message. */
|
|
1073
|
+
turnState(): 'working' | 'idle';
|
|
1074
|
+
onTurnEnd(listener: (reason: StructuredTurnEnd) => void): void;
|
|
1075
|
+
onEvent(listener: (event: StructuredEvent) => void): void;
|
|
1076
|
+
/**
|
|
1077
|
+
* Send a user message: at once when idle; while a turn runs, handed to the
|
|
1078
|
+
* runner for its next step where it can take one, otherwise queued until
|
|
1079
|
+
* the turn ends (ADR-0023). Returns its id, for {@link removeQueued}.
|
|
1080
|
+
*/
|
|
1081
|
+
sendMessage(text: string): string;
|
|
1082
|
+
/**
|
|
1083
|
+
* Force send (ADR-0023, F1–F3): interrupt the running turn, as
|
|
1084
|
+
* {@link interrupt} does, and deliver this message as the turn that
|
|
1085
|
+
* replaces it, ahead of anything still queued. The task does not wait for
|
|
1086
|
+
* input in between. With no turn running it is {@link sendMessage}.
|
|
1087
|
+
*/
|
|
1088
|
+
forceSend(text: string): string;
|
|
1089
|
+
/** Force send a message still queued, by id. False once it was handed over or delivered. */
|
|
1090
|
+
forceSendQueued(id: string): boolean;
|
|
1091
|
+
/** Take a message back before the runner has it. False once it was handed over or delivered. */
|
|
1092
|
+
removeQueued(id: string): boolean;
|
|
1093
|
+
/** Messages not yet delivered, oldest first: queued ones, and ones handed over that the runner owes. */
|
|
1094
|
+
queued(): QueuedTaskMessage[];
|
|
1095
|
+
/**
|
|
1096
|
+
* Stop the running turn, keeping the session: a soft interrupt first, then —
|
|
1097
|
+
* if the runner does not answer in time — kill and resume. Either way the
|
|
1098
|
+
* turn ends `interrupted`. Resolves once it has.
|
|
1099
|
+
*/
|
|
1100
|
+
interrupt(): Promise<void>;
|
|
1101
|
+
/** The runner's own session id once announced — what a continue resumes (ADR-0018, K1). */
|
|
1102
|
+
nativeSessionId(): string | null;
|
|
1103
|
+
/**
|
|
1104
|
+
* Answer a `permission_request` this session emitted, by its event id. False
|
|
1105
|
+
* when it is no longer open — answered, withdrawn, or never asked.
|
|
1106
|
+
*/
|
|
1107
|
+
answerPermission(id: string, decision: ApprovalDecision): boolean;
|
|
1108
|
+
/**
|
|
1109
|
+
* The runner's `task_complete` calls on this attempt's token (ADR-0022):
|
|
1110
|
+
* the only completion evidence, for `VerdictEngine` to weigh.
|
|
1111
|
+
*/
|
|
1112
|
+
onTaskComplete(listener: (report: TaskCompleteArgs) => void): void;
|
|
1113
|
+
/**
|
|
1114
|
+
* Answers the runner's `checkpoint` calls (ADR-0022, V5): the call stays
|
|
1115
|
+
* open until the returned promise settles, and its result is the answer.
|
|
1116
|
+
* `signal` aborts when the caller goes away.
|
|
1117
|
+
*/
|
|
1118
|
+
onToolCheckpoint(handler: (question: string, signal: AbortSignal) => Promise<CheckpointAnswer>): void;
|
|
1119
|
+
}
|
|
1120
|
+
interface IRunner {
|
|
1121
|
+
spawn(opts: {
|
|
1122
|
+
taskId: string;
|
|
1123
|
+
runner: string;
|
|
1124
|
+
prompt: string;
|
|
1125
|
+
modelId?: string;
|
|
1126
|
+
thinkingEffort?: string;
|
|
1127
|
+
modelVariants?: string[];
|
|
1128
|
+
mode?: string;
|
|
1129
|
+
cwd: string;
|
|
1130
|
+
registry?: RunnerRegistry;
|
|
1131
|
+
/** Task order and title — surfaces use these to label task_started/output events. */
|
|
1132
|
+
order?: number;
|
|
1133
|
+
title?: string;
|
|
1134
|
+
/**
|
|
1135
|
+
* The owning plan session. Task ids are only unique within one plan, so
|
|
1136
|
+
* a runner that keys anything by task (the attempt's MCP token) needs this
|
|
1137
|
+
* to keep two plans' identically named tasks apart.
|
|
1138
|
+
*/
|
|
1139
|
+
planSessionId?: string;
|
|
1140
|
+
/**
|
|
1141
|
+
* The workspace's own variables (ADR-0016), under the runner's: a
|
|
1142
|
+
* manifest's env still wins over them.
|
|
1143
|
+
*/
|
|
1144
|
+
env?: Record<string, string>;
|
|
1145
|
+
/** The runner's own session to continue in (ADR-0018, K1). */
|
|
1146
|
+
resumeSessionId?: string;
|
|
1147
|
+
/**
|
|
1148
|
+
* Which run of the task this is, from 1. A structured runner binds the
|
|
1149
|
+
* attempt's MCP token to it (ADR-0022, A2).
|
|
1150
|
+
*/
|
|
1151
|
+
attempt?: number;
|
|
1152
|
+
/**
|
|
1153
|
+
* The task skills already rendered into `prompt`, as resolved for this
|
|
1154
|
+
* attempt. Runners ignore it; it is for what wraps one to record (task logs).
|
|
1155
|
+
*/
|
|
1156
|
+
skills?: readonly TaskSkillSnapshot[];
|
|
1157
|
+
/** Something the user should know about how the spawn went that did not stop it — a respawn, most often. */
|
|
1158
|
+
onNotice?: (message: string) => void;
|
|
1159
|
+
}): Promise<IRunnerSession>;
|
|
1160
|
+
stop(sessionId: string): void;
|
|
1161
|
+
stopAll(): void;
|
|
1162
|
+
activeCount: number;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
export { type RunnerManifest as $, type AgentAdapter as A, type McpToolReply as B, type CatalogModel as C, DENY_ALL as D, type EditPlanArgs as E, type FetchAllProviderModelsOptions as F, ModelCatalog as G, type ModelShortcut as H, type IApproval as I, ORDEWELL_MCP_PATH as J, ORDEWELL_MCP_SERVER_NAME as K, LineBuffer as L, type McpClientConfig as M, type OrchestratorOption as N, ORCHESTRATOR_SHORTCUTS as O, OrdewellMcpServer as P, type OwnerOnlyFile as Q, PLANNER_TOOLS as R, type PlannerStartOptions as S, type PlannerTokenScope as T, type PlannerToolHandler as U, type ProviderCredentialSource as V, type ProviderModelLists as W, type ProviderModelsResult as X, type QueuedTaskMessage as Y, type RunnerEntry as Z, type RunnerFeatures as _, type AgentAdapterFactory as a, type RunnerMode as a0, type RunnerModelDiscovery as a1, RunnerRegistry as a2, type SpawnFn as a3, type StructuredEvent as a4, type StructuredTurnEnd as a5, type SubmitPlanArgs as a6, TASK_COMPLETE_TOOL as a7, TASK_TOOLS as a8, type TaskCompleteArgs as a9, type TaskModeAgentAdapter as aa, TaskModeUnsupportedError as ab, type TaskOutputArgs as ac, type TaskQueryArgs as ad, type TaskRunnerFlags as ae, type TaskStartOptions as af, type TaskTokenScope as ag, type TaskToolHandler as ah, approvalScopes as ai, collectProviderCredentials as aj, enabledRunners as ak, fetchAllProviderModels as al, isGranted as am, isRunnerApproval as an, knownModelId as ao, mcpClientConfig as ap, ownerOnlyConfigFile as aq, resolveModelShortcut as ar, resolveProvider as as, sharedMcpServer as at, toApprovalDecision as au, toOrchestratorOptions as av, type AgentEvent as b, type AgentProcessDeps as c, type AgentStartOptions as d, type AiProvider as e, type AllProviderModels as f, type ApprovalAnswer as g, type ApprovalDecision as h, type ApprovalKind as i, type ApprovalMode as j, ApprovalPolicy as k, type ApprovalPolicyOptions as l, type ApprovalRequest as m, type ApprovalSource as n, type CheckpointAnswer as o, type CheckpointArgs as p, type DiscoveryCommand as q, type IConfig as r, type IRunner as s, type IRunnerSession as t, type ListModelsArgs as u, type ListRunnersArgs as v, type LoadSkillArgs as w, type McpCredential as x, type McpTool as y, type McpToolContext as z };
|