agentweaver 0.1.2 → 0.1.4
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/README.md +58 -23
- package/dist/artifacts.js +58 -2
- package/dist/executors/claude-executor.js +12 -2
- package/dist/executors/claude-summary-executor.js +1 -1
- package/dist/executors/codex-docker-executor.js +1 -1
- package/dist/executors/codex-local-executor.js +1 -1
- package/dist/executors/configs/claude-config.js +2 -1
- package/dist/executors/verify-build-executor.js +110 -9
- package/dist/index.js +466 -452
- package/dist/interactive-ui.js +538 -194
- package/dist/jira.js +3 -1
- package/dist/pipeline/auto-flow.js +9 -0
- package/dist/pipeline/checks.js +5 -0
- package/dist/pipeline/context.js +2 -0
- package/dist/pipeline/declarative-flow-runner.js +262 -0
- package/dist/pipeline/declarative-flows.js +24 -0
- package/dist/pipeline/flow-specs/auto.json +485 -0
- package/dist/pipeline/flow-specs/bug-analyze.json +140 -0
- package/dist/pipeline/flow-specs/bug-fix.json +44 -0
- package/dist/pipeline/flow-specs/implement.json +47 -0
- package/dist/pipeline/flow-specs/mr-description.json +61 -0
- package/dist/pipeline/flow-specs/plan.json +88 -0
- package/dist/pipeline/flow-specs/preflight.json +174 -0
- package/dist/pipeline/flow-specs/review-fix.json +76 -0
- package/dist/pipeline/flow-specs/review.json +233 -0
- package/dist/pipeline/flow-specs/run-linter-loop.json +149 -0
- package/dist/pipeline/flow-specs/run-tests-loop.json +149 -0
- package/dist/pipeline/flow-specs/task-describe.json +61 -0
- package/dist/pipeline/flow-specs/test-fix.json +24 -0
- package/dist/pipeline/flow-specs/test-linter-fix.json +24 -0
- package/dist/pipeline/flow-specs/test.json +19 -0
- package/dist/pipeline/flows/implement-flow.js +3 -4
- package/dist/pipeline/flows/preflight-flow.js +17 -57
- package/dist/pipeline/flows/review-fix-flow.js +3 -4
- package/dist/pipeline/flows/review-flow.js +8 -4
- package/dist/pipeline/flows/test-fix-flow.js +3 -4
- package/dist/pipeline/node-registry.js +74 -0
- package/dist/pipeline/node-runner.js +9 -3
- package/dist/pipeline/nodes/build-failure-summary-node.js +4 -4
- package/dist/pipeline/nodes/claude-prompt-node.js +54 -0
- package/dist/pipeline/nodes/claude-summary-node.js +12 -6
- package/dist/pipeline/nodes/codex-docker-prompt-node.js +1 -0
- package/dist/pipeline/nodes/codex-local-prompt-node.js +32 -0
- package/dist/pipeline/nodes/file-check-node.js +15 -0
- package/dist/pipeline/nodes/flow-run-node.js +40 -0
- package/dist/pipeline/nodes/summary-file-load-node.js +16 -0
- package/dist/pipeline/nodes/task-summary-node.js +12 -6
- package/dist/pipeline/nodes/verify-build-node.js +1 -0
- package/dist/pipeline/prompt-registry.js +27 -0
- package/dist/pipeline/prompt-runtime.js +18 -0
- package/dist/pipeline/registry.js +0 -2
- package/dist/pipeline/spec-compiler.js +213 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +1 -0
- package/dist/pipeline/spec-validator.js +302 -0
- package/dist/pipeline/value-resolver.js +217 -0
- package/dist/prompts.js +22 -3
- package/dist/runtime/process-runner.js +24 -23
- package/dist/structured-artifacts.js +178 -0
- package/dist/tui.js +39 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -11,26 +11,30 @@ The package is designed to run as an npm CLI and includes an interactive termina
|
|
|
11
11
|
## What It Does
|
|
12
12
|
|
|
13
13
|
- Fetches a Jira issue by key or browse URL
|
|
14
|
-
- Generates workflow artifacts such as design, implementation plan, QA plan, reviews, and summaries
|
|
15
|
-
-
|
|
16
|
-
-
|
|
14
|
+
- Generates workflow artifacts such as design, implementation plan, QA plan, bug analysis, reviews, and summaries
|
|
15
|
+
- For bug-analysis flows, structured JSON artifacts are the machine-readable source of truth, while Markdown artifacts are for human inspection
|
|
16
|
+
- Runs workflow stages like `bug-analyze`, `bug-fix`, `mr-description`, `plan`, `task-describe`, `implement`, `review`, `review-fix`, `test`, and `auto`
|
|
17
|
+
- Persists compact `auto` pipeline state on disk so runs can resume without storing large agent outputs
|
|
17
18
|
- Uses Docker runtime services for isolated Codex execution and build verification
|
|
18
19
|
|
|
19
20
|
## Architecture
|
|
20
21
|
|
|
21
|
-
The CLI now uses an executor
|
|
22
|
+
The CLI now uses an executor + node + declarative flow architecture.
|
|
22
23
|
|
|
23
|
-
- `src/index.ts` remains the
|
|
24
|
-
- `src/executors/` contains first-class executors for external actions such as Jira fetch, local Codex, Docker
|
|
25
|
-
- `src/
|
|
24
|
+
- `src/index.ts` remains the CLI entrypoint and high-level orchestration layer
|
|
25
|
+
- `src/executors/` contains first-class executors for external actions such as Jira fetch, local Codex, Docker-based build verification, Claude, Claude summaries, and process execution
|
|
26
|
+
- `src/pipeline/nodes/` contains reusable runtime nodes built on top of executors
|
|
27
|
+
- `src/pipeline/flow-specs/` contains declarative JSON flow specs for `preflight`, `bug-analyze`, `bug-fix`, `mr-description`, `plan`, `task-describe`, `implement`, `review`, `review-fix`, `test`, `test-fix`, `test-linter-fix`, `run-tests-loop`, `run-linter-loop`, and `auto`
|
|
26
28
|
- `src/runtime/` contains shared runtime services such as command resolution, Docker runtime environment setup, and subprocess execution
|
|
27
29
|
|
|
28
|
-
This keeps command handlers focused on
|
|
30
|
+
This keeps command handlers focused on choosing a flow and providing parameters instead of assembling prompts and subprocess wiring inline.
|
|
29
31
|
|
|
30
32
|
## Repository Layout
|
|
31
33
|
|
|
32
34
|
- `src/` — main TypeScript sources
|
|
33
35
|
- `src/index.ts` — CLI entrypoint and workflow orchestration
|
|
36
|
+
- `src/pipeline/flow-specs/` — declarative JSON specs for workflow stages
|
|
37
|
+
- `src/pipeline/nodes/` — reusable pipeline nodes executed by the declarative runner
|
|
34
38
|
- `src/interactive-ui.ts` — interactive TUI built with `neo-blessed`
|
|
35
39
|
- `src/markdown.ts` — markdown-to-terminal renderer for the TUI
|
|
36
40
|
- `src/executors/` — executor modules for concrete execution families
|
|
@@ -38,7 +42,9 @@ This keeps command handlers focused on workflow composition instead of inline su
|
|
|
38
42
|
- `src/runtime/` — shared runtime services used by executors
|
|
39
43
|
- `docker-compose.yml` — runtime services for Codex and build verification
|
|
40
44
|
- `Dockerfile.codex` — container image for Codex runtime
|
|
41
|
-
- `verify_build.sh` —
|
|
45
|
+
- `verify_build.sh` — aggregated verification entrypoint used by `verify-build`
|
|
46
|
+
- `run_tests.sh` — isolated test and coverage verification entrypoint
|
|
47
|
+
- `run_linter.sh` — isolated generate + lint verification entrypoint
|
|
42
48
|
- `package.json` — npm package metadata and scripts
|
|
43
49
|
- `tsconfig.json` — TypeScript configuration
|
|
44
50
|
|
|
@@ -47,7 +53,7 @@ This keeps command handlers focused on workflow composition instead of inline su
|
|
|
47
53
|
- Node.js `>= 18.19.0`
|
|
48
54
|
- npm
|
|
49
55
|
- Docker with `docker compose` or `docker-compose`
|
|
50
|
-
- `codex` CLI for `
|
|
56
|
+
- `codex` CLI for `bug-analyze`, `bug-fix`, `mr-description`, `plan`, and other Codex-driven steps
|
|
51
57
|
- `claude` CLI for review and summary steps
|
|
52
58
|
|
|
53
59
|
## Installation
|
|
@@ -84,9 +90,8 @@ Common optional variables:
|
|
|
84
90
|
- `DOCKER_COMPOSE_BIN` — override compose command, for example `docker compose`
|
|
85
91
|
- `CODEX_BIN` — override `codex` executable path
|
|
86
92
|
- `CLAUDE_BIN` — override `claude` executable path
|
|
87
|
-
- `CODEX_MODEL` —
|
|
88
|
-
- `
|
|
89
|
-
- `CLAUDE_SUMMARY_MODEL` — defaults to `haiku`
|
|
93
|
+
- `CODEX_MODEL` — fallback model for Codex executors when the flow spec does not set `params.model`
|
|
94
|
+
- `CLAUDE_MODEL` — fallback Claude model when the flow spec does not set `params.model`
|
|
90
95
|
|
|
91
96
|
Example `.env`:
|
|
92
97
|
|
|
@@ -97,8 +102,7 @@ AGENTWEAVER_HOME=/absolute/path/to/AgentWeaver
|
|
|
97
102
|
CODEX_BIN=codex
|
|
98
103
|
CLAUDE_BIN=claude
|
|
99
104
|
CODEX_MODEL=gpt-5.4
|
|
100
|
-
|
|
101
|
-
CLAUDE_SUMMARY_MODEL=haiku
|
|
105
|
+
CLAUDE_MODEL=opus
|
|
102
106
|
GOPRIVATE=gitlab.example.org/*
|
|
103
107
|
GONOSUMDB=gitlab.example.org/*
|
|
104
108
|
GONOPROXY=gitlab.example.org/*
|
|
@@ -111,8 +115,14 @@ Direct CLI usage:
|
|
|
111
115
|
|
|
112
116
|
```bash
|
|
113
117
|
agentweaver plan DEMO-3288
|
|
118
|
+
agentweaver bug-analyze DEMO-3288
|
|
119
|
+
agentweaver bug-fix DEMO-3288
|
|
120
|
+
agentweaver mr-description DEMO-3288
|
|
121
|
+
agentweaver task-describe DEMO-3288
|
|
114
122
|
agentweaver implement DEMO-3288
|
|
115
123
|
agentweaver review DEMO-3288
|
|
124
|
+
agentweaver run-tests-loop DEMO-3288
|
|
125
|
+
agentweaver run-linter-loop DEMO-3288
|
|
116
126
|
agentweaver auto DEMO-3288
|
|
117
127
|
```
|
|
118
128
|
|
|
@@ -120,6 +130,10 @@ From source checkout:
|
|
|
120
130
|
|
|
121
131
|
```bash
|
|
122
132
|
node dist/index.js plan DEMO-3288
|
|
133
|
+
node dist/index.js bug-analyze DEMO-3288
|
|
134
|
+
node dist/index.js bug-fix DEMO-3288
|
|
135
|
+
node dist/index.js mr-description DEMO-3288
|
|
136
|
+
node dist/index.js task-describe DEMO-3288
|
|
123
137
|
node dist/index.js auto DEMO-3288
|
|
124
138
|
```
|
|
125
139
|
|
|
@@ -144,28 +158,35 @@ agentweaver auto-status DEMO-3288
|
|
|
144
158
|
agentweaver auto-reset DEMO-3288
|
|
145
159
|
```
|
|
146
160
|
|
|
161
|
+
Notes:
|
|
162
|
+
|
|
163
|
+
- `--verbose` streams child process `stdout/stderr` in direct CLI mode
|
|
164
|
+
- the interactive `Activity` pane is intentionally structured: it shows launch separators, prompts, summaries, and short status messages instead of raw Codex/Claude logs by default
|
|
165
|
+
|
|
147
166
|
## Interactive TUI
|
|
148
167
|
|
|
149
168
|
Interactive mode opens a full-screen terminal UI with:
|
|
150
169
|
|
|
151
|
-
-
|
|
170
|
+
- flow list
|
|
171
|
+
- current flow progress
|
|
152
172
|
- activity log
|
|
153
173
|
- task summary pane
|
|
154
|
-
- command list/help
|
|
155
174
|
- keyboard navigation between panes
|
|
156
175
|
|
|
157
176
|
Current navigation:
|
|
158
177
|
|
|
159
|
-
- `Enter` — run
|
|
178
|
+
- `Enter` — run selected flow
|
|
160
179
|
- `Tab` / `Shift+Tab` — switch panes
|
|
161
|
-
- `Ctrl+J` — focus activity log
|
|
162
|
-
- `Ctrl+K` — focus command input
|
|
163
|
-
- `Ctrl+U` — focus task summary
|
|
164
|
-
- `Ctrl+H` — focus commands pane
|
|
165
180
|
- `PgUp` / `PgDn` / `Home` / `End` — scroll focused panes
|
|
166
|
-
-
|
|
181
|
+
- `h` — help overlay
|
|
167
182
|
- `q` or `Ctrl+C` — exit
|
|
168
183
|
|
|
184
|
+
Activity pane behavior:
|
|
185
|
+
|
|
186
|
+
- each external launch is separated with a framed block that shows the current `node`, `executor`, and `model` when available
|
|
187
|
+
- prompts and summaries are rendered as plain text for readability
|
|
188
|
+
- live raw Codex/Claude output is not shown there in normal mode
|
|
189
|
+
|
|
169
190
|
## Docker Runtime
|
|
170
191
|
|
|
171
192
|
Docker is used as an isolated execution environment for Codex and build/test verification.
|
|
@@ -175,6 +196,8 @@ Main services:
|
|
|
175
196
|
- `codex` — interactive Codex container
|
|
176
197
|
- `codex-exec` — non-interactive `codex exec`
|
|
177
198
|
- `verify-build` — project verification script inside container
|
|
199
|
+
- `run-tests` — isolated `run_tests.sh` execution inside container
|
|
200
|
+
- `run-linter` — isolated `run_linter.sh` execution inside container
|
|
178
201
|
- `codex-login` — interactive login container
|
|
179
202
|
- `dockerd` — internal Docker daemon for testcontainers/build flows
|
|
180
203
|
|
|
@@ -204,6 +227,18 @@ Build verification:
|
|
|
204
227
|
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm verify-build
|
|
205
228
|
```
|
|
206
229
|
|
|
230
|
+
Tests only:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-tests
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Linter only:
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
PROJECT_DIR="$PWD" docker compose -f "$AGENTWEAVER_HOME/docker-compose.yml" run --rm run-linter
|
|
240
|
+
```
|
|
241
|
+
|
|
207
242
|
## Development
|
|
208
243
|
|
|
209
244
|
Install dependencies and build:
|
package/dist/artifacts.js
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import process from "node:process";
|
|
2
4
|
import { TaskRunnerError } from "./errors.js";
|
|
3
5
|
export const REVIEW_FILE_RE = /^review-(.+)-(\d+)\.md$/;
|
|
4
6
|
export const REVIEW_REPLY_FILE_RE = /^review-reply-(.+)-(\d+)\.md$/;
|
|
5
7
|
export const READY_TO_MERGE_FILE = "ready-to-merge.md";
|
|
8
|
+
export function taskWorkspaceDir(taskKey) {
|
|
9
|
+
return path.join(process.cwd(), `.agentweaver-${taskKey}`);
|
|
10
|
+
}
|
|
11
|
+
export function ensureTaskWorkspaceDir(taskKey) {
|
|
12
|
+
const workspaceDir = taskWorkspaceDir(taskKey);
|
|
13
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
14
|
+
return workspaceDir;
|
|
15
|
+
}
|
|
16
|
+
export function taskWorkspaceFile(taskKey, fileName) {
|
|
17
|
+
return path.join(taskWorkspaceDir(taskKey), fileName);
|
|
18
|
+
}
|
|
6
19
|
export function artifactFile(prefix, taskKey, iteration) {
|
|
7
|
-
return `${prefix}-${taskKey}-${iteration}.md
|
|
20
|
+
return taskWorkspaceFile(taskKey, `${prefix}-${taskKey}-${iteration}.md`);
|
|
8
21
|
}
|
|
9
22
|
export function designFile(taskKey) {
|
|
10
23
|
return artifactFile("design", taskKey, 1);
|
|
@@ -12,15 +25,58 @@ export function designFile(taskKey) {
|
|
|
12
25
|
export function planFile(taskKey) {
|
|
13
26
|
return artifactFile("plan", taskKey, 1);
|
|
14
27
|
}
|
|
28
|
+
export function bugAnalyzeFile(taskKey) {
|
|
29
|
+
return taskWorkspaceFile(taskKey, `bug-analyze-${taskKey}.md`);
|
|
30
|
+
}
|
|
31
|
+
export function bugAnalyzeJsonFile(taskKey) {
|
|
32
|
+
return taskWorkspaceFile(taskKey, `bug-analyze-${taskKey}.json`);
|
|
33
|
+
}
|
|
34
|
+
export function bugFixDesignFile(taskKey) {
|
|
35
|
+
return taskWorkspaceFile(taskKey, `bug-fix-design-${taskKey}.md`);
|
|
36
|
+
}
|
|
37
|
+
export function bugFixDesignJsonFile(taskKey) {
|
|
38
|
+
return taskWorkspaceFile(taskKey, `bug-fix-design-${taskKey}.json`);
|
|
39
|
+
}
|
|
40
|
+
export function bugFixPlanFile(taskKey) {
|
|
41
|
+
return taskWorkspaceFile(taskKey, `bug-fix-plan-${taskKey}.md`);
|
|
42
|
+
}
|
|
43
|
+
export function bugFixPlanJsonFile(taskKey) {
|
|
44
|
+
return taskWorkspaceFile(taskKey, `bug-fix-plan-${taskKey}.json`);
|
|
45
|
+
}
|
|
15
46
|
export function qaFile(taskKey) {
|
|
16
47
|
return artifactFile("qa", taskKey, 1);
|
|
17
48
|
}
|
|
18
49
|
export function taskSummaryFile(taskKey) {
|
|
19
50
|
return artifactFile("task", taskKey, 1);
|
|
20
51
|
}
|
|
52
|
+
export function readyToMergeFile(taskKey) {
|
|
53
|
+
return taskWorkspaceFile(taskKey, READY_TO_MERGE_FILE);
|
|
54
|
+
}
|
|
55
|
+
export function jiraTaskFile(taskKey) {
|
|
56
|
+
return taskWorkspaceFile(taskKey, `${taskKey}.json`);
|
|
57
|
+
}
|
|
58
|
+
export function jiraDescriptionFile(taskKey) {
|
|
59
|
+
return taskWorkspaceFile(taskKey, `jira-${taskKey}-description.md`);
|
|
60
|
+
}
|
|
61
|
+
export function mrDescriptionFile(taskKey) {
|
|
62
|
+
return taskWorkspaceFile(taskKey, `mr-description-${taskKey}.md`);
|
|
63
|
+
}
|
|
64
|
+
export function autoStateFile(taskKey) {
|
|
65
|
+
return taskWorkspaceFile(taskKey, `.agentweaver-state-${taskKey}.json`);
|
|
66
|
+
}
|
|
21
67
|
export function planArtifacts(taskKey) {
|
|
22
68
|
return [designFile(taskKey), planFile(taskKey), qaFile(taskKey)];
|
|
23
69
|
}
|
|
70
|
+
export function bugAnalyzeArtifacts(taskKey) {
|
|
71
|
+
return [
|
|
72
|
+
bugAnalyzeFile(taskKey),
|
|
73
|
+
bugAnalyzeJsonFile(taskKey),
|
|
74
|
+
bugFixDesignFile(taskKey),
|
|
75
|
+
bugFixDesignJsonFile(taskKey),
|
|
76
|
+
bugFixPlanFile(taskKey),
|
|
77
|
+
bugFixPlanJsonFile(taskKey),
|
|
78
|
+
];
|
|
79
|
+
}
|
|
24
80
|
export function requireArtifacts(paths, message) {
|
|
25
81
|
const missing = paths.filter((filePath) => !existsSync(filePath));
|
|
26
82
|
if (missing.length > 0) {
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { claudeExecutorDefaultConfig } from "./configs/claude-config.js";
|
|
2
2
|
import { processExecutor } from "./process-executor.js";
|
|
3
3
|
function resolveModel(config, env) {
|
|
4
|
-
|
|
4
|
+
const primaryModel = env[config.modelEnvVar]?.trim();
|
|
5
|
+
if (primaryModel) {
|
|
6
|
+
return primaryModel;
|
|
7
|
+
}
|
|
8
|
+
for (const envVarName of config.legacyModelEnvVars ?? []) {
|
|
9
|
+
const legacyModel = env[envVarName]?.trim();
|
|
10
|
+
if (legacyModel) {
|
|
11
|
+
return legacyModel;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return config.defaultModel;
|
|
5
15
|
}
|
|
6
16
|
export const claudeExecutor = {
|
|
7
17
|
kind: "claude",
|
|
@@ -10,7 +20,7 @@ export const claudeExecutor = {
|
|
|
10
20
|
async execute(context, input, config) {
|
|
11
21
|
const env = input.env ?? context.env;
|
|
12
22
|
const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
13
|
-
const model = resolveModel(config, env);
|
|
23
|
+
const model = input.model?.trim() || resolveModel(config, env);
|
|
14
24
|
const argv = [command, "--model", model, config.promptFlag, `--allowedTools=${config.allowedTools}`];
|
|
15
25
|
if (config.outputFormat) {
|
|
16
26
|
argv.push("--output-format", config.outputFormat);
|
|
@@ -12,7 +12,7 @@ export const claudeSummaryExecutor = {
|
|
|
12
12
|
async execute(context, input, config) {
|
|
13
13
|
const env = input.env ?? context.env;
|
|
14
14
|
const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
15
|
-
const model = resolveModel(config, env);
|
|
15
|
+
const model = input.model?.trim() || resolveModel(config, env);
|
|
16
16
|
const argv = [command, "--model", model, config.promptFlag, `--allowedTools=${config.allowedTools}`, input.prompt];
|
|
17
17
|
const processInput = {
|
|
18
18
|
argv,
|
|
@@ -10,7 +10,7 @@ export const codexDockerExecutor = {
|
|
|
10
10
|
async execute(context, input, config) {
|
|
11
11
|
const composeCommand = context.runtime.resolveDockerComposeCmd();
|
|
12
12
|
const env = context.runtime.dockerRuntimeEnv();
|
|
13
|
-
const model = resolveModel(config, env);
|
|
13
|
+
const model = input.model?.trim() || resolveModel(config, env);
|
|
14
14
|
env[config.promptEnvVar] = input.prompt;
|
|
15
15
|
env[config.flagsEnvVar] = config.execFlagsTemplate.replace("{model}", model);
|
|
16
16
|
const result = await processExecutor.execute(context, {
|
|
@@ -10,7 +10,7 @@ export const codexLocalExecutor = {
|
|
|
10
10
|
async execute(context, input, config) {
|
|
11
11
|
const env = input.env ?? context.env;
|
|
12
12
|
const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
|
|
13
|
-
const model = resolveModel(config, env);
|
|
13
|
+
const model = input.model?.trim() || resolveModel(config, env);
|
|
14
14
|
const result = await processExecutor.execute(context, {
|
|
15
15
|
argv: [command, config.subcommand, "--model", model, config.fullAutoFlag, input.prompt],
|
|
16
16
|
env,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export const claudeExecutorDefaultConfig = {
|
|
2
2
|
commandEnvVar: "CLAUDE_BIN",
|
|
3
3
|
defaultCommand: "claude",
|
|
4
|
-
modelEnvVar: "
|
|
4
|
+
modelEnvVar: "CLAUDE_MODEL",
|
|
5
|
+
legacyModelEnvVars: ["CLAUDE_REVIEW_MODEL"],
|
|
5
6
|
defaultModel: "opus",
|
|
6
7
|
promptFlag: "-p",
|
|
7
8
|
allowedTools: "Read,Write,Edit",
|
|
@@ -1,22 +1,123 @@
|
|
|
1
1
|
import { verifyBuildExecutorDefaultConfig } from "./configs/verify-build-config.js";
|
|
2
|
+
import { TaskRunnerError } from "../errors.js";
|
|
2
3
|
import { processExecutor } from "./process-executor.js";
|
|
4
|
+
function parseStructuredResult(output, service) {
|
|
5
|
+
const lines = output
|
|
6
|
+
.split(/\r?\n/)
|
|
7
|
+
.map((line) => line.replace(/\u001b\[[0-9;]*m/g, "").trim())
|
|
8
|
+
.filter(Boolean);
|
|
9
|
+
if (lines.length === 0) {
|
|
10
|
+
throw new TaskRunnerError(`Structured result is missing from service '${service}' output.`);
|
|
11
|
+
}
|
|
12
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
13
|
+
const line = lines[index];
|
|
14
|
+
if (!line) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const candidates = [];
|
|
18
|
+
if (line.startsWith("{") && line.endsWith("}")) {
|
|
19
|
+
candidates.push(line);
|
|
20
|
+
}
|
|
21
|
+
const firstBrace = line.indexOf("{");
|
|
22
|
+
const lastBrace = line.lastIndexOf("}");
|
|
23
|
+
if (firstBrace >= 0 && lastBrace > firstBrace) {
|
|
24
|
+
const slice = line.slice(firstBrace, lastBrace + 1).trim();
|
|
25
|
+
if (slice && !candidates.includes(slice)) {
|
|
26
|
+
candidates.push(slice);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const rawJson of candidates) {
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = JSON.parse(rawJson);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const candidate = parsed;
|
|
41
|
+
if (typeof candidate.ok !== "boolean" ||
|
|
42
|
+
typeof candidate.kind !== "string" ||
|
|
43
|
+
typeof candidate.stage !== "string" ||
|
|
44
|
+
typeof candidate.exitCode !== "number" ||
|
|
45
|
+
typeof candidate.summary !== "string" ||
|
|
46
|
+
typeof candidate.command !== "string") {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const details = candidate.details;
|
|
50
|
+
if (details !== undefined && (!details || typeof details !== "object" || Array.isArray(details))) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
ok: candidate.ok,
|
|
55
|
+
kind: candidate.kind,
|
|
56
|
+
stage: candidate.stage,
|
|
57
|
+
exitCode: candidate.exitCode,
|
|
58
|
+
summary: candidate.summary,
|
|
59
|
+
command: candidate.command,
|
|
60
|
+
details: details ?? {},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
throw new TaskRunnerError(`Structured result is missing or invalid in service '${service}' output.`);
|
|
65
|
+
}
|
|
3
66
|
export const verifyBuildExecutor = {
|
|
4
67
|
kind: "verify-build",
|
|
5
68
|
version: 1,
|
|
6
69
|
defaultConfig: verifyBuildExecutorDefaultConfig,
|
|
7
70
|
async execute(context, input, config) {
|
|
8
71
|
const composeCommand = context.runtime.resolveDockerComposeCmd();
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
72
|
+
const service = input.service ?? config.service;
|
|
73
|
+
if (context.dryRun) {
|
|
74
|
+
await processExecutor.execute(context, {
|
|
75
|
+
argv: [...composeCommand, config.composeFileFlag, input.dockerComposeFile, ...config.runArgs, service],
|
|
76
|
+
env: context.runtime.dockerRuntimeEnv(),
|
|
77
|
+
verbose: config.verbose,
|
|
78
|
+
label: service,
|
|
79
|
+
}, {
|
|
80
|
+
printFailureOutput: config.printFailureOutput,
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
output: "",
|
|
84
|
+
composeCommand,
|
|
85
|
+
parsed: {
|
|
86
|
+
ok: true,
|
|
87
|
+
kind: service,
|
|
88
|
+
stage: "dry_run",
|
|
89
|
+
exitCode: 0,
|
|
90
|
+
summary: `Dry run for service '${service}'`,
|
|
91
|
+
command: [...composeCommand, config.composeFileFlag, input.dockerComposeFile, ...config.runArgs, service].join(" "),
|
|
92
|
+
details: {},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
let output = "";
|
|
97
|
+
let exitCode = 0;
|
|
98
|
+
try {
|
|
99
|
+
const result = await processExecutor.execute(context, {
|
|
100
|
+
argv: [...composeCommand, config.composeFileFlag, input.dockerComposeFile, ...config.runArgs, service],
|
|
101
|
+
env: context.runtime.dockerRuntimeEnv(),
|
|
102
|
+
verbose: config.verbose,
|
|
103
|
+
label: service,
|
|
104
|
+
}, {
|
|
105
|
+
printFailureOutput: config.printFailureOutput,
|
|
106
|
+
});
|
|
107
|
+
output = result.output;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
output = String(error.output ?? "");
|
|
111
|
+
exitCode = Number(error.returnCode ?? 1);
|
|
112
|
+
}
|
|
113
|
+
const parsed = parseStructuredResult(output, service);
|
|
114
|
+
if (parsed.exitCode !== exitCode && exitCode !== 0) {
|
|
115
|
+
throw new TaskRunnerError(`Structured result exit code mismatch for service '${service}': script=${parsed.exitCode}, runtime=${exitCode}.`);
|
|
116
|
+
}
|
|
17
117
|
return {
|
|
18
|
-
output
|
|
118
|
+
output,
|
|
19
119
|
composeCommand,
|
|
120
|
+
parsed,
|
|
20
121
|
};
|
|
21
122
|
},
|
|
22
123
|
};
|