@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.
Files changed (41) hide show
  1. package/LICENSE +211 -0
  2. package/README.md +37 -0
  3. package/dist/ITerminalRunner-Bbpe8uts.d.ts +535 -0
  4. package/dist/ITerminalRunner-D8Bf-HD4.d.mts +535 -0
  5. package/dist/Task-1NwmUImI.d.mts +264 -0
  6. package/dist/Task-1NwmUImI.d.ts +264 -0
  7. package/dist/chunk-4KIWPW4K.mjs +510 -0
  8. package/dist/chunk-4KIWPW4K.mjs.map +1 -0
  9. package/dist/chunk-SRGQBGI5.mjs +463 -0
  10. package/dist/chunk-SRGQBGI5.mjs.map +1 -0
  11. package/dist/chunk-YXAIQKVE.mjs +398 -0
  12. package/dist/chunk-YXAIQKVE.mjs.map +1 -0
  13. package/dist/index.d.mts +2990 -0
  14. package/dist/index.d.ts +2990 -0
  15. package/dist/index.js +12927 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.mjs +11449 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/parsing-RjN9JbyG.d.ts +161 -0
  20. package/dist/parsing-xpozY5ac.d.mts +161 -0
  21. package/dist/parsing.d.mts +2 -0
  22. package/dist/parsing.d.ts +2 -0
  23. package/dist/parsing.js +432 -0
  24. package/dist/parsing.js.map +1 -0
  25. package/dist/parsing.mjs +15 -0
  26. package/dist/parsing.mjs.map +1 -0
  27. package/dist/plan-utils-Cgc0cCH1.d.ts +111 -0
  28. package/dist/plan-utils-nfHKSbd3.d.mts +111 -0
  29. package/dist/plan-utils.d.mts +2 -0
  30. package/dist/plan-utils.d.ts +2 -0
  31. package/dist/plan-utils.js +181 -0
  32. package/dist/plan-utils.js.map +1 -0
  33. package/dist/plan-utils.mjs +18 -0
  34. package/dist/plan-utils.mjs.map +1 -0
  35. package/dist/testing.d.mts +28 -0
  36. package/dist/testing.d.ts +28 -0
  37. package/dist/testing.js +113 -0
  38. package/dist/testing.js.map +1 -0
  39. package/dist/testing.mjs +86 -0
  40. package/dist/testing.mjs.map +1 -0
  41. package/package.json +92 -0
@@ -0,0 +1,535 @@
1
+ import { h as RunnerId } from './Task-1NwmUImI.mjs';
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 };