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,119 @@
|
|
|
1
|
+
import { spawn } from "@poe-code/agent-spawn";
|
|
2
|
+
import { resolveRoleCwd } from "./resolve-cwd.js";
|
|
3
|
+
import { buildInspectorSystemPrompt, prependSystemPrompt } from "./system-prompt.js";
|
|
4
|
+
import { resolveTemplate } from "./templates.js";
|
|
5
|
+
export async function runInspector(name, config, doc, context, options) {
|
|
6
|
+
const userPrompt = options.promptOverride ??
|
|
7
|
+
resolveTemplate(config.prompt, buildTemplateContext(doc, context));
|
|
8
|
+
const systemPrompt = buildInspectorSystemPrompt({
|
|
9
|
+
inspectorName: name,
|
|
10
|
+
...(context.builder
|
|
11
|
+
? {
|
|
12
|
+
builder: {
|
|
13
|
+
summary: context.builder.summary,
|
|
14
|
+
...(context.builder.log_path ? { log_path: context.builder.log_path } : {})
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
: {})
|
|
18
|
+
});
|
|
19
|
+
const prompt = prependSystemPrompt(systemPrompt, userPrompt);
|
|
20
|
+
const output = await runAutonomous({
|
|
21
|
+
agent: config.agent,
|
|
22
|
+
mode: config.mode,
|
|
23
|
+
prompt,
|
|
24
|
+
cwd: resolveRoleCwd(config, doc.filePath, options.defaultCwd),
|
|
25
|
+
mcpServers: buildMcpServers(doc, config),
|
|
26
|
+
...(options.logPath ? { logPath: options.logPath } : {})
|
|
27
|
+
});
|
|
28
|
+
const logPath = extractLogPath(output);
|
|
29
|
+
return {
|
|
30
|
+
name,
|
|
31
|
+
summary: extractSummary(output),
|
|
32
|
+
...(logPath ? { log_path: logPath } : {})
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function buildMcpServers(doc, config) {
|
|
36
|
+
const merged = {
|
|
37
|
+
...(doc.frontmatter.mcp ?? {}),
|
|
38
|
+
...(config.mcp ?? {})
|
|
39
|
+
};
|
|
40
|
+
if (Object.keys(merged).length === 0) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const servers = {};
|
|
44
|
+
for (const [name, mcpConfig] of Object.entries(merged)) {
|
|
45
|
+
servers[name] = {
|
|
46
|
+
command: mcpConfig.command,
|
|
47
|
+
...(mcpConfig.args ? { args: [...mcpConfig.args] } : {}),
|
|
48
|
+
...(mcpConfig.timeout !== undefined ? { timeout: mcpConfig.timeout } : {})
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return servers;
|
|
52
|
+
}
|
|
53
|
+
export async function runAllInspectors(doc, context, options) {
|
|
54
|
+
const inspectors = doc.frontmatter.inspectors;
|
|
55
|
+
if (inspectors === undefined) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const inspectorSummaries = { ...(context.inspectors ?? {}) };
|
|
59
|
+
const results = [];
|
|
60
|
+
for (const [name, config] of Object.entries(inspectors)) {
|
|
61
|
+
const result = await runInspector(name, config, doc, {
|
|
62
|
+
...context,
|
|
63
|
+
inspectors: inspectorSummaries
|
|
64
|
+
}, options);
|
|
65
|
+
results.push(result);
|
|
66
|
+
inspectorSummaries[name] = result.summary;
|
|
67
|
+
}
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
function buildTemplateContext(doc, context) {
|
|
71
|
+
return {
|
|
72
|
+
...context,
|
|
73
|
+
plan: {
|
|
74
|
+
...(context.plan ?? { path: doc.filePath }),
|
|
75
|
+
path: doc.filePath
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async function runAutonomous(input) {
|
|
80
|
+
const spawnApi = spawn;
|
|
81
|
+
if (typeof spawnApi.autonomous === "function") {
|
|
82
|
+
return spawnApi.autonomous(input.agent, {
|
|
83
|
+
cwd: input.cwd,
|
|
84
|
+
prompt: input.prompt,
|
|
85
|
+
mode: input.mode,
|
|
86
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
87
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const result = await spawn(input.agent, {
|
|
91
|
+
cwd: input.cwd,
|
|
92
|
+
prompt: input.prompt,
|
|
93
|
+
mode: input.mode,
|
|
94
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
95
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
96
|
+
});
|
|
97
|
+
return {
|
|
98
|
+
stdout: result.stdout,
|
|
99
|
+
...(result.logFile ? { logFile: result.logFile } : {})
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function extractLogPath(result) {
|
|
103
|
+
if (typeof result === "string")
|
|
104
|
+
return undefined;
|
|
105
|
+
return typeof result.logFile === "string" ? result.logFile : undefined;
|
|
106
|
+
}
|
|
107
|
+
function extractSummary(result) {
|
|
108
|
+
if (typeof result === "string") {
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
return (readString(result.summary) ??
|
|
112
|
+
readString(result.output) ??
|
|
113
|
+
readString(result.stdout) ??
|
|
114
|
+
readString(result.text) ??
|
|
115
|
+
"");
|
|
116
|
+
}
|
|
117
|
+
function readString(value) {
|
|
118
|
+
return typeof value === "string" ? value : undefined;
|
|
119
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SuperintendentDoc } from "../document/parse.js";
|
|
2
|
+
import { type TemplateContext } from "./templates.js";
|
|
3
|
+
import { type WorkflowTransition } from "./workflow-tool.js";
|
|
4
|
+
type OwnerTransition = Extract<WorkflowTransition, {
|
|
5
|
+
action: "approve_completion";
|
|
6
|
+
} | {
|
|
7
|
+
action: "request_changes";
|
|
8
|
+
}>;
|
|
9
|
+
export type OwnerResult = {
|
|
10
|
+
transition: OwnerTransition;
|
|
11
|
+
log_path?: string;
|
|
12
|
+
};
|
|
13
|
+
export type RunOwnerReviewOptions = {
|
|
14
|
+
defaultCwd: string;
|
|
15
|
+
logPath?: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function runOwnerReview(doc: SuperintendentDoc, context: Partial<TemplateContext>, options: RunOwnerReviewOptions): Promise<OwnerResult>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { spawn } from "@poe-code/agent-spawn";
|
|
2
|
+
import { resolveRoleCwd } from "./resolve-cwd.js";
|
|
3
|
+
import { buildOwnerSystemPrompt, prependSystemPrompt } from "./system-prompt.js";
|
|
4
|
+
import { resolveTemplate } from "./templates.js";
|
|
5
|
+
import { createWorkflowTool, parseWorkflowCall } from "./workflow-tool.js";
|
|
6
|
+
const WORKFLOW_SERVER_NAME = "owner-workflow";
|
|
7
|
+
const WORKFLOW_SERVER_COMMAND = "poe-superintendent-mcp";
|
|
8
|
+
const WORKFLOW_SERVER_SUBCOMMAND = "workflow-transition";
|
|
9
|
+
const WORKFLOW_SERVER_TIMEOUT_SECONDS = 7200;
|
|
10
|
+
export async function runOwnerReview(doc, context, options) {
|
|
11
|
+
const userPrompt = resolveTemplate(doc.frontmatter.owner.prompt, buildTemplateContext(doc, context));
|
|
12
|
+
const prompt = prependSystemPrompt(buildOwnerSystemPrompt(), userPrompt);
|
|
13
|
+
const result = await runAutonomous({
|
|
14
|
+
agent: doc.frontmatter.owner.agent,
|
|
15
|
+
mode: doc.frontmatter.owner.mode,
|
|
16
|
+
prompt,
|
|
17
|
+
cwd: resolveRoleCwd(doc.frontmatter.owner, doc.filePath, options.defaultCwd),
|
|
18
|
+
mcpServers: buildMcpServers(doc),
|
|
19
|
+
...(options.logPath ? { logPath: options.logPath } : {})
|
|
20
|
+
});
|
|
21
|
+
const logPath = extractLogPath(result);
|
|
22
|
+
return {
|
|
23
|
+
transition: extractOwnerTransition(result),
|
|
24
|
+
...(logPath ? { log_path: logPath } : {})
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function buildTemplateContext(doc, context) {
|
|
28
|
+
return { ...context, plan: { path: doc.filePath } };
|
|
29
|
+
}
|
|
30
|
+
function buildMcpServers(doc) {
|
|
31
|
+
const servers = {
|
|
32
|
+
[WORKFLOW_SERVER_NAME]: createWorkflowServer()
|
|
33
|
+
};
|
|
34
|
+
const merged = {
|
|
35
|
+
...(doc.frontmatter.mcp ?? {}),
|
|
36
|
+
...(doc.frontmatter.owner.mcp ?? {})
|
|
37
|
+
};
|
|
38
|
+
for (const [name, config] of Object.entries(merged)) {
|
|
39
|
+
servers[name] = toSpawnMcpServer(config);
|
|
40
|
+
}
|
|
41
|
+
return servers;
|
|
42
|
+
}
|
|
43
|
+
function createWorkflowServer() {
|
|
44
|
+
const workflowTool = createWorkflowTool("owner", "review");
|
|
45
|
+
return {
|
|
46
|
+
command: WORKFLOW_SERVER_COMMAND,
|
|
47
|
+
args: [WORKFLOW_SERVER_SUBCOMMAND, encodeJson(workflowTool)],
|
|
48
|
+
timeout: WORKFLOW_SERVER_TIMEOUT_SECONDS
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function toSpawnMcpServer(config) {
|
|
52
|
+
return {
|
|
53
|
+
command: config.command,
|
|
54
|
+
...(config.args ? { args: [...config.args] } : {}),
|
|
55
|
+
...(config.timeout !== undefined ? { timeout: config.timeout } : {})
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async function runAutonomous(input) {
|
|
59
|
+
const spawnApi = spawn;
|
|
60
|
+
if (typeof spawnApi.autonomous === "function") {
|
|
61
|
+
return spawnApi.autonomous(input.agent, {
|
|
62
|
+
cwd: input.cwd,
|
|
63
|
+
prompt: input.prompt,
|
|
64
|
+
mode: input.mode,
|
|
65
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
66
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const result = await spawn(input.agent, {
|
|
70
|
+
cwd: input.cwd,
|
|
71
|
+
prompt: input.prompt,
|
|
72
|
+
mode: input.mode,
|
|
73
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
74
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
stdout: result.stdout,
|
|
78
|
+
...(result.logFile ? { logFile: result.logFile } : {})
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function extractLogPath(result) {
|
|
82
|
+
if (typeof result === "string")
|
|
83
|
+
return undefined;
|
|
84
|
+
return typeof result.logFile === "string" ? result.logFile : undefined;
|
|
85
|
+
}
|
|
86
|
+
function extractOwnerTransition(result) {
|
|
87
|
+
const transition = extractTransition(result);
|
|
88
|
+
if (transition === undefined) {
|
|
89
|
+
throw new Error(`Owner review must end with workflow_transition.${describeMissingTransition(result)}`);
|
|
90
|
+
}
|
|
91
|
+
if (transition.action !== "approve_completion" && transition.action !== "request_changes") {
|
|
92
|
+
throw new Error(`Owner review returned invalid transition: ${transition.action}`);
|
|
93
|
+
}
|
|
94
|
+
return transition;
|
|
95
|
+
}
|
|
96
|
+
function describeMissingTransition(result) {
|
|
97
|
+
const parts = [];
|
|
98
|
+
const names = collectToolNames(result);
|
|
99
|
+
parts.push(names.length === 0 ? " No tool calls were captured." : ` Observed tool calls: ${names.join(", ")}.`);
|
|
100
|
+
const logPath = extractLogPath(result);
|
|
101
|
+
if (logPath) {
|
|
102
|
+
parts.push(` See spawn log: ${logPath}`);
|
|
103
|
+
}
|
|
104
|
+
return parts.join("");
|
|
105
|
+
}
|
|
106
|
+
function collectToolNames(result) {
|
|
107
|
+
if (typeof result === "string") {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const names = [];
|
|
111
|
+
collectToolNamesFrom(result.toolCalls, names);
|
|
112
|
+
if (isRecord(result.sessionResult)) {
|
|
113
|
+
collectToolNamesFrom(result.sessionResult.toolCalls, names);
|
|
114
|
+
}
|
|
115
|
+
return names;
|
|
116
|
+
}
|
|
117
|
+
function collectToolNamesFrom(value, out) {
|
|
118
|
+
if (!Array.isArray(value)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const entry of value) {
|
|
122
|
+
const toolCall = readToolCall(entry);
|
|
123
|
+
const name = toolCall ? readToolCallName(toolCall) : undefined;
|
|
124
|
+
if (name) {
|
|
125
|
+
out.push(name);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function extractTransition(result) {
|
|
130
|
+
if (typeof result === "string") {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
const toolCallTransition = readTransitionFromToolCalls(result.toolCalls);
|
|
134
|
+
if (toolCallTransition) {
|
|
135
|
+
return toolCallTransition;
|
|
136
|
+
}
|
|
137
|
+
return readTransitionFromSessionResult(result.sessionResult);
|
|
138
|
+
}
|
|
139
|
+
function readTransitionFromToolCalls(value) {
|
|
140
|
+
if (!Array.isArray(value)) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
for (const entry of value) {
|
|
144
|
+
const toolCall = readToolCall(entry);
|
|
145
|
+
if (!toolCall || !isWorkflowToolName(readToolCallName(toolCall))) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
const argumentsValue = readToolCallArguments(toolCall);
|
|
149
|
+
if (argumentsValue === undefined) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
return parseWorkflowCall(parseJsonValue(argumentsValue));
|
|
153
|
+
}
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
function readTransitionFromSessionResult(value) {
|
|
157
|
+
if (!isRecord(value)) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return readTransitionFromToolCalls(value.toolCalls);
|
|
161
|
+
}
|
|
162
|
+
function readToolCall(value) {
|
|
163
|
+
return isRecord(value) ? value : undefined;
|
|
164
|
+
}
|
|
165
|
+
function readToolCallName(toolCall) {
|
|
166
|
+
return (readString(toolCall.name) ??
|
|
167
|
+
readString(toolCall.tool) ??
|
|
168
|
+
readString(toolCall.title) ??
|
|
169
|
+
readString(toolCall.path));
|
|
170
|
+
}
|
|
171
|
+
function readToolCallArguments(toolCall) {
|
|
172
|
+
return toolCall.arguments ?? toolCall.args ?? toolCall.input;
|
|
173
|
+
}
|
|
174
|
+
function isWorkflowToolName(name) {
|
|
175
|
+
if (!name)
|
|
176
|
+
return false;
|
|
177
|
+
if (name === "workflow_transition")
|
|
178
|
+
return true;
|
|
179
|
+
return name.startsWith("mcp__") && name.endsWith("__workflow_transition");
|
|
180
|
+
}
|
|
181
|
+
function parseJsonValue(value) {
|
|
182
|
+
if (typeof value !== "string") {
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
const trimmed = value.trim();
|
|
186
|
+
if (trimmed.length === 0) {
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
const parsed = tryParseJson(trimmed);
|
|
190
|
+
return parsed === undefined ? value : parsed;
|
|
191
|
+
}
|
|
192
|
+
function tryParseJson(value) {
|
|
193
|
+
try {
|
|
194
|
+
return JSON.parse(value);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function encodeJson(value) {
|
|
201
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
|
|
202
|
+
}
|
|
203
|
+
function readString(value) {
|
|
204
|
+
return typeof value === "string" ? value : undefined;
|
|
205
|
+
}
|
|
206
|
+
function isRecord(value) {
|
|
207
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
208
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SuperintendentDoc } from "../document/parse.js";
|
|
2
|
+
import { type TemplateContext } from "./templates.js";
|
|
3
|
+
import { type WorkflowTransition } from "./workflow-tool.js";
|
|
4
|
+
export type SuperintendentResult = {
|
|
5
|
+
summary: string;
|
|
6
|
+
transition?: WorkflowTransition;
|
|
7
|
+
log_path?: string;
|
|
8
|
+
};
|
|
9
|
+
export type RunSuperintendentOptions = {
|
|
10
|
+
defaultCwd: string;
|
|
11
|
+
logPath?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function runSuperintendent(doc: SuperintendentDoc, context: Partial<TemplateContext>, options: RunSuperintendentOptions): Promise<SuperintendentResult>;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { spawn } from "@poe-code/agent-spawn";
|
|
2
|
+
import { resolveRoleCwd } from "./resolve-cwd.js";
|
|
3
|
+
import { buildSuperintendentSystemPrompt, prependSystemPrompt } from "./system-prompt.js";
|
|
4
|
+
import { resolveTemplate } from "./templates.js";
|
|
5
|
+
import { parseWorkflowCall } from "./workflow-tool.js";
|
|
6
|
+
const SUPERINTENDENT_TOOLS_SERVER_NAME = "superintendent-tools";
|
|
7
|
+
const SUPERINTENDENT_TOOLS_SERVER_COMMAND = "poe-superintendent-mcp";
|
|
8
|
+
const SUPERINTENDENT_TOOLS_SERVER_SUBCOMMAND = "superintendent-tools";
|
|
9
|
+
const SUPERINTENDENT_TOOLS_TIMEOUT_SECONDS = 7200;
|
|
10
|
+
export async function runSuperintendent(doc, context, options) {
|
|
11
|
+
const userPrompt = resolveTemplate(doc.frontmatter.superintendent.prompt, buildTemplateContext(doc, context));
|
|
12
|
+
const systemPrompt = buildSuperintendentSystemPrompt({
|
|
13
|
+
state: doc.frontmatter.status.state,
|
|
14
|
+
inspectorNames: Object.keys(doc.frontmatter.inspectors ?? {})
|
|
15
|
+
});
|
|
16
|
+
const prompt = prependSystemPrompt(systemPrompt, userPrompt);
|
|
17
|
+
const result = await runAutonomous({
|
|
18
|
+
agent: doc.frontmatter.superintendent.agent,
|
|
19
|
+
mode: doc.frontmatter.superintendent.mode,
|
|
20
|
+
prompt,
|
|
21
|
+
cwd: resolveRoleCwd(doc.frontmatter.superintendent, doc.filePath, options.defaultCwd),
|
|
22
|
+
mcpServers: buildMcpServers(doc),
|
|
23
|
+
...(options.logPath ? { logPath: options.logPath } : {})
|
|
24
|
+
});
|
|
25
|
+
const transition = extractTransition(result);
|
|
26
|
+
const logPath = extractLogPath(result);
|
|
27
|
+
return {
|
|
28
|
+
summary: extractSummary(result, transition),
|
|
29
|
+
...(transition ? { transition } : {}),
|
|
30
|
+
...(logPath ? { log_path: logPath } : {})
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function buildTemplateContext(doc, context) {
|
|
34
|
+
return {
|
|
35
|
+
...context,
|
|
36
|
+
plan: {
|
|
37
|
+
...(context.plan ?? { path: doc.filePath }),
|
|
38
|
+
path: doc.filePath
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function buildMcpServers(doc) {
|
|
43
|
+
const servers = {
|
|
44
|
+
[SUPERINTENDENT_TOOLS_SERVER_NAME]: createSuperintendentToolsServer(doc)
|
|
45
|
+
};
|
|
46
|
+
const merged = {
|
|
47
|
+
...(doc.frontmatter.mcp ?? {}),
|
|
48
|
+
...(doc.frontmatter.superintendent.mcp ?? {})
|
|
49
|
+
};
|
|
50
|
+
for (const [name, config] of Object.entries(merged)) {
|
|
51
|
+
servers[name] = toSpawnMcpServer(config);
|
|
52
|
+
}
|
|
53
|
+
return servers;
|
|
54
|
+
}
|
|
55
|
+
function createSuperintendentToolsServer(doc) {
|
|
56
|
+
const payload = {
|
|
57
|
+
docPath: doc.filePath,
|
|
58
|
+
state: doc.frontmatter.status.state,
|
|
59
|
+
inspectorNames: Object.keys(doc.frontmatter.inspectors ?? {})
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
command: SUPERINTENDENT_TOOLS_SERVER_COMMAND,
|
|
63
|
+
args: [SUPERINTENDENT_TOOLS_SERVER_SUBCOMMAND, encodeJson(payload)],
|
|
64
|
+
timeout: SUPERINTENDENT_TOOLS_TIMEOUT_SECONDS
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function toSpawnMcpServer(config) {
|
|
68
|
+
return {
|
|
69
|
+
command: config.command,
|
|
70
|
+
...(config.args ? { args: [...config.args] } : {}),
|
|
71
|
+
...(config.timeout !== undefined ? { timeout: config.timeout } : {})
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async function runAutonomous(input) {
|
|
75
|
+
const spawnApi = spawn;
|
|
76
|
+
if (typeof spawnApi.autonomous === "function") {
|
|
77
|
+
return spawnApi.autonomous(input.agent, {
|
|
78
|
+
cwd: input.cwd,
|
|
79
|
+
prompt: input.prompt,
|
|
80
|
+
mode: input.mode,
|
|
81
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
82
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const result = await spawn(input.agent, {
|
|
86
|
+
cwd: input.cwd,
|
|
87
|
+
prompt: input.prompt,
|
|
88
|
+
mode: input.mode,
|
|
89
|
+
...(input.mcpServers ? { mcpServers: input.mcpServers } : {}),
|
|
90
|
+
...(input.logPath ? { logPath: input.logPath } : {})
|
|
91
|
+
});
|
|
92
|
+
return {
|
|
93
|
+
stdout: result.stdout,
|
|
94
|
+
...(result.logFile ? { logFile: result.logFile } : {})
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function extractLogPath(result) {
|
|
98
|
+
if (typeof result === "string")
|
|
99
|
+
return undefined;
|
|
100
|
+
return typeof result.logFile === "string" ? result.logFile : undefined;
|
|
101
|
+
}
|
|
102
|
+
function extractTransition(result) {
|
|
103
|
+
if (typeof result === "string") {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const toolCallTransition = readTransitionFromToolCalls(result.toolCalls);
|
|
107
|
+
if (toolCallTransition) {
|
|
108
|
+
return toolCallTransition;
|
|
109
|
+
}
|
|
110
|
+
return readTransitionFromSessionResult(result.sessionResult);
|
|
111
|
+
}
|
|
112
|
+
function readTransitionFromToolCalls(value) {
|
|
113
|
+
if (!Array.isArray(value)) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
for (const entry of value) {
|
|
117
|
+
const toolCall = readToolCall(entry);
|
|
118
|
+
if (!toolCall || !isWorkflowToolName(readToolCallName(toolCall))) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const argumentsValue = readToolCallArguments(toolCall);
|
|
122
|
+
if (argumentsValue === undefined) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
return parseWorkflowCall(parseJsonValue(argumentsValue));
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
function readTransitionFromSessionResult(value) {
|
|
130
|
+
if (!isRecord(value)) {
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
return readTransitionFromToolCalls(value.toolCalls);
|
|
134
|
+
}
|
|
135
|
+
function extractSummary(result, transition) {
|
|
136
|
+
if (typeof result !== "string") {
|
|
137
|
+
const explicitSummary = readString(result.summary)?.trim();
|
|
138
|
+
if (explicitSummary) {
|
|
139
|
+
return explicitSummary;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (transition?.action === "request_review") {
|
|
143
|
+
return transition.summary;
|
|
144
|
+
}
|
|
145
|
+
const firstNonEmptyLine = splitLines(extractOutputText(result))
|
|
146
|
+
.map((line) => line.trim())
|
|
147
|
+
.find((line) => line.length > 0);
|
|
148
|
+
return firstNonEmptyLine ?? "Superintendent completed without output.";
|
|
149
|
+
}
|
|
150
|
+
function extractOutputText(result) {
|
|
151
|
+
if (typeof result === "string") {
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
return (readString(result.output) ??
|
|
155
|
+
readString(result.stdout) ??
|
|
156
|
+
readString(result.text) ??
|
|
157
|
+
"");
|
|
158
|
+
}
|
|
159
|
+
function readToolCall(value) {
|
|
160
|
+
return isRecord(value) ? value : undefined;
|
|
161
|
+
}
|
|
162
|
+
function readToolCallName(toolCall) {
|
|
163
|
+
return (readString(toolCall.name) ??
|
|
164
|
+
readString(toolCall.tool) ??
|
|
165
|
+
readString(toolCall.title) ??
|
|
166
|
+
readString(toolCall.path));
|
|
167
|
+
}
|
|
168
|
+
function readToolCallArguments(toolCall) {
|
|
169
|
+
return toolCall.arguments ?? toolCall.args ?? toolCall.input;
|
|
170
|
+
}
|
|
171
|
+
function isWorkflowToolName(name) {
|
|
172
|
+
if (!name)
|
|
173
|
+
return false;
|
|
174
|
+
if (name === "workflow_transition")
|
|
175
|
+
return true;
|
|
176
|
+
return name.startsWith("mcp__") && name.endsWith("__workflow_transition");
|
|
177
|
+
}
|
|
178
|
+
function parseJsonValue(value) {
|
|
179
|
+
if (typeof value !== "string") {
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
const trimmed = value.trim();
|
|
183
|
+
if (trimmed.length === 0) {
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
const parsed = tryParseJson(trimmed);
|
|
187
|
+
return parsed === undefined ? value : parsed;
|
|
188
|
+
}
|
|
189
|
+
function tryParseJson(value) {
|
|
190
|
+
try {
|
|
191
|
+
return JSON.parse(value);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function encodeJson(value) {
|
|
198
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
|
|
199
|
+
}
|
|
200
|
+
function splitLines(value) {
|
|
201
|
+
return value.split("\n").map((line) => (line.endsWith("\r") ? line.slice(0, -1) : line));
|
|
202
|
+
}
|
|
203
|
+
function readString(value) {
|
|
204
|
+
return typeof value === "string" ? value : undefined;
|
|
205
|
+
}
|
|
206
|
+
function isRecord(value) {
|
|
207
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
208
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { StatusBlock } from "../document/parse.js";
|
|
2
|
+
type SuperintendentSystemPromptInput = {
|
|
3
|
+
state: StatusBlock["state"];
|
|
4
|
+
inspectorNames: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function buildSuperintendentSystemPrompt(input: SuperintendentSystemPromptInput): string;
|
|
7
|
+
type InspectorSystemPromptInput = {
|
|
8
|
+
inspectorName: string;
|
|
9
|
+
builder?: {
|
|
10
|
+
summary: string;
|
|
11
|
+
log_path?: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export declare function buildInspectorSystemPrompt(input: InspectorSystemPromptInput): string;
|
|
15
|
+
export declare function buildOwnerSystemPrompt(): string;
|
|
16
|
+
export declare function prependSystemPrompt(systemPrompt: string, userPrompt: string): string;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export function buildSuperintendentSystemPrompt(input) {
|
|
2
|
+
const sections = [
|
|
3
|
+
"# System",
|
|
4
|
+
"",
|
|
5
|
+
"You operate inside an autonomous build-inspect-review loop. The runtime advances only when you invoke MCP tools — narrative text is NOT observed. A decision is only recorded when you call the corresponding tool.",
|
|
6
|
+
"",
|
|
7
|
+
"## `workflow_transition` — control flow (required when work is ready)",
|
|
8
|
+
"",
|
|
9
|
+
"Invoke the `workflow_transition` MCP tool to hand off to the owner:",
|
|
10
|
+
"",
|
|
11
|
+
'- arguments: `{ "action": "request_review", "summary": "<why the work is ready>" }`',
|
|
12
|
+
"",
|
|
13
|
+
"Without this tool call, the loop starts another builder round. Do not narrate readiness — always invoke the tool.",
|
|
14
|
+
"",
|
|
15
|
+
"## `builder_run` — spawn the builder mid-round (optional)",
|
|
16
|
+
"",
|
|
17
|
+
"Invoke the `builder_run` MCP tool to run the builder with a custom prompt without waiting for the next auto-run round:",
|
|
18
|
+
"",
|
|
19
|
+
'- arguments: `{ "prompt": "<full builder prompt>" }`',
|
|
20
|
+
"",
|
|
21
|
+
"The prompt replaces the configured `builder.prompt` template for this call only."
|
|
22
|
+
];
|
|
23
|
+
if (input.inspectorNames.length > 0) {
|
|
24
|
+
sections.push("", "## `inspector_run` — re-run an inspector mid-round (optional)", "", "Invoke the `inspector_run` MCP tool to re-run a specific inspector (e.g. to verify a fix):", "", `- arguments: \`{ "name": "<inspector-name>", "prompt"?: "<override>" }\` — available inspectors: ${input.inspectorNames.join(", ")}.`);
|
|
25
|
+
}
|
|
26
|
+
return sections.join("\n");
|
|
27
|
+
}
|
|
28
|
+
export function buildInspectorSystemPrompt(input) {
|
|
29
|
+
const sections = [
|
|
30
|
+
"# System",
|
|
31
|
+
"",
|
|
32
|
+
`You are the \`${input.inspectorName}\` inspector. Review the most recent builder round; scope your review to the change reported below — do not wander into unrelated areas of the repo.`
|
|
33
|
+
];
|
|
34
|
+
if (input.builder) {
|
|
35
|
+
sections.push("", "## Builder summary", "", input.builder.summary || "(builder produced no summary)");
|
|
36
|
+
if (input.builder.log_path) {
|
|
37
|
+
sections.push("", "## Builder replay log", "", `Replay the builder's tool calls with: \`npm run replay -- ${input.builder.log_path}\``);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return sections.join("\n");
|
|
41
|
+
}
|
|
42
|
+
export function buildOwnerSystemPrompt() {
|
|
43
|
+
return [
|
|
44
|
+
"# System",
|
|
45
|
+
"",
|
|
46
|
+
"You are the owner reviewing the superintendent's work. The runtime advances only when you invoke MCP tools — narrative text is NOT observed. You MUST end your turn by invoking the `workflow_transition` MCP tool:",
|
|
47
|
+
"",
|
|
48
|
+
'- arguments: `{ "action": "approve_completion" }` — accept the work. Ends the loop.',
|
|
49
|
+
'- arguments: `{ "action": "request_changes", "feedback": "<what needs to change>" }` — send the work back; the loop continues with a new builder round.'
|
|
50
|
+
].join("\n");
|
|
51
|
+
}
|
|
52
|
+
export function prependSystemPrompt(systemPrompt, userPrompt) {
|
|
53
|
+
return systemPrompt + "\n\n# Task\n\n" + userPrompt;
|
|
54
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type TemplateContext = {
|
|
2
|
+
plan: {
|
|
3
|
+
path: string;
|
|
4
|
+
};
|
|
5
|
+
builder: {
|
|
6
|
+
summary: string;
|
|
7
|
+
log: string;
|
|
8
|
+
log_path: string;
|
|
9
|
+
};
|
|
10
|
+
inspectors: Record<string, string>;
|
|
11
|
+
inspector_logs: Record<string, string>;
|
|
12
|
+
superintendent: {
|
|
13
|
+
summary: string;
|
|
14
|
+
log_path?: string;
|
|
15
|
+
};
|
|
16
|
+
owner: {
|
|
17
|
+
feedback: string;
|
|
18
|
+
log_path?: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function resolveTemplate(template: string, context: Partial<TemplateContext>): string;
|
|
22
|
+
export declare function collectReferencedInspectors(template: string): Set<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const templateVariablePattern = /{{\s*([A-Za-z0-9_.-]+)\s*}}/g;
|
|
2
|
+
const inspectorReferencePattern = /{{\s*inspectors\.([A-Za-z0-9_-]+)\s*}}/g;
|
|
3
|
+
export function resolveTemplate(template, context) {
|
|
4
|
+
return template.replace(templateVariablePattern, (_match, variablePath) => {
|
|
5
|
+
const value = readTemplateValue(context, variablePath);
|
|
6
|
+
return typeof value === "string" ? value : "";
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export function collectReferencedInspectors(template) {
|
|
10
|
+
const names = new Set();
|
|
11
|
+
for (const match of template.matchAll(inspectorReferencePattern)) {
|
|
12
|
+
names.add(match[1]);
|
|
13
|
+
}
|
|
14
|
+
return names;
|
|
15
|
+
}
|
|
16
|
+
function readTemplateValue(context, variablePath) {
|
|
17
|
+
return variablePath
|
|
18
|
+
.split(".")
|
|
19
|
+
.reduce((value, segment) => (isRecord(value) ? value[segment] : undefined), context);
|
|
20
|
+
}
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return typeof value === "object" && value !== null;
|
|
23
|
+
}
|