agentweaver 0.1.18 → 0.1.20

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/README.md +54 -6
  2. package/dist/artifacts.js +9 -0
  3. package/dist/executors/git-commit-executor.js +24 -6
  4. package/dist/flow-state.js +3 -8
  5. package/dist/git/git-diff-parser.js +223 -0
  6. package/dist/git/git-service.js +562 -0
  7. package/dist/git/git-stage-selection.js +24 -0
  8. package/dist/git/git-status-parser.js +171 -0
  9. package/dist/git/git-types.js +1 -0
  10. package/dist/index.js +454 -108
  11. package/dist/interactive/auto-flow.js +644 -0
  12. package/dist/interactive/controller.js +489 -7
  13. package/dist/interactive/progress.js +194 -1
  14. package/dist/interactive/state.js +34 -0
  15. package/dist/interactive/web/index.js +237 -5
  16. package/dist/interactive/web/protocol.js +222 -1
  17. package/dist/interactive/web/server.js +497 -3
  18. package/dist/interactive/web/static/app.js +2462 -37
  19. package/dist/interactive/web/static/index.html +113 -11
  20. package/dist/interactive/web/static/styles.css +1 -1
  21. package/dist/interactive/web/static/styles.input.css +1383 -149
  22. package/dist/pipeline/auto-flow-blocks.js +307 -0
  23. package/dist/pipeline/auto-flow-config.js +273 -0
  24. package/dist/pipeline/auto-flow-identity.js +49 -0
  25. package/dist/pipeline/auto-flow-presets.js +52 -0
  26. package/dist/pipeline/auto-flow-resolver.js +830 -0
  27. package/dist/pipeline/auto-flow-types.js +17 -0
  28. package/dist/pipeline/context.js +1 -0
  29. package/dist/pipeline/declarative-flows.js +27 -1
  30. package/dist/pipeline/flow-specs/auto-common-guided.json +11 -0
  31. package/dist/pipeline/flow-specs/auto-golang.json +12 -1
  32. package/dist/pipeline/flow-specs/bugz/bug-analyze.json +54 -1
  33. package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +19 -1
  34. package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +33 -1
  35. package/dist/pipeline/flow-specs/review/review-project.json +19 -1
  36. package/dist/pipeline/flow-specs/task-source/manual-jira-input.json +70 -0
  37. package/dist/pipeline/node-registry.js +9 -0
  38. package/dist/pipeline/nodes/codex-prompt-node.js +8 -1
  39. package/dist/pipeline/nodes/flow-run-node.js +5 -3
  40. package/dist/pipeline/nodes/git-status-node.js +2 -168
  41. package/dist/pipeline/nodes/manual-jira-task-input-node.js +146 -0
  42. package/dist/pipeline/nodes/opencode-prompt-node.js +8 -1
  43. package/dist/pipeline/nodes/plan-codex-node.js +8 -1
  44. package/dist/pipeline/spec-loader.js +14 -4
  45. package/dist/runtime/artifact-catalog.js +403 -0
  46. package/dist/runtime/settings.js +114 -0
  47. package/dist/scope.js +14 -4
  48. package/package.json +1 -1
  49. package/dist/pipeline/flow-specs/auto-common.json +0 -179
  50. package/dist/pipeline/flow-specs/auto-simple.json +0 -141
@@ -0,0 +1,114 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { agentweaverConfigDir } from "./env-loader.js";
4
+ export const WEB_UI_AUTO_FLOW_HEIGHT_MIN = 120;
5
+ export const WEB_UI_AUTO_FLOW_HEIGHT_MAX = 640;
6
+ export const WEB_UI_WORKSPACE_SPLIT_MIN = 24;
7
+ export const WEB_UI_WORKSPACE_SPLIT_MAX = 58;
8
+ export const DEFAULT_AGENTWEAVER_WEB_UI_SETTINGS = {
9
+ theme: "light",
10
+ autoFlowHeight: null,
11
+ workspaceSplit: 36,
12
+ logAutoscroll: true,
13
+ };
14
+ export function agentweaverSettingsPath() {
15
+ return path.join(agentweaverConfigDir(), "settings.json");
16
+ }
17
+ function isRecord(value) {
18
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19
+ }
20
+ function clampInteger(value, min, max, fallback) {
21
+ const numeric = Number(value);
22
+ if (!Number.isFinite(numeric)) {
23
+ return fallback;
24
+ }
25
+ return Math.min(max, Math.max(min, Math.round(numeric)));
26
+ }
27
+ function normalizeTheme(value, fallback) {
28
+ return value === "dark" || value === "light" ? value : fallback;
29
+ }
30
+ export function normalizeWebUiSettings(value) {
31
+ const raw = isRecord(value) ? value : {};
32
+ const defaults = DEFAULT_AGENTWEAVER_WEB_UI_SETTINGS;
33
+ const rawHeight = raw["autoFlowHeight"];
34
+ const autoFlowHeight = rawHeight === null
35
+ ? null
36
+ : Number.isFinite(Number(rawHeight))
37
+ ? clampInteger(rawHeight, WEB_UI_AUTO_FLOW_HEIGHT_MIN, WEB_UI_AUTO_FLOW_HEIGHT_MAX, defaults.autoFlowHeight ?? WEB_UI_AUTO_FLOW_HEIGHT_MAX)
38
+ : defaults.autoFlowHeight;
39
+ return {
40
+ theme: normalizeTheme(raw["theme"], defaults.theme),
41
+ autoFlowHeight,
42
+ workspaceSplit: clampInteger(raw["workspaceSplit"], WEB_UI_WORKSPACE_SPLIT_MIN, WEB_UI_WORKSPACE_SPLIT_MAX, defaults.workspaceSplit),
43
+ logAutoscroll: typeof raw["logAutoscroll"] === "boolean" ? raw["logAutoscroll"] : defaults.logAutoscroll,
44
+ };
45
+ }
46
+ export function normalizeWebUiSettingsPatch(patch) {
47
+ const normalized = {};
48
+ if (patch.theme !== undefined) {
49
+ normalized.theme = normalizeTheme(patch.theme, DEFAULT_AGENTWEAVER_WEB_UI_SETTINGS.theme);
50
+ }
51
+ if ("autoFlowHeight" in patch) {
52
+ normalized.autoFlowHeight = patch.autoFlowHeight === null || patch.autoFlowHeight === undefined
53
+ ? null
54
+ : clampInteger(patch.autoFlowHeight, WEB_UI_AUTO_FLOW_HEIGHT_MIN, WEB_UI_AUTO_FLOW_HEIGHT_MAX, WEB_UI_AUTO_FLOW_HEIGHT_MAX);
55
+ }
56
+ if (patch.workspaceSplit !== undefined) {
57
+ normalized.workspaceSplit = clampInteger(patch.workspaceSplit, WEB_UI_WORKSPACE_SPLIT_MIN, WEB_UI_WORKSPACE_SPLIT_MAX, DEFAULT_AGENTWEAVER_WEB_UI_SETTINGS.workspaceSplit);
58
+ }
59
+ if (patch.logAutoscroll !== undefined) {
60
+ normalized.logAutoscroll = Boolean(patch.logAutoscroll);
61
+ }
62
+ return normalized;
63
+ }
64
+ function readRawSettings() {
65
+ const filePath = agentweaverSettingsPath();
66
+ if (!existsSync(filePath)) {
67
+ return {};
68
+ }
69
+ try {
70
+ const parsed = JSON.parse(readFileSync(filePath, "utf8"));
71
+ return isRecord(parsed) ? parsed : {};
72
+ }
73
+ catch {
74
+ return {};
75
+ }
76
+ }
77
+ function writeJsonAtomic(filePath, value) {
78
+ mkdirSync(path.dirname(filePath), { recursive: true });
79
+ const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
80
+ writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
81
+ renameSync(tempPath, filePath);
82
+ }
83
+ export function loadAgentWeaverSettings() {
84
+ const raw = readRawSettings();
85
+ return {
86
+ kind: "agentweaver-settings",
87
+ version: 1,
88
+ webUi: normalizeWebUiSettings(raw["webUi"]),
89
+ };
90
+ }
91
+ export function saveAgentWeaverSettings(settings) {
92
+ const raw = readRawSettings();
93
+ const normalized = {
94
+ kind: "agentweaver-settings",
95
+ version: 1,
96
+ webUi: normalizeWebUiSettings(settings.webUi),
97
+ };
98
+ writeJsonAtomic(agentweaverSettingsPath(), {
99
+ ...raw,
100
+ ...normalized,
101
+ });
102
+ return normalized;
103
+ }
104
+ export function updateWebUiSettings(patch) {
105
+ const current = loadAgentWeaverSettings();
106
+ const next = saveAgentWeaverSettings({
107
+ ...current,
108
+ webUi: {
109
+ ...current.webUi,
110
+ ...normalizeWebUiSettingsPatch(patch),
111
+ },
112
+ });
113
+ return next.webUi;
114
+ }
package/dist/scope.js CHANGED
@@ -109,19 +109,24 @@ export function attachJiraContext(scope, jiraRef) {
109
109
  jiraTaskFile: jiraTaskFile(scope.scopeKey),
110
110
  };
111
111
  }
112
- export function buildJiraTaskInputForm() {
112
+ export function buildJiraTaskInputForm(options = {}) {
113
+ const required = options.required ?? true;
113
114
  return {
114
115
  formId: "jira-task-input",
115
116
  title: "Jira Task",
116
- description: "Provide a Jira issue key or browse URL for a task-driven flow.",
117
+ description: required
118
+ ? "Provide a Jira issue key or browse URL for a task-driven flow."
119
+ : "Provide a Jira issue key or browse URL, or leave it empty to paste the task description manually.",
117
120
  submitLabel: "Continue",
118
121
  fields: [
119
122
  {
120
123
  id: "jira_ref",
121
124
  type: "text",
122
125
  label: "Jira issue key or browse URL",
123
- help: "Example: DEMO-3288 or https://jira.example.com/browse/DEMO-3288",
124
- required: true,
126
+ help: required
127
+ ? "Example: DEMO-3288 or https://jira.example.com/browse/DEMO-3288"
128
+ : "Leave empty to enter the task description manually in the next step.",
129
+ required,
125
130
  },
126
131
  ],
127
132
  };
@@ -134,3 +139,8 @@ export async function requestJiraContext(requestUserInput) {
134
139
  }
135
140
  return parseJiraContext(jiraRef);
136
141
  }
142
+ export async function requestOptionalJiraContext(requestUserInput) {
143
+ const result = await requestUserInput(buildJiraTaskInputForm({ required: false }));
144
+ const jiraRef = String(result.values.jira_ref ?? "").trim();
145
+ return jiraRef ? parseJiraContext(jiraRef) : null;
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentweaver",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "CLI orchestrator for Jira/Codex engineering workflows",
5
5
  "keywords": [
6
6
  "agent",
@@ -1,179 +0,0 @@
1
- {
2
- "kind": "auto-flow",
3
- "version": 1,
4
- "description": "End-to-end resumable pipeline without language-specific checks. Runs: Jira fetch → task source normalization → plan → design-review loop → implement → review loop. Planning gate requires design-review approval, or an explicit user decision to continue after the maximum revision attempts, before implementation.",
5
- "phases": [
6
- {
7
- "id": "source",
8
- "steps": [
9
- {
10
- "id": "fetch_jira_source",
11
- "node": "flow-run",
12
- "params": {
13
- "fileName": { "const": "jira-fetch.json" },
14
- "labelText": { "const": "Fetching Jira task source" },
15
- "jiraApiUrl": { "ref": "params.jiraApiUrl" },
16
- "taskKey": { "ref": "params.taskKey" }
17
- }
18
- }
19
- ]
20
- },
21
- {
22
- "id": "normalize",
23
- "steps": [
24
- {
25
- "id": "run_normalize_source",
26
- "node": "flow-run",
27
- "params": {
28
- "fileName": { "const": "normalize-task-source.json" },
29
- "labelText": { "const": "Normalizing task source" },
30
- "taskKey": { "ref": "params.taskKey" },
31
- "iteration": { "ref": "params.taskContextIteration" },
32
- "llmExecutor": { "ref": "params.llmExecutor" },
33
- "llmModel": { "ref": "params.llmModel" },
34
- "extraPrompt": { "ref": "params.extraPrompt" }
35
- }
36
- }
37
- ]
38
- },
39
- {
40
- "id": "plan",
41
- "steps": [
42
- {
43
- "id": "run_plan_flow",
44
- "node": "flow-run",
45
- "params": {
46
- "fileName": { "const": "plan.json" },
47
- "labelText": { "const": "Running planning flow" },
48
- "taskKey": { "ref": "params.taskKey" },
49
- "taskContextIteration": { "ref": "params.taskContextIteration" },
50
- "designIteration": { "ref": "params.designIteration" },
51
- "planIteration": { "ref": "params.planIteration" },
52
- "qaIteration": { "ref": "params.qaIteration" },
53
- "llmExecutor": { "ref": "params.llmExecutor" },
54
- "llmModel": { "ref": "params.llmModel" },
55
- "extraPrompt": { "ref": "params.extraPrompt" },
56
- "mdLang": { "ref": "params.mdLang" }
57
- }
58
- }
59
- ]
60
- },
61
- {
62
- "id": "design_review_loop",
63
- "steps": [
64
- {
65
- "id": "run_design_review_loop",
66
- "node": "flow-run",
67
- "params": {
68
- "fileName": { "const": "design-review-loop.json" },
69
- "labelText": { "const": "Running design-review loop" },
70
- "taskKey": { "ref": "params.taskKey" },
71
- "baseIteration": { "ref": "params.designReviewBaseIteration" },
72
- "workspaceDir": { "ref": "params.workspaceDir" },
73
- "extraPrompt": { "ref": "params.extraPrompt" },
74
- "llmExecutor": { "ref": "params.llmExecutor" },
75
- "llmModel": { "ref": "params.llmModel" }
76
- },
77
- "stopFlowIf": {
78
- "equals": [
79
- { "ref": "steps.design_review_loop.run_design_review_loop.value.executionState.terminationOutcome" },
80
- { "const": "stopped" }
81
- ]
82
- },
83
- "stopFlowOutcome": "stopped"
84
- }
85
- ]
86
- },
87
- {
88
- "id": "implement",
89
- "steps": [
90
- {
91
- "id": "resolve_planning_bundle",
92
- "node": "planning-bundle",
93
- "params": {
94
- "taskKey": { "ref": "params.taskKey" }
95
- }
96
- },
97
- {
98
- "id": "run_implement",
99
- "node": "llm-prompt",
100
- "routingGroup": "implementation",
101
- "prompt": {
102
- "templateRef": "implement",
103
- "vars": {
104
- "design_file": { "ref": "steps.implement.resolve_planning_bundle.value.designFile" },
105
- "design_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.designJsonFile" },
106
- "plan_file": { "ref": "steps.implement.resolve_planning_bundle.value.planFile" },
107
- "plan_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.planJsonFile" },
108
- "qa_file": { "ref": "steps.implement.resolve_planning_bundle.value.qaFile" },
109
- "qa_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.qaJsonFile" },
110
- "project_guidance_file": { "const": "not provided" },
111
- "project_guidance_json_file": { "const": "not provided" }
112
- },
113
- "extraPrompt": { "ref": "params.extraPrompt" },
114
- "format": "task-prompt"
115
- },
116
- "params": {
117
- "labelText": { "const": "Running implementation mode locally" },
118
- "model": { "ref": "params.llmModel" },
119
- "executor": { "ref": "params.llmExecutor" }
120
- }
121
- },
122
- {
123
- "id": "notify_implement_complete",
124
- "node": "telegram-notify",
125
- "params": {
126
- "message": {
127
- "template": "Implementation phase for {taskKey} complete.",
128
- "vars": {
129
- "taskKey": { "ref": "params.taskKey" }
130
- }
131
- }
132
- }
133
- }
134
- ]
135
- },
136
- {
137
- "id": "review-loop",
138
- "steps": [
139
- {
140
- "id": "run_review_loop",
141
- "node": "flow-run",
142
- "stopFlowIf": {
143
- "not": {
144
- "equals": [
145
- { "ref": "steps.review-loop.run_review_loop.value.executionState.terminationOutcome" },
146
- { "const": "success" }
147
- ]
148
- }
149
- },
150
- "stopFlowOutcome": "stopped",
151
- "params": {
152
- "fileName": { "const": "review-loop.json" },
153
- "labelText": { "const": "Running review-loop" },
154
- "taskKey": { "ref": "params.taskKey" },
155
- "baseIteration": { "ref": "params.baseIteration" },
156
- "workspaceDir": { "ref": "params.workspaceDir" },
157
- "extraPrompt": { "ref": "params.extraPrompt" },
158
- "reviewFixPoints": { "ref": "params.reviewFixPoints" },
159
- "reviewBlockingSeverities": { "ref": "params.reviewBlockingSeverities" },
160
- "llmExecutor": { "ref": "params.llmExecutor" },
161
- "llmModel": { "ref": "params.llmModel" }
162
- }
163
- },
164
- {
165
- "id": "notify_task_complete",
166
- "node": "telegram-notify",
167
- "params": {
168
- "message": {
169
- "template": "Task {taskKey} complete.",
170
- "vars": {
171
- "taskKey": { "ref": "params.taskKey" }
172
- }
173
- }
174
- }
175
- }
176
- ]
177
- }
178
- ]
179
- }
@@ -1,141 +0,0 @@
1
- {
2
- "kind": "auto-flow",
3
- "version": 1,
4
- "description": "End-to-end resumable pipeline without language-specific checks. Runs: Jira fetch → task source normalization → plan → implement → review loop. Simplified alternative to auto-golang for projects that do not need Go linter/test loops.",
5
- "phases": [
6
- {
7
- "id": "source",
8
- "steps": [
9
- {
10
- "id": "fetch_jira_source",
11
- "node": "flow-run",
12
- "params": {
13
- "fileName": { "const": "jira-fetch.json" },
14
- "labelText": { "const": "Fetching Jira task source" },
15
- "jiraApiUrl": { "ref": "params.jiraApiUrl" },
16
- "taskKey": { "ref": "params.taskKey" }
17
- }
18
- }
19
- ]
20
- },
21
- {
22
- "id": "normalize",
23
- "steps": [
24
- {
25
- "id": "run_normalize_source",
26
- "node": "flow-run",
27
- "params": {
28
- "fileName": { "const": "normalize-task-source.json" },
29
- "labelText": { "const": "Normalizing task source" },
30
- "taskKey": { "ref": "params.taskKey" },
31
- "iteration": { "ref": "params.taskContextIteration" },
32
- "llmExecutor": { "ref": "params.llmExecutor" },
33
- "llmModel": { "ref": "params.llmModel" },
34
- "extraPrompt": { "ref": "params.extraPrompt" }
35
- }
36
- }
37
- ]
38
- },
39
- {
40
- "id": "plan",
41
- "steps": [
42
- {
43
- "id": "run_plan_flow",
44
- "node": "flow-run",
45
- "params": {
46
- "fileName": { "const": "plan.json" },
47
- "labelText": { "const": "Running planning flow" },
48
- "taskKey": { "ref": "params.taskKey" },
49
- "taskContextIteration": { "ref": "params.taskContextIteration" },
50
- "designIteration": { "ref": "params.designIteration" },
51
- "planIteration": { "ref": "params.planIteration" },
52
- "qaIteration": { "ref": "params.qaIteration" },
53
- "llmExecutor": { "ref": "params.llmExecutor" },
54
- "llmModel": { "ref": "params.llmModel" },
55
- "extraPrompt": { "ref": "params.extraPrompt" },
56
- "mdLang": { "ref": "params.mdLang" }
57
- }
58
- }
59
- ]
60
- },
61
- {
62
- "id": "implement",
63
- "steps": [
64
- {
65
- "id": "resolve_planning_bundle",
66
- "node": "planning-bundle",
67
- "params": {
68
- "taskKey": { "ref": "params.taskKey" }
69
- }
70
- },
71
- {
72
- "id": "run_implement",
73
- "node": "llm-prompt",
74
- "prompt": {
75
- "templateRef": "implement",
76
- "vars": {
77
- "design_file": { "ref": "steps.implement.resolve_planning_bundle.value.designFile" },
78
- "design_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.designJsonFile" },
79
- "plan_file": { "ref": "steps.implement.resolve_planning_bundle.value.planFile" },
80
- "plan_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.planJsonFile" },
81
- "qa_file": { "ref": "steps.implement.resolve_planning_bundle.value.qaFile" },
82
- "qa_json_file": { "ref": "steps.implement.resolve_planning_bundle.value.qaJsonFile" }
83
- },
84
- "extraPrompt": { "ref": "params.extraPrompt" },
85
- "format": "task-prompt"
86
- },
87
- "params": {
88
- "labelText": { "const": "Running implementation mode locally" },
89
- "model": { "ref": "params.llmModel" },
90
- "executor": { "ref": "params.llmExecutor" }
91
- }
92
- },
93
- {
94
- "id": "notify_implement_complete",
95
- "node": "telegram-notify",
96
- "params": {
97
- "message": {
98
- "template": "Implementation phase for {taskKey} complete.",
99
- "vars": {
100
- "taskKey": { "ref": "params.taskKey" }
101
- }
102
- }
103
- }
104
- }
105
- ]
106
- },
107
- {
108
- "id": "review-loop",
109
- "steps": [
110
- {
111
- "id": "run_review_loop",
112
- "node": "flow-run",
113
- "params": {
114
- "fileName": { "const": "review-loop.json" },
115
- "labelText": { "const": "Running review-loop" },
116
- "taskKey": { "ref": "params.taskKey" },
117
- "baseIteration": { "ref": "params.baseIteration" },
118
- "workspaceDir": { "ref": "params.workspaceDir" },
119
- "extraPrompt": { "ref": "params.extraPrompt" },
120
- "reviewFixPoints": { "ref": "params.reviewFixPoints" },
121
- "reviewBlockingSeverities": { "ref": "params.reviewBlockingSeverities" },
122
- "llmExecutor": { "ref": "params.llmExecutor" },
123
- "llmModel": { "ref": "params.llmModel" }
124
- }
125
- },
126
- {
127
- "id": "notify_task_complete",
128
- "node": "telegram-notify",
129
- "params": {
130
- "message": {
131
- "template": "Task {taskKey} complete.",
132
- "vars": {
133
- "taskKey": { "ref": "params.taskKey" }
134
- }
135
- }
136
- }
137
- }
138
- ]
139
- }
140
- ]
141
- }