agentweaver 0.1.0 → 0.1.3

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.
Files changed (77) hide show
  1. package/README.md +30 -5
  2. package/dist/artifacts.js +24 -2
  3. package/dist/executors/claude-executor.js +46 -0
  4. package/dist/executors/claude-summary-executor.js +31 -0
  5. package/dist/executors/codex-docker-executor.js +27 -0
  6. package/dist/executors/codex-local-executor.js +25 -0
  7. package/dist/executors/command-check-executor.js +14 -0
  8. package/dist/executors/configs/claude-config.js +12 -0
  9. package/dist/executors/configs/claude-summary-config.js +8 -0
  10. package/dist/executors/configs/codex-docker-config.js +10 -0
  11. package/dist/executors/configs/codex-local-config.js +8 -0
  12. package/dist/executors/configs/jira-fetch-config.js +4 -0
  13. package/dist/executors/configs/process-config.js +3 -0
  14. package/dist/executors/configs/verify-build-config.js +7 -0
  15. package/dist/executors/jira-fetch-executor.js +11 -0
  16. package/dist/executors/process-executor.js +21 -0
  17. package/dist/executors/types.js +1 -0
  18. package/dist/executors/verify-build-executor.js +22 -0
  19. package/dist/index.js +456 -699
  20. package/dist/interactive-ui.js +536 -182
  21. package/dist/jira.js +3 -1
  22. package/dist/pipeline/auto-flow.js +9 -0
  23. package/dist/pipeline/build-failure-summary.js +6 -0
  24. package/dist/pipeline/checks.js +15 -0
  25. package/dist/pipeline/context.js +19 -0
  26. package/dist/pipeline/declarative-flow-runner.js +246 -0
  27. package/dist/pipeline/declarative-flows.js +24 -0
  28. package/dist/pipeline/flow-runner.js +13 -0
  29. package/dist/pipeline/flow-specs/auto.json +471 -0
  30. package/dist/pipeline/flow-specs/implement.json +47 -0
  31. package/dist/pipeline/flow-specs/plan.json +88 -0
  32. package/dist/pipeline/flow-specs/preflight.json +174 -0
  33. package/dist/pipeline/flow-specs/review-fix.json +76 -0
  34. package/dist/pipeline/flow-specs/review.json +233 -0
  35. package/dist/pipeline/flow-specs/test-fix.json +24 -0
  36. package/dist/pipeline/flow-specs/test-linter-fix.json +24 -0
  37. package/dist/pipeline/flow-specs/test.json +19 -0
  38. package/dist/pipeline/flow-types.js +1 -0
  39. package/dist/pipeline/flows/implement-flow.js +47 -0
  40. package/dist/pipeline/flows/plan-flow.js +42 -0
  41. package/dist/pipeline/flows/preflight-flow.js +19 -0
  42. package/dist/pipeline/flows/review-fix-flow.js +62 -0
  43. package/dist/pipeline/flows/review-flow.js +124 -0
  44. package/dist/pipeline/flows/test-fix-flow.js +12 -0
  45. package/dist/pipeline/flows/test-flow.js +32 -0
  46. package/dist/pipeline/node-registry.js +71 -0
  47. package/dist/pipeline/node-runner.js +20 -0
  48. package/dist/pipeline/nodes/build-failure-summary-node.js +71 -0
  49. package/dist/pipeline/nodes/claude-prompt-node.js +54 -0
  50. package/dist/pipeline/nodes/claude-summary-node.js +38 -0
  51. package/dist/pipeline/nodes/codex-docker-prompt-node.js +32 -0
  52. package/dist/pipeline/nodes/codex-local-prompt-node.js +32 -0
  53. package/dist/pipeline/nodes/command-check-node.js +10 -0
  54. package/dist/pipeline/nodes/file-check-node.js +15 -0
  55. package/dist/pipeline/nodes/implement-codex-node.js +16 -0
  56. package/dist/pipeline/nodes/jira-fetch-node.js +25 -0
  57. package/dist/pipeline/nodes/plan-codex-node.js +32 -0
  58. package/dist/pipeline/nodes/review-claude-node.js +38 -0
  59. package/dist/pipeline/nodes/review-reply-codex-node.js +40 -0
  60. package/dist/pipeline/nodes/summary-file-load-node.js +16 -0
  61. package/dist/pipeline/nodes/task-summary-node.js +42 -0
  62. package/dist/pipeline/nodes/verify-build-node.js +14 -0
  63. package/dist/pipeline/prompt-registry.js +22 -0
  64. package/dist/pipeline/prompt-runtime.js +18 -0
  65. package/dist/pipeline/registry.js +23 -0
  66. package/dist/pipeline/spec-compiler.js +200 -0
  67. package/dist/pipeline/spec-loader.js +14 -0
  68. package/dist/pipeline/spec-types.js +1 -0
  69. package/dist/pipeline/spec-validator.js +290 -0
  70. package/dist/pipeline/types.js +10 -0
  71. package/dist/pipeline/value-resolver.js +199 -0
  72. package/dist/prompts.js +1 -3
  73. package/dist/runtime/command-resolution.js +139 -0
  74. package/dist/runtime/docker-runtime.js +51 -0
  75. package/dist/runtime/process-runner.js +112 -0
  76. package/dist/tui.js +73 -0
  77. package/package.json +3 -2
package/README.md CHANGED
@@ -16,12 +16,29 @@ The package is designed to run as an npm CLI and includes an interactive termina
16
16
  - Persists `auto` pipeline state on disk so runs can resume
17
17
  - Uses Docker runtime services for isolated Codex execution and build verification
18
18
 
19
+ ## Architecture
20
+
21
+ The CLI now uses an executor + node + declarative flow architecture.
22
+
23
+ - `src/index.ts` remains the CLI entrypoint and high-level orchestration layer
24
+ - `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
25
+ - `src/pipeline/nodes/` contains reusable runtime nodes built on top of executors
26
+ - `src/pipeline/flow-specs/` contains declarative JSON flow specs for `preflight`, `plan`, `implement`, `review`, `review-fix`, `test`, `test-fix`, `test-linter-fix`, and `auto`
27
+ - `src/runtime/` contains shared runtime services such as command resolution, Docker runtime environment setup, and subprocess execution
28
+
29
+ This keeps command handlers focused on choosing a flow and providing parameters instead of assembling prompts and subprocess wiring inline.
30
+
19
31
  ## Repository Layout
20
32
 
21
33
  - `src/` — main TypeScript sources
22
34
  - `src/index.ts` — CLI entrypoint and workflow orchestration
35
+ - `src/pipeline/flow-specs/` — declarative JSON specs for workflow stages
36
+ - `src/pipeline/nodes/` — reusable pipeline nodes executed by the declarative runner
23
37
  - `src/interactive-ui.ts` — interactive TUI built with `neo-blessed`
24
38
  - `src/markdown.ts` — markdown-to-terminal renderer for the TUI
39
+ - `src/executors/` — executor modules for concrete execution families
40
+ - `src/executors/configs/` — default executor configs kept as plain data
41
+ - `src/runtime/` — shared runtime services used by executors
25
42
  - `docker-compose.yml` — runtime services for Codex and build verification
26
43
  - `Dockerfile.codex` — container image for Codex runtime
27
44
  - `verify_build.sh` — project-specific verification entrypoint used by `verify-build`
@@ -70,9 +87,8 @@ Common optional variables:
70
87
  - `DOCKER_COMPOSE_BIN` — override compose command, for example `docker compose`
71
88
  - `CODEX_BIN` — override `codex` executable path
72
89
  - `CLAUDE_BIN` — override `claude` executable path
73
- - `CODEX_MODEL` — defaults to `gpt-5.4`
74
- - `CLAUDE_REVIEW_MODEL` — defaults to `opus`
75
- - `CLAUDE_SUMMARY_MODEL` — defaults to `haiku`
90
+ - `CODEX_MODEL` — fallback model for Codex executors when the flow spec does not set `params.model`
91
+ - `CLAUDE_MODEL` — fallback Claude model when the flow spec does not set `params.model`
76
92
 
77
93
  Example `.env`:
78
94
 
@@ -83,8 +99,7 @@ AGENTWEAVER_HOME=/absolute/path/to/AgentWeaver
83
99
  CODEX_BIN=codex
84
100
  CLAUDE_BIN=claude
85
101
  CODEX_MODEL=gpt-5.4
86
- CLAUDE_REVIEW_MODEL=opus
87
- CLAUDE_SUMMARY_MODEL=haiku
102
+ CLAUDE_MODEL=opus
88
103
  GOPRIVATE=gitlab.example.org/*
89
104
  GONOSUMDB=gitlab.example.org/*
90
105
  GONOPROXY=gitlab.example.org/*
@@ -217,6 +232,16 @@ Run from source in dev mode:
217
232
  npm run dev -- --help
218
233
  ```
219
234
 
235
+ Representative smoke checks during development:
236
+
237
+ ```bash
238
+ node dist/index.js --help
239
+ node dist/index.js auto --help-phases
240
+ node dist/index.js plan --dry DEMO-123
241
+ node dist/index.js implement --dry DEMO-123
242
+ node dist/index.js review --dry DEMO-123
243
+ ```
244
+
220
245
  ## Publishing
221
246
 
222
247
  The package is prepared for npm publication and currently includes:
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);
@@ -18,6 +31,15 @@ export function qaFile(taskKey) {
18
31
  export function taskSummaryFile(taskKey) {
19
32
  return artifactFile("task", taskKey, 1);
20
33
  }
34
+ export function readyToMergeFile(taskKey) {
35
+ return taskWorkspaceFile(taskKey, READY_TO_MERGE_FILE);
36
+ }
37
+ export function jiraTaskFile(taskKey) {
38
+ return taskWorkspaceFile(taskKey, `${taskKey}.json`);
39
+ }
40
+ export function autoStateFile(taskKey) {
41
+ return taskWorkspaceFile(taskKey, `.agentweaver-state-${taskKey}.json`);
42
+ }
21
43
  export function planArtifacts(taskKey) {
22
44
  return [designFile(taskKey), planFile(taskKey), qaFile(taskKey)];
23
45
  }
@@ -0,0 +1,46 @@
1
+ import { claudeExecutorDefaultConfig } from "./configs/claude-config.js";
2
+ import { processExecutor } from "./process-executor.js";
3
+ function resolveModel(config, env) {
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;
15
+ }
16
+ export const claudeExecutor = {
17
+ kind: "claude",
18
+ version: 1,
19
+ defaultConfig: claudeExecutorDefaultConfig,
20
+ async execute(context, input, config) {
21
+ const env = input.env ?? context.env;
22
+ const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
23
+ const model = input.model?.trim() || resolveModel(config, env);
24
+ const argv = [command, "--model", model, config.promptFlag, `--allowedTools=${config.allowedTools}`];
25
+ if (config.outputFormat) {
26
+ argv.push("--output-format", config.outputFormat);
27
+ }
28
+ if (config.verboseMode) {
29
+ argv.push("--verbose");
30
+ }
31
+ if (config.includePartialMessages) {
32
+ argv.push("--include-partial-messages");
33
+ }
34
+ argv.push(input.prompt);
35
+ const result = await processExecutor.execute(context, {
36
+ argv,
37
+ env,
38
+ label: `claude:${model}`,
39
+ }, processExecutor.defaultConfig);
40
+ return {
41
+ output: result.output,
42
+ command,
43
+ model,
44
+ };
45
+ },
46
+ };
@@ -0,0 +1,31 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { requireArtifacts } from "../artifacts.js";
3
+ import { claudeSummaryExecutorDefaultConfig } from "./configs/claude-summary-config.js";
4
+ import { processExecutor } from "./process-executor.js";
5
+ function resolveModel(config, env) {
6
+ return env[config.modelEnvVar]?.trim() || config.defaultModel;
7
+ }
8
+ export const claudeSummaryExecutor = {
9
+ kind: "claude-summary",
10
+ version: 1,
11
+ defaultConfig: claudeSummaryExecutorDefaultConfig,
12
+ async execute(context, input, config) {
13
+ const env = input.env ?? context.env;
14
+ const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
15
+ const model = input.model?.trim() || resolveModel(config, env);
16
+ const argv = [command, "--model", model, config.promptFlag, `--allowedTools=${config.allowedTools}`, input.prompt];
17
+ const processInput = {
18
+ argv,
19
+ env,
20
+ label: `claude:${model}`,
21
+ };
22
+ const result = await processExecutor.execute(context, input.verbose === undefined ? processInput : { ...processInput, verbose: input.verbose }, processExecutor.defaultConfig);
23
+ requireArtifacts([input.outputFile], `Claude summary did not produce ${input.outputFile}.`);
24
+ return {
25
+ output: result.output,
26
+ artifactText: readFileSync(input.outputFile, "utf8").trim(),
27
+ command,
28
+ model,
29
+ };
30
+ },
31
+ };
@@ -0,0 +1,27 @@
1
+ import { codexDockerExecutorDefaultConfig } from "./configs/codex-docker-config.js";
2
+ import { processExecutor } from "./process-executor.js";
3
+ function resolveModel(config, env) {
4
+ return env[config.modelEnvVar]?.trim() || config.defaultModel;
5
+ }
6
+ export const codexDockerExecutor = {
7
+ kind: "codex-docker",
8
+ version: 1,
9
+ defaultConfig: codexDockerExecutorDefaultConfig,
10
+ async execute(context, input, config) {
11
+ const composeCommand = context.runtime.resolveDockerComposeCmd();
12
+ const env = context.runtime.dockerRuntimeEnv();
13
+ const model = input.model?.trim() || resolveModel(config, env);
14
+ env[config.promptEnvVar] = input.prompt;
15
+ env[config.flagsEnvVar] = config.execFlagsTemplate.replace("{model}", model);
16
+ const result = await processExecutor.execute(context, {
17
+ argv: [...composeCommand, config.composeFileFlag, input.dockerComposeFile, ...config.runArgs, config.service],
18
+ env,
19
+ label: `codex:${model}`,
20
+ }, processExecutor.defaultConfig);
21
+ return {
22
+ output: result.output,
23
+ composeCommand,
24
+ model,
25
+ };
26
+ },
27
+ };
@@ -0,0 +1,25 @@
1
+ import { codexLocalExecutorDefaultConfig } from "./configs/codex-local-config.js";
2
+ import { processExecutor } from "./process-executor.js";
3
+ function resolveModel(config, env) {
4
+ return env[config.modelEnvVar]?.trim() || config.defaultModel;
5
+ }
6
+ export const codexLocalExecutor = {
7
+ kind: "codex-local",
8
+ version: 1,
9
+ defaultConfig: codexLocalExecutorDefaultConfig,
10
+ async execute(context, input, config) {
11
+ const env = input.env ?? context.env;
12
+ const command = input.command ?? context.runtime.resolveCmd(config.defaultCommand, config.commandEnvVar);
13
+ const model = input.model?.trim() || resolveModel(config, env);
14
+ const result = await processExecutor.execute(context, {
15
+ argv: [command, config.subcommand, "--model", model, config.fullAutoFlag, input.prompt],
16
+ env,
17
+ label: `codex:${model}`,
18
+ }, processExecutor.defaultConfig);
19
+ return {
20
+ output: result.output,
21
+ command,
22
+ model,
23
+ };
24
+ },
25
+ };
@@ -0,0 +1,14 @@
1
+ export const commandCheckExecutor = {
2
+ kind: "command-check",
3
+ version: 1,
4
+ defaultConfig: {},
5
+ async execute(context, input) {
6
+ return {
7
+ resolved: input.commands.map((candidate) => ({
8
+ commandName: candidate.commandName,
9
+ envVarName: candidate.envVarName,
10
+ path: context.runtime.resolveCmd(candidate.commandName, candidate.envVarName),
11
+ })),
12
+ };
13
+ },
14
+ };
@@ -0,0 +1,12 @@
1
+ export const claudeExecutorDefaultConfig = {
2
+ commandEnvVar: "CLAUDE_BIN",
3
+ defaultCommand: "claude",
4
+ modelEnvVar: "CLAUDE_MODEL",
5
+ legacyModelEnvVars: ["CLAUDE_REVIEW_MODEL"],
6
+ defaultModel: "opus",
7
+ promptFlag: "-p",
8
+ allowedTools: "Read,Write,Edit",
9
+ outputFormat: "stream-json",
10
+ includePartialMessages: true,
11
+ verboseMode: true,
12
+ };
@@ -0,0 +1,8 @@
1
+ export const claudeSummaryExecutorDefaultConfig = {
2
+ commandEnvVar: "CLAUDE_BIN",
3
+ defaultCommand: "claude",
4
+ modelEnvVar: "CLAUDE_SUMMARY_MODEL",
5
+ defaultModel: "haiku",
6
+ promptFlag: "-p",
7
+ allowedTools: "Read,Write,Edit",
8
+ };
@@ -0,0 +1,10 @@
1
+ export const codexDockerExecutorDefaultConfig = {
2
+ service: "codex-exec",
3
+ composeFileFlag: "-f",
4
+ runArgs: ["run", "--rm"],
5
+ modelEnvVar: "CODEX_MODEL",
6
+ defaultModel: "gpt-5.4",
7
+ promptEnvVar: "CODEX_PROMPT",
8
+ flagsEnvVar: "CODEX_EXEC_FLAGS",
9
+ execFlagsTemplate: "--model {model} --dangerously-bypass-approvals-and-sandbox",
10
+ };
@@ -0,0 +1,8 @@
1
+ export const codexLocalExecutorDefaultConfig = {
2
+ commandEnvVar: "CODEX_BIN",
3
+ defaultCommand: "codex",
4
+ modelEnvVar: "CODEX_MODEL",
5
+ defaultModel: "gpt-5.4",
6
+ subcommand: "exec",
7
+ fullAutoFlag: "--full-auto",
8
+ };
@@ -0,0 +1,4 @@
1
+ export const jiraFetchExecutorDefaultConfig = {
2
+ authEnvVar: "JIRA_API_KEY",
3
+ acceptHeader: "application/json",
4
+ };
@@ -0,0 +1,3 @@
1
+ export const processExecutorDefaultConfig = {
2
+ printFailureOutput: true,
3
+ };
@@ -0,0 +1,7 @@
1
+ export const verifyBuildExecutorDefaultConfig = {
2
+ service: "verify-build",
3
+ composeFileFlag: "-f",
4
+ runArgs: ["run", "--rm"],
5
+ printFailureOutput: false,
6
+ verbose: false,
7
+ };
@@ -0,0 +1,11 @@
1
+ import { jiraFetchExecutorDefaultConfig } from "./configs/jira-fetch-config.js";
2
+ import { fetchJiraIssue } from "../jira.js";
3
+ export const jiraFetchExecutor = {
4
+ kind: "jira-fetch",
5
+ version: 1,
6
+ defaultConfig: jiraFetchExecutorDefaultConfig,
7
+ async execute(_context, input) {
8
+ await fetchJiraIssue(input.jiraApiUrl, input.outputFile);
9
+ return { outputFile: input.outputFile };
10
+ },
11
+ };
@@ -0,0 +1,21 @@
1
+ import { processExecutorDefaultConfig } from "./configs/process-config.js";
2
+ export const processExecutor = {
3
+ kind: "process",
4
+ version: 1,
5
+ defaultConfig: processExecutorDefaultConfig,
6
+ async execute(context, input, config) {
7
+ const options = {
8
+ dryRun: input.dryRun ?? context.dryRun,
9
+ verbose: input.verbose ?? context.verbose,
10
+ printFailureOutput: config.printFailureOutput,
11
+ };
12
+ if (input.env) {
13
+ options.env = input.env;
14
+ }
15
+ if (input.label) {
16
+ options.label = input.label;
17
+ }
18
+ const output = await context.runtime.runCommand(input.argv, options);
19
+ return { output };
20
+ },
21
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import { verifyBuildExecutorDefaultConfig } from "./configs/verify-build-config.js";
2
+ import { processExecutor } from "./process-executor.js";
3
+ export const verifyBuildExecutor = {
4
+ kind: "verify-build",
5
+ version: 1,
6
+ defaultConfig: verifyBuildExecutorDefaultConfig,
7
+ async execute(context, input, config) {
8
+ const composeCommand = context.runtime.resolveDockerComposeCmd();
9
+ const result = await processExecutor.execute(context, {
10
+ argv: [...composeCommand, config.composeFileFlag, input.dockerComposeFile, ...config.runArgs, config.service],
11
+ env: context.runtime.dockerRuntimeEnv(),
12
+ verbose: config.verbose,
13
+ label: config.service,
14
+ }, {
15
+ printFailureOutput: config.printFailureOutput,
16
+ });
17
+ return {
18
+ output: result.output,
19
+ composeCommand,
20
+ };
21
+ },
22
+ };