agentweaver 0.1.7 → 0.1.9

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 (50) hide show
  1. package/Dockerfile.codex +3 -3
  2. package/README.md +24 -10
  3. package/dist/artifacts.js +30 -0
  4. package/dist/executors/configs/fetch-gitlab-diff-config.js +3 -0
  5. package/dist/executors/configs/opencode-config.js +6 -0
  6. package/dist/executors/fetch-gitlab-diff-executor.js +26 -0
  7. package/dist/executors/jira-fetch-executor.js +8 -2
  8. package/dist/executors/opencode-executor.js +35 -0
  9. package/dist/gitlab.js +199 -5
  10. package/dist/index.js +160 -121
  11. package/dist/interactive-ui.js +45 -10
  12. package/dist/jira.js +116 -14
  13. package/dist/pipeline/auto-flow.js +1 -1
  14. package/dist/pipeline/declarative-flows.js +41 -6
  15. package/dist/pipeline/flow-catalog.js +66 -0
  16. package/dist/pipeline/flow-specs/auto.json +183 -1
  17. package/dist/pipeline/flow-specs/bug-analyze.json +1 -1
  18. package/dist/pipeline/flow-specs/gitlab-diff-review.json +226 -0
  19. package/dist/pipeline/flow-specs/gitlab-review.json +1 -31
  20. package/dist/pipeline/flow-specs/plan-opencode.json +603 -0
  21. package/dist/pipeline/flow-specs/plan.json +183 -1
  22. package/dist/pipeline/flow-specs/run-go-linter-loop.json +83 -7
  23. package/dist/pipeline/flow-specs/run-go-tests-loop.json +83 -7
  24. package/dist/pipeline/flow-specs/task-describe.json +1 -1
  25. package/dist/pipeline/node-registry.js +80 -8
  26. package/dist/pipeline/nodes/fetch-gitlab-diff-node.js +34 -0
  27. package/dist/pipeline/nodes/flow-run-node.js +2 -2
  28. package/dist/pipeline/nodes/jira-fetch-node.js +26 -2
  29. package/dist/pipeline/nodes/local-script-check-node.js +50 -8
  30. package/dist/pipeline/nodes/opencode-prompt-node.js +32 -0
  31. package/dist/pipeline/nodes/planning-questions-form-node.js +69 -0
  32. package/dist/pipeline/nodes/user-input-node.js +9 -1
  33. package/dist/pipeline/prompt-registry.js +4 -1
  34. package/dist/pipeline/registry.js +10 -0
  35. package/dist/pipeline/spec-loader.js +37 -3
  36. package/dist/pipeline/spec-types.js +43 -1
  37. package/dist/pipeline/spec-validator.js +53 -7
  38. package/dist/pipeline/value-resolver.js +25 -1
  39. package/dist/prompts.js +54 -14
  40. package/dist/scope.js +25 -16
  41. package/dist/structured-artifact-schemas.json +560 -0
  42. package/dist/structured-artifacts.js +103 -262
  43. package/dist/user-input.js +7 -0
  44. package/docker-compose.yml +2 -2
  45. package/package.json +3 -3
  46. package/run_go_linter.py +128 -0
  47. package/run_go_tests.py +120 -0
  48. package/verify_build.sh +3 -3
  49. package/run_go_linter.sh +0 -89
  50. package/run_go_tests.sh +0 -83
@@ -3,6 +3,7 @@ import { claudePromptNode } from "./nodes/claude-prompt-node.js";
3
3
  import { codexDockerPromptNode } from "./nodes/codex-docker-prompt-node.js";
4
4
  import { codexLocalPromptNode } from "./nodes/codex-local-prompt-node.js";
5
5
  import { commandCheckNode } from "./nodes/command-check-node.js";
6
+ import { fetchGitLabDiffNode } from "./nodes/fetch-gitlab-diff-node.js";
6
7
  import { fetchGitLabReviewNode } from "./nodes/fetch-gitlab-review-node.js";
7
8
  import { fileCheckNode } from "./nodes/file-check-node.js";
8
9
  import { flowRunNode } from "./nodes/flow-run-node.js";
@@ -10,7 +11,9 @@ import { gitlabReviewArtifactsNode } from "./nodes/gitlab-review-artifacts-node.
10
11
  import { jiraFetchNode } from "./nodes/jira-fetch-node.js";
11
12
  import { jiraIssueCheckNode } from "./nodes/jira-issue-check-node.js";
12
13
  import { localScriptCheckNode } from "./nodes/local-script-check-node.js";
14
+ import { opencodePromptNode } from "./nodes/opencode-prompt-node.js";
13
15
  import { planCodexNode } from "./nodes/plan-codex-node.js";
16
+ import { planningQuestionsFormNode } from "./nodes/planning-questions-form-node.js";
14
17
  import { reviewClaudeNode } from "./nodes/review-claude-node.js";
15
18
  import { reviewFindingsFormNode } from "./nodes/review-findings-form-node.js";
16
19
  import { reviewReplyCodexNode } from "./nodes/review-reply-codex-node.js";
@@ -23,6 +26,7 @@ const builtInNodes = {
23
26
  "codex-docker-prompt": codexDockerPromptNode,
24
27
  "codex-local-prompt": codexLocalPromptNode,
25
28
  "command-check": commandCheckNode,
29
+ "fetch-gitlab-diff": fetchGitLabDiffNode,
26
30
  "fetch-gitlab-review": fetchGitLabReviewNode,
27
31
  "file-check": fileCheckNode,
28
32
  "flow-run": flowRunNode,
@@ -30,7 +34,9 @@ const builtInNodes = {
30
34
  "jira-fetch": jiraFetchNode,
31
35
  "jira-issue-check": jiraIssueCheckNode,
32
36
  "local-script-check": localScriptCheckNode,
37
+ "opencode-prompt": opencodePromptNode,
33
38
  "plan-codex": planCodexNode,
39
+ "planning-questions-form": planningQuestionsFormNode,
34
40
  "review-claude": reviewClaudeNode,
35
41
  "review-findings-form": reviewFindingsFormNode,
36
42
  "review-reply-codex": reviewReplyCodexNode,
@@ -39,31 +45,76 @@ const builtInNodes = {
39
45
  "verify-build": verifyBuildNode,
40
46
  };
41
47
  const builtInNodeMetadata = {
42
- "build-failure-summary": { kind: "build-failure-summary", version: 1, prompt: "forbidden", requiredParams: ["output"] },
43
- "claude-prompt": { kind: "claude-prompt", version: 1, prompt: "required", requiredParams: ["labelText"] },
48
+ "build-failure-summary": {
49
+ kind: "build-failure-summary",
50
+ version: 1,
51
+ prompt: "forbidden",
52
+ requiredParams: ["output"],
53
+ executors: ["process"],
54
+ },
55
+ "claude-prompt": {
56
+ kind: "claude-prompt",
57
+ version: 1,
58
+ prompt: "required",
59
+ requiredParams: ["labelText"],
60
+ executors: ["claude"],
61
+ },
44
62
  "codex-docker-prompt": {
45
63
  kind: "codex-docker-prompt",
46
64
  version: 1,
47
65
  prompt: "required",
48
66
  requiredParams: ["dockerComposeFile", "labelText"],
67
+ executors: ["codex-docker"],
68
+ },
69
+ "codex-local-prompt": {
70
+ kind: "codex-local-prompt",
71
+ version: 1,
72
+ prompt: "required",
73
+ requiredParams: ["labelText"],
74
+ executors: ["codex-local"],
75
+ },
76
+ "command-check": {
77
+ kind: "command-check",
78
+ version: 1,
79
+ prompt: "forbidden",
80
+ requiredParams: ["commands"],
81
+ executors: ["command-check"],
82
+ },
83
+ "fetch-gitlab-diff": {
84
+ kind: "fetch-gitlab-diff",
85
+ version: 1,
86
+ prompt: "forbidden",
87
+ requiredParams: ["mergeRequestUrl", "outputFile", "outputJsonFile"],
88
+ executors: ["fetch-gitlab-diff"],
49
89
  },
50
- "codex-local-prompt": { kind: "codex-local-prompt", version: 1, prompt: "required", requiredParams: ["labelText"] },
51
- "command-check": { kind: "command-check", version: 1, prompt: "forbidden", requiredParams: ["commands"] },
52
90
  "fetch-gitlab-review": {
53
91
  kind: "fetch-gitlab-review",
54
92
  version: 1,
55
93
  prompt: "forbidden",
56
94
  requiredParams: ["mergeRequestUrl", "outputFile", "outputJsonFile"],
95
+ executors: ["fetch-gitlab-review"],
57
96
  },
58
97
  "file-check": { kind: "file-check", version: 1, prompt: "forbidden", requiredParams: ["path"] },
59
- "flow-run": { kind: "flow-run", version: 1, prompt: "forbidden", requiredParams: ["fileName"] },
98
+ "flow-run": {
99
+ kind: "flow-run",
100
+ version: 1,
101
+ prompt: "forbidden",
102
+ requiredParams: ["fileName"],
103
+ nestedFlowParam: "fileName",
104
+ },
60
105
  "gitlab-review-artifacts": {
61
106
  kind: "gitlab-review-artifacts",
62
107
  version: 1,
63
108
  prompt: "forbidden",
64
109
  requiredParams: ["gitlabReviewJsonFile", "reviewFile", "reviewJsonFile"],
65
110
  },
66
- "jira-fetch": { kind: "jira-fetch", version: 1, prompt: "forbidden", requiredParams: ["jiraApiUrl", "outputFile"] },
111
+ "jira-fetch": {
112
+ kind: "jira-fetch",
113
+ version: 1,
114
+ prompt: "forbidden",
115
+ requiredParams: ["jiraApiUrl", "outputFile"],
116
+ executors: ["jira-fetch"],
117
+ },
67
118
  "jira-issue-check": {
68
119
  kind: "jira-issue-check",
69
120
  version: 1,
@@ -71,12 +122,26 @@ const builtInNodeMetadata = {
71
122
  requiredParams: ["jiraTaskFile", "allowedIssueTypes"],
72
123
  },
73
124
  "local-script-check": { kind: "local-script-check", version: 1, prompt: "forbidden", requiredParams: ["argv", "labelText"] },
74
- "plan-codex": { kind: "plan-codex", version: 1, prompt: "forbidden", requiredParams: ["prompt", "requiredArtifacts"] },
125
+ "opencode-prompt": { kind: "opencode-prompt", version: 1, prompt: "required", requiredParams: ["labelText"] },
126
+ "plan-codex": {
127
+ kind: "plan-codex",
128
+ version: 1,
129
+ prompt: "forbidden",
130
+ requiredParams: ["prompt", "requiredArtifacts"],
131
+ executors: ["codex-local"],
132
+ },
133
+ "planning-questions-form": {
134
+ kind: "planning-questions-form",
135
+ version: 1,
136
+ prompt: "forbidden",
137
+ requiredParams: ["planningQuestionsJsonFile", "formId", "title"],
138
+ },
75
139
  "review-claude": {
76
140
  kind: "review-claude",
77
141
  version: 1,
78
142
  prompt: "forbidden",
79
143
  requiredParams: ["jiraTaskFile", "taskKey", "iteration", "claudeCmd"],
144
+ executors: ["claude"],
80
145
  },
81
146
  "review-findings-form": {
82
147
  kind: "review-findings-form",
@@ -89,6 +154,7 @@ const builtInNodeMetadata = {
89
154
  version: 1,
90
155
  prompt: "forbidden",
91
156
  requiredParams: ["jiraTaskFile", "taskKey", "iteration", "codexCmd"],
157
+ executors: ["codex-local"],
92
158
  },
93
159
  "summary-file-load": { kind: "summary-file-load", version: 1, prompt: "forbidden", requiredParams: ["path"] },
94
160
  "user-input": {
@@ -97,7 +163,13 @@ const builtInNodeMetadata = {
97
163
  prompt: "forbidden",
98
164
  requiredParams: ["formId", "title", "fields", "outputFile"],
99
165
  },
100
- "verify-build": { kind: "verify-build", version: 1, prompt: "forbidden", requiredParams: ["dockerComposeFile", "labelText"] },
166
+ "verify-build": {
167
+ kind: "verify-build",
168
+ version: 1,
169
+ prompt: "forbidden",
170
+ requiredParams: ["dockerComposeFile", "labelText"],
171
+ executors: ["verify-build"],
172
+ },
101
173
  };
102
174
  export function createNodeRegistry() {
103
175
  return {
@@ -0,0 +1,34 @@
1
+ import { toExecutorContext } from "../types.js";
2
+ export const fetchGitLabDiffNode = {
3
+ kind: "fetch-gitlab-diff",
4
+ version: 1,
5
+ async run(context, params) {
6
+ const executor = context.executors.get("fetch-gitlab-diff");
7
+ const value = await executor.execute(toExecutorContext(context), {
8
+ mergeRequestUrl: params.mergeRequestUrl,
9
+ outputFile: params.outputFile,
10
+ outputJsonFile: params.outputJsonFile,
11
+ }, executor.defaultConfig);
12
+ return {
13
+ value,
14
+ outputs: [
15
+ { kind: "artifact", path: params.outputFile, required: true },
16
+ { kind: "artifact", path: params.outputJsonFile, required: true },
17
+ ],
18
+ };
19
+ },
20
+ checks(_context, params) {
21
+ return [
22
+ {
23
+ kind: "require-file",
24
+ path: params.outputFile,
25
+ message: `Fetch GitLab diff node did not produce ${params.outputFile}.`,
26
+ },
27
+ {
28
+ kind: "require-file",
29
+ path: params.outputJsonFile,
30
+ message: `Fetch GitLab diff node did not produce ${params.outputJsonFile}.`,
31
+ },
32
+ ];
33
+ },
34
+ };
@@ -1,6 +1,6 @@
1
1
  import { printInfo } from "../../tui.js";
2
2
  import { runExpandedPhase } from "../declarative-flow-runner.js";
3
- import { loadDeclarativeFlow } from "../declarative-flows.js";
3
+ import { loadNamedDeclarativeFlow } from "../declarative-flows.js";
4
4
  export const flowRunNode = {
5
5
  kind: "flow-run",
6
6
  version: 1,
@@ -12,7 +12,7 @@ export const flowRunNode = {
12
12
  if (labelText) {
13
13
  printInfo(String(labelText));
14
14
  }
15
- const flow = loadDeclarativeFlow(fileName);
15
+ const flow = loadNamedDeclarativeFlow(fileName, context.cwd);
16
16
  const executionState = {
17
17
  flowKind: flow.kind,
18
18
  flowVersion: flow.version,
@@ -7,19 +7,43 @@ export const jiraFetchNode = {
7
7
  const value = await executor.execute(toExecutorContext(context), {
8
8
  jiraApiUrl: params.jiraApiUrl,
9
9
  outputFile: params.outputFile,
10
+ ...(params.attachmentsManifestFile ? { attachmentsManifestFile: params.attachmentsManifestFile } : {}),
11
+ ...(params.attachmentsContextFile ? { attachmentsContextFile: params.attachmentsContextFile } : {}),
10
12
  }, executor.defaultConfig);
13
+ const outputs = [{ kind: "file", path: params.outputFile, required: true }];
14
+ if (params.attachmentsManifestFile) {
15
+ outputs.push({ kind: "artifact", path: params.attachmentsManifestFile, required: true });
16
+ }
17
+ if (params.attachmentsContextFile) {
18
+ outputs.push({ kind: "artifact", path: params.attachmentsContextFile, required: true });
19
+ }
11
20
  return {
12
21
  value,
13
- outputs: [{ kind: "file", path: params.outputFile, required: true }],
22
+ outputs,
14
23
  };
15
24
  },
16
25
  checks(_context, params) {
17
- return [
26
+ const checks = [
18
27
  {
19
28
  kind: "require-file",
20
29
  path: params.outputFile,
21
30
  message: `Jira fetch node did not produce ${params.outputFile}.`,
22
31
  },
23
32
  ];
33
+ if (params.attachmentsManifestFile) {
34
+ checks.push({
35
+ kind: "require-file",
36
+ path: params.attachmentsManifestFile,
37
+ message: `Jira fetch node did not produce ${params.attachmentsManifestFile}.`,
38
+ });
39
+ }
40
+ if (params.attachmentsContextFile) {
41
+ checks.push({
42
+ kind: "require-file",
43
+ path: params.attachmentsContextFile,
44
+ message: `Jira fetch node did not produce ${params.attachmentsContextFile}.`,
45
+ });
46
+ }
47
+ return checks;
24
48
  },
25
49
  };
@@ -1,3 +1,5 @@
1
+ import { mkdirSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
1
3
  import { TaskRunnerError } from "../../errors.js";
2
4
  import { printInfo } from "../../tui.js";
3
5
  function parseStructuredResult(output, commandLabel) {
@@ -59,22 +61,62 @@ function parseStructuredResult(output, commandLabel) {
59
61
  }
60
62
  throw new TaskRunnerError(`Structured result is missing or invalid in output of '${commandLabel}'.`);
61
63
  }
64
+ function fallbackStructuredResult(output, commandLabel, exitCode) {
65
+ return {
66
+ ok: false,
67
+ kind: "check",
68
+ stage: commandLabel,
69
+ exitCode,
70
+ summary: `${commandLabel} failed`,
71
+ command: commandLabel,
72
+ details: output.trim().length > 0 ? { raw: output } : {},
73
+ };
74
+ }
75
+ function persistStructuredResult(filePath, parsed) {
76
+ mkdirSync(path.dirname(filePath), { recursive: true });
77
+ writeFileSync(filePath, `${JSON.stringify(parsed, null, 2)}\n`, "utf8");
78
+ }
62
79
  export const localScriptCheckNode = {
63
80
  kind: "local-script-check",
64
81
  version: 1,
65
82
  async run(context, params) {
66
83
  printInfo(params.labelText);
67
- const output = await context.runtime.runCommand(params.argv, {
68
- dryRun: context.dryRun,
69
- verbose: context.verbose,
70
- label: params.argv.join(" "),
71
- printFailureOutput: true,
72
- env: { ...context.env },
73
- });
84
+ const commandLabel = params.argv.join(" ");
85
+ let output = "";
86
+ let parsed;
87
+ try {
88
+ output = await context.runtime.runCommand(params.argv, {
89
+ dryRun: context.dryRun,
90
+ verbose: context.verbose,
91
+ label: commandLabel,
92
+ printFailureOutput: true,
93
+ env: { ...context.env },
94
+ });
95
+ parsed = parseStructuredResult(output, commandLabel);
96
+ }
97
+ catch (error) {
98
+ output = String(error.output ?? "");
99
+ const exitCode = Number(error.returnCode ?? 1);
100
+ try {
101
+ parsed = parseStructuredResult(output, commandLabel);
102
+ }
103
+ catch {
104
+ parsed = fallbackStructuredResult(output, commandLabel, exitCode);
105
+ }
106
+ }
107
+ if (typeof parsed.details.raw !== "string") {
108
+ parsed.details = {
109
+ ...parsed.details,
110
+ raw: output,
111
+ };
112
+ }
113
+ if (params.outputFile) {
114
+ persistStructuredResult(params.outputFile, parsed);
115
+ }
74
116
  return {
75
117
  value: {
76
118
  output,
77
- parsed: parseStructuredResult(output, params.argv.join(" ")),
119
+ parsed,
78
120
  },
79
121
  };
80
122
  },
@@ -0,0 +1,32 @@
1
+ import { printInfo, printPrompt } from "../../tui.js";
2
+ import { toExecutorContext } from "../types.js";
3
+ export const opencodePromptNode = {
4
+ kind: "opencode-prompt",
5
+ version: 1,
6
+ async run(context, params) {
7
+ printInfo(params.labelText);
8
+ printPrompt("OpenCode", params.prompt);
9
+ const executor = context.executors.get("opencode");
10
+ const value = await executor.execute(toExecutorContext(context), {
11
+ prompt: params.prompt,
12
+ ...(params.model ? { model: params.model } : {}),
13
+ env: { ...context.env },
14
+ }, executor.defaultConfig);
15
+ return {
16
+ value,
17
+ outputs: (params.requiredArtifacts ?? []).map((path) => ({ kind: "artifact", path, required: true })),
18
+ };
19
+ },
20
+ checks(_context, params) {
21
+ if (!params.requiredArtifacts || params.requiredArtifacts.length === 0) {
22
+ return [];
23
+ }
24
+ return [
25
+ {
26
+ kind: "require-artifacts",
27
+ paths: params.requiredArtifacts,
28
+ message: params.missingArtifactsMessage ?? "OpenCode node did not produce required artifacts.",
29
+ },
30
+ ];
31
+ },
32
+ };
@@ -0,0 +1,69 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { TaskRunnerError } from "../../errors.js";
3
+ function normalizeQuestionId(value, index) {
4
+ if (typeof value === "string" && value.trim().length > 0) {
5
+ return value.trim();
6
+ }
7
+ return `question_${index + 1}`;
8
+ }
9
+ function toQuestionField(question, index) {
10
+ if (typeof question.question !== "string" || question.question.trim().length === 0) {
11
+ return null;
12
+ }
13
+ return {
14
+ id: normalizeQuestionId(question.id, index),
15
+ type: "text",
16
+ label: question.question.trim(),
17
+ ...(typeof question.details === "string" && question.details.trim().length > 0
18
+ ? { help: question.details.trim() }
19
+ : {}),
20
+ required: question.required !== false,
21
+ multiline: question.multiline === true,
22
+ default: "",
23
+ ...(typeof question.placeholder === "string" && question.placeholder.trim().length > 0
24
+ ? { placeholder: question.placeholder.trim() }
25
+ : {}),
26
+ };
27
+ }
28
+ export const planningQuestionsFormNode = {
29
+ kind: "planning-questions-form",
30
+ version: 1,
31
+ async run(_context, params) {
32
+ if (!existsSync(params.planningQuestionsJsonFile)) {
33
+ return {
34
+ value: {
35
+ formId: params.formId,
36
+ title: params.title,
37
+ ...(params.description ? { description: params.description } : {}),
38
+ submitLabel: "Continue planning",
39
+ fields: [],
40
+ summary: "",
41
+ questionCount: 0,
42
+ },
43
+ };
44
+ }
45
+ let parsed;
46
+ try {
47
+ parsed = JSON.parse(readFileSync(params.planningQuestionsJsonFile, "utf8"));
48
+ }
49
+ catch (error) {
50
+ throw new TaskRunnerError(`Failed to read planning questions from ${params.planningQuestionsJsonFile}: ${error.message}`);
51
+ }
52
+ const artifact = parsed;
53
+ const rawQuestions = Array.isArray(artifact.questions) ? artifact.questions : [];
54
+ const fields = rawQuestions
55
+ .map((question, index) => toQuestionField(question, index))
56
+ .filter((field) => field !== null);
57
+ return {
58
+ value: {
59
+ formId: params.formId,
60
+ title: params.title,
61
+ ...(params.description ? { description: params.description } : {}),
62
+ submitLabel: "Continue planning",
63
+ fields,
64
+ summary: typeof artifact.summary === "string" ? artifact.summary.trim() : "",
65
+ questionCount: fields.length,
66
+ },
67
+ };
68
+ },
69
+ };
@@ -36,6 +36,12 @@ function buildPromptSuffix(params, values) {
36
36
  if (params.formId === "review-fix-selection") {
37
37
  return buildReviewFixPromptSuffix(params, values);
38
38
  }
39
+ if (params.fields.length === 0) {
40
+ return {
41
+ promptSuffix: "",
42
+ summaryText: "",
43
+ };
44
+ }
39
45
  const lines = params.fields.map((field) => {
40
46
  const raw = values[field.id];
41
47
  if (typeof raw === "boolean") {
@@ -77,7 +83,9 @@ export const userInputNode = {
77
83
  values: result.values,
78
84
  };
79
85
  writeFileSync(params.outputFile, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
80
- printSummary(params.title, rendered.summaryText);
86
+ if (rendered.summaryText.trim().length > 0) {
87
+ printSummary(params.title, rendered.summaryText);
88
+ }
81
89
  return {
82
90
  value: {
83
91
  formId: result.formId,
@@ -1,9 +1,12 @@
1
- import { BUG_ANALYZE_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
1
+ import { BUG_ANALYZE_PROMPT_TEMPLATE, GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, JIRA_DESCRIPTION_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_QUESTIONS_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
2
2
  const promptTemplates = {
3
3
  "bug-analyze": BUG_ANALYZE_PROMPT_TEMPLATE,
4
4
  "bug-fix": BUG_FIX_PROMPT_TEMPLATE,
5
+ "gitlab-diff-review": GITLAB_DIFF_REVIEW_PROMPT_TEMPLATE,
5
6
  implement: IMPLEMENT_PROMPT_TEMPLATE,
7
+ "task-describe": JIRA_DESCRIPTION_PROMPT_TEMPLATE,
6
8
  "mr-description": MR_DESCRIPTION_PROMPT_TEMPLATE,
9
+ "plan-questions": PLAN_QUESTIONS_PROMPT_TEMPLATE,
7
10
  plan: PLAN_PROMPT_TEMPLATE,
8
11
  review: REVIEW_PROMPT_TEMPLATE,
9
12
  "review-project": REVIEW_PROJECT_PROMPT_TEMPLATE,
@@ -2,17 +2,21 @@ import { commandCheckExecutor } from "../executors/command-check-executor.js";
2
2
  import { claudeExecutor } from "../executors/claude-executor.js";
3
3
  import { codexDockerExecutor } from "../executors/codex-docker-executor.js";
4
4
  import { codexLocalExecutor } from "../executors/codex-local-executor.js";
5
+ import { fetchGitLabDiffExecutor } from "../executors/fetch-gitlab-diff-executor.js";
5
6
  import { fetchGitLabReviewExecutor } from "../executors/fetch-gitlab-review-executor.js";
6
7
  import { jiraFetchExecutor } from "../executors/jira-fetch-executor.js";
8
+ import { opencodeExecutor } from "../executors/opencode-executor.js";
7
9
  import { processExecutor } from "../executors/process-executor.js";
8
10
  import { verifyBuildExecutor } from "../executors/verify-build-executor.js";
9
11
  const builtInExecutors = {
10
12
  process: processExecutor,
11
13
  "command-check": commandCheckExecutor,
14
+ "fetch-gitlab-diff": fetchGitLabDiffExecutor,
12
15
  "fetch-gitlab-review": fetchGitLabReviewExecutor,
13
16
  "jira-fetch": jiraFetchExecutor,
14
17
  "codex-local": codexLocalExecutor,
15
18
  "codex-docker": codexDockerExecutor,
19
+ opencode: opencodeExecutor,
16
20
  claude: claudeExecutor,
17
21
  "verify-build": verifyBuildExecutor,
18
22
  };
@@ -21,5 +25,11 @@ export function createExecutorRegistry() {
21
25
  get(id) {
22
26
  return builtInExecutors[id];
23
27
  },
28
+ has(id) {
29
+ return id in builtInExecutors;
30
+ },
31
+ ids() {
32
+ return Object.keys(builtInExecutors);
33
+ },
24
34
  };
25
35
  }
@@ -1,10 +1,10 @@
1
- import { readFileSync } from "node:fs";
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { TaskRunnerError } from "../errors.js";
5
5
  const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
6
- export function loadFlowSpecSync(fileName) {
7
- const filePath = path.join(MODULE_DIR, "flow-specs", fileName);
6
+ const BUILT_IN_FLOW_SPECS_DIR = path.join(MODULE_DIR, "flow-specs");
7
+ function parseFlowSpec(filePath) {
8
8
  try {
9
9
  return JSON.parse(readFileSync(filePath, "utf8"));
10
10
  }
@@ -12,3 +12,37 @@ export function loadFlowSpecSync(fileName) {
12
12
  throw new TaskRunnerError(`Failed to load flow spec ${filePath}: ${error.message}`);
13
13
  }
14
14
  }
15
+ export function resolveBuiltInFlowSpecPath(fileName) {
16
+ return path.join(BUILT_IN_FLOW_SPECS_DIR, fileName);
17
+ }
18
+ export function projectFlowSpecsDir(cwd) {
19
+ return path.join(cwd, ".agentweaver", ".flows");
20
+ }
21
+ export function listBuiltInFlowSpecFiles() {
22
+ if (!existsSync(BUILT_IN_FLOW_SPECS_DIR)) {
23
+ return [];
24
+ }
25
+ return readdirSync(BUILT_IN_FLOW_SPECS_DIR, { withFileTypes: true })
26
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
27
+ .map((entry) => entry.name)
28
+ .sort((left, right) => left.localeCompare(right));
29
+ }
30
+ export function listProjectFlowSpecFiles(cwd) {
31
+ const directory = projectFlowSpecsDir(cwd);
32
+ if (!existsSync(directory)) {
33
+ return [];
34
+ }
35
+ return readdirSync(directory, { withFileTypes: true })
36
+ .filter((entry) => entry.isFile() && entry.name.endsWith(".json"))
37
+ .map((entry) => path.join(directory, entry.name))
38
+ .sort((left, right) => left.localeCompare(right));
39
+ }
40
+ export function loadFlowSpecSync(source) {
41
+ return parseFlowSpec(source.source === "built-in" ? resolveBuiltInFlowSpecPath(source.fileName) : source.filePath);
42
+ }
43
+ export function loadBuiltInFlowSpecSync(fileName) {
44
+ return loadFlowSpecSync({ source: "built-in", fileName });
45
+ }
46
+ export function loadProjectFlowSpecSync(filePath) {
47
+ return loadFlowSpecSync({ source: "project-local", filePath });
48
+ }
@@ -1 +1,43 @@
1
- export {};
1
+ export const ARTIFACT_REF_KINDS = [
2
+ "bug-analyze-file",
3
+ "bug-analyze-json-file",
4
+ "bug-fix-design-file",
5
+ "bug-fix-design-json-file",
6
+ "bug-fix-plan-file",
7
+ "bug-fix-plan-json-file",
8
+ "design-file",
9
+ "design-json-file",
10
+ "gitlab-diff-file",
11
+ "gitlab-diff-json-file",
12
+ "gitlab-diff-review-input-json-file",
13
+ "gitlab-review-file",
14
+ "gitlab-review-input-json-file",
15
+ "gitlab-review-json-file",
16
+ "jira-attachments-context-file",
17
+ "jira-attachments-manifest-file",
18
+ "jira-description-file",
19
+ "jira-description-json-file",
20
+ "jira-task-file",
21
+ "mr-description-file",
22
+ "mr-description-json-file",
23
+ "planning-answers-json-file",
24
+ "planning-questions-json-file",
25
+ "plan-file",
26
+ "plan-json-file",
27
+ "qa-file",
28
+ "qa-json-file",
29
+ "ready-to-merge-file",
30
+ "review-file",
31
+ "review-json-file",
32
+ "review-fix-file",
33
+ "review-fix-json-file",
34
+ "review-reply-file",
35
+ "review-reply-json-file",
36
+ "run-go-linter-result-json-file",
37
+ "run-go-tests-result-json-file",
38
+ "review-reply-summary-file",
39
+ "review-summary-file",
40
+ "task-summary-file",
41
+ "task-summary-json-file",
42
+ ];
43
+ export const ARTIFACT_LIST_REF_KINDS = ["bug-analyze-artifacts", "plan-artifacts"];