@ikarmic/forge-core 5.1.1 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.js +14 -3
- package/dist/agent/goal.d.ts +5 -8
- package/dist/agent/race-abort.d.ts +8 -0
- package/dist/agent/race-abort.js +24 -0
- package/dist/agent/stack-facts.d.ts +23 -0
- package/dist/agent/stack-facts.js +150 -0
- package/dist/code-index/parser.js +48 -3
- package/dist/github/github-tools.d.ts +2 -18
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/journey/answers-block.js +14 -1
- package/dist/journey/offer.js +2 -1
- package/dist/mcp/json-schema-to-zod.js +12 -1
- package/dist/orchestrator/index.d.ts +1 -1
- package/dist/orchestrator/index.js +1 -1
- package/dist/orchestrator/orchestrator.d.ts +45 -6
- package/dist/orchestrator/orchestrator.js +62 -12
- package/dist/orchestrator/router.d.ts +1 -1
- package/dist/orchestrator/router.js +4 -1
- package/dist/orchestrator/specialists.d.ts +6 -1
- package/dist/orchestrator/specialists.js +165 -68
- package/dist/orchestrator/types.d.ts +1 -1
- package/dist/policy/policy.d.ts +6 -59
- package/dist/pricing.d.ts +2 -0
- package/dist/pricing.js +35 -16
- package/dist/structured/schema.js +9 -12
- package/dist/tools/apply-patch.d.ts +1 -5
- package/dist/tools/ask-user.d.ts +2 -10
- package/dist/tools/ask-user.js +12 -4
- package/dist/tools/browser-tools.d.ts +15 -31
- package/dist/tools/codebase-search.d.ts +1 -7
- package/dist/tools/dependency-audit.d.ts +30 -0
- package/dist/tools/dependency-audit.js +197 -0
- package/dist/tools/edit-file.d.ts +1 -15
- package/dist/tools/fetch-url.d.ts +1 -18
- package/dist/tools/find-references.d.ts +1 -5
- package/dist/tools/find-symbol.d.ts +10 -8
- package/dist/tools/git-diff.d.ts +13 -0
- package/dist/tools/git-diff.js +85 -0
- package/dist/tools/index.d.ts +3 -1
- package/dist/tools/index.js +5 -1
- package/dist/tools/list-files.d.ts +1 -19
- package/dist/tools/list-symbols.d.ts +1 -5
- package/dist/tools/memory.d.ts +23 -43
- package/dist/tools/notebook.d.ts +11 -17
- package/dist/tools/read-file.d.ts +1 -11
- package/dist/tools/read-image.d.ts +1 -12
- package/dist/tools/read-only.d.ts +1 -1
- package/dist/tools/read-only.js +2 -0
- package/dist/tools/run-command.d.ts +1 -17
- package/dist/tools/search-files.d.ts +1 -17
- package/dist/tools/sub-agent-wait.d.ts +2 -8
- package/dist/tools/sub-agent.d.ts +1 -69
- package/dist/tools/todo.d.ts +8 -20
- package/dist/tools/web-search.d.ts +1 -7
- package/dist/tools/write-file.d.ts +1 -7
- package/dist/types.d.ts +2 -0
- package/package.json +3 -3
package/dist/agent/agent.js
CHANGED
|
@@ -31,9 +31,11 @@ import { redact } from '../tools/redact.js';
|
|
|
31
31
|
import { composeSkillsPrompt, selectSkills } from '../skills/activator.js';
|
|
32
32
|
import { MAX_TOOL_INJECTIONS, selectAtStart, selectOnToolTouch, toWorkspaceRelative, wrapSteering } from '../steering/select.js';
|
|
33
33
|
import { applyCacheHints } from './cache-hints.js';
|
|
34
|
+
import { raceAbort } from './race-abort.js';
|
|
34
35
|
import { attachmentParts, formatBytes, mediaPartTokens } from '../attachments.js';
|
|
35
36
|
import { renderAnswersBlock } from '../journey/answers-block.js';
|
|
36
37
|
import { CONTINUE_PROMPT, DEFAULT_PLAN_MODE_SUFFIX, DEFAULT_SPEC_MODE_SUFFIX, DEFAULT_SYSTEM_PROMPT, environmentBlock } from './prompts.js';
|
|
38
|
+
import { detectStackFacts, stackBlock } from './stack-facts.js';
|
|
37
39
|
/** Read-only tool names whose output flows through the redactor. */
|
|
38
40
|
const DEFAULT_MAX_CONTINUATIONS = 3;
|
|
39
41
|
export const DEFAULT_MAX_DURATION_MS = 10 * 60 * 1000;
|
|
@@ -1020,8 +1022,7 @@ export class Agent {
|
|
|
1020
1022
|
if (abortSignal?.aborted)
|
|
1021
1023
|
return { approved: false };
|
|
1022
1024
|
const answered = Promise.resolve(this.config.approve(request));
|
|
1023
|
-
const
|
|
1024
|
-
const decision = await Promise.race([answered, aborted]);
|
|
1025
|
+
const decision = await raceAbort(answered, abortSignal, 'aborted');
|
|
1025
1026
|
if (decision === 'aborted')
|
|
1026
1027
|
return { approved: false };
|
|
1027
1028
|
return typeof decision === 'boolean' ? { approved: decision } : decision;
|
|
@@ -1215,6 +1216,16 @@ async function buildInitialMessages(config, task, skills, steeringSystem = [], u
|
|
|
1215
1216
|
// the first run: an answer that arrives on turn 3 can never enter the system
|
|
1216
1217
|
// message, and a middle turn would be summarised away by compaction.
|
|
1217
1218
|
const answersBlock = renderAnswersBlock(config.journeyAnswers ?? []);
|
|
1219
|
+
// The versions the workspace's files state, so code is written for them and not for what training saw most.
|
|
1220
|
+
let stackFactsBlock = '';
|
|
1221
|
+
if (!config.disableStackFacts) {
|
|
1222
|
+
try {
|
|
1223
|
+
stackFactsBlock = stackBlock(await detectStackFacts(cwd));
|
|
1224
|
+
}
|
|
1225
|
+
catch {
|
|
1226
|
+
// Skipped, never fatal.
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1218
1229
|
// Facts the model would otherwise have to guess: the platform decides
|
|
1219
1230
|
// whether `cat` or `type` works, and it cannot see the date at all.
|
|
1220
1231
|
const envBlock = environmentBlock({
|
|
@@ -1229,7 +1240,7 @@ async function buildInitialMessages(config, task, skills, steeringSystem = [], u
|
|
|
1229
1240
|
// stable order so cache hits survive across runs that share state. The
|
|
1230
1241
|
// environment block goes last: it is the part that varies per session.
|
|
1231
1242
|
const steeringBlock = steeringSystem.map(wrapSteering).join('\n\n');
|
|
1232
|
-
const blocks = [steeringBlock, instructionsBlock, extraInstructionsBlock, config.mcpInstructions ?? '', config.projectCommands ?? '', memoryBlock, skillsBlock, answersBlock, mapBlock, envBlock].filter((b) => b.length > 0);
|
|
1243
|
+
const blocks = [steeringBlock, instructionsBlock, extraInstructionsBlock, config.mcpInstructions ?? '', config.projectCommands ?? '', memoryBlock, skillsBlock, answersBlock, mapBlock, stackFactsBlock, envBlock].filter((b) => b.length > 0);
|
|
1233
1244
|
const systemContent = blocks.length > 0 ? `${basePrompt}\n\n${blocks.join('\n\n')}` : basePrompt;
|
|
1234
1245
|
return [
|
|
1235
1246
|
{ role: 'system', content: systemContent },
|
package/dist/agent/goal.d.ts
CHANGED
|
@@ -39,15 +39,12 @@ export declare function resumeGoal(g: GoalState): GoalState;
|
|
|
39
39
|
/** The message that drives one goal turn. */
|
|
40
40
|
export declare function goalPrompt(g: GoalState): string;
|
|
41
41
|
declare const reportParams: z.ZodObject<{
|
|
42
|
-
kind: z.ZodEnum<
|
|
42
|
+
kind: z.ZodEnum<{
|
|
43
|
+
blocked: "blocked";
|
|
44
|
+
complete: "complete";
|
|
45
|
+
}>;
|
|
43
46
|
reason: z.ZodString;
|
|
44
|
-
},
|
|
45
|
-
kind: "blocked" | "complete";
|
|
46
|
-
reason: string;
|
|
47
|
-
}, {
|
|
48
|
-
kind: "blocked" | "complete";
|
|
49
|
-
reason: string;
|
|
50
|
-
}>;
|
|
47
|
+
}, z.core.$strip>;
|
|
51
48
|
export declare function createGoalReportTool(onReport: (r: GoalReport) => void): ToolDefinition<z.infer<typeof reportParams>, {
|
|
52
49
|
recorded: true;
|
|
53
50
|
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Race `work` against `signal`, resolving to `onAbort` if the signal fires first.
|
|
3
|
+
*
|
|
4
|
+
* The listener is removed once the race settles. A run's signal lives for the
|
|
5
|
+
* whole run, so a listener added per question or per approval and left behind
|
|
6
|
+
* keeps every one of those closures alive until the run ends.
|
|
7
|
+
*/
|
|
8
|
+
export declare function raceAbort<T, A>(work: Promise<T>, signal: AbortSignal | undefined, onAbort: A): Promise<T | A>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Race `work` against `signal`, resolving to `onAbort` if the signal fires first.
|
|
3
|
+
*
|
|
4
|
+
* The listener is removed once the race settles. A run's signal lives for the
|
|
5
|
+
* whole run, so a listener added per question or per approval and left behind
|
|
6
|
+
* keeps every one of those closures alive until the run ends.
|
|
7
|
+
*/
|
|
8
|
+
export async function raceAbort(work, signal, onAbort) {
|
|
9
|
+
if (!signal)
|
|
10
|
+
return work;
|
|
11
|
+
if (signal.aborted)
|
|
12
|
+
return onAbort;
|
|
13
|
+
let listener;
|
|
14
|
+
const aborted = new Promise((resolve) => {
|
|
15
|
+
listener = () => resolve(onAbort);
|
|
16
|
+
signal.addEventListener('abort', listener, { once: true });
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
return await Promise.race([work, aborted]);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
signal.removeEventListener('abort', listener);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const MAX_STACK_LIBRARIES = 25;
|
|
2
|
+
export interface StackFacts {
|
|
3
|
+
runtimes: {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
source: string;
|
|
7
|
+
}[];
|
|
8
|
+
libraries: {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
range: boolean;
|
|
12
|
+
}[];
|
|
13
|
+
tools: {
|
|
14
|
+
test?: string;
|
|
15
|
+
lint?: string;
|
|
16
|
+
format?: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** JSON with comments and trailing commas (tsconfig.json): comments outside strings removed, then trailing commas. */
|
|
20
|
+
export declare function parseJsonc(text: string): Record<string, unknown> | undefined;
|
|
21
|
+
export declare function detectStackFacts(cwd: string): Promise<StackFacts>;
|
|
22
|
+
/** The facts as a block for the system prompt; '' when there are none. */
|
|
23
|
+
export declare function stackBlock(facts: StackFacts): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<stack>` block: the language, runtime and library versions the workspace's own files state, so an
|
|
3
|
+
* agent writes code for the versions in use instead of the ones it saw most in training. File reads only,
|
|
4
|
+
* no model and no tree walk (the journey survey's rule: a missing fact costs less than a wrong one). Every
|
|
5
|
+
* source is read on its own; one that is missing or unreadable leaves its facts out and never fails a run.
|
|
6
|
+
* Only the workspace root's files are read.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
export const MAX_STACK_LIBRARIES = 25;
|
|
11
|
+
const TEST_TOOLS = { vitest: 'vitest', jest: 'jest', mocha: 'mocha', ava: 'ava', pytest: 'pytest' };
|
|
12
|
+
const LINT_TOOLS = { eslint: 'eslint', '@biomejs/biome': 'biome', ruff: 'ruff', flake8: 'flake8', pylint: 'pylint' };
|
|
13
|
+
const FORMAT_TOOLS = { prettier: 'prettier', '@biomejs/biome': 'biome', black: 'black', ruff: 'ruff' };
|
|
14
|
+
async function read(cwd, rel) {
|
|
15
|
+
try {
|
|
16
|
+
return await readFile(path.join(cwd, rel), 'utf8');
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function json(text) {
|
|
23
|
+
if (text === undefined)
|
|
24
|
+
return undefined;
|
|
25
|
+
try {
|
|
26
|
+
const v = JSON.parse(text);
|
|
27
|
+
return v && typeof v === 'object' && !Array.isArray(v) ? v : undefined;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** JSON with comments and trailing commas (tsconfig.json): comments outside strings removed, then trailing commas. */
|
|
34
|
+
export function parseJsonc(text) {
|
|
35
|
+
let out = '';
|
|
36
|
+
let inString = false;
|
|
37
|
+
for (let i = 0; i < text.length; i++) {
|
|
38
|
+
const c = text[i];
|
|
39
|
+
if (inString) {
|
|
40
|
+
out += c;
|
|
41
|
+
if (c === '\\')
|
|
42
|
+
out += text[++i] ?? '';
|
|
43
|
+
else if (c === '"')
|
|
44
|
+
inString = false;
|
|
45
|
+
}
|
|
46
|
+
else if (c === '"') {
|
|
47
|
+
inString = true;
|
|
48
|
+
out += c;
|
|
49
|
+
}
|
|
50
|
+
else if (c === '/' && text[i + 1] === '/') {
|
|
51
|
+
while (i < text.length && text[i] !== '\n')
|
|
52
|
+
i++;
|
|
53
|
+
out += '\n';
|
|
54
|
+
}
|
|
55
|
+
else if (c === '/' && text[i + 1] === '*') {
|
|
56
|
+
const end = text.indexOf('*/', i + 2);
|
|
57
|
+
i = end < 0 ? text.length : end + 1;
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
out += c;
|
|
61
|
+
}
|
|
62
|
+
return json(out.replace(/,(\s*[}\]])/g, '$1'));
|
|
63
|
+
}
|
|
64
|
+
const strings = (v) => Object.fromEntries(Object.entries(v && typeof v === 'object' ? v : {}).filter((e) => typeof e[1] === 'string'));
|
|
65
|
+
async function installedVersion(cwd, name, lock) {
|
|
66
|
+
const own = json(await read(cwd, path.join('node_modules', name, 'package.json')));
|
|
67
|
+
if (typeof own?.version === 'string')
|
|
68
|
+
return own.version;
|
|
69
|
+
const entry = lock?.packages?.[`node_modules/${name}`];
|
|
70
|
+
if (typeof entry?.version === 'string')
|
|
71
|
+
return entry.version;
|
|
72
|
+
const legacy = lock?.dependencies?.[name];
|
|
73
|
+
return typeof legacy?.version === 'string' ? legacy.version : undefined;
|
|
74
|
+
}
|
|
75
|
+
function firstMatch(text, re) {
|
|
76
|
+
return text?.match(re)?.[1]?.trim() || undefined;
|
|
77
|
+
}
|
|
78
|
+
export async function detectStackFacts(cwd) {
|
|
79
|
+
const facts = { runtimes: [], libraries: [], tools: {} };
|
|
80
|
+
const runtime = (name, version, source) => {
|
|
81
|
+
if (version)
|
|
82
|
+
facts.runtimes.push({ name, version, source });
|
|
83
|
+
};
|
|
84
|
+
const noteTool = (dep) => {
|
|
85
|
+
facts.tools.test ??= TEST_TOOLS[dep];
|
|
86
|
+
facts.tools.lint ??= LINT_TOOLS[dep];
|
|
87
|
+
facts.tools.format ??= FORMAT_TOOLS[dep];
|
|
88
|
+
};
|
|
89
|
+
// Node and npm-style libraries.
|
|
90
|
+
const manifest = json(await read(cwd, 'package.json'));
|
|
91
|
+
const engines = strings(manifest?.engines);
|
|
92
|
+
runtime('node', engines.node, 'package.json engines');
|
|
93
|
+
runtime('node', firstMatch(await read(cwd, '.nvmrc'), /^\s*(\S+)/), '.nvmrc');
|
|
94
|
+
runtime('node', firstMatch(await read(cwd, '.node-version'), /^\s*(\S+)/), '.node-version');
|
|
95
|
+
if (manifest) {
|
|
96
|
+
const lock = json(await read(cwd, 'package-lock.json'));
|
|
97
|
+
const deps = Object.entries({ ...strings(manifest.dependencies) });
|
|
98
|
+
const dev = Object.entries(strings(manifest.devDependencies)).filter(([n]) => !deps.some(([d]) => d === n));
|
|
99
|
+
for (const [name] of [...deps, ...dev])
|
|
100
|
+
noteTool(name);
|
|
101
|
+
for (const [name, range] of [...deps, ...dev].slice(0, MAX_STACK_LIBRARIES)) {
|
|
102
|
+
const exact = await installedVersion(cwd, name, lock);
|
|
103
|
+
facts.libraries.push(exact ? { name, version: exact, range: false } : { name, version: range, range: true });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const tsconfig = await read(cwd, 'tsconfig.json');
|
|
107
|
+
const target = tsconfig === undefined ? undefined : parseJsonc(tsconfig)?.compilerOptions?.target;
|
|
108
|
+
if (typeof target === 'string')
|
|
109
|
+
runtime('tsconfig target', target, 'tsconfig.json');
|
|
110
|
+
// Python.
|
|
111
|
+
runtime('python', firstMatch(await read(cwd, 'pyproject.toml'), /^\s*requires-python\s*=\s*["']([^"']+)["']/m), 'pyproject.toml');
|
|
112
|
+
runtime('python', firstMatch(await read(cwd, '.python-version'), /^\s*(\S+)/), '.python-version');
|
|
113
|
+
const requirements = await read(cwd, 'requirements.txt');
|
|
114
|
+
for (const line of requirements?.split(/\r?\n/) ?? []) {
|
|
115
|
+
const m = line.match(/^\s*([A-Za-z0-9._-]+)\s*==\s*([^\s;#]+)/);
|
|
116
|
+
if (!m)
|
|
117
|
+
continue;
|
|
118
|
+
noteTool(m[1].toLowerCase());
|
|
119
|
+
if (facts.libraries.length < MAX_STACK_LIBRARIES)
|
|
120
|
+
facts.libraries.push({ name: m[1], version: m[2], range: false });
|
|
121
|
+
}
|
|
122
|
+
// Go, Rust, Java.
|
|
123
|
+
runtime('go', firstMatch(await read(cwd, 'go.mod'), /^\s*go\s+(\d[\w.]*)\s*$/m), 'go.mod');
|
|
124
|
+
runtime('rust edition', firstMatch(await read(cwd, 'Cargo.toml'), /^\s*edition\s*=\s*["']([^"']+)["']/m), 'Cargo.toml');
|
|
125
|
+
runtime('rust', firstMatch(await read(cwd, 'rust-toolchain.toml'), /^\s*channel\s*=\s*["']([^"']+)["']/m), 'rust-toolchain.toml');
|
|
126
|
+
runtime('rust', firstMatch(await read(cwd, 'rust-toolchain'), /^\s*(\S+)/), 'rust-toolchain');
|
|
127
|
+
const pom = await read(cwd, 'pom.xml');
|
|
128
|
+
runtime('java', firstMatch(pom, /<maven\.compiler\.release>\s*([^<\s]+)\s*</) ?? firstMatch(pom, /<java\.version>\s*([^<\s]+)\s*</), 'pom.xml');
|
|
129
|
+
for (const gradle of ['build.gradle.kts', 'build.gradle']) {
|
|
130
|
+
const text = await read(cwd, gradle);
|
|
131
|
+
runtime('java', firstMatch(text, /JavaLanguageVersion\.of\(\s*(\d+)\s*\)/) ?? firstMatch(text, /JavaVersion\.VERSION_(\d+(?:_\d+)?)/), gradle);
|
|
132
|
+
}
|
|
133
|
+
for (const k of Object.keys(facts.tools))
|
|
134
|
+
if (facts.tools[k] === undefined)
|
|
135
|
+
delete facts.tools[k];
|
|
136
|
+
return facts;
|
|
137
|
+
}
|
|
138
|
+
/** The facts as a block for the system prompt; '' when there are none. */
|
|
139
|
+
export function stackBlock(facts) {
|
|
140
|
+
const lines = [
|
|
141
|
+
...facts.runtimes.map((r) => `${r.name} ${r.version} (${r.source})`),
|
|
142
|
+
...facts.libraries.map((l) => (l.range ? `${l.name} ${l.version} (range in the manifest; installed version unknown)` : `${l.name} ${l.version}`)),
|
|
143
|
+
...(facts.tools.test ? [`test runner: ${facts.tools.test}`] : []),
|
|
144
|
+
...(facts.tools.lint ? [`linter: ${facts.tools.lint}`] : []),
|
|
145
|
+
...(facts.tools.format ? [`formatter: ${facts.tools.format}`] : []),
|
|
146
|
+
];
|
|
147
|
+
if (lines.length === 0)
|
|
148
|
+
return '';
|
|
149
|
+
return ['<stack>', "Versions this workspace's files state (read from the files, not guessed):", ...lines, '</stack>'].join('\n');
|
|
150
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import { createRequire } from 'node:module';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import Parser from 'web-tree-sitter';
|
|
@@ -44,6 +45,47 @@ const KIND_BY_NODE_TYPE = {
|
|
|
44
45
|
method_definition: 'method',
|
|
45
46
|
method_signature: 'method',
|
|
46
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* The folder of a bundle that carries its wasm files beside it, or null. The VS Code extension's build copies the
|
|
50
|
+
* runtime and grammar wasm into `dist/` next to `extension.js`, and its VSIX has no node_modules to resolve from.
|
|
51
|
+
* `typeof` keeps this safe under real ESM, where `__dirname` is not defined.
|
|
52
|
+
*/
|
|
53
|
+
function bundledWasmDir() {
|
|
54
|
+
if (typeof __dirname !== 'string')
|
|
55
|
+
return null;
|
|
56
|
+
return existsSync(path.join(__dirname, 'tree-sitter.wasm')) ? __dirname : null;
|
|
57
|
+
}
|
|
58
|
+
/** web-tree-sitter's runtime wasm, beside the bundle or resolved from the package; throws when this build does not carry it. */
|
|
59
|
+
function treeSitterWasm() {
|
|
60
|
+
const bundled = bundledWasmDir();
|
|
61
|
+
if (bundled)
|
|
62
|
+
return path.join(bundled, 'tree-sitter.wasm');
|
|
63
|
+
let file;
|
|
64
|
+
try {
|
|
65
|
+
file = path.join(path.dirname(getRequire().resolve('web-tree-sitter/package.json')), 'tree-sitter.wasm');
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error('Symbol tools are not available in this build: tree-sitter (web-tree-sitter) is not installed. Use search_files instead.');
|
|
69
|
+
}
|
|
70
|
+
if (!existsSync(file)) {
|
|
71
|
+
throw new Error(`Symbol tools are not available in this build: ${file} is missing. Use search_files instead.`);
|
|
72
|
+
}
|
|
73
|
+
return file;
|
|
74
|
+
}
|
|
75
|
+
/** A grammar's wasm, beside the bundle or from `tree-sitter-wasms`; throws when this build does not carry it. */
|
|
76
|
+
function grammarWasm(grammarFile) {
|
|
77
|
+
let file;
|
|
78
|
+
try {
|
|
79
|
+
file = path.join(bundledWasmDir() ?? path.join(path.dirname(getRequire().resolve('tree-sitter-wasms/package.json')), 'out'), grammarFile);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
throw new Error('Symbol tools are not available in this build: tree-sitter grammars (tree-sitter-wasms) are not installed. Use search_files instead.');
|
|
83
|
+
}
|
|
84
|
+
if (!existsSync(file)) {
|
|
85
|
+
throw new Error(`Symbol tools are not available in this build: ${file} is missing. Use search_files instead.`);
|
|
86
|
+
}
|
|
87
|
+
return file;
|
|
88
|
+
}
|
|
47
89
|
let parserInitialized = false;
|
|
48
90
|
const languageCache = new Map();
|
|
49
91
|
async function loadLanguage(ext) {
|
|
@@ -54,11 +96,14 @@ async function loadLanguage(ext) {
|
|
|
54
96
|
if (cached)
|
|
55
97
|
return cached;
|
|
56
98
|
if (!parserInitialized) {
|
|
57
|
-
|
|
99
|
+
// Point web-tree-sitter at its own wasm. Left to itself it looks next to the running script, which in the
|
|
100
|
+
// extension's one-file CommonJS bundle is dist/, and aborts when the file is not there: the promise never
|
|
101
|
+
// settles and every symbol tool call hangs (RB-40). A missing wasm is a clear, immediate error instead.
|
|
102
|
+
const wasm = treeSitterWasm();
|
|
103
|
+
await Parser.init({ locateFile: () => wasm });
|
|
58
104
|
parserInitialized = true;
|
|
59
105
|
}
|
|
60
|
-
const
|
|
61
|
-
const lang = await Parser.Language.load(path.join(wasmDir, grammarFile));
|
|
106
|
+
const lang = await Parser.Language.load(grammarWasm(grammarFile));
|
|
62
107
|
languageCache.set(grammarFile, lang);
|
|
63
108
|
return lang;
|
|
64
109
|
}
|
|
@@ -49,11 +49,7 @@ export interface PullRequestReport {
|
|
|
49
49
|
}
|
|
50
50
|
declare const readParams: z.ZodObject<{
|
|
51
51
|
number: z.ZodOptional<z.ZodNumber>;
|
|
52
|
-
},
|
|
53
|
-
number?: number | undefined;
|
|
54
|
-
}, {
|
|
55
|
-
number?: number | undefined;
|
|
56
|
-
}>;
|
|
52
|
+
}, z.core.$strip>;
|
|
57
53
|
export declare function createGitHubReadTool(cfg: GitHubConfig): ToolDefinition<z.infer<typeof readParams>, PullRequestReport>;
|
|
58
54
|
declare const createParams: z.ZodObject<{
|
|
59
55
|
title: z.ZodString;
|
|
@@ -61,19 +57,7 @@ declare const createParams: z.ZodObject<{
|
|
|
61
57
|
base: z.ZodOptional<z.ZodString>;
|
|
62
58
|
head: z.ZodOptional<z.ZodString>;
|
|
63
59
|
draft: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
-
},
|
|
65
|
-
body: string;
|
|
66
|
-
title: string;
|
|
67
|
-
draft?: boolean | undefined;
|
|
68
|
-
base?: string | undefined;
|
|
69
|
-
head?: string | undefined;
|
|
70
|
-
}, {
|
|
71
|
-
body: string;
|
|
72
|
-
title: string;
|
|
73
|
-
draft?: boolean | undefined;
|
|
74
|
-
base?: string | undefined;
|
|
75
|
-
head?: string | undefined;
|
|
76
|
-
}>;
|
|
60
|
+
}, z.core.$strip>;
|
|
77
61
|
export declare function createGitHubCreateTool(cfg: GitHubConfig): ToolDefinition<z.infer<typeof createParams>, {
|
|
78
62
|
number: number;
|
|
79
63
|
url: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export { createLanguageModel, formatModelId, pickAvailableProvider, resolveModel
|
|
|
42
42
|
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
43
43
|
export type { Session, ListEntry, FormatOptions, SessionUpdate, WatchSessionOptions, SessionMatch, SearchSessionsOptions, SessionPruneOptions, SessionPruneResult } from './sessions/index.js';
|
|
44
44
|
export { commandDirs, expandCustomCommand, formatCustomCommands, loadCustomCommands, parseCommandFile, type CustomCommand, } from './commands/custom-commands.js';
|
|
45
|
-
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
45
|
+
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, gitDiffTool, dependencyAuditTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
46
46
|
export type { AgentConfig, AgentEvent, AgentRunOptions, AgentRunReason, AgentRunResult, AnyLanguageModel, ApprovalDecision, CommandRunner, ModelRouter, VerifyConfig, ApprovalRequest, LanguageModelFactory, ModelConfig, PricePerMillionTokens, ProviderName, RedactOptions, TodoItem, ToolContext, UserQuestion, ToolDefinition, ToolPolicy, ToolSandbox, } from './types.js';
|
|
47
47
|
export type { CacheKeyParts, CacheStats } from './tools/index.js';
|
|
48
48
|
export type { RedactionRule, RedactionResult } from './tools/index.js';
|
|
@@ -82,7 +82,7 @@ export { CheckpointStore, type CheckpointStoreLimits } from './checkpoints/index
|
|
|
82
82
|
export type { CaptureOptions, Checkpoint, CheckpointFile, CheckpointFileStatus, CheckpointSummary, CheckpointTrigger, PruneResult, RestoreResult, } from './checkpoints/index.js';
|
|
83
83
|
export { SpecStore, isSafeSpecId, runKey, slugifyTaskForSpecId, SPEC_READONLY_TOOLS, splitRequirementsDesign, splitSpecSections, splitTasksSection, convertToCheckboxes, parseTasks, setTaskDone, changedSince, changeSize, keepDoneTasks, referencedPaths, specDrift, syncSpecTask } from './specs/index.js';
|
|
84
84
|
export type { SpecDraft, SpecRunRecord, SpecRuns, SpecSections, SpecSummary, SpecTask, SpecDrift } from './specs/index.js';
|
|
85
|
-
export { BUILTIN_SPECIALISTS, defaultConfigPath, effectiveToolsFor, BOARD_TOOL_NAMES, createBoardTools, DEFAULT_BOARD_CAP, getRegisteredSpecialist, getSpecialist, MessageBoard, listSpecialists, loadSpecialistsFromConfig, parseRouterOutput, registerSpecialist, resolveEffectiveModel, ROUTER_SYSTEM_PROMPT, runOrchestrator, runRouter, saveSpecialistsToConfig, unregisterSpecialist, validateSpecialistConfig, _resetSpecialistsForTests, _customSpecialistCount, } from './orchestrator/index.js';
|
|
85
|
+
export { BUILTIN_SPECIALISTS, defaultConfigPath, effectiveToolsFor, BOARD_TOOL_NAMES, createBoardTools, DEFAULT_BOARD_CAP, getRegisteredSpecialist, getSpecialist, MessageBoard, listSpecialists, loadSpecialistsFromConfig, parseRouterOutput, registerSpecialist, resolveEffectiveModel, ROUTER_SYSTEM_PROMPT, specialistAgentConfig, runOrchestrator, runRouter, saveSpecialistsToConfig, unregisterSpecialist, validateSpecialistConfig, _resetSpecialistsForTests, _customSpecialistCount, } from './orchestrator/index.js';
|
|
86
86
|
export type { BoardMessage } from './orchestrator/index.js';
|
|
87
87
|
export type { BuiltInSpecialistId, CustomSpecialistConfig, LoadSpecialistsResult, OrchestratorOptions, OrchestratorPlan, OrchestratorProgressEvent, OrchestratorRunResult, OrchestratorStep, OrchestratorStepResult, SpecialistConfig, SpecialistId, SpecialistsConfigFile, } from './orchestrator/index.js';
|
|
88
88
|
export { computeUnifiedDiff, computeDiffSummary, type DiffOptions, type DiffResult, type DiffSummary, } from './diff/index.js';
|
|
@@ -95,6 +95,9 @@ export { formatSteeringLine, isSafeSteeringName, loadSteering, overrideFilePath,
|
|
|
95
95
|
export type { StartSelection, SteeringConfig, SteeringDoc, SteeringInclusion, SteeringLoadResult, SteeringSkip, } from './steering/index.js';
|
|
96
96
|
export { CONFIG_KEY_COVERAGE, FORGE_CONFIG_SCHEMA } from './config-schema.js';
|
|
97
97
|
export { FILE_WRITE_TOOL_NAMES, filesTouchedBy } from './tools/write-tools.js';
|
|
98
|
+
export { isSafeGitRef, MAX_DIFF_CHARS } from './tools/git-diff.js';
|
|
99
|
+
export { detectStackFacts, stackBlock, MAX_STACK_LIBRARIES, type StackFacts } from './agent/stack-facts.js';
|
|
100
|
+
export { pickAuditors, type AuditFinding, type AuditorPlan } from './tools/dependency-audit.js';
|
|
98
101
|
export { shellEnv } from './tools/shell-env.js';
|
|
99
102
|
export { previewPatch } from './tools/apply-patch.js';
|
|
100
103
|
export type { PatchPreview } from './tools/apply-patch.js';
|
package/dist/index.js
CHANGED
|
@@ -26,7 +26,7 @@ export { loadMcpConfig, parseMcpConfig, connectAll, connectOne, closeAll, mcpRes
|
|
|
26
26
|
export { createLanguageModel, formatModelId, pickAvailableProvider, resolveModelFromEnv, resolveModelFromEnvAsync } from './providers.js';
|
|
27
27
|
export { defaultSessionDir, generateSessionId, saveSession, loadSession, deleteSession, listSessions, findLatestSession, formatSessionMarkdown, formatSessionJson, appendedSince, summarizeMessage, watchSession, searchSessions, sessionText, pruneSessions, pruneByRetention, } from './sessions/index.js';
|
|
28
28
|
export { commandDirs, expandCustomCommand, formatCustomCommands, loadCustomCommands, parseCommandFile, } from './commands/custom-commands.js';
|
|
29
|
-
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
29
|
+
export { BUILTIN_TOOLS, editFileTool, fetchUrlTool, findSymbolTool, gitDiffTool, dependencyAuditTool, listFilesTool, memoryReadTool, memoryForgetTool, memoryWriteTool, readFileTool, runCommandTool, searchFilesTool, subAgentTool, writeFileTool, checkPolicyViolation, globToRegex, mergeToolSandbox, normalizePathPattern, pathMatchesAny, redact, countRedactions, buildRules, ToolResultCache, buildCacheKey, cachedExecute, } from './tools/index.js';
|
|
30
30
|
// Skills system
|
|
31
31
|
export { buildSkillsBlock, builtinSkills, composeSkillsPrompt, discoverSkills, fetchSkillsCatalog, installSkillFromCatalog, loadSkillsRegistry, loadSkillsRegistryAsync, parseSkill, parseSkillsDir, resolveSkillRoots, scoreSkill, searchSkills, selectSkills, skillsRegistryFromList, DEFAULT_SKILL_CATALOG_URL, GLOBAL_SKILLS_DIR, LOCAL_SKILLS_DIR, PROJECT_SKILLS_DIR, SKILL_CATALOG_VERSION, } from './skills/index.js';
|
|
32
32
|
export { cosine, embedderFromEnv, hashingEmbedder, openAiCompatibleEmbedder, } from './semantic/embedder.js';
|
|
@@ -55,7 +55,7 @@ export { CheckpointStore } from './checkpoints/index.js';
|
|
|
55
55
|
// Specs system (spec-driven planning mode)
|
|
56
56
|
export { SpecStore, isSafeSpecId, runKey, slugifyTaskForSpecId, SPEC_READONLY_TOOLS, splitRequirementsDesign, splitSpecSections, splitTasksSection, convertToCheckboxes, parseTasks, setTaskDone, changedSince, changeSize, keepDoneTasks, referencedPaths, specDrift, syncSpecTask } from './specs/index.js';
|
|
57
57
|
// Orchestrator system
|
|
58
|
-
export { BUILTIN_SPECIALISTS, defaultConfigPath, effectiveToolsFor, BOARD_TOOL_NAMES, createBoardTools, DEFAULT_BOARD_CAP, getRegisteredSpecialist, getSpecialist, MessageBoard, listSpecialists, loadSpecialistsFromConfig, parseRouterOutput, registerSpecialist, resolveEffectiveModel, ROUTER_SYSTEM_PROMPT, runOrchestrator, runRouter, saveSpecialistsToConfig, unregisterSpecialist, validateSpecialistConfig, _resetSpecialistsForTests, _customSpecialistCount, } from './orchestrator/index.js';
|
|
58
|
+
export { BUILTIN_SPECIALISTS, defaultConfigPath, effectiveToolsFor, BOARD_TOOL_NAMES, createBoardTools, DEFAULT_BOARD_CAP, getRegisteredSpecialist, getSpecialist, MessageBoard, listSpecialists, loadSpecialistsFromConfig, parseRouterOutput, registerSpecialist, resolveEffectiveModel, ROUTER_SYSTEM_PROMPT, specialistAgentConfig, runOrchestrator, runRouter, saveSpecialistsToConfig, unregisterSpecialist, validateSpecialistConfig, _resetSpecialistsForTests, _customSpecialistCount, } from './orchestrator/index.js';
|
|
59
59
|
// Diff utilities (line-level unified diff)
|
|
60
60
|
export { computeUnifiedDiff, computeDiffSummary, } from './diff/index.js';
|
|
61
61
|
// Structured output (`--schema` mode)
|
|
@@ -75,6 +75,9 @@ export { branchChangedFiles, branchDiff, commitAllInWorktree, compareWorktreeCon
|
|
|
75
75
|
export { formatSteeringLine, isSafeSteeringName, loadSteering, overrideFilePath, parseSteering, pathMatchesGlob, readOverride, selectAtStart, selectOnToolTouch, setSteeringDisabled, stripSteering, wrapSteering, } from './steering/index.js';
|
|
76
76
|
export { CONFIG_KEY_COVERAGE, FORGE_CONFIG_SCHEMA } from './config-schema.js';
|
|
77
77
|
export { FILE_WRITE_TOOL_NAMES, filesTouchedBy } from './tools/write-tools.js';
|
|
78
|
+
export { isSafeGitRef, MAX_DIFF_CHARS } from './tools/git-diff.js';
|
|
79
|
+
export { detectStackFacts, stackBlock, MAX_STACK_LIBRARIES } from './agent/stack-facts.js';
|
|
80
|
+
export { pickAuditors } from './tools/dependency-audit.js';
|
|
78
81
|
export { shellEnv } from './tools/shell-env.js';
|
|
79
82
|
export { previewPatch } from './tools/apply-patch.js';
|
|
80
83
|
export { applyPatchTool, parsePatch, patchedPaths } from './tools/apply-patch.js';
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One pass is not enough: removing the tag from `</journey-</journey-answers>answers>`
|
|
3
|
+
* joins the halves into a fresh one. Repeat until nothing changes.
|
|
4
|
+
*/
|
|
5
|
+
function stripClosingTag(text) {
|
|
6
|
+
let prev;
|
|
7
|
+
let out = text;
|
|
8
|
+
do {
|
|
9
|
+
prev = out;
|
|
10
|
+
out = out.replace(/<\/journey-answers>/gi, '');
|
|
11
|
+
} while (out !== prev);
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
1
14
|
export function renderAnswersBlock(answers) {
|
|
2
15
|
// A dismissed question comes back with an empty answer. Rendering it under
|
|
3
16
|
// "these are decisions" would present an open question as settled, which
|
|
@@ -5,7 +18,7 @@ export function renderAnswersBlock(answers) {
|
|
|
5
18
|
const answered = answers.filter((a) => a.answer.trim() !== '');
|
|
6
19
|
if (answered.length === 0)
|
|
7
20
|
return '';
|
|
8
|
-
const lines = answered.map((a) => `- ${a.question}: ${a.answer
|
|
21
|
+
const lines = answered.map((a) => `- ${a.question}: ${stripClosingTag(a.answer)}`);
|
|
9
22
|
return [
|
|
10
23
|
'<journey-answers>',
|
|
11
24
|
'The person answered these before work started. They are decisions, not suggestions:',
|
package/dist/journey/offer.js
CHANGED
|
@@ -27,7 +27,8 @@ function areaOf(rel) {
|
|
|
27
27
|
export function decideOffer(facts, verdict) {
|
|
28
28
|
if (!verdict.survey)
|
|
29
29
|
return { offer: false, evidence: [] };
|
|
30
|
-
|
|
30
|
+
// A root file is not an area, so it neither counts toward MIN_AREAS nor appears in the evidence.
|
|
31
|
+
const areas = [...new Set(facts.relatedSymbols.map(areaOf))].filter((a) => a !== ROOT_AREA);
|
|
31
32
|
if (facts.relatedSymbols.length === 0) {
|
|
32
33
|
const where = facts.sourceFileCount === 0
|
|
33
34
|
? 'no source files here yet'
|
|
@@ -55,7 +55,18 @@ export function jsonSchemaToZod(schema) {
|
|
|
55
55
|
const propZod = jsonSchemaToZod(propSchema);
|
|
56
56
|
shape[key] = required.has(key) ? propZod : propZod.optional();
|
|
57
57
|
}
|
|
58
|
-
|
|
58
|
+
const objectZod = z.object(shape).passthrough();
|
|
59
|
+
// Zod 4 reads a missing `__proto__` key off the prototype chain and skips the property, so a required one is checked on the raw input first.
|
|
60
|
+
inner =
|
|
61
|
+
required.has('__proto__') && Object.prototype.hasOwnProperty.call(s.properties, '__proto__')
|
|
62
|
+
? z
|
|
63
|
+
.any()
|
|
64
|
+
.refine((v) => typeof v === 'object' && v !== null && Object.prototype.hasOwnProperty.call(v, '__proto__'), {
|
|
65
|
+
message: 'Invalid input: required property "__proto__" is missing',
|
|
66
|
+
path: ['__proto__'],
|
|
67
|
+
})
|
|
68
|
+
.pipe(objectZod)
|
|
69
|
+
: objectZod;
|
|
59
70
|
}
|
|
60
71
|
else if (s.additionalProperties === true) {
|
|
61
72
|
inner = z.record(z.string(), z.any());
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { BUILTIN_SPECIALISTS, getSpecialist, effectiveToolsFor } from './specialists.js';
|
|
9
9
|
export { parseRouterOutput, ROUTER_SYSTEM_PROMPT } from './router.js';
|
|
10
|
-
export { runOrchestrator, runRouter, groupStepsByParallel, resolveEffectiveModel, _dispatchGroup, type OrchestratorOptions, type OrchestratorProgressEvent, type OrchestratorWorktreeMode, } from './orchestrator.js';
|
|
10
|
+
export { runOrchestrator, runRouter, groupStepsByParallel, resolveEffectiveModel, specialistAgentConfig, handoffBlock, MAX_HANDOFF_CHARS, _dispatchGroup, type OrchestratorOptions, type StepLimits, type OrchestratorProgressEvent, type OrchestratorWorktreeMode, } from './orchestrator.js';
|
|
11
11
|
export { MessageBoard, DEFAULT_BOARD_CAP, type BoardMessage } from './board.js';
|
|
12
12
|
export { createBoardTools, BOARD_TOOL_NAMES } from './board-tools.js';
|
|
13
13
|
export { registerSpecialist, unregisterSpecialist, listSpecialists, getRegisteredSpecialist, loadSpecialistsFromConfig, saveSpecialistsToConfig, validateSpecialistConfig, defaultConfigPath, _resetSpecialistsForTests, _customSpecialistCount, type CustomSpecialistConfig, type SpecialistsConfigFile, type LoadSpecialistsResult, } from './specialists-registry.js';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { BUILTIN_SPECIALISTS, getSpecialist, effectiveToolsFor } from './specialists.js';
|
|
9
9
|
export { parseRouterOutput, ROUTER_SYSTEM_PROMPT } from './router.js';
|
|
10
|
-
export { runOrchestrator, runRouter, groupStepsByParallel, resolveEffectiveModel, _dispatchGroup, } from './orchestrator.js';
|
|
10
|
+
export { runOrchestrator, runRouter, groupStepsByParallel, resolveEffectiveModel, specialistAgentConfig, handoffBlock, MAX_HANDOFF_CHARS, _dispatchGroup, } from './orchestrator.js';
|
|
11
11
|
export { MessageBoard, DEFAULT_BOARD_CAP } from './board.js';
|
|
12
12
|
export { createBoardTools, BOARD_TOOL_NAMES } from './board-tools.js';
|
|
13
13
|
export { registerSpecialist, unregisterSpecialist, listSpecialists, getRegisteredSpecialist, loadSpecialistsFromConfig, saveSpecialistsToConfig, validateSpecialistConfig, defaultConfigPath, _resetSpecialistsForTests, _customSpecialistCount, } from './specialists-registry.js';
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
* AND the step is part of a parallel group. Solo steps never get
|
|
30
30
|
* a worktree (it's wasted overhead).
|
|
31
31
|
*/
|
|
32
|
-
import type {
|
|
32
|
+
import type { PermissionConfig } from '../tools/permission-rules.js';
|
|
33
|
+
import type { AgentConfig, AgentRunResult, ModelConfig, ToolSandbox } from '../types.js';
|
|
33
34
|
import { MessageBoard, type BoardMessage } from './board.js';
|
|
34
35
|
import type { OrchestratorPlan, OrchestratorRunResult, OrchestratorStep, OrchestratorStepResult, SpecialistConfig } from './types.js';
|
|
35
36
|
/**
|
|
@@ -63,6 +64,12 @@ export interface OrchestratorOptions {
|
|
|
63
64
|
maxParallelism?: number;
|
|
64
65
|
/** Approval callback for the router (specialists don't ask the user: they're scoped). */
|
|
65
66
|
approve?: AgentConfig['approve'];
|
|
67
|
+
/** Tools a step runs without asking (the person's `autoApproveTools`); default: the read-only tools. */
|
|
68
|
+
autoApproveTools?: readonly string[];
|
|
69
|
+
/** The person's permission rules, kept by every step. */
|
|
70
|
+
permissionRules?: PermissionConfig;
|
|
71
|
+
/** The person's tool sandbox; a step's tools are narrowed to its `allowTools`. */
|
|
72
|
+
toolSandbox?: ToolSandbox;
|
|
66
73
|
/** Optional modelFactory override (for tests). */
|
|
67
74
|
modelFactory?: AgentConfig['modelFactory'];
|
|
68
75
|
/**
|
|
@@ -180,11 +187,7 @@ export declare function runOrchestrator(options: OrchestratorOptions): Promise<O
|
|
|
180
187
|
* git worktree. When `always`, every step gets a worktree regardless
|
|
181
188
|
* of group size. `never` disables the feature.
|
|
182
189
|
*/
|
|
183
|
-
export declare function _dispatchGroup(group: OrchestratorStep[], base: {
|
|
184
|
-
model: ModelConfig;
|
|
185
|
-
cwd?: string;
|
|
186
|
-
modelFactory?: AgentConfig['modelFactory'];
|
|
187
|
-
}, dispatchOpts: {
|
|
190
|
+
export declare function _dispatchGroup(group: OrchestratorStep[], base: StepBase, dispatchOpts: {
|
|
188
191
|
worktrees: OrchestratorWorktreeMode;
|
|
189
192
|
cleanupBranches?: boolean;
|
|
190
193
|
commitChanges?: boolean;
|
|
@@ -195,6 +198,8 @@ export declare function _dispatchGroup(group: OrchestratorStep[], base: {
|
|
|
195
198
|
}) => void;
|
|
196
199
|
onWorktreeEvent?: OrchestratorOptions['onWorktreeEvent'];
|
|
197
200
|
board?: MessageBoard;
|
|
201
|
+
/** Results of the groups that ran before this one, handed to every step of this group. */
|
|
202
|
+
prior?: readonly OrchestratorStepResult[];
|
|
198
203
|
}, maxParallelism: number): Promise<OrchestratorStepResult[]>;
|
|
199
204
|
/**
|
|
200
205
|
* Run the router agent. Exposed for testing + for the
|
|
@@ -233,3 +238,37 @@ export declare function runRouter(args: {
|
|
|
233
238
|
* without going through `Agent.run()`.
|
|
234
239
|
*/
|
|
235
240
|
export declare function resolveEffectiveModel(spec: SpecialistConfig, baseModel: ModelConfig): ModelConfig;
|
|
241
|
+
/** The most of one earlier step's reply handed to a later step. */
|
|
242
|
+
export declare const MAX_HANDOFF_CHARS = 6000;
|
|
243
|
+
/**
|
|
244
|
+
* What the earlier steps of an orchestrator run produced, for a later step. Without it each step saw only the
|
|
245
|
+
* line the router wrote before any step ran, so in "plan, then code" Code never saw Plan's plan.
|
|
246
|
+
*/
|
|
247
|
+
export declare function handoffBlock(prior: readonly OrchestratorStepResult[]): string;
|
|
248
|
+
/** What a step inherits from the run: the model, where it works, and the limits the person set. */
|
|
249
|
+
interface StepBase {
|
|
250
|
+
model: ModelConfig;
|
|
251
|
+
cwd?: string;
|
|
252
|
+
modelFactory?: AgentConfig['modelFactory'];
|
|
253
|
+
limits?: StepLimits;
|
|
254
|
+
}
|
|
255
|
+
/** The person's limits a step must keep: a step has no one to ask, so these decide what it may do (RB-14, RB-39). */
|
|
256
|
+
export interface StepLimits {
|
|
257
|
+
autoApproveTools?: readonly string[];
|
|
258
|
+
permissionRules?: PermissionConfig;
|
|
259
|
+
toolSandbox?: ToolSandbox;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The Agent configuration for one orchestrator step. The step sees exactly its agent's effective tools
|
|
263
|
+
* (builtins off, the sandbox narrowed to that list), and runs its read-only tools without asking, as a
|
|
264
|
+
* `sub_agent` child does: there is no one to ask, so without the list every such call is refused.
|
|
265
|
+
*/
|
|
266
|
+
export declare function specialistAgentConfig(args: {
|
|
267
|
+
spec: SpecialistConfig;
|
|
268
|
+
model: ModelConfig;
|
|
269
|
+
cwd?: string;
|
|
270
|
+
modelFactory?: AgentConfig['modelFactory'];
|
|
271
|
+
board?: MessageBoard;
|
|
272
|
+
limits: StepLimits;
|
|
273
|
+
}): AgentConfig;
|
|
274
|
+
export {};
|