poe-code 3.0.196 → 3.0.198
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/cli/commands/configure.d.ts +0 -7
- package/dist/cli/commands/configure.js +11 -14
- package/dist/cli/commands/configure.js.map +1 -1
- package/dist/cli/commands/provider.js +8 -1
- package/dist/cli/commands/provider.js.map +1 -1
- package/dist/index.js +263 -269
- package/dist/index.js.map +4 -4
- package/dist/providers/claude-code.js +6 -20
- package/dist/providers/claude-code.js.map +3 -3
- package/dist/providers/codex.js +6 -20
- package/dist/providers/codex.js.map +3 -3
- package/dist/providers/create-provider.js +0 -2
- package/dist/providers/create-provider.js.map +1 -1
- package/dist/providers/goose.js +14 -25
- package/dist/providers/goose.js.map +3 -3
- package/dist/providers/kimi.js +6 -20
- package/dist/providers/kimi.js.map +3 -3
- package/dist/providers/opencode.js +6 -20
- package/dist/providers/opencode.js.map +3 -3
- package/dist/providers/poe-agent.js +66 -84
- package/dist/providers/poe-agent.js.map +4 -4
- package/dist/utils/command-checks.d.ts +2 -1
- package/dist/utils/command-checks.js +3 -1
- package/dist/utils/command-checks.js.map +1 -1
- package/package.json +4 -1
- package/packages/memory/dist/cache.js +1 -1
- package/packages/memory/dist/explain.js +1 -1
- package/packages/memory/dist/index.js +18 -7
- package/packages/memory/dist/index.js.map +3 -3
- package/packages/memory/dist/query.js +1 -1
- package/packages/memory/dist/tokens.js +1 -1
- package/packages/superintendent/dist/cli.d.ts +2 -0
- package/packages/superintendent/dist/cli.js +41 -0
- package/packages/superintendent/dist/commands/builder-group.d.ts +52 -0
- package/packages/superintendent/dist/commands/builder-group.js +73 -0
- package/packages/superintendent/dist/commands/complete.d.ts +19 -0
- package/packages/superintendent/dist/commands/complete.js +54 -0
- package/packages/superintendent/dist/commands/index.d.ts +4 -0
- package/packages/superintendent/dist/commands/index.js +4 -0
- package/packages/superintendent/dist/commands/inspector-group.d.ts +115 -0
- package/packages/superintendent/dist/commands/inspector-group.js +133 -0
- package/packages/superintendent/dist/commands/install.d.ts +31 -0
- package/packages/superintendent/dist/commands/install.js +148 -0
- package/packages/superintendent/dist/commands/plan-path.d.ts +9 -0
- package/packages/superintendent/dist/commands/plan-path.js +40 -0
- package/packages/superintendent/dist/commands/poe-agent-runner.d.ts +5 -0
- package/packages/superintendent/dist/commands/poe-agent-runner.js +27 -0
- package/packages/superintendent/dist/commands/run.d.ts +86 -0
- package/packages/superintendent/dist/commands/run.js +945 -0
- package/packages/superintendent/dist/commands/superintendent-group.d.ts +325 -0
- package/packages/superintendent/dist/commands/superintendent-group.js +238 -0
- package/packages/superintendent/dist/config-scope.d.ts +8 -0
- package/packages/superintendent/dist/config-scope.js +9 -0
- package/packages/superintendent/dist/direct-execution.d.ts +1 -0
- package/packages/superintendent/dist/direct-execution.js +20 -0
- package/packages/superintendent/dist/document/parse.d.ts +59 -0
- package/packages/superintendent/dist/document/parse.js +409 -0
- package/packages/superintendent/dist/document/tasks.d.ts +12 -0
- package/packages/superintendent/dist/document/tasks.js +96 -0
- package/packages/superintendent/dist/document/write.d.ts +6 -0
- package/packages/superintendent/dist/document/write.js +156 -0
- package/packages/superintendent/dist/index.d.ts +12 -0
- package/packages/superintendent/dist/index.js +15 -0
- package/packages/superintendent/dist/mcp.d.ts +24 -0
- package/packages/superintendent/dist/mcp.js +202 -0
- package/packages/superintendent/dist/runtime/agentic-tools.d.ts +33 -0
- package/packages/superintendent/dist/runtime/agentic-tools.js +74 -0
- package/packages/superintendent/dist/runtime/loop.d.ts +88 -0
- package/packages/superintendent/dist/runtime/loop.js +446 -0
- package/packages/superintendent/dist/runtime/resolve-cwd.d.ts +2 -0
- package/packages/superintendent/dist/runtime/resolve-cwd.js +10 -0
- package/packages/superintendent/dist/runtime/run-builder.d.ts +13 -0
- package/packages/superintendent/dist/runtime/run-builder.js +102 -0
- package/packages/superintendent/dist/runtime/run-inspector.d.ts +16 -0
- package/packages/superintendent/dist/runtime/run-inspector.js +119 -0
- package/packages/superintendent/dist/runtime/run-owner-review.d.ts +18 -0
- package/packages/superintendent/dist/runtime/run-owner-review.js +208 -0
- package/packages/superintendent/dist/runtime/run-superintendent.d.ts +13 -0
- package/packages/superintendent/dist/runtime/run-superintendent.js +208 -0
- package/packages/superintendent/dist/runtime/system-prompt.d.ts +17 -0
- package/packages/superintendent/dist/runtime/system-prompt.js +54 -0
- package/packages/superintendent/dist/runtime/templates.d.ts +22 -0
- package/packages/superintendent/dist/runtime/templates.js +23 -0
- package/packages/superintendent/dist/runtime/types.d.ts +4 -0
- package/packages/superintendent/dist/runtime/types.js +1 -0
- package/packages/superintendent/dist/runtime/workflow-tool.d.ts +29 -0
- package/packages/superintendent/dist/runtime/workflow-tool.js +83 -0
- package/packages/superintendent/dist/state/machine.d.ts +14 -0
- package/packages/superintendent/dist/state/machine.js +53 -0
- package/packages/superintendent/dist/templates/SKILL_superintendent.md +193 -0
- package/packages/superintendent/dist/testing/index.d.ts +2 -0
- package/packages/superintendent/dist/testing/index.js +1 -0
- package/packages/superintendent/dist/testing/simulation.d.ts +57 -0
- package/packages/superintendent/dist/testing/simulation.js +346 -0
- package/dist/providers/tiny-http-mcp-server.d.ts +0 -22
- package/dist/providers/tiny-http-mcp-server.js +0 -1471
- package/dist/providers/tiny-http-mcp-server.js.map +0 -7
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import * as fsPromises from "node:fs/promises";
|
|
3
|
+
import { lockWorkflow, makeRunLogFileName, resolveWorkflowPath } from "@poe-code/agent-harness-tools";
|
|
4
|
+
import { spawn } from "@poe-code/agent-spawn";
|
|
5
|
+
import { parseSuperintendentDoc } from "../document/parse.js";
|
|
6
|
+
import { parseTaskBoard } from "../document/tasks.js";
|
|
7
|
+
import { updateStatus } from "../document/write.js";
|
|
8
|
+
import { createLoopState } from "../state/machine.js";
|
|
9
|
+
import { runBuilder } from "./run-builder.js";
|
|
10
|
+
import { runInspector } from "./run-inspector.js";
|
|
11
|
+
import { runOwnerReview } from "./run-owner-review.js";
|
|
12
|
+
import { runSuperintendent } from "./run-superintendent.js";
|
|
13
|
+
import { collectReferencedInspectors } from "./templates.js";
|
|
14
|
+
export async function runLoop(input, callbacks) {
|
|
15
|
+
const options = normalizeOptions(input, callbacks);
|
|
16
|
+
const releaseLock = await lockWorkflow(options.docPath, {
|
|
17
|
+
fs: options.fs
|
|
18
|
+
});
|
|
19
|
+
try {
|
|
20
|
+
return await withInjectedAgentRunner(options, async () => {
|
|
21
|
+
let state = createLoopState(await readDocument(options.fs, options.docPath));
|
|
22
|
+
let context = {
|
|
23
|
+
inspectors: {},
|
|
24
|
+
inspectorLogs: {}
|
|
25
|
+
};
|
|
26
|
+
while (true) {
|
|
27
|
+
const stopReason = readLoopStopReason(options, state);
|
|
28
|
+
if (stopReason) {
|
|
29
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
30
|
+
}
|
|
31
|
+
if (state.state === "in_progress") {
|
|
32
|
+
const roundStartState = { ...state };
|
|
33
|
+
const roundSnapshot = await readDocumentContent(options.fs, options.docPath);
|
|
34
|
+
state = beginRound(state);
|
|
35
|
+
emitStateChange(options.callbacks, state);
|
|
36
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
37
|
+
options.callbacks.onBuilderStart?.();
|
|
38
|
+
let builderResult;
|
|
39
|
+
try {
|
|
40
|
+
builderResult = await options.runners.builder(await readDocument(options.fs, options.docPath), createTemplateContext(context), buildRoleOptions(options, "builder"));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
await restoreDocument(options.fs, options.docPath, roundSnapshot);
|
|
44
|
+
const normalizedError = toError(error);
|
|
45
|
+
options.callbacks.onBuilderFailed?.(normalizedError);
|
|
46
|
+
throw normalizedError;
|
|
47
|
+
}
|
|
48
|
+
options.callbacks.onBuilderComplete?.(builderResult);
|
|
49
|
+
context = {
|
|
50
|
+
...context,
|
|
51
|
+
builder: builderResult,
|
|
52
|
+
inspectors: {},
|
|
53
|
+
inspectorLogs: {}
|
|
54
|
+
};
|
|
55
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
56
|
+
const stopReason = readInterruptionReason(options, state);
|
|
57
|
+
if (stopReason) {
|
|
58
|
+
if (stopReason === "aborted") {
|
|
59
|
+
state = await rollbackRoundStatus(options, roundStartState);
|
|
60
|
+
}
|
|
61
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
62
|
+
}
|
|
63
|
+
const docForInspectors = await readDocument(options.fs, options.docPath);
|
|
64
|
+
const inspectorEntries = filterAutoRunInspectors(docForInspectors);
|
|
65
|
+
for (const [name, config] of inspectorEntries) {
|
|
66
|
+
options.callbacks.onInspectorStart?.(name);
|
|
67
|
+
const inspectorSnapshot = await readDocumentContent(options.fs, options.docPath);
|
|
68
|
+
let inspectorResult;
|
|
69
|
+
try {
|
|
70
|
+
inspectorResult = await options.runners.inspector(name, config, await readDocument(options.fs, options.docPath), createTemplateContext(context), buildRoleOptions(options, `inspector-${name}`));
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
await restoreDocument(options.fs, options.docPath, inspectorSnapshot);
|
|
74
|
+
const normalizedError = toError(error);
|
|
75
|
+
options.callbacks.onInspectorFailed?.(name, normalizedError);
|
|
76
|
+
throw normalizedError;
|
|
77
|
+
}
|
|
78
|
+
options.callbacks.onInspectorComplete?.(inspectorResult);
|
|
79
|
+
context = {
|
|
80
|
+
...context,
|
|
81
|
+
inspectors: {
|
|
82
|
+
...context.inspectors,
|
|
83
|
+
[inspectorResult.name]: inspectorResult.summary
|
|
84
|
+
},
|
|
85
|
+
inspectorLogs: {
|
|
86
|
+
...context.inspectorLogs,
|
|
87
|
+
...(inspectorResult.log_path
|
|
88
|
+
? { [inspectorResult.name]: inspectorResult.log_path }
|
|
89
|
+
: {})
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
93
|
+
const stopReason = readInterruptionReason(options, state);
|
|
94
|
+
if (stopReason) {
|
|
95
|
+
if (stopReason === "aborted") {
|
|
96
|
+
state = await rollbackRoundStatus(options, roundStartState);
|
|
97
|
+
}
|
|
98
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const superintendentResult = await executeSuperintendent(options, context);
|
|
102
|
+
context = {
|
|
103
|
+
...context,
|
|
104
|
+
superintendentSummary: superintendentResult.summary,
|
|
105
|
+
...(superintendentResult.log_path
|
|
106
|
+
? { superintendentLogPath: superintendentResult.log_path }
|
|
107
|
+
: {})
|
|
108
|
+
};
|
|
109
|
+
if (superintendentResult.transition?.action === "request_review") {
|
|
110
|
+
context = {
|
|
111
|
+
...context,
|
|
112
|
+
ownerFeedback: undefined
|
|
113
|
+
};
|
|
114
|
+
state = {
|
|
115
|
+
...state,
|
|
116
|
+
state: "review",
|
|
117
|
+
reviewTurn: 0
|
|
118
|
+
};
|
|
119
|
+
emitStateChange(options.callbacks, state);
|
|
120
|
+
}
|
|
121
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
122
|
+
if (state.state === "in_progress") {
|
|
123
|
+
options.callbacks.onRoundComplete?.(state.round);
|
|
124
|
+
}
|
|
125
|
+
{
|
|
126
|
+
const stopReason = readLoopStopReason(options, state);
|
|
127
|
+
if (stopReason) {
|
|
128
|
+
if (stopReason === "aborted" && state.state === "in_progress") {
|
|
129
|
+
state = await rollbackRoundStatus(options, roundStartState);
|
|
130
|
+
}
|
|
131
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (context.ownerFeedback &&
|
|
137
|
+
shouldContinueReview(await readDocument(options.fs, options.docPath))) {
|
|
138
|
+
const superintendentResult = await executeSuperintendent(options, context);
|
|
139
|
+
if (superintendentResult.transition?.action !== "request_review") {
|
|
140
|
+
throw new Error("Superintendent must call request_review to continue a review exchange");
|
|
141
|
+
}
|
|
142
|
+
context = {
|
|
143
|
+
...context,
|
|
144
|
+
superintendentSummary: superintendentResult.summary,
|
|
145
|
+
...(superintendentResult.log_path
|
|
146
|
+
? { superintendentLogPath: superintendentResult.log_path }
|
|
147
|
+
: {}),
|
|
148
|
+
ownerFeedback: undefined
|
|
149
|
+
};
|
|
150
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
151
|
+
{
|
|
152
|
+
const stopReason = readInterruptionReason(options, state);
|
|
153
|
+
if (stopReason) {
|
|
154
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
options.callbacks.onOwnerStart?.();
|
|
160
|
+
const ownerSnapshot = await readDocumentContent(options.fs, options.docPath);
|
|
161
|
+
let ownerResult;
|
|
162
|
+
try {
|
|
163
|
+
ownerResult = await options.runners.ownerReview(await readDocument(options.fs, options.docPath), createTemplateContext(context), buildRoleOptions(options, "owner"));
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
await restoreDocument(options.fs, options.docPath, ownerSnapshot);
|
|
167
|
+
throw toError(error);
|
|
168
|
+
}
|
|
169
|
+
options.callbacks.onOwnerComplete?.(ownerResult);
|
|
170
|
+
if (ownerResult.transition.action === "approve_completion") {
|
|
171
|
+
context = {
|
|
172
|
+
...context,
|
|
173
|
+
...(ownerResult.log_path ? { ownerLogPath: ownerResult.log_path } : {})
|
|
174
|
+
};
|
|
175
|
+
state = {
|
|
176
|
+
...state,
|
|
177
|
+
state: "completed"
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
context = {
|
|
182
|
+
...context,
|
|
183
|
+
ownerFeedback: ownerResult.transition.feedback,
|
|
184
|
+
...(ownerResult.log_path ? { ownerLogPath: ownerResult.log_path } : {})
|
|
185
|
+
};
|
|
186
|
+
state = applyOwnerFeedback(state, shouldContinueReview(await readDocument(options.fs, options.docPath)));
|
|
187
|
+
}
|
|
188
|
+
emitStateChange(options.callbacks, state);
|
|
189
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
190
|
+
if (state.state !== "review") {
|
|
191
|
+
options.callbacks.onRoundComplete?.(state.round);
|
|
192
|
+
}
|
|
193
|
+
{
|
|
194
|
+
const stopReason = readLoopStopReason(options, state);
|
|
195
|
+
if (stopReason) {
|
|
196
|
+
return finishLoop(options.callbacks, state, stopReason);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
await releaseLock();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function normalizeOptions(input, callbacks) {
|
|
207
|
+
if (typeof input !== "string") {
|
|
208
|
+
return {
|
|
209
|
+
docPath: resolveWorkflowPath(input.docPath, input.cwd, input.homeDir),
|
|
210
|
+
cwd: input.cwd,
|
|
211
|
+
homeDir: input.homeDir,
|
|
212
|
+
fs: input.fs ?? createDefaultFs(),
|
|
213
|
+
callbacks: input.callbacks ?? {},
|
|
214
|
+
runners: resolveRunners(input.runners),
|
|
215
|
+
...(input.runAgent ? { runAgent: input.runAgent } : {}),
|
|
216
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
217
|
+
...(input.logDir ? { logDir: input.logDir } : {})
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const cwd = process.cwd();
|
|
221
|
+
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? cwd;
|
|
222
|
+
return {
|
|
223
|
+
docPath: resolveWorkflowPath(input, cwd, homeDir),
|
|
224
|
+
cwd,
|
|
225
|
+
homeDir,
|
|
226
|
+
fs: createDefaultFs(),
|
|
227
|
+
callbacks: callbacks ?? {},
|
|
228
|
+
runners: resolveRunners()
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function resolveRunners(overrides) {
|
|
232
|
+
return {
|
|
233
|
+
builder: overrides?.builder ?? runBuilder,
|
|
234
|
+
inspector: overrides?.inspector ?? runInspector,
|
|
235
|
+
superintendent: overrides?.superintendent ?? runSuperintendent,
|
|
236
|
+
ownerReview: overrides?.ownerReview ?? runOwnerReview
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function createDefaultFs() {
|
|
240
|
+
const fs = {
|
|
241
|
+
readFile: fsPromises.readFile,
|
|
242
|
+
writeFile: fsPromises.writeFile,
|
|
243
|
+
readdir: fsPromises.readdir,
|
|
244
|
+
open: (filePath, flags) => fsPromises.open(filePath, flags),
|
|
245
|
+
stat: async (filePath) => {
|
|
246
|
+
const stat = await fsPromises.stat(filePath);
|
|
247
|
+
return {
|
|
248
|
+
isFile: () => stat.isFile(),
|
|
249
|
+
isDirectory: () => stat.isDirectory(),
|
|
250
|
+
mtimeMs: stat.mtimeMs
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
unlink: async (filePath) => {
|
|
254
|
+
await fsPromises.unlink(filePath);
|
|
255
|
+
},
|
|
256
|
+
mkdir: async (filePath, options) => {
|
|
257
|
+
await fsPromises.mkdir(filePath, options);
|
|
258
|
+
},
|
|
259
|
+
rmdir: async (filePath) => {
|
|
260
|
+
await fsPromises.rmdir(filePath);
|
|
261
|
+
},
|
|
262
|
+
rename: async (oldPath, newPath) => {
|
|
263
|
+
await fsPromises.rename(oldPath, newPath);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
return fs;
|
|
267
|
+
}
|
|
268
|
+
async function readDocument(fs, docPath) {
|
|
269
|
+
const content = await readDocumentContent(fs, docPath);
|
|
270
|
+
return parseSuperintendentDoc(docPath, content);
|
|
271
|
+
}
|
|
272
|
+
async function readDocumentContent(fs, docPath) {
|
|
273
|
+
return fs.readFile(docPath, "utf8");
|
|
274
|
+
}
|
|
275
|
+
async function writeLoopState(fs, docPath, state) {
|
|
276
|
+
const content = await fs.readFile(docPath, "utf8");
|
|
277
|
+
const updatedContent = updateStatus(docPath, content, {
|
|
278
|
+
state: state.state,
|
|
279
|
+
round: state.round,
|
|
280
|
+
review_turn: state.reviewTurn
|
|
281
|
+
});
|
|
282
|
+
await fs.writeFile(docPath, updatedContent, { encoding: "utf8" });
|
|
283
|
+
}
|
|
284
|
+
async function restoreDocument(fs, docPath, content) {
|
|
285
|
+
await fs.writeFile(docPath, content, { encoding: "utf8" });
|
|
286
|
+
}
|
|
287
|
+
async function rollbackRoundStatus(options, state) {
|
|
288
|
+
await writeLoopState(options.fs, options.docPath, state);
|
|
289
|
+
emitStateChange(options.callbacks, state);
|
|
290
|
+
return state;
|
|
291
|
+
}
|
|
292
|
+
function createTemplateContext(context) {
|
|
293
|
+
return {
|
|
294
|
+
...(context.builder ? { builder: context.builder } : {}),
|
|
295
|
+
inspectors: { ...context.inspectors },
|
|
296
|
+
inspector_logs: { ...context.inspectorLogs },
|
|
297
|
+
...(context.superintendentSummary
|
|
298
|
+
? {
|
|
299
|
+
superintendent: {
|
|
300
|
+
summary: context.superintendentSummary,
|
|
301
|
+
...(context.superintendentLogPath ? { log_path: context.superintendentLogPath } : {})
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
: {}),
|
|
305
|
+
...(context.ownerFeedback
|
|
306
|
+
? {
|
|
307
|
+
owner: {
|
|
308
|
+
feedback: context.ownerFeedback,
|
|
309
|
+
...(context.ownerLogPath ? { log_path: context.ownerLogPath } : {})
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
: {})
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function beginRound(state) {
|
|
316
|
+
return {
|
|
317
|
+
...state,
|
|
318
|
+
state: "in_progress",
|
|
319
|
+
round: state.round + 1,
|
|
320
|
+
reviewTurn: 0
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function applyOwnerFeedback(state, continueReview) {
|
|
324
|
+
const nextReviewTurn = state.reviewTurn + 1;
|
|
325
|
+
if (continueReview && nextReviewTurn < state.maxReviewTurns) {
|
|
326
|
+
return {
|
|
327
|
+
...state,
|
|
328
|
+
state: "review",
|
|
329
|
+
reviewTurn: nextReviewTurn
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
...state,
|
|
334
|
+
state: "in_progress",
|
|
335
|
+
reviewTurn: 0
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
async function executeSuperintendent(options, context) {
|
|
339
|
+
options.callbacks.onSuperintendentStart?.();
|
|
340
|
+
const snapshot = await readDocumentContent(options.fs, options.docPath);
|
|
341
|
+
try {
|
|
342
|
+
const doc = await readDocument(options.fs, options.docPath);
|
|
343
|
+
const result = await options.runners.superintendent(doc, createTemplateContext(context), buildRoleOptions(options, "superintendent"));
|
|
344
|
+
options.callbacks.onSuperintendentComplete?.(result);
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
await restoreDocument(options.fs, options.docPath, snapshot);
|
|
349
|
+
throw toError(error);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function buildRoleOptions(options, role) {
|
|
353
|
+
return {
|
|
354
|
+
defaultCwd: options.cwd,
|
|
355
|
+
...(options.logDir ? { logPath: path.join(options.logDir, makeRunLogFileName(role)) } : {})
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function shouldContinueReview(doc) {
|
|
359
|
+
return parseTaskBoard(doc.body).allDone;
|
|
360
|
+
}
|
|
361
|
+
function emitStateChange(callbacks, state) {
|
|
362
|
+
callbacks.onStateChange?.({ ...state });
|
|
363
|
+
}
|
|
364
|
+
function readLoopStopReason(options, state) {
|
|
365
|
+
if (state.state === "completed") {
|
|
366
|
+
return "completed";
|
|
367
|
+
}
|
|
368
|
+
if (state.state === "in_progress" && state.round >= state.maxRounds) {
|
|
369
|
+
return "max_rounds";
|
|
370
|
+
}
|
|
371
|
+
return readInterruptionReason(options, state);
|
|
372
|
+
}
|
|
373
|
+
function readInterruptionReason(options, _state) {
|
|
374
|
+
if (options.signal?.aborted) {
|
|
375
|
+
return "aborted";
|
|
376
|
+
}
|
|
377
|
+
if (options.callbacks.shouldStop?.() === true) {
|
|
378
|
+
return "stopped";
|
|
379
|
+
}
|
|
380
|
+
if (options.callbacks.shouldPause?.() === true) {
|
|
381
|
+
return "paused";
|
|
382
|
+
}
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
function finishLoop(callbacks, state, stopReason) {
|
|
386
|
+
const snapshot = {
|
|
387
|
+
...state,
|
|
388
|
+
stopReason
|
|
389
|
+
};
|
|
390
|
+
callbacks.onLoopComplete?.(snapshot);
|
|
391
|
+
return snapshot;
|
|
392
|
+
}
|
|
393
|
+
function toError(error) {
|
|
394
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
395
|
+
}
|
|
396
|
+
function filterAutoRunInspectors(doc) {
|
|
397
|
+
const inspectors = doc.frontmatter.inspectors ?? {};
|
|
398
|
+
const configuredNames = new Set(Object.keys(inspectors));
|
|
399
|
+
const selected = new Set();
|
|
400
|
+
const queue = [...collectReferencedInspectors(doc.frontmatter.superintendent.prompt)].filter((name) => configuredNames.has(name));
|
|
401
|
+
while (queue.length > 0) {
|
|
402
|
+
const name = queue.shift();
|
|
403
|
+
if (selected.has(name)) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
selected.add(name);
|
|
407
|
+
const inspectorPrompt = inspectors[name]?.prompt ?? "";
|
|
408
|
+
for (const referenced of collectReferencedInspectors(inspectorPrompt)) {
|
|
409
|
+
if (configuredNames.has(referenced) && !selected.has(referenced)) {
|
|
410
|
+
queue.push(referenced);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return Object.entries(inspectors).filter(([name]) => selected.has(name));
|
|
415
|
+
}
|
|
416
|
+
async function withInjectedAgentRunner(options, operation) {
|
|
417
|
+
if (!options.runAgent) {
|
|
418
|
+
return operation();
|
|
419
|
+
}
|
|
420
|
+
const spawnApi = spawn;
|
|
421
|
+
const originalAutonomous = spawnApi.autonomous;
|
|
422
|
+
spawnApi.autonomous = async (agent, input) => {
|
|
423
|
+
const result = await options.runAgent?.({
|
|
424
|
+
agent,
|
|
425
|
+
prompt: input.prompt,
|
|
426
|
+
cwd: input.cwd ?? process.cwd(),
|
|
427
|
+
...(input.mode ? { mode: input.mode } : {}),
|
|
428
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
429
|
+
...(input.logPath ? { logPath: input.logPath } : {}),
|
|
430
|
+
...(options.signal ? { signal: options.signal } : {})
|
|
431
|
+
});
|
|
432
|
+
if (!result) {
|
|
433
|
+
throw new Error(`Agent \`${agent}\` returned no result.`);
|
|
434
|
+
}
|
|
435
|
+
if (result.exitCode !== 0) {
|
|
436
|
+
throw new Error(result.stderr || result.stdout || `Agent \`${agent}\` failed with exit code ${result.exitCode}`);
|
|
437
|
+
}
|
|
438
|
+
return result;
|
|
439
|
+
};
|
|
440
|
+
try {
|
|
441
|
+
return await operation();
|
|
442
|
+
}
|
|
443
|
+
finally {
|
|
444
|
+
spawnApi.autonomous = originalAutonomous;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
export function resolveRoleCwd(role, docPath, defaultCwd) {
|
|
3
|
+
if (role.cwd === undefined) {
|
|
4
|
+
return defaultCwd;
|
|
5
|
+
}
|
|
6
|
+
if (path.isAbsolute(role.cwd)) {
|
|
7
|
+
return role.cwd;
|
|
8
|
+
}
|
|
9
|
+
return path.resolve(path.dirname(docPath), role.cwd);
|
|
10
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SuperintendentDoc } from "../document/parse.js";
|
|
2
|
+
import { type TemplateContext } from "./templates.js";
|
|
3
|
+
export type BuilderResult = {
|
|
4
|
+
summary: string;
|
|
5
|
+
log: string;
|
|
6
|
+
log_path: string;
|
|
7
|
+
};
|
|
8
|
+
export type RunBuilderOptions = {
|
|
9
|
+
promptOverride?: string;
|
|
10
|
+
defaultCwd: string;
|
|
11
|
+
logPath?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function runBuilder(doc: SuperintendentDoc, context: Partial<TemplateContext>, options: RunBuilderOptions): Promise<BuilderResult>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { spawn } from "@poe-code/agent-spawn";
|
|
2
|
+
import { resolveRoleCwd } from "./resolve-cwd.js";
|
|
3
|
+
import { resolveTemplate } from "./templates.js";
|
|
4
|
+
export async function runBuilder(doc, context, options) {
|
|
5
|
+
const prompt = options.promptOverride ??
|
|
6
|
+
resolveTemplate(doc.frontmatter.builder.prompt, buildTemplateContext(doc, context));
|
|
7
|
+
const result = await runAutonomous({
|
|
8
|
+
agent: doc.frontmatter.builder.agent,
|
|
9
|
+
mode: doc.frontmatter.builder.mode,
|
|
10
|
+
prompt,
|
|
11
|
+
cwd: resolveRoleCwd(doc.frontmatter.builder, doc.filePath, options.defaultCwd),
|
|
12
|
+
mcpServers: buildMcpServers(doc),
|
|
13
|
+
...(options.logPath ? { logPath: options.logPath } : {})
|
|
14
|
+
});
|
|
15
|
+
const log = extractLog(result);
|
|
16
|
+
return {
|
|
17
|
+
summary: extractSummary(result, log),
|
|
18
|
+
log,
|
|
19
|
+
log_path: extractLogPath(result, options)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function buildMcpServers(doc) {
|
|
23
|
+
const merged = {
|
|
24
|
+
...(doc.frontmatter.mcp ?? {}),
|
|
25
|
+
...(doc.frontmatter.builder.mcp ?? {})
|
|
26
|
+
};
|
|
27
|
+
if (Object.keys(merged).length === 0) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const servers = {};
|
|
31
|
+
for (const [name, config] of Object.entries(merged)) {
|
|
32
|
+
servers[name] = {
|
|
33
|
+
command: config.command,
|
|
34
|
+
...(config.args ? { args: [...config.args] } : {}),
|
|
35
|
+
...(config.timeout !== undefined ? { timeout: config.timeout } : {})
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return servers;
|
|
39
|
+
}
|
|
40
|
+
function buildTemplateContext(doc, context) {
|
|
41
|
+
return {
|
|
42
|
+
...context,
|
|
43
|
+
plan: {
|
|
44
|
+
...(context.plan ?? { path: doc.filePath }),
|
|
45
|
+
path: doc.filePath
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function runAutonomous(input) {
|
|
50
|
+
const spawnApi = spawn;
|
|
51
|
+
if (typeof spawnApi.autonomous === "function") {
|
|
52
|
+
return spawnApi.autonomous(input.agent, {
|
|
53
|
+
cwd: input.cwd,
|
|
54
|
+
prompt: input.prompt,
|
|
55
|
+
mode: input.mode,
|
|
56
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
57
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
const result = await spawn(input.agent, {
|
|
61
|
+
cwd: input.cwd,
|
|
62
|
+
prompt: input.prompt,
|
|
63
|
+
mode: input.mode,
|
|
64
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
65
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
stdout: result.stdout,
|
|
69
|
+
...(result.logFile ? { logFile: result.logFile } : {})
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function extractLog(result) {
|
|
73
|
+
if (typeof result === "string") {
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
return readString(result.log) ?? readString(result.output) ?? readString(result.stdout) ?? readString(result.text) ?? "";
|
|
77
|
+
}
|
|
78
|
+
function extractLogPath(result, options) {
|
|
79
|
+
if (typeof result !== "string") {
|
|
80
|
+
const logFile = readString(result.logFile);
|
|
81
|
+
if (logFile) {
|
|
82
|
+
return logFile;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return options.logPath ?? "";
|
|
86
|
+
}
|
|
87
|
+
function extractSummary(result, log) {
|
|
88
|
+
if (typeof result !== "string") {
|
|
89
|
+
const explicitSummary = readString(result.summary)?.trim();
|
|
90
|
+
if (explicitSummary) {
|
|
91
|
+
return explicitSummary;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const firstNonEmptyLine = log
|
|
95
|
+
.split("\n")
|
|
96
|
+
.map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line).trim())
|
|
97
|
+
.find((line) => line.length > 0);
|
|
98
|
+
return firstNonEmptyLine ?? "Builder completed without output.";
|
|
99
|
+
}
|
|
100
|
+
function readString(value) {
|
|
101
|
+
return typeof value === "string" ? value : undefined;
|
|
102
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentRoleConfig, SuperintendentDoc } from "../document/parse.js";
|
|
2
|
+
import { type TemplateContext } from "./templates.js";
|
|
3
|
+
export type InspectorResult = {
|
|
4
|
+
name: string;
|
|
5
|
+
summary: string;
|
|
6
|
+
log_path?: string;
|
|
7
|
+
};
|
|
8
|
+
export type RunInspectorOptions = {
|
|
9
|
+
promptOverride?: string;
|
|
10
|
+
defaultCwd: string;
|
|
11
|
+
logPath?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function runInspector(name: string, config: AgentRoleConfig, doc: SuperintendentDoc, context: Partial<TemplateContext>, options: RunInspectorOptions): Promise<InspectorResult>;
|
|
14
|
+
export declare function runAllInspectors(doc: SuperintendentDoc, context: Partial<TemplateContext>, options: {
|
|
15
|
+
defaultCwd: string;
|
|
16
|
+
}): Promise<InspectorResult[]>;
|