@ordewell/core 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/LICENSE +211 -0
- package/README.md +37 -0
- package/dist/ITerminalRunner-Bbpe8uts.d.ts +535 -0
- package/dist/ITerminalRunner-D8Bf-HD4.d.mts +535 -0
- package/dist/Task-1NwmUImI.d.mts +264 -0
- package/dist/Task-1NwmUImI.d.ts +264 -0
- package/dist/chunk-4KIWPW4K.mjs +510 -0
- package/dist/chunk-4KIWPW4K.mjs.map +1 -0
- package/dist/chunk-SRGQBGI5.mjs +463 -0
- package/dist/chunk-SRGQBGI5.mjs.map +1 -0
- package/dist/chunk-YXAIQKVE.mjs +398 -0
- package/dist/chunk-YXAIQKVE.mjs.map +1 -0
- package/dist/index.d.mts +2990 -0
- package/dist/index.d.ts +2990 -0
- package/dist/index.js +12927 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +11449 -0
- package/dist/index.mjs.map +1 -0
- package/dist/parsing-RjN9JbyG.d.ts +161 -0
- package/dist/parsing-xpozY5ac.d.mts +161 -0
- package/dist/parsing.d.mts +2 -0
- package/dist/parsing.d.ts +2 -0
- package/dist/parsing.js +432 -0
- package/dist/parsing.js.map +1 -0
- package/dist/parsing.mjs +15 -0
- package/dist/parsing.mjs.map +1 -0
- package/dist/plan-utils-Cgc0cCH1.d.ts +111 -0
- package/dist/plan-utils-nfHKSbd3.d.mts +111 -0
- package/dist/plan-utils.d.mts +2 -0
- package/dist/plan-utils.d.ts +2 -0
- package/dist/plan-utils.js +181 -0
- package/dist/plan-utils.js.map +1 -0
- package/dist/plan-utils.mjs +18 -0
- package/dist/plan-utils.mjs.map +1 -0
- package/dist/testing.d.mts +28 -0
- package/dist/testing.d.ts +28 -0
- package/dist/testing.js +113 -0
- package/dist/testing.js.map +1 -0
- package/dist/testing.mjs +86 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,535 @@
|
|
|
1
|
+
import { h as RunnerId } from './Task-1NwmUImI.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The planner's single approval seam. Every capability that reaches beyond the
|
|
5
|
+
* default read-only, in-workspace envelope — a path outside the workspace root,
|
|
6
|
+
* a shell command outside the auto-allowed set, a URL fetch — routes through
|
|
7
|
+
* one `request()` so the policy has exactly one owner (the same "one repair
|
|
8
|
+
* owner" shape as PlanRepair).
|
|
9
|
+
*
|
|
10
|
+
* Surfaces supply the human channel. VS Code answers with a modal; the web
|
|
11
|
+
* server currently has no prompt UI, so it denies unless the scope was
|
|
12
|
+
* pre-approved through config. Denial is always a visible, actionable tool
|
|
13
|
+
* result — never a silent success.
|
|
14
|
+
*/
|
|
15
|
+
type ApprovalKind = 'external_path' | 'shell_command' | 'url_fetch';
|
|
16
|
+
interface ApprovalRequest {
|
|
17
|
+
kind: ApprovalKind;
|
|
18
|
+
/** The concrete thing being asked about: an absolute path, a command line, a URL. */
|
|
19
|
+
subject: string;
|
|
20
|
+
/**
|
|
21
|
+
* What a grant covers. Approving remembers this, not `subject`, so reading a
|
|
22
|
+
* second file from an already-approved directory does not prompt again.
|
|
23
|
+
*/
|
|
24
|
+
scope: string;
|
|
25
|
+
/** One-line context for the prompt. */
|
|
26
|
+
detail?: string;
|
|
27
|
+
}
|
|
28
|
+
interface IApproval {
|
|
29
|
+
request(req: ApprovalRequest): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
/** Denies everything. The safe default when a surface wires no approval channel. */
|
|
32
|
+
declare const DENY_ALL: IApproval;
|
|
33
|
+
|
|
34
|
+
interface ToolOutcome {
|
|
35
|
+
success: boolean;
|
|
36
|
+
output: string;
|
|
37
|
+
truncated: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface ReadFileOpts {
|
|
40
|
+
maxBytes?: number;
|
|
41
|
+
offset?: number;
|
|
42
|
+
limit?: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `content` returns matching lines, `files` only the paths that matched, and
|
|
46
|
+
* `count` a per-file tally. Cheap models otherwise grep and then read whole
|
|
47
|
+
* files to answer "which files touch this", burning rounds against the budget.
|
|
48
|
+
*/
|
|
49
|
+
type GrepOutputMode = 'content' | 'files' | 'count';
|
|
50
|
+
interface GrepOptions {
|
|
51
|
+
/** File glob filter, e.g. `*.ts`. */
|
|
52
|
+
include?: string;
|
|
53
|
+
/** Search root. Relative to the workspace unless approved as external. */
|
|
54
|
+
path?: string;
|
|
55
|
+
outputMode?: GrepOutputMode;
|
|
56
|
+
/** Lines of context around each match (`content` mode only). */
|
|
57
|
+
contextBefore?: number;
|
|
58
|
+
contextAfter?: number;
|
|
59
|
+
/** Treat the pattern as a literal string rather than a regex. */
|
|
60
|
+
literal?: boolean;
|
|
61
|
+
caseInsensitive?: boolean;
|
|
62
|
+
/** Global cap on returned rows. Defaults to {@link GREP_DEFAULT_HEAD_LIMIT}. */
|
|
63
|
+
headLimit?: number;
|
|
64
|
+
}
|
|
65
|
+
interface GlobOptions {
|
|
66
|
+
/** Search root. Relative to the workspace unless approved as external. */
|
|
67
|
+
path?: string;
|
|
68
|
+
headLimit?: number;
|
|
69
|
+
}
|
|
70
|
+
interface FindSymbolOptions {
|
|
71
|
+
/** Language id or file extension, e.g. `typescript` or `.go`. Narrows the keyword set. */
|
|
72
|
+
language?: string;
|
|
73
|
+
/** Search root. Relative to the workspace unless approved as external. */
|
|
74
|
+
path?: string;
|
|
75
|
+
}
|
|
76
|
+
/** Global row cap for grep. A per-file cap is not a budget — see PoolFileSystem. */
|
|
77
|
+
declare const GREP_DEFAULT_HEAD_LIMIT = 100;
|
|
78
|
+
/**
|
|
79
|
+
* Directories that are never interesting to a planner and would otherwise eat
|
|
80
|
+
* the result budget. Applied by every search entry point, not just `glob` —
|
|
81
|
+
* `dist/` and `.ordewell/` are frequently not gitignored.
|
|
82
|
+
*/
|
|
83
|
+
declare const SEARCH_EXCLUSIONS: string[];
|
|
84
|
+
interface IFileSystem {
|
|
85
|
+
readFile(path: string, opts?: ReadFileOpts): Promise<ToolOutcome>;
|
|
86
|
+
readFiles(paths: string[]): Promise<ToolOutcome>;
|
|
87
|
+
glob(pattern: string, opts?: GlobOptions): Promise<ToolOutcome>;
|
|
88
|
+
grep(pattern: string, opts?: GrepOptions): Promise<ToolOutcome>;
|
|
89
|
+
listDir(path: string, depth?: number): Promise<ToolOutcome>;
|
|
90
|
+
bash(command: string): Promise<ToolOutcome>;
|
|
91
|
+
/** Definition-first lookup for one symbol. See `symbolPatterns.ts`. */
|
|
92
|
+
findSymbol(symbol: string, opts?: FindSymbolOptions): Promise<ToolOutcome>;
|
|
93
|
+
getWorkspaceRoot(): string;
|
|
94
|
+
/**
|
|
95
|
+
* Inject the human-approval channel for out-of-envelope access. Optional so
|
|
96
|
+
* test doubles stay small; every adapter extending `BaseFileSystem` has it.
|
|
97
|
+
*/
|
|
98
|
+
setApproval?(approval: IApproval): void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Decides whether one out-of-envelope capability may run, and remembers the
|
|
103
|
+
* answer for the rest of the session.
|
|
104
|
+
*
|
|
105
|
+
* Grants are keyed on {@link ApprovalRequest.scope}, never on the concrete
|
|
106
|
+
* subject: approving a read of `/tmp/foo/a.log` grants `/tmp/foo/*`, and
|
|
107
|
+
* approving `az group list` grants `az group`. Without that, a planner doing
|
|
108
|
+
* real research would prompt on every single call and the feature would be
|
|
109
|
+
* unusable.
|
|
110
|
+
*
|
|
111
|
+
* `mode` is the policy floor:
|
|
112
|
+
* ask consult the human channel; no channel means deny (headless, web)
|
|
113
|
+
* allow grant everything the tier system did not already refuse
|
|
114
|
+
* deny grant nothing beyond `preApproved`
|
|
115
|
+
*
|
|
116
|
+
* Note the ordering: `preApproved` is honored under every mode including
|
|
117
|
+
* `deny`, because it is an explicit operator decision rather than a default.
|
|
118
|
+
*/
|
|
119
|
+
type ApprovalMode = 'ask' | 'allow' | 'deny';
|
|
120
|
+
interface ApprovalPolicyOptions {
|
|
121
|
+
mode?: ApprovalMode;
|
|
122
|
+
/** Scopes granted up front from config. A trailing `*` matches by prefix. */
|
|
123
|
+
preApproved?: string[];
|
|
124
|
+
/** The human channel. Absent means there is nobody to ask. */
|
|
125
|
+
ask?: (req: ApprovalRequest) => Promise<boolean>;
|
|
126
|
+
/** Called whenever a decision is reached, for surfacing in a UI or a log. */
|
|
127
|
+
onDecision?: (req: ApprovalRequest, granted: boolean, source: ApprovalSource) => void;
|
|
128
|
+
}
|
|
129
|
+
type ApprovalSource = 'pre-approved' | 'remembered' | 'mode' | 'asked' | 'no-channel';
|
|
130
|
+
declare class ApprovalPolicy implements IApproval {
|
|
131
|
+
private readonly mode;
|
|
132
|
+
private readonly preApproved;
|
|
133
|
+
private readonly asker?;
|
|
134
|
+
private readonly onDecision?;
|
|
135
|
+
private readonly granted;
|
|
136
|
+
private readonly refused;
|
|
137
|
+
/** One in-flight ask per scope: a parallel tool round must not prompt twice for the same thing. */
|
|
138
|
+
private readonly inFlight;
|
|
139
|
+
private generation;
|
|
140
|
+
constructor(opts?: ApprovalPolicyOptions);
|
|
141
|
+
request(req: ApprovalRequest): Promise<boolean>;
|
|
142
|
+
/** Scopes the user has granted this session — for display and for persistence. */
|
|
143
|
+
grantedScopes(): string[];
|
|
144
|
+
/** Drop every session-scoped decision. Called on session reset. */
|
|
145
|
+
reset(): void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
interface CatalogModel {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
description: string;
|
|
152
|
+
pricing: {
|
|
153
|
+
prompt: string;
|
|
154
|
+
completion: string;
|
|
155
|
+
};
|
|
156
|
+
contextLength: number;
|
|
157
|
+
}
|
|
158
|
+
declare class ModelCatalog {
|
|
159
|
+
static fetchModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<CatalogModel[]>;
|
|
160
|
+
/**
|
|
161
|
+
* Delete the on-disk catalog cache for a base URL so the next fetch re-runs.
|
|
162
|
+
* Used by the resolver's `invalidate()` in production (no injected fetch);
|
|
163
|
+
* best-effort — a missing file or unreadable dir is a no-op.
|
|
164
|
+
*/
|
|
165
|
+
static clearCache(baseUrl?: string): void;
|
|
166
|
+
private static readCache;
|
|
167
|
+
private static writeCache;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
interface ModelShortcut {
|
|
171
|
+
label: string;
|
|
172
|
+
id: string;
|
|
173
|
+
provider: string;
|
|
174
|
+
description: string;
|
|
175
|
+
pricing?: string;
|
|
176
|
+
}
|
|
177
|
+
declare const ORCHESTRATOR_SHORTCUTS: ModelShortcut[];
|
|
178
|
+
declare function resolveModelShortcut(input: string, shortcuts: ModelShortcut[]): string | null;
|
|
179
|
+
/**
|
|
180
|
+
* Resolves a value to a model id ONLY when it is in the supplied catalog
|
|
181
|
+
* option list — either directly or via a shortcut label. Free-typed, unknown,
|
|
182
|
+
* or not-currently-available values return null, so callers never store an id
|
|
183
|
+
* the user couldn't have selected from the list. Keeps model-setting list-only.
|
|
184
|
+
*/
|
|
185
|
+
declare function knownModelId(value: string, optionIds: string[], shortcuts: ModelShortcut[]): string | null;
|
|
186
|
+
|
|
187
|
+
type ProviderModelLists = Record<string, string[]>;
|
|
188
|
+
interface OrchestratorOption {
|
|
189
|
+
id: string;
|
|
190
|
+
label: string;
|
|
191
|
+
provider: string;
|
|
192
|
+
apiProvider: AiProvider;
|
|
193
|
+
description?: string;
|
|
194
|
+
pricing?: string;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
interface FetchAllProviderModelsOptions {
|
|
198
|
+
apiKeys: Record<string, string>;
|
|
199
|
+
baseUrls: Record<string, string>;
|
|
200
|
+
fetchImpl?: typeof fetch;
|
|
201
|
+
}
|
|
202
|
+
type AllProviderModels = Record<string, CatalogModel[]>;
|
|
203
|
+
/**
|
|
204
|
+
* Result of a picker-catalog fetch fan-out: the per-provider model lists plus
|
|
205
|
+
* the per-provider failures. `errors` is keyed by provider id and holds the
|
|
206
|
+
* failure message for any provider whose catalog fetch rejected — the seam the
|
|
207
|
+
* surfaces (CLI, VS Code) use to flag "this configured provider didn't work"
|
|
208
|
+
* rather than silently showing a short list.
|
|
209
|
+
*/
|
|
210
|
+
interface ProviderModelsResult {
|
|
211
|
+
models: AllProviderModels;
|
|
212
|
+
errors: Record<string, string>;
|
|
213
|
+
}
|
|
214
|
+
/** The provider config fields the discovery fan-out needs. */
|
|
215
|
+
interface ProviderCredentialSource {
|
|
216
|
+
getProviderApiKey(provider: AiProvider): string;
|
|
217
|
+
getProviderBaseUrl(provider: AiProvider): string;
|
|
218
|
+
openaiCompatibleBaseUrl: string;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Collect the API keys and base URLs the picker fan-out should probe, applying
|
|
222
|
+
* the single "configured" policy shared by every surface (CLI + VS Code):
|
|
223
|
+
* - a preset is discovered only when it has an API key (OpenRouter included —
|
|
224
|
+
* its public catalog is not probed keyless, matching the product rule that
|
|
225
|
+
* only key-configured providers appear);
|
|
226
|
+
* - `openai_compatible` is discovered only when an explicit endpoint is set
|
|
227
|
+
* (keyless local servers like ollama / LM Studio).
|
|
228
|
+
* Base URLs are handed through only for providers that pass the gate, so the
|
|
229
|
+
* fan-out never touches an unconfigured third-party endpoint.
|
|
230
|
+
*/
|
|
231
|
+
declare function collectProviderCredentials(config: ProviderCredentialSource): {
|
|
232
|
+
apiKeys: Record<string, string>;
|
|
233
|
+
baseUrls: Record<string, string>;
|
|
234
|
+
};
|
|
235
|
+
declare function fetchAllProviderModels(opts: FetchAllProviderModelsOptions): Promise<ProviderModelsResult>;
|
|
236
|
+
declare function resolveProvider(modelId: string, providerModelLists: Record<string, string[]>): AiProvider | null;
|
|
237
|
+
declare function toOrchestratorOptions(providerModels: AllProviderModels, shortcuts: ModelShortcut[]): OrchestratorOption[];
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Who plans. Mostly LLM vendors reached over HTTP; the last three are *harness
|
|
241
|
+
* planners* (ADR-0009) — a coding agent CLI already installed on the machine,
|
|
242
|
+
* driven as the planner over its own programmatic transport and authenticated
|
|
243
|
+
* by the subscription the user already holds. They are runners in the provider
|
|
244
|
+
* axis, deliberately: "what plans for me?" is one question, and it belongs in
|
|
245
|
+
* one setting. `isCliProvider` is the single guard that tells the two kinds
|
|
246
|
+
* apart.
|
|
247
|
+
*/
|
|
248
|
+
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';
|
|
249
|
+
interface IConfig {
|
|
250
|
+
aiProvider: AiProvider;
|
|
251
|
+
apiKey: string;
|
|
252
|
+
planningModel: string;
|
|
253
|
+
enabledRunners: string[];
|
|
254
|
+
maxParallelSessions: number;
|
|
255
|
+
researchEnabled: boolean;
|
|
256
|
+
researchMaxSteps: number;
|
|
257
|
+
researchMaxFileSize: number;
|
|
258
|
+
openAiBaseUrl: string;
|
|
259
|
+
openAiApiKey: string;
|
|
260
|
+
/** Provider keys + base URL the ModelResolver uses to fetch the picker catalogs. */
|
|
261
|
+
openrouterKey: string;
|
|
262
|
+
geminiKey: string;
|
|
263
|
+
geminiBaseUrl?: string;
|
|
264
|
+
/** Base URL + API key for a user-provided OpenAI-compatible endpoint (ollama, vLLM, LM Studio, etc.). */
|
|
265
|
+
openaiCompatibleBaseUrl: string;
|
|
266
|
+
openaiCompatibleApiKey: string;
|
|
267
|
+
orchestratorModel: string;
|
|
268
|
+
geminiModel: string;
|
|
269
|
+
/** Model for research subagents (issue #34); defaults to the (cheap) planner model. */
|
|
270
|
+
researchSubagentModel: string;
|
|
271
|
+
/**
|
|
272
|
+
* Thinking effort / model variant for a harness planner (ADR-0009), chosen
|
|
273
|
+
* from the agent's own discovered variants. Separate from the per-task
|
|
274
|
+
* efforts the plan carries — this one is the planner's own dial.
|
|
275
|
+
*/
|
|
276
|
+
plannerThinkingEffort?: string;
|
|
277
|
+
planMapEnabled: boolean;
|
|
278
|
+
autonomousMode: boolean;
|
|
279
|
+
/**
|
|
280
|
+
* What to do when planner research reaches outside its default envelope — an
|
|
281
|
+
* out-of-workspace path, or a shell command beyond the auto-allowed read-only
|
|
282
|
+
* set. `ask` prompts the user (and denies where no surface can prompt, such as
|
|
283
|
+
* headless runs); `allow` and `deny` skip the prompt entirely.
|
|
284
|
+
*/
|
|
285
|
+
approvalMode: ApprovalMode;
|
|
286
|
+
/** Scopes granted up front, so CI and power users never see a prompt. Trailing `*` matches by prefix. */
|
|
287
|
+
approvalPreApproved: string[];
|
|
288
|
+
/** Get the base URL for an OpenAI-compatible provider. */
|
|
289
|
+
getProviderBaseUrl(provider: AiProvider): string;
|
|
290
|
+
/** Get the API key for a provider. */
|
|
291
|
+
getProviderApiKey(provider: AiProvider): string;
|
|
292
|
+
/**
|
|
293
|
+
* Push the canonical provider routing lists in (sole producer: ModelResolver).
|
|
294
|
+
* Config consumes them when resolving a chosen model id to its serving API.
|
|
295
|
+
*/
|
|
296
|
+
setProviderModelLists(lists: ProviderModelLists): void;
|
|
297
|
+
}
|
|
298
|
+
declare function enabledRunners(cfg: IConfig): RunnerId[];
|
|
299
|
+
|
|
300
|
+
interface RunnerPluginManifest {
|
|
301
|
+
name: string;
|
|
302
|
+
displayName: string;
|
|
303
|
+
description: string;
|
|
304
|
+
version: string;
|
|
305
|
+
author?: string;
|
|
306
|
+
homepage?: string;
|
|
307
|
+
runner: PluginRunnerDef;
|
|
308
|
+
features: PluginFeatures;
|
|
309
|
+
modelDiscovery: PluginModelDiscovery;
|
|
310
|
+
contextFile?: string;
|
|
311
|
+
contextFileAltPath?: string;
|
|
312
|
+
modes?: PluginMode[];
|
|
313
|
+
}
|
|
314
|
+
interface PluginRunnerDef {
|
|
315
|
+
command: string;
|
|
316
|
+
argsTemplate: string[];
|
|
317
|
+
promptInArgs: boolean;
|
|
318
|
+
env?: Record<string, string>;
|
|
319
|
+
/** When true, the runner requires a PTY. HeadlessRunner wraps with `script` to allocate one. */
|
|
320
|
+
requiresTty?: boolean;
|
|
321
|
+
}
|
|
322
|
+
interface PluginFeatures {
|
|
323
|
+
modelSelection: boolean;
|
|
324
|
+
thinkingEffort: boolean;
|
|
325
|
+
planMode: boolean;
|
|
326
|
+
planModeFlag: string;
|
|
327
|
+
buildModeFlag?: string;
|
|
328
|
+
/** Flag appended when headless mode is on, so the agent never prompts for permission (e.g. Claude's --dangerously-skip-permissions). */
|
|
329
|
+
headlessFlag?: string;
|
|
330
|
+
thinkingFlag?: string;
|
|
331
|
+
thinkingValueEnabled?: string;
|
|
332
|
+
thinkingValueDisabled?: string;
|
|
333
|
+
thinkingValueAdaptive?: string;
|
|
334
|
+
/** Maps mode IDs to the CLI --permission-mode value. Used by {{feature:permissionModeVal}}. */
|
|
335
|
+
permissionModeValues?: Record<string, string>;
|
|
336
|
+
}
|
|
337
|
+
type PluginParser = 'claude-help' | 'opencode-models' | 'opencode-models-verbose' | 'anthropic-models' | 'line-by-line' | 'json' | 'json-table';
|
|
338
|
+
interface DiscoveryCommand {
|
|
339
|
+
command: string;
|
|
340
|
+
args: string[];
|
|
341
|
+
parser?: PluginParser;
|
|
342
|
+
}
|
|
343
|
+
type ApiAuthMethod = {
|
|
344
|
+
type: 'env';
|
|
345
|
+
varName: string;
|
|
346
|
+
header: string;
|
|
347
|
+
prefix?: string;
|
|
348
|
+
} | {
|
|
349
|
+
type: 'file';
|
|
350
|
+
path: string;
|
|
351
|
+
jsonPath: string;
|
|
352
|
+
header: string;
|
|
353
|
+
prefix?: string;
|
|
354
|
+
};
|
|
355
|
+
interface ApiDiscoveryConfig {
|
|
356
|
+
url: string;
|
|
357
|
+
headers?: Record<string, string>;
|
|
358
|
+
auth: ApiAuthMethod[];
|
|
359
|
+
parser: PluginParser;
|
|
360
|
+
}
|
|
361
|
+
interface PluginModelDiscovery {
|
|
362
|
+
method: 'command' | 'hardcoded';
|
|
363
|
+
command?: string;
|
|
364
|
+
args?: string[];
|
|
365
|
+
parser?: PluginParser;
|
|
366
|
+
jsonPath?: string;
|
|
367
|
+
/**
|
|
368
|
+
* Stdio JSON-RPC discovery (Codex `app-server`): spawn the command, send
|
|
369
|
+
* `initialize` then `model/list`, and read the catalog from the response.
|
|
370
|
+
* Tried BEFORE apiDiscovery and command discovery. When the call fails,
|
|
371
|
+
* `cacheFile` (the runner's own on-disk catalog cache, `~` expanded) is
|
|
372
|
+
* read before falling through to the remaining discovery methods.
|
|
373
|
+
*/
|
|
374
|
+
appServer?: {
|
|
375
|
+
command: string;
|
|
376
|
+
args: string[];
|
|
377
|
+
cacheFile?: string;
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* Optional last-resort list for user plugins whose CLI cannot enumerate
|
|
381
|
+
* models. Used only when command discovery fails entirely or the CLI is
|
|
382
|
+
* unavailable. Built-in manifests must NOT use this: anything listed here is
|
|
383
|
+
* shown to the user as available even when it isn't.
|
|
384
|
+
*/
|
|
385
|
+
fallbackModels?: {
|
|
386
|
+
modelId: string;
|
|
387
|
+
modelLabel: string;
|
|
388
|
+
}[];
|
|
389
|
+
/**
|
|
390
|
+
* Stable `--model` aliases that the runner's CLI always accepts but its help
|
|
391
|
+
* text may omit (e.g. Claude's 'haiku'). Merged into successful discovery
|
|
392
|
+
* results to fill gaps — discovered models take precedence, missing aliases
|
|
393
|
+
* are appended — and used as the last resort when discovery fails entirely.
|
|
394
|
+
* Unlike `fallbackModels`, entries must be stable CLI-accepted aliases
|
|
395
|
+
* (contracts that always resolve), not arbitrary model IDs.
|
|
396
|
+
*/
|
|
397
|
+
canonicalAliases?: {
|
|
398
|
+
modelId: string;
|
|
399
|
+
modelLabel: string;
|
|
400
|
+
}[];
|
|
401
|
+
/**
|
|
402
|
+
* HTTP API discovery — tried BEFORE command discovery. When the runner's CLI
|
|
403
|
+
* has no model-listing subcommand (Claude Code), an API endpoint can serve as
|
|
404
|
+
* the authoritative source. Auth methods are tried in order; the first that
|
|
405
|
+
* yields a token is used. If no auth method yields a token or the request
|
|
406
|
+
* fails, discovery falls through to `discoveryCommands` + `canonicalAliases`.
|
|
407
|
+
*/
|
|
408
|
+
apiDiscovery?: ApiDiscoveryConfig;
|
|
409
|
+
preferredPatterns?: {
|
|
410
|
+
id: string;
|
|
411
|
+
label: string;
|
|
412
|
+
}[];
|
|
413
|
+
variants?: {
|
|
414
|
+
id: string;
|
|
415
|
+
label: string;
|
|
416
|
+
}[];
|
|
417
|
+
discoveryCommands?: DiscoveryCommand[];
|
|
418
|
+
}
|
|
419
|
+
interface PluginMode {
|
|
420
|
+
id: string;
|
|
421
|
+
label: string;
|
|
422
|
+
description: string;
|
|
423
|
+
/** CLI value passed to the runner's permission/mode flag. Defaults to id if omitted. */
|
|
424
|
+
cliValue?: string;
|
|
425
|
+
/** Marks this mode as the runner's most permissive mode — the resolved default when autonomous mode is ON. */
|
|
426
|
+
autonomous?: boolean;
|
|
427
|
+
/** Marks this mode as the runner's conservative build mode — the resolved default when autonomous mode is OFF. */
|
|
428
|
+
safe?: boolean;
|
|
429
|
+
}
|
|
430
|
+
interface PluginEntry {
|
|
431
|
+
manifest: RunnerPluginManifest;
|
|
432
|
+
source: 'builtin' | 'user';
|
|
433
|
+
installPath?: string;
|
|
434
|
+
}
|
|
435
|
+
interface ResolveContext {
|
|
436
|
+
prompt: string;
|
|
437
|
+
model?: string;
|
|
438
|
+
thinkingEffort?: string;
|
|
439
|
+
/** All variant ids the assigned model offers — lets {{opencodeVariantConfig}} disable the non-chosen ones. */
|
|
440
|
+
modelVariants?: string[];
|
|
441
|
+
mode: string;
|
|
442
|
+
/** When true, resolve {{if headless}} blocks and the {{feature:headless}} token. */
|
|
443
|
+
headless?: boolean;
|
|
444
|
+
}
|
|
445
|
+
interface RunnerInvocation {
|
|
446
|
+
command: string;
|
|
447
|
+
args: string[];
|
|
448
|
+
env: Record<string, string>;
|
|
449
|
+
promptInArgs: boolean;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Persistent storage seam for plugin manifests. The RunnerRegistry delegates
|
|
453
|
+
* all filesystem operations to this interface so the plugin lifecycle is
|
|
454
|
+
* testable without real I/O.
|
|
455
|
+
*/
|
|
456
|
+
interface IPluginStore {
|
|
457
|
+
/** Path to the user plugins directory (~/.config/ordewell/plugins/). */
|
|
458
|
+
getUserPluginsDir(): string;
|
|
459
|
+
/** List subdirectory names inside the user plugins directory. */
|
|
460
|
+
listUserPluginDirs(): string[];
|
|
461
|
+
/** Read and parse a manifest.json from pluginDir. Returns null on failure. */
|
|
462
|
+
loadManifest(pluginDir: string): RunnerPluginManifest | null;
|
|
463
|
+
/** Recursively copy sourceDir to destDir. */
|
|
464
|
+
copyDir(sourceDir: string, destDir: string): void;
|
|
465
|
+
/** Recursively remove a directory. */
|
|
466
|
+
removeDir(dir: string): void;
|
|
467
|
+
/** Ensure a directory exists (mkdir -p). */
|
|
468
|
+
ensureDir(dir: string): void;
|
|
469
|
+
/** Write a text file. */
|
|
470
|
+
writeFile(filePath: string, content: string): void;
|
|
471
|
+
/** Read a UTF-8 text file. Returns null on ENOENT or read error. */
|
|
472
|
+
readFile(filePath: string): string | null;
|
|
473
|
+
/** True if path exists and is a directory. */
|
|
474
|
+
dirExists(path: string): boolean;
|
|
475
|
+
/** True if path exists. */
|
|
476
|
+
exists(path: string): boolean;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
declare class RunnerRegistry {
|
|
480
|
+
private plugins;
|
|
481
|
+
private store;
|
|
482
|
+
constructor(store?: IPluginStore);
|
|
483
|
+
private loadBuiltins;
|
|
484
|
+
loadUserPlugins(): void;
|
|
485
|
+
get(id: string): PluginEntry | undefined;
|
|
486
|
+
getManifest(id: string): RunnerPluginManifest | undefined;
|
|
487
|
+
list(): PluginEntry[];
|
|
488
|
+
listEnabled(config: IConfig): PluginEntry[];
|
|
489
|
+
listEnabledIds(config: IConfig): string[];
|
|
490
|
+
isBuiltIn(id: string): boolean;
|
|
491
|
+
installFromPath(sourcePath: string): RunnerPluginManifest;
|
|
492
|
+
installFromGit(url: string): RunnerPluginManifest;
|
|
493
|
+
private finishInstall;
|
|
494
|
+
remove(name: string): void;
|
|
495
|
+
createSkeleton(name: string, outputDir: string): string;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
interface ITerminalSession {
|
|
499
|
+
id: string;
|
|
500
|
+
taskId: string;
|
|
501
|
+
onOutput(callback: (text: string) => void): void;
|
|
502
|
+
onExit(callback: (code: number) => void): void;
|
|
503
|
+
kill(): void;
|
|
504
|
+
getOutput(): string;
|
|
505
|
+
write(text: string): void;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
interface ITerminalRunner {
|
|
509
|
+
spawn(opts: {
|
|
510
|
+
taskId: string;
|
|
511
|
+
runner: string;
|
|
512
|
+
prompt: string;
|
|
513
|
+
modelId?: string;
|
|
514
|
+
thinkingEffort?: string;
|
|
515
|
+
modelVariants?: string[];
|
|
516
|
+
mode?: string;
|
|
517
|
+
headless?: boolean;
|
|
518
|
+
cwd: string;
|
|
519
|
+
registry?: RunnerRegistry;
|
|
520
|
+
/** Task order and title — surfaces use these to label task_started/output events. */
|
|
521
|
+
order?: number;
|
|
522
|
+
title?: string;
|
|
523
|
+
/**
|
|
524
|
+
* The owning plan session. Task ids are only unique within one plan, so
|
|
525
|
+
* transports that key OS resources by task (tmux windows, log files) need
|
|
526
|
+
* this to keep two plans' identically named tasks apart.
|
|
527
|
+
*/
|
|
528
|
+
planSessionId?: string;
|
|
529
|
+
}): Promise<ITerminalSession>;
|
|
530
|
+
stop(sessionId: string): void;
|
|
531
|
+
stopAll(): void;
|
|
532
|
+
activeCount: number;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
export { type AiProvider as A, type ResolveContext as B, type CatalogModel as C, DENY_ALL as D, type RunnerInvocation as E, type FetchAllProviderModelsOptions as F, GREP_DEFAULT_HEAD_LIMIT as G, type RunnerPluginManifest as H, type IApproval as I, RunnerRegistry as J, collectProviderCredentials as K, enabledRunners as L, ModelCatalog as M, fetchAllProviderModels as N, ORCHESTRATOR_SHORTCUTS as O, type PluginEntry as P, knownModelId as Q, type ReadFileOpts as R, SEARCH_EXCLUSIONS as S, type ToolOutcome as T, resolveModelShortcut as U, resolveProvider as V, toOrchestratorOptions as W, type AllProviderModels as a, type ApprovalKind as b, type ApprovalMode as c, ApprovalPolicy as d, type ApprovalPolicyOptions as e, type ApprovalRequest as f, type ApprovalSource as g, type DiscoveryCommand as h, type FindSymbolOptions as i, type GlobOptions as j, type GrepOptions as k, type GrepOutputMode as l, type IConfig as m, type IFileSystem as n, type IPluginStore as o, type ITerminalRunner as p, type ITerminalSession as q, type ModelShortcut as r, type OrchestratorOption as s, type PluginFeatures as t, type PluginMode as u, type PluginModelDiscovery as v, type PluginRunnerDef as w, type ProviderCredentialSource as x, type ProviderModelLists as y, type ProviderModelsResult as z };
|