@fiftth/fiftth-cli 1.0.1 → 1.1.1
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/.fiftthnexus/.github/workflows/copilot-orchestrator.yml +78 -0
- package/.fiftthnexus/actions/Dockerfile +34 -0
- package/.fiftthnexus/actions/copilot-agent.mjs +269 -0
- package/.fiftthnexus/actions/package.json +8 -0
- package/.fiftthnexus/orchestrator.ts +2304 -0
- package/.fiftthnexus/skills/env-implement-prompt.md +65 -0
- package/.fiftthnexus/skills/env-plan-prompt.md +33 -0
- package/.fiftthnexus/skills/env-review-prompt.md +61 -0
- package/.fiftthnexus/skills/grill-me.md +9 -0
- package/.fiftthnexus/skills/prd-to-issues.md +150 -0
- package/.fiftthnexus/skills/write-prd.md +70 -0
- package/README.md +216 -25
- package/dist/api/client.d.ts +6 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +13 -2
- package/dist/api/client.js.map +1 -1
- package/dist/commands/checkout.d.ts +6 -1
- package/dist/commands/checkout.d.ts.map +1 -1
- package/dist/commands/checkout.js +415 -44
- package/dist/commands/checkout.js.map +1 -1
- package/dist/commands/login.d.ts +0 -2
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +83 -32
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/model.d.ts +2 -0
- package/dist/commands/model.d.ts.map +1 -0
- package/dist/commands/model.js +32 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/planningContext.d.ts +6 -0
- package/dist/commands/planningContext.d.ts.map +1 -0
- package/dist/commands/planningContext.js +91 -0
- package/dist/commands/planningContext.js.map +1 -0
- package/dist/commands/repo.d.ts.map +1 -1
- package/dist/commands/repo.js +38 -15
- package/dist/commands/repo.js.map +1 -1
- package/dist/commands/skills.d.ts +2 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +123 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/use.d.ts +1 -5
- package/dist/commands/use.d.ts.map +1 -1
- package/dist/commands/use.js +63 -48
- package/dist/commands/use.js.map +1 -1
- package/dist/index.js +86 -27
- package/dist/index.js.map +1 -1
- package/dist/services/nexusService.d.ts +30 -0
- package/dist/services/nexusService.d.ts.map +1 -0
- package/dist/services/nexusService.js +188 -0
- package/dist/services/nexusService.js.map +1 -0
- package/dist/services/prdService.d.ts +12 -0
- package/dist/services/prdService.d.ts.map +1 -0
- package/dist/services/prdService.js +103 -0
- package/dist/services/prdService.js.map +1 -0
- package/dist/services/taskSelection.d.ts +10 -0
- package/dist/services/taskSelection.d.ts.map +1 -0
- package/dist/services/taskSelection.js +112 -0
- package/dist/services/taskSelection.js.map +1 -0
- package/dist/services/taskService.d.ts +23 -1
- package/dist/services/taskService.d.ts.map +1 -1
- package/dist/services/taskService.js +118 -12
- package/dist/services/taskService.js.map +1 -1
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +20 -3
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/dashboard.d.ts +65 -0
- package/dist/utils/dashboard.d.ts.map +1 -0
- package/dist/utils/dashboard.js +205 -0
- package/dist/utils/dashboard.js.map +1 -0
- package/dist/utils/models.d.ts +14 -0
- package/dist/utils/models.d.ts.map +1 -0
- package/dist/utils/models.js +89 -0
- package/dist/utils/models.js.map +1 -0
- package/dist/utils/ui.d.ts +6 -0
- package/dist/utils/ui.d.ts.map +1 -1
- package/dist/utils/ui.js +22 -1
- package/dist/utils/ui.js.map +1 -1
- package/dist/utils/version.d.ts +4 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +26 -0
- package/dist/utils/version.js.map +1 -0
- package/package.json +9 -4
- package/.github/workflows/publish-npm.yml +0 -62
- package/dist/commands/tasks.d.ts +0 -2
- package/dist/commands/tasks.d.ts.map +0 -1
- package/dist/commands/tasks.js +0 -69
- package/dist/commands/tasks.js.map +0 -1
- package/dist/context/runtimeContext.d.ts +0 -14
- package/dist/context/runtimeContext.d.ts.map +0 -1
- package/dist/context/runtimeContext.js +0 -21
- package/dist/context/runtimeContext.js.map +0 -1
- package/dist/services/taskContext.d.ts +0 -14
- package/dist/services/taskContext.d.ts.map +0 -1
- package/dist/services/taskContext.js +0 -15
- package/dist/services/taskContext.js.map +0 -1
- package/dist/utils/api.d.ts +0 -10
- package/dist/utils/api.d.ts.map +0 -1
- package/dist/utils/api.js +0 -25
- package/dist/utils/api.js.map +0 -1
- package/src/api/client.ts +0 -31
- package/src/commands/checkout.ts +0 -101
- package/src/commands/login.ts +0 -145
- package/src/commands/repo.ts +0 -113
- package/src/commands/tasks.ts +0 -86
- package/src/commands/use.ts +0 -149
- package/src/config/configService.ts +0 -56
- package/src/context/runtimeContext.ts +0 -42
- package/src/git/gitService.ts +0 -29
- package/src/index.ts +0 -133
- package/src/services/taskContext.ts +0 -32
- package/src/services/taskService.ts +0 -53
- package/src/utils/api.ts +0 -41
- package/src/utils/config.ts +0 -48
- package/src/utils/ui.ts +0 -46
- package/tsconfig.json +0 -18
- package/vitest.config.ts +0 -8
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Copilot Parallel Orchestrator
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Run manually
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
inputs:
|
|
7
|
+
max_parallel:
|
|
8
|
+
description: "Max issues in parallel"
|
|
9
|
+
default: "3"
|
|
10
|
+
type: string
|
|
11
|
+
max_iterations:
|
|
12
|
+
description: "Max orchestrator iterations"
|
|
13
|
+
default: "10"
|
|
14
|
+
type: string
|
|
15
|
+
label:
|
|
16
|
+
description: "Label to filter issues"
|
|
17
|
+
default: "ai-running-orchestrator"
|
|
18
|
+
type: string
|
|
19
|
+
|
|
20
|
+
# Run when an issue gets the ai-running-orchestrator label
|
|
21
|
+
issues:
|
|
22
|
+
types: [labeled]
|
|
23
|
+
|
|
24
|
+
# Poll every 30 minutes for newly unblocked issues
|
|
25
|
+
schedule:
|
|
26
|
+
- cron: "*/30 * * * *"
|
|
27
|
+
|
|
28
|
+
permissions:
|
|
29
|
+
contents: write
|
|
30
|
+
issues: write
|
|
31
|
+
pull-requests: write
|
|
32
|
+
|
|
33
|
+
# Only one orchestrator at a time
|
|
34
|
+
concurrency:
|
|
35
|
+
group: copilot-orchestrator
|
|
36
|
+
cancel-in-progress: false
|
|
37
|
+
|
|
38
|
+
jobs:
|
|
39
|
+
orchestrate:
|
|
40
|
+
# Skip if triggered by label event and label is not ai-running-orchestrator
|
|
41
|
+
if: >
|
|
42
|
+
github.event_name != 'issues' || github.event.label.name == 'ai-running-orchestrator'
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
timeout-minutes: 120
|
|
45
|
+
|
|
46
|
+
steps:
|
|
47
|
+
- name: Checkout
|
|
48
|
+
uses: actions/checkout@v4
|
|
49
|
+
|
|
50
|
+
- name: Setup Node.js
|
|
51
|
+
uses: actions/setup-node@v4
|
|
52
|
+
with:
|
|
53
|
+
node-version: "22"
|
|
54
|
+
|
|
55
|
+
- name: Install tsx
|
|
56
|
+
run: npm install -g tsx
|
|
57
|
+
|
|
58
|
+
- name: Run Orchestrator
|
|
59
|
+
env:
|
|
60
|
+
GH_TOKEN: "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"
|
|
61
|
+
GITHUB_REPOSITORY: ${{ github.repository }}
|
|
62
|
+
MAX_PARALLEL: ${{ inputs.max_parallel || '3' }}
|
|
63
|
+
MAX_ITERATIONS: ${{ inputs.max_iterations || '10' }}
|
|
64
|
+
ORCHESTRATOR_LABEL: ${{ inputs.label || 'ai-running-orchestrator' }}
|
|
65
|
+
POLL_INTERVAL_MS: "60000"
|
|
66
|
+
MAX_WAIT_MS: "3600000"
|
|
67
|
+
run: npx tsx custom-agents/actions/orchestrator.ts
|
|
68
|
+
|
|
69
|
+
- name: Write Summary
|
|
70
|
+
if: always()
|
|
71
|
+
run: |
|
|
72
|
+
echo "## Copilot Orchestrator Run" >> $GITHUB_STEP_SUMMARY
|
|
73
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
74
|
+
echo "- **Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
|
|
75
|
+
echo "- **Max parallel:** ${{ inputs.max_parallel || '3' }}" >> $GITHUB_STEP_SUMMARY
|
|
76
|
+
echo "- **Label:** ${{ inputs.label || 'ai-running-orchestrator' }}" >> $GITHUB_STEP_SUMMARY
|
|
77
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
78
|
+
echo "Check the job logs for detailed output." >> $GITHUB_STEP_SUMMARY
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
FROM node:22-slim
|
|
2
|
+
|
|
3
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
4
|
+
git \
|
|
5
|
+
curl \
|
|
6
|
+
ca-certificates \
|
|
7
|
+
jq \
|
|
8
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
9
|
+
|
|
10
|
+
# Install GitHub CLI
|
|
11
|
+
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
|
12
|
+
-o /usr/share/keyrings/githubcli-archive-keyring.gpg \
|
|
13
|
+
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
|
|
14
|
+
> /etc/apt/sources.list.d/github-cli.list \
|
|
15
|
+
&& apt-get update \
|
|
16
|
+
&& apt-get install -y gh \
|
|
17
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
18
|
+
|
|
19
|
+
# Install Copilot CLI (required by @github/copilot-sdk)
|
|
20
|
+
RUN npm install -g @github/copilot@latest
|
|
21
|
+
|
|
22
|
+
RUN git config --global user.name "copilot-orchestrator" \
|
|
23
|
+
&& git config --global user.email "copilot-orchestrator@local" \
|
|
24
|
+
&& git config --global init.defaultBranch main
|
|
25
|
+
|
|
26
|
+
# Install SDK dependencies
|
|
27
|
+
COPY package.json /opt/package.json
|
|
28
|
+
RUN cd /opt && npm install --omit=dev
|
|
29
|
+
|
|
30
|
+
COPY copilot-agent.mjs /opt/copilot-agent.mjs
|
|
31
|
+
|
|
32
|
+
WORKDIR /workspace
|
|
33
|
+
|
|
34
|
+
ENTRYPOINT ["node", "/opt/copilot-agent.mjs"]
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { approveAll, CopilotClient } from "@github/copilot-sdk";
|
|
3
|
+
|
|
4
|
+
const STAGE_MARKER = "__FIFTTH_AGENT_STAGE__";
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// CLI Args
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
function parseArgs() {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const defaultModel = process.env.FIFTTH_DEFAULT_MODEL ?? "gpt-5.4";
|
|
12
|
+
const opts = {
|
|
13
|
+
promptFile: "",
|
|
14
|
+
planPromptFile: "",
|
|
15
|
+
implementPromptFile: "",
|
|
16
|
+
reviewPromptFile: "",
|
|
17
|
+
stage: "plan",
|
|
18
|
+
model: defaultModel,
|
|
19
|
+
verbose: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < args.length; i++) {
|
|
23
|
+
switch (args[i]) {
|
|
24
|
+
case "--prompt":
|
|
25
|
+
opts.promptFile = args[++i] ?? "";
|
|
26
|
+
break;
|
|
27
|
+
case "--plan-prompt":
|
|
28
|
+
opts.planPromptFile = args[++i] ?? "";
|
|
29
|
+
break;
|
|
30
|
+
case "--implement-prompt":
|
|
31
|
+
opts.implementPromptFile = args[++i] ?? "";
|
|
32
|
+
break;
|
|
33
|
+
case "--review-prompt":
|
|
34
|
+
opts.reviewPromptFile = args[++i] ?? "";
|
|
35
|
+
break;
|
|
36
|
+
case "--stage":
|
|
37
|
+
opts.stage = args[++i] ?? "plan";
|
|
38
|
+
break;
|
|
39
|
+
case "--model":
|
|
40
|
+
opts.model = args[++i] ?? defaultModel;
|
|
41
|
+
break;
|
|
42
|
+
case "--verbose":
|
|
43
|
+
opts.verbose = true;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const isSingleStage = Boolean(opts.promptFile);
|
|
49
|
+
const isPipeline = Boolean(opts.planPromptFile && opts.implementPromptFile && opts.reviewPromptFile);
|
|
50
|
+
|
|
51
|
+
if (!isSingleStage && !isPipeline) {
|
|
52
|
+
console.error("ERROR: provide --prompt <file> or the full pipeline prompt set (--plan-prompt, --implement-prompt, --review-prompt)");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
return opts;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Logging
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
function log(msg) {
|
|
62
|
+
process.stderr.write(`[agent] ${msg}\n`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function emitStageEvent(stage, event) {
|
|
66
|
+
log(`${STAGE_MARKER} ${stage}:${event}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function applyPromptContext(template, replacements) {
|
|
70
|
+
let result = template;
|
|
71
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
72
|
+
result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function finishPipeline(client, pipelineResult, exitCode = 0) {
|
|
78
|
+
process.stdout.write(JSON.stringify(pipelineResult));
|
|
79
|
+
await client.stop();
|
|
80
|
+
if (exitCode !== 0) {
|
|
81
|
+
process.exit(exitCode);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
const SYSTEM_PROMPTS = {
|
|
87
|
+
plan:
|
|
88
|
+
`You are a senior software architect. You have tools to explore the codebase.
|
|
89
|
+
Use them to understand the project structure before producing your plan.
|
|
90
|
+
After exploring, output your plan as a JSON object wrapped in <plan> tags.`,
|
|
91
|
+
|
|
92
|
+
implement:
|
|
93
|
+
`You are a senior full-stack developer implementing features in an existing codebase.
|
|
94
|
+
You have tools to explore, read, search, and write files, plus run shell commands.
|
|
95
|
+
|
|
96
|
+
WORKFLOW:
|
|
97
|
+
1. EXPLORE: Use tools to understand the existing codebase, tech stack, patterns, and conventions.
|
|
98
|
+
2. IMPLEMENT: Create/update files. Match the existing stack and style EXACTLY.
|
|
99
|
+
3. COMMIT: git add and git commit your changes.
|
|
100
|
+
|
|
101
|
+
RULES:
|
|
102
|
+
- ALWAYS explore relevant existing files before writing new ones
|
|
103
|
+
- Match existing patterns, imports, and conventions exactly
|
|
104
|
+
- Do NOT introduce frameworks or libraries not already in package.json
|
|
105
|
+
- Write complete file contents (not diffs or partial content)
|
|
106
|
+
- Run validation after writing code`,
|
|
107
|
+
|
|
108
|
+
review:
|
|
109
|
+
`You are a senior code reviewer performing a lightweight final pass on an already-implemented change.
|
|
110
|
+
You have tools to inspect the diff, read nearby code, run focused validation, and make small follow-up fixes.
|
|
111
|
+
|
|
112
|
+
WORKFLOW:
|
|
113
|
+
1. Inspect only the current diff and directly affected code paths.
|
|
114
|
+
2. Run only targeted validation for the changed paths.
|
|
115
|
+
3. If you find one concrete correctness or test gap, fix it and commit once.
|
|
116
|
+
4. If there is no concrete blocker, stop immediately and output COMPLETE.
|
|
117
|
+
|
|
118
|
+
Avoid broad refactors, exhaustive analysis, or reopening implementation work that already passed.`,
|
|
119
|
+
|
|
120
|
+
merge: `You are a senior developer responsible for merging branches.
|
|
121
|
+
You have tools to run git commands and resolve conflicts.
|
|
122
|
+
Follow the merge instructions carefully.`,
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
async function runStage(client, stage, prompt, model, verbose) {
|
|
126
|
+
emitStageEvent(stage, "start");
|
|
127
|
+
const systemPrompt = SYSTEM_PROMPTS[stage] ?? SYSTEM_PROMPTS.plan;
|
|
128
|
+
const session = await client.createSession({
|
|
129
|
+
model,
|
|
130
|
+
systemMessage: {
|
|
131
|
+
mode: "replace",
|
|
132
|
+
content: systemPrompt,
|
|
133
|
+
},
|
|
134
|
+
onPermissionRequest: approveAll,
|
|
135
|
+
infiniteSessions: { enabled: true },
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
let toolCalls = 0;
|
|
139
|
+
let writeCount = 0;
|
|
140
|
+
|
|
141
|
+
session.on("tool.execution_start", (event) => {
|
|
142
|
+
toolCalls++;
|
|
143
|
+
if (verbose) {
|
|
144
|
+
log(` tool(${stage}): ${event.data?.toolName ?? "unknown"}`);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
session.on("tool.execution_complete", (event) => {
|
|
149
|
+
if (
|
|
150
|
+
event.data?.toolName === "write_file" ||
|
|
151
|
+
event.data?.toolName === "edit_file"
|
|
152
|
+
) {
|
|
153
|
+
writeCount++;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
session.on("assistant.message_delta", (event) => {
|
|
158
|
+
if (verbose && event.data?.deltaContent) {
|
|
159
|
+
process.stderr.write(event.data.deltaContent);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
log(`Sending ${stage} prompt...`);
|
|
165
|
+
const response = await session.sendAndWait(
|
|
166
|
+
{ prompt },
|
|
167
|
+
10 * 60 * 1000,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const output = response?.data?.content ?? "";
|
|
171
|
+
log(`${stage} done (${toolCalls} tool calls, ${writeCount} writes, ${output.length} chars)`);
|
|
172
|
+
emitStageEvent(stage, "done");
|
|
173
|
+
await session.disconnect();
|
|
174
|
+
return {
|
|
175
|
+
success: true,
|
|
176
|
+
output,
|
|
177
|
+
toolCalls,
|
|
178
|
+
writes: writeCount,
|
|
179
|
+
errorText: "",
|
|
180
|
+
};
|
|
181
|
+
} catch (err) {
|
|
182
|
+
const errorText = err instanceof Error ? err.message : String(err);
|
|
183
|
+
emitStageEvent(stage, "failed");
|
|
184
|
+
await session.disconnect().catch(() => {});
|
|
185
|
+
return {
|
|
186
|
+
success: false,
|
|
187
|
+
output: "",
|
|
188
|
+
toolCalls,
|
|
189
|
+
writes: writeCount,
|
|
190
|
+
errorText,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
// Main
|
|
197
|
+
// ---------------------------------------------------------------------------
|
|
198
|
+
async function main() {
|
|
199
|
+
const opts = parseArgs();
|
|
200
|
+
|
|
201
|
+
log(`stage=${opts.stage} model=${opts.model} verbose=${opts.verbose}`);
|
|
202
|
+
|
|
203
|
+
log("Starting Copilot SDK client...");
|
|
204
|
+
const client = new CopilotClient({
|
|
205
|
+
githubToken: process.env.GITHUB_TOKEN,
|
|
206
|
+
});
|
|
207
|
+
await client.start();
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
if (opts.promptFile) {
|
|
211
|
+
const prompt = readFileSync(opts.promptFile, "utf-8");
|
|
212
|
+
log(`Prompt ready (${prompt.length} chars)`);
|
|
213
|
+
const result = await runStage(client, opts.stage, prompt, opts.model, opts.verbose);
|
|
214
|
+
process.stdout.write(result.output);
|
|
215
|
+
await client.stop();
|
|
216
|
+
if (!result.success) {
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const planPrompt = readFileSync(opts.planPromptFile, "utf-8");
|
|
223
|
+
const implementPromptTemplate = readFileSync(opts.implementPromptFile, "utf-8");
|
|
224
|
+
const reviewPromptTemplate = readFileSync(opts.reviewPromptFile, "utf-8");
|
|
225
|
+
log(`Pipeline prompts ready (${planPrompt.length}/${implementPromptTemplate.length}/${reviewPromptTemplate.length} chars)`);
|
|
226
|
+
|
|
227
|
+
const pipelineResult = {
|
|
228
|
+
plan: await runStage(client, "plan", planPrompt, opts.model, opts.verbose),
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
if (!pipelineResult.plan.success) {
|
|
232
|
+
await finishPipeline(client, pipelineResult, 1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
pipelineResult.implement = await runStage(
|
|
236
|
+
client,
|
|
237
|
+
"implement",
|
|
238
|
+
applyPromptContext(implementPromptTemplate, {
|
|
239
|
+
PLAN_OUTPUT: pipelineResult.plan.output,
|
|
240
|
+
}),
|
|
241
|
+
opts.model,
|
|
242
|
+
opts.verbose,
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
if (!pipelineResult.implement.success) {
|
|
246
|
+
await finishPipeline(client, pipelineResult, 1);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
pipelineResult.review = await runStage(
|
|
250
|
+
client,
|
|
251
|
+
"review",
|
|
252
|
+
applyPromptContext(reviewPromptTemplate, {
|
|
253
|
+
IMPLEMENTATION_OUTPUT: pipelineResult.implement.output,
|
|
254
|
+
}),
|
|
255
|
+
opts.model,
|
|
256
|
+
opts.verbose,
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
await finishPipeline(client, pipelineResult, pipelineResult.review.success ? 0 : 1);
|
|
260
|
+
} catch (err) {
|
|
261
|
+
await client.forceStop().catch(() => {});
|
|
262
|
+
throw err;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
main().catch((err) => {
|
|
267
|
+
console.error(`[agent] FATAL: ${err.message}`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
});
|