agentweaver 0.1.10 → 0.1.12

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 (110) hide show
  1. package/README.md +218 -224
  2. package/dist/artifacts.js +109 -55
  3. package/dist/executors/{codex-local-executor.js → codex-executor.js} +6 -5
  4. package/dist/executors/configs/{codex-local-config.js → codex-config.js} +1 -1
  5. package/dist/executors/configs/jira-fetch-config.js +2 -0
  6. package/dist/executors/configs/telegram-notifier-config.js +3 -0
  7. package/dist/executors/fetch-gitlab-diff-executor.js +1 -1
  8. package/dist/executors/fetch-gitlab-review-executor.js +1 -1
  9. package/dist/executors/git-commit-executor.js +25 -0
  10. package/dist/executors/jira-fetch-executor.js +1 -0
  11. package/dist/executors/opencode-executor.js +22 -11
  12. package/dist/executors/process-executor.js +3 -0
  13. package/dist/executors/telegram-notifier-executor.js +54 -0
  14. package/dist/flow-state.js +46 -1
  15. package/dist/gitlab.js +13 -8
  16. package/dist/index.js +477 -514
  17. package/dist/interactive-ui.js +609 -88
  18. package/dist/jira.js +109 -5
  19. package/dist/pipeline/auto-flow.js +6 -6
  20. package/dist/pipeline/context.js +1 -0
  21. package/dist/pipeline/flow-catalog.js +34 -4
  22. package/dist/pipeline/flow-model-settings.js +77 -0
  23. package/dist/pipeline/flow-specs/auto-common.json +446 -0
  24. package/dist/pipeline/flow-specs/auto-golang.json +563 -0
  25. package/dist/pipeline/flow-specs/{bug-analyze.json → bugz/bug-analyze.json} +43 -25
  26. package/dist/pipeline/flow-specs/{bug-fix.json → bugz/bug-fix.json} +5 -4
  27. package/dist/pipeline/flow-specs/git-commit.json +196 -0
  28. package/dist/pipeline/flow-specs/{gitlab-diff-review.json → gitlab/gitlab-diff-review.json} +20 -50
  29. package/dist/pipeline/flow-specs/{gitlab-review.json → gitlab/gitlab-review.json} +65 -133
  30. package/dist/pipeline/flow-specs/{mr-description.json → gitlab/mr-description.json} +17 -10
  31. package/dist/pipeline/flow-specs/{run-go-linter-loop.json → go/run-go-linter-loop.json} +40 -14
  32. package/dist/pipeline/flow-specs/{run-go-tests-loop.json → go/run-go-tests-loop.json} +40 -14
  33. package/dist/pipeline/flow-specs/implement.json +5 -4
  34. package/dist/pipeline/flow-specs/plan.json +40 -148
  35. package/dist/pipeline/flow-specs/{review-fix.json → review/review-fix.json} +74 -13
  36. package/dist/pipeline/flow-specs/review/review-loop.json +282 -0
  37. package/dist/pipeline/flow-specs/review/review-project.json +87 -0
  38. package/dist/pipeline/flow-specs/review/review.json +126 -0
  39. package/dist/pipeline/flow-specs/task-describe.json +252 -11
  40. package/dist/pipeline/launch-profile-config.js +38 -0
  41. package/dist/pipeline/node-registry.js +75 -45
  42. package/dist/pipeline/nodes/build-failure-summary-node.js +16 -29
  43. package/dist/pipeline/nodes/build-review-fix-prompt-node.js +36 -0
  44. package/dist/pipeline/nodes/codex-prompt-node.js +41 -0
  45. package/dist/pipeline/nodes/commit-message-form-node.js +79 -0
  46. package/dist/pipeline/nodes/git-commit-form-node.js +138 -0
  47. package/dist/pipeline/nodes/git-commit-node.js +28 -0
  48. package/dist/pipeline/nodes/git-status-node.js +221 -0
  49. package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +10 -6
  50. package/dist/pipeline/nodes/jira-context-node.js +10 -0
  51. package/dist/pipeline/nodes/jira-fetch-node.js +3 -0
  52. package/dist/pipeline/nodes/llm-prompt-node.js +62 -0
  53. package/dist/pipeline/nodes/plan-codex-node.js +1 -1
  54. package/dist/pipeline/nodes/read-file-node.js +11 -0
  55. package/dist/pipeline/nodes/review-findings-form-node.js +48 -14
  56. package/dist/pipeline/nodes/select-files-form-node.js +72 -0
  57. package/dist/pipeline/nodes/telegram-notifier-node.js +28 -0
  58. package/dist/pipeline/nodes/user-input-node.js +43 -8
  59. package/dist/pipeline/nodes/write-selection-file-node.js +46 -0
  60. package/dist/pipeline/prompt-registry.js +3 -4
  61. package/dist/pipeline/prompt-runtime.js +13 -3
  62. package/dist/pipeline/registry.js +6 -8
  63. package/dist/pipeline/spec-compiler.js +5 -0
  64. package/dist/pipeline/spec-types.js +9 -3
  65. package/dist/pipeline/spec-validator.js +4 -0
  66. package/dist/pipeline/types.js +1 -0
  67. package/dist/pipeline/value-resolver.js +50 -38
  68. package/dist/prompts.js +119 -110
  69. package/dist/runtime/agentweaver-home.js +8 -0
  70. package/dist/runtime/command-resolution.js +0 -38
  71. package/dist/runtime/env-loader.js +43 -0
  72. package/dist/runtime/process-runner.js +9 -3
  73. package/dist/structured-artifact-schema-registry.js +54 -0
  74. package/dist/structured-artifact-schemas.json +22 -20
  75. package/dist/structured-artifacts.js +3 -43
  76. package/dist/user-input.js +38 -3
  77. package/package.json +2 -6
  78. package/Dockerfile.codex +0 -56
  79. package/dist/executors/claude-executor.js +0 -46
  80. package/dist/executors/codex-docker-executor.js +0 -27
  81. package/dist/executors/configs/claude-config.js +0 -12
  82. package/dist/executors/configs/codex-docker-config.js +0 -10
  83. package/dist/executors/configs/verify-build-config.js +0 -7
  84. package/dist/executors/verify-build-executor.js +0 -123
  85. package/dist/pipeline/flow-specs/auto.json +0 -979
  86. package/dist/pipeline/flow-specs/opencode/auto-opencode.json +0 -1365
  87. package/dist/pipeline/flow-specs/opencode/bugz/bug-analyze-opencode.json +0 -382
  88. package/dist/pipeline/flow-specs/opencode/bugz/bug-fix-opencode.json +0 -56
  89. package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-diff-review-opencode.json +0 -308
  90. package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-review-opencode.json +0 -437
  91. package/dist/pipeline/flow-specs/opencode/gitlab/mr-description-opencode.json +0 -117
  92. package/dist/pipeline/flow-specs/opencode/go/run-go-linter-loop-opencode.json +0 -321
  93. package/dist/pipeline/flow-specs/opencode/go/run-go-tests-loop-opencode.json +0 -321
  94. package/dist/pipeline/flow-specs/opencode/implement-opencode.json +0 -64
  95. package/dist/pipeline/flow-specs/opencode/plan-opencode.json +0 -603
  96. package/dist/pipeline/flow-specs/opencode/review/review-fix-opencode.json +0 -209
  97. package/dist/pipeline/flow-specs/opencode/review/review-opencode.json +0 -452
  98. package/dist/pipeline/flow-specs/opencode/task-describe-opencode.json +0 -148
  99. package/dist/pipeline/flow-specs/review-project.json +0 -243
  100. package/dist/pipeline/flow-specs/review.json +0 -312
  101. package/dist/pipeline/flows/preflight-flow.js +0 -19
  102. package/dist/pipeline/nodes/claude-prompt-node.js +0 -54
  103. package/dist/pipeline/nodes/codex-docker-prompt-node.js +0 -32
  104. package/dist/pipeline/nodes/codex-local-prompt-node.js +0 -32
  105. package/dist/pipeline/nodes/review-claude-node.js +0 -38
  106. package/dist/pipeline/nodes/review-reply-codex-node.js +0 -40
  107. package/dist/pipeline/nodes/verify-build-node.js +0 -15
  108. package/dist/runtime/docker-runtime.js +0 -51
  109. package/docker-compose.yml +0 -445
  110. package/verify_build.sh +0 -105
package/dist/jira.js CHANGED
@@ -5,6 +5,57 @@ import { TaskRunnerError } from "./errors.js";
5
5
  const ISSUE_KEY_RE = /^[A-Z][A-Z0-9_]*-[0-9]+$/;
6
6
  const TEXT_ATTACHMENT_EXTENSIONS = new Set([".md", ".json", ".txt"]);
7
7
  const DOWNLOAD_ONLY_ATTACHMENT_EXTENSIONS = new Set([".doc"]);
8
+ const JIRA_AUTH_MODES = new Set(["auto", "basic", "bearer"]);
9
+ function parseJiraAuthMode(rawMode) {
10
+ const mode = rawMode?.trim().toLowerCase() || "auto";
11
+ if (!JIRA_AUTH_MODES.has(mode)) {
12
+ throw new TaskRunnerError("JIRA_AUTH_MODE must be one of: auto, basic, bearer.");
13
+ }
14
+ return mode;
15
+ }
16
+ export function detectJiraDeployment(url) {
17
+ try {
18
+ return new URL(url).hostname.toLowerCase().includes("atlassian") ? "cloud" : "server";
19
+ }
20
+ catch {
21
+ return url.toLowerCase().includes("atlassian") ? "cloud" : "server";
22
+ }
23
+ }
24
+ export function resolveJiraAuthMode(url) {
25
+ const authMode = parseJiraAuthMode(process.env.JIRA_AUTH_MODE);
26
+ if (authMode !== "auto") {
27
+ return authMode;
28
+ }
29
+ return detectJiraDeployment(url) === "cloud" ? "basic" : "bearer";
30
+ }
31
+ export function buildJiraAuthHeaders(url) {
32
+ const jiraApiKey = process.env.JIRA_API_KEY?.trim();
33
+ if (!jiraApiKey) {
34
+ throw new TaskRunnerError("JIRA_API_KEY is required for Jira authentication.");
35
+ }
36
+ const authMode = resolveJiraAuthMode(url);
37
+ if (authMode === "bearer") {
38
+ return {
39
+ Authorization: `Bearer ${jiraApiKey}`,
40
+ };
41
+ }
42
+ const jiraUsername = process.env.JIRA_USERNAME?.trim();
43
+ if (!jiraUsername) {
44
+ const host = (() => {
45
+ try {
46
+ return new URL(url).host;
47
+ }
48
+ catch {
49
+ return "unknown";
50
+ }
51
+ })();
52
+ throw new TaskRunnerError(`JIRA_USERNAME is required for Jira Cloud Basic auth (detected from URL host: ${host}).`);
53
+ }
54
+ const encodedCredentials = Buffer.from(`${jiraUsername}:${jiraApiKey}`).toString("base64");
55
+ return {
56
+ Authorization: `Basic ${encodedCredentials}`,
57
+ };
58
+ }
8
59
  function sanitizeAttachmentFileName(fileName) {
9
60
  const parsed = path.parse(fileName);
10
61
  const baseName = parsed.name
@@ -29,13 +80,9 @@ function parseJiraAttachments(issueBody) {
29
80
  }
30
81
  }
31
82
  async function fetchAuthorizedBuffer(url, accept) {
32
- const jiraApiKey = process.env.JIRA_API_KEY;
33
- if (!jiraApiKey) {
34
- throw new TaskRunnerError("JIRA_API_KEY is required for Jira fetch.");
35
- }
36
83
  const response = await fetch(url, {
37
84
  headers: {
38
- Authorization: `Bearer ${jiraApiKey}`,
85
+ ...buildJiraAuthHeaders(url),
39
86
  Accept: accept,
40
87
  },
41
88
  });
@@ -44,6 +91,26 @@ async function fetchAuthorizedBuffer(url, accept) {
44
91
  }
45
92
  return Buffer.from(await response.arrayBuffer());
46
93
  }
94
+ function isSubtask(issue) {
95
+ return issue.fields?.issuetype?.subtask === true;
96
+ }
97
+ function getParentKey(issue) {
98
+ if (!issue.fields?.parent?.key) {
99
+ return null;
100
+ }
101
+ return issue.fields.parent.key;
102
+ }
103
+ function normalizeIssue(jiraRaw) {
104
+ const issue = jiraRaw;
105
+ const key = issue.key ?? null;
106
+ const summary = typeof issue.fields?.summary === "string" ? issue.fields.summary : "";
107
+ const description = typeof issue.fields?.description === "string" ? issue.fields.description : "";
108
+ const type = typeof issue.fields?.issuetype?.name === "string" ? issue.fields.issuetype.name : "";
109
+ if (!key) {
110
+ return null;
111
+ }
112
+ return { key, type, summary, description };
113
+ }
47
114
  function toTextAttachmentContent(fileName, body) {
48
115
  return [
49
116
  `=== Attachment: ${fileName} ===`,
@@ -85,6 +152,42 @@ export async function fetchJiraIssue(jiraApiUrl, jiraTaskFile, attachmentsManife
85
152
  const body = await fetchAuthorizedBuffer(jiraApiUrl, "application/json");
86
153
  mkdirSync(path.dirname(jiraTaskFile), { recursive: true });
87
154
  await writeFile(jiraTaskFile, body);
155
+ let enrichedFile;
156
+ try {
157
+ const rawIssue = JSON.parse(body.toString("utf8"));
158
+ const normalizedChild = normalizeIssue(rawIssue);
159
+ if (normalizedChild && isSubtask(rawIssue)) {
160
+ const parentKey = getParentKey(rawIssue);
161
+ let parentNormalized = null;
162
+ if (parentKey) {
163
+ try {
164
+ const parentUrl = buildJiraApiUrl(parentKey);
165
+ const parentBody = await fetchAuthorizedBuffer(parentUrl, "application/json");
166
+ const parentRaw = JSON.parse(parentBody.toString("utf8"));
167
+ parentNormalized = normalizeIssue(parentRaw);
168
+ }
169
+ catch {
170
+ parentNormalized = null;
171
+ }
172
+ }
173
+ if (normalizedChild) {
174
+ const enrichedArtifact = {
175
+ issue: normalizedChild,
176
+ parent: parentNormalized,
177
+ context: {
178
+ scopeSource: normalizedChild.key,
179
+ businessContextSource: parentNormalized?.key ?? normalizedChild.key,
180
+ },
181
+ };
182
+ const parsedPath = path.parse(jiraTaskFile);
183
+ enrichedFile = path.join(parsedPath.dir, `${parsedPath.name}-enriched${parsedPath.ext}`);
184
+ await writeFile(enrichedFile, `${JSON.stringify(enrichedArtifact, null, 2)}\n`, "utf8");
185
+ }
186
+ }
187
+ }
188
+ catch {
189
+ // Non-JSON response or parse error - skip enrichment
190
+ }
88
191
  const attachments = parseJiraAttachments(body);
89
192
  const manifestItems = [];
90
193
  const planningContextChunks = [];
@@ -151,6 +254,7 @@ export async function fetchJiraIssue(jiraApiUrl, jiraTaskFile, attachmentsManife
151
254
  planningContextAttachments: manifest.summary.planningContextCount,
152
255
  ...(attachmentsManifestFile ? { attachmentsManifestFile } : {}),
153
256
  ...(attachmentsContextFile ? { attachmentsContextFile } : {}),
257
+ ...(enrichedFile ? { enrichedFile } : {}),
154
258
  };
155
259
  }
156
260
  export function requireJiraTaskFile(jiraTaskFile) {
@@ -1,9 +1,9 @@
1
1
  import { loadDeclarativeFlow } from "./declarative-flows.js";
2
- let cachedAutoFlow = null;
3
- export function loadAutoFlow() {
4
- if (cachedAutoFlow) {
5
- return cachedAutoFlow;
2
+ let cachedAutoGolangFlow = null;
3
+ export function loadAutoGolangFlow() {
4
+ if (cachedAutoGolangFlow) {
5
+ return cachedAutoGolangFlow;
6
6
  }
7
- cachedAutoFlow = loadDeclarativeFlow({ source: "built-in", fileName: "auto.json" });
8
- return cachedAutoFlow;
7
+ cachedAutoGolangFlow = loadDeclarativeFlow({ source: "built-in", fileName: "auto-golang.json" });
8
+ return cachedAutoGolangFlow;
9
9
  }
@@ -11,6 +11,7 @@ export function createPipelineContext(input) {
11
11
  ui: getOutputAdapter(),
12
12
  dryRun: input.dryRun,
13
13
  verbose: input.verbose,
14
+ mdLang: input.mdLang ?? null,
14
15
  runtime: input.runtime,
15
16
  executors: createExecutorRegistry(),
16
17
  nodes: createNodeRegistry(),
@@ -1,12 +1,14 @@
1
1
  import path from "node:path";
2
2
  import { TaskRunnerError } from "../errors.js";
3
- import { loadAutoFlow } from "./auto-flow.js";
3
+ import { loadAutoGolangFlow } from "./auto-flow.js";
4
4
  import { loadDeclarativeFlow } from "./declarative-flows.js";
5
5
  import { listBuiltInFlowSpecFiles, listProjectFlowSpecFiles, projectFlowSpecsDir } from "./spec-loader.js";
6
6
  export const BUILT_IN_COMMAND_FLOW_IDS = [
7
- "auto",
7
+ "auto-golang",
8
+ "auto-common",
8
9
  "bug-analyze",
9
10
  "bug-fix",
11
+ "git-commit",
10
12
  "gitlab-diff-review",
11
13
  "gitlab-review",
12
14
  "mr-description",
@@ -15,13 +17,41 @@ export const BUILT_IN_COMMAND_FLOW_IDS = [
15
17
  "implement",
16
18
  "review",
17
19
  "review-fix",
20
+ "review-loop",
18
21
  "run-go-tests-loop",
19
22
  "run-go-linter-loop",
20
23
  ];
24
+ const BUILT_IN_COMMAND_FLOW_FILES = {
25
+ "auto-golang": "auto-golang.json",
26
+ "auto-common": "auto-common.json",
27
+ "bug-analyze": "bugz/bug-analyze.json",
28
+ "bug-fix": "bugz/bug-fix.json",
29
+ "git-commit": "git-commit.json",
30
+ "gitlab-diff-review": "gitlab/gitlab-diff-review.json",
31
+ "gitlab-review": "gitlab/gitlab-review.json",
32
+ "mr-description": "gitlab/mr-description.json",
33
+ plan: "plan.json",
34
+ "task-describe": "task-describe.json",
35
+ implement: "implement.json",
36
+ review: "review/review.json",
37
+ "review-fix": "review/review-fix.json",
38
+ "review-loop": "review/review-loop.json",
39
+ "run-go-tests-loop": "go/run-go-tests-loop.json",
40
+ "run-go-linter-loop": "go/run-go-linter-loop.json",
41
+ };
42
+ function builtInCommandIdForFile(fileName) {
43
+ for (const [flowId, candidate] of Object.entries(BUILT_IN_COMMAND_FLOW_FILES)) {
44
+ if (candidate === fileName) {
45
+ return flowId;
46
+ }
47
+ }
48
+ return null;
49
+ }
21
50
  function loadBuiltInCatalogEntry(fileName) {
51
+ const commandId = builtInCommandIdForFile(fileName);
22
52
  const relativePath = fileName.replace(/\.json$/i, "").split(/[\\/]+/).filter((segment) => segment.length > 0);
23
- const id = relativePath.join("/");
24
- const flow = id === "auto" ? loadAutoFlow() : loadDeclarativeFlow({ source: "built-in", fileName });
53
+ const id = commandId ?? relativePath.join("/");
54
+ const flow = id === "auto-golang" ? loadAutoGolangFlow() : loadDeclarativeFlow({ source: "built-in", fileName });
25
55
  return {
26
56
  id,
27
57
  source: "built-in",
@@ -0,0 +1,77 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { DEFAULT_MODEL_BY_EXECUTOR, defaultModelForExecutor } from "./launch-profile-config.js";
4
+ import { scopeArtifactsDir } from "../artifacts.js";
5
+ const FLOW_MODEL_SETTINGS_FILE = "agentweaver-flow-model-settings.json";
6
+ function flowModelSettingsPath(scopeKey) {
7
+ return path.join(scopeArtifactsDir(scopeKey), FLOW_MODEL_SETTINGS_FILE);
8
+ }
9
+ function ensureArtifactsDir(scopeKey) {
10
+ const artifactsDir = scopeArtifactsDir(scopeKey);
11
+ if (!existsSync(artifactsDir)) {
12
+ mkdirSync(artifactsDir, { recursive: true });
13
+ }
14
+ }
15
+ export function loadFlowModelSettings(scopeKey) {
16
+ const filePath = flowModelSettingsPath(scopeKey);
17
+ if (!existsSync(filePath)) {
18
+ return {};
19
+ }
20
+ try {
21
+ const content = readFileSync(filePath, "utf8");
22
+ const parsed = JSON.parse(content);
23
+ if (typeof parsed !== "object" || parsed === null) {
24
+ return {};
25
+ }
26
+ return parsed;
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ }
32
+ export function saveFlowModelSettings(scopeKey, store) {
33
+ ensureArtifactsDir(scopeKey);
34
+ const filePath = flowModelSettingsPath(scopeKey);
35
+ const tempPath = `${filePath}.tmp`;
36
+ const content = JSON.stringify(store, null, 2);
37
+ writeFileSync(tempPath, content, "utf8");
38
+ renameSync(tempPath, filePath);
39
+ }
40
+ export function getEffectiveModelForFlow(flowId, scopeKey, executor) {
41
+ const store = loadFlowModelSettings(scopeKey);
42
+ const flowSettings = store[flowId];
43
+ if (!flowSettings) {
44
+ return defaultModelForExecutor(executor);
45
+ }
46
+ if (flowSettings.lastSelectedModel && flowSettings.lastSelectedModel !== "default") {
47
+ return flowSettings.lastSelectedModel;
48
+ }
49
+ if (flowSettings.defaultModel && flowSettings.defaultModel !== "default") {
50
+ return flowSettings.defaultModel;
51
+ }
52
+ return defaultModelForExecutor(executor);
53
+ }
54
+ export function updateLastSelectedModel(flowId, scopeKey, executor, model) {
55
+ const store = loadFlowModelSettings(scopeKey);
56
+ const existingSettings = store[flowId];
57
+ if (existingSettings) {
58
+ store[flowId] = {
59
+ ...existingSettings,
60
+ executor,
61
+ defaultModel: model,
62
+ lastSelectedModel: model,
63
+ };
64
+ }
65
+ else {
66
+ store[flowId] = {
67
+ executor,
68
+ defaultModel: DEFAULT_MODEL_BY_EXECUTOR[executor],
69
+ lastSelectedModel: model,
70
+ };
71
+ }
72
+ saveFlowModelSettings(scopeKey, store);
73
+ }
74
+ export function getFlowModelSettings(flowId, scopeKey) {
75
+ const store = loadFlowModelSettings(scopeKey);
76
+ return store[flowId] ?? null;
77
+ }