agentweaver 0.1.16 → 0.1.18
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 +148 -27
- package/dist/artifacts.js +114 -3
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/flow-state.js +138 -1
- package/dist/index.js +421 -82
- package/dist/interactive/controller.js +305 -36
- package/dist/interactive/ink/index.js +24 -3
- package/dist/interactive/state.js +1 -0
- package/dist/interactive/tree.js +2 -2
- package/dist/interactive/web/index.js +179 -0
- package/dist/interactive/web/protocol.js +154 -0
- package/dist/interactive/web/server.js +575 -0
- package/dist/interactive/web/static/app.js +709 -0
- package/dist/interactive/web/static/index.html +77 -0
- package/dist/interactive/web/static/styles.css +2 -0
- package/dist/interactive/web/static/styles.input.css +469 -0
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +6 -5
- package/dist/pipeline/declarative-flows.js +39 -20
- package/dist/pipeline/flow-catalog.js +40 -14
- package/dist/pipeline/flow-specs/auto-common-guided.json +313 -0
- package/dist/pipeline/flow-specs/auto-common.json +4 -1
- package/dist/pipeline/flow-specs/auto-golang.json +27 -1
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +15 -1
- package/dist/pipeline/flow-specs/design-review.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +3 -1
- package/dist/pipeline/flow-specs/plan.json +8 -2
- package/dist/pipeline/flow-specs/playbook-init.json +199 -0
- package/dist/pipeline/flow-specs/review/review-fix.json +3 -1
- package/dist/pipeline/flow-specs/review/review-loop.json +4 -0
- package/dist/pipeline/flow-specs/review/review.json +2 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +119 -5
- package/dist/pipeline/nodes/flow-run-node.js +200 -173
- package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
- package/dist/pipeline/nodes/playbook-ensure-node.js +115 -0
- package/dist/pipeline/nodes/playbook-inventory-node.js +51 -0
- package/dist/pipeline/nodes/playbook-questions-form-node.js +166 -0
- package/dist/pipeline/nodes/playbook-write-node.js +243 -0
- package/dist/pipeline/nodes/project-guidance-node.js +69 -0
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +4 -1
- package/dist/pipeline/prompt-runtime.js +6 -2
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/spec-compiler.js +1 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +19 -0
- package/dist/pipeline/spec-validator.js +6 -0
- package/dist/pipeline/value-resolver.js +41 -2
- package/dist/playbook/practice-candidates.js +12 -0
- package/dist/playbook/repo-inventory.js +208 -0
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +31 -0
- package/dist/runtime/artifact-registry.js +3 -0
- package/dist/runtime/execution-routing.js +25 -19
- package/dist/runtime/interactive-execution-routing.js +66 -57
- package/dist/runtime/playbook.js +485 -0
- package/dist/runtime/project-guidance.js +339 -0
- package/dist/structured-artifact-schema-registry.js +8 -0
- package/dist/structured-artifact-schemas.json +235 -0
- package/dist/structured-artifacts.js +7 -1
- package/docs/declarative-workflows.md +565 -0
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/features.md +77 -0
- package/docs/playbook.md +327 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +13 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { printInfo } from "../../tui.js";
|
|
2
|
+
import { nextArtifactIteration } from "../../artifacts.js";
|
|
2
3
|
import { resolveDesignReviewInputContract } from "../../runtime/design-review-input-contract.js";
|
|
3
4
|
import { resolvePlanReviseInputContract } from "../../runtime/plan-revise-input-contract.js";
|
|
4
5
|
import { inspectReviewInputContract } from "../../runtime/review-input-contract.js";
|
|
@@ -20,6 +21,195 @@ function withArtifactLineageRefPaths(params, lineageRefs) {
|
|
|
20
21
|
[ARTIFACT_LINEAGE_REF_PATHS_PARAM]: merged,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
24
|
+
function parsePositiveInteger(value) {
|
|
25
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
26
|
+
}
|
|
27
|
+
export function resolveNestedFlowParams(flowKind, flowParams) {
|
|
28
|
+
let resolvedFlowParams = withCanonicalReviewLoopParams(flowKind, flowParams);
|
|
29
|
+
if (flowKind === "design-review-flow") {
|
|
30
|
+
const taskKey = String(flowParams["taskKey"] ?? "");
|
|
31
|
+
if (!taskKey) {
|
|
32
|
+
return resolvedFlowParams;
|
|
33
|
+
}
|
|
34
|
+
const contract = resolveDesignReviewInputContract(taskKey);
|
|
35
|
+
const iteration = parsePositiveInteger(flowParams["iteration"]) ?? nextArtifactIteration(taskKey, "design-review");
|
|
36
|
+
return withArtifactLineageRefPaths({
|
|
37
|
+
...flowParams,
|
|
38
|
+
iteration,
|
|
39
|
+
planningIteration: contract.planningIteration,
|
|
40
|
+
designFile: contract.designFile,
|
|
41
|
+
designJsonFile: contract.designJsonFile,
|
|
42
|
+
planFile: contract.planFile,
|
|
43
|
+
planJsonFile: contract.planJsonFile,
|
|
44
|
+
hasQaArtifacts: contract.hasQaArtifacts,
|
|
45
|
+
qaFilePath: contract.qaFilePath,
|
|
46
|
+
qaJsonFilePath: contract.qaJsonFilePath,
|
|
47
|
+
qaFile: contract.qaFile,
|
|
48
|
+
qaJsonFile: contract.qaJsonFile,
|
|
49
|
+
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
50
|
+
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
51
|
+
taskContextJsonFile: contract.taskContextJsonFile,
|
|
52
|
+
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
53
|
+
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
54
|
+
jiraTaskFile: contract.jiraTaskFile,
|
|
55
|
+
hasJiraAttachmentsManifestFile: contract.hasJiraAttachmentsManifestFile,
|
|
56
|
+
jiraAttachmentsManifestFilePath: contract.jiraAttachmentsManifestFilePath,
|
|
57
|
+
jiraAttachmentsManifestFile: contract.jiraAttachmentsManifestFile,
|
|
58
|
+
hasJiraAttachmentsContextFile: contract.hasJiraAttachmentsContextFile,
|
|
59
|
+
jiraAttachmentsContextFilePath: contract.jiraAttachmentsContextFilePath,
|
|
60
|
+
jiraAttachmentsContextFile: contract.jiraAttachmentsContextFile,
|
|
61
|
+
hasPlanningAnswersJsonFile: contract.hasPlanningAnswersJsonFile,
|
|
62
|
+
planningAnswersJsonFilePath: contract.planningAnswersJsonFilePath,
|
|
63
|
+
planningAnswersJsonFile: contract.planningAnswersJsonFile,
|
|
64
|
+
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
65
|
+
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
66
|
+
taskInputJsonFile: contract.taskInputJsonFile,
|
|
67
|
+
projectGuidanceFile: flowParams["projectGuidanceFile"] ?? "not provided",
|
|
68
|
+
projectGuidanceJsonFile: flowParams["projectGuidanceJsonFile"] ?? "not provided",
|
|
69
|
+
}, {
|
|
70
|
+
"params.designFile": contract.designFile,
|
|
71
|
+
"params.designJsonFile": contract.designJsonFile,
|
|
72
|
+
"params.planFile": contract.planFile,
|
|
73
|
+
"params.planJsonFile": contract.planJsonFile,
|
|
74
|
+
...(contract.qaFilePath ? { "params.qaFile": contract.qaFilePath } : {}),
|
|
75
|
+
...(contract.qaJsonFilePath ? { "params.qaJsonFile": contract.qaJsonFilePath } : {}),
|
|
76
|
+
...(contract.taskContextJsonFilePath
|
|
77
|
+
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
78
|
+
: {}),
|
|
79
|
+
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
80
|
+
...(contract.jiraAttachmentsManifestFilePath
|
|
81
|
+
? { "params.jiraAttachmentsManifestFile": contract.jiraAttachmentsManifestFilePath }
|
|
82
|
+
: {}),
|
|
83
|
+
...(contract.jiraAttachmentsContextFilePath
|
|
84
|
+
? { "params.jiraAttachmentsContextFile": contract.jiraAttachmentsContextFilePath }
|
|
85
|
+
: {}),
|
|
86
|
+
...(contract.planningAnswersJsonFilePath
|
|
87
|
+
? { "params.planningAnswersJsonFile": contract.planningAnswersJsonFilePath }
|
|
88
|
+
: {}),
|
|
89
|
+
...(contract.taskInputJsonFilePath
|
|
90
|
+
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
91
|
+
: {}),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
if (flowKind === "plan-revise-flow") {
|
|
95
|
+
const taskKey = String(flowParams["taskKey"] ?? "");
|
|
96
|
+
if (!taskKey) {
|
|
97
|
+
return resolvedFlowParams;
|
|
98
|
+
}
|
|
99
|
+
const contract = resolvePlanReviseInputContract(taskKey);
|
|
100
|
+
return withArtifactLineageRefPaths({
|
|
101
|
+
...flowParams,
|
|
102
|
+
reviewIteration: contract.reviewIteration,
|
|
103
|
+
reviewFile: contract.reviewFile,
|
|
104
|
+
reviewJsonFile: contract.reviewJsonFile,
|
|
105
|
+
sourcePlanningIteration: contract.sourcePlanningIteration,
|
|
106
|
+
outputIteration: contract.outputIteration,
|
|
107
|
+
designFile: contract.designFile,
|
|
108
|
+
designJsonFile: contract.designJsonFile,
|
|
109
|
+
planFile: contract.planFile,
|
|
110
|
+
planJsonFile: contract.planJsonFile,
|
|
111
|
+
hasQaArtifacts: contract.hasQaArtifacts,
|
|
112
|
+
qaFilePath: contract.qaFilePath,
|
|
113
|
+
qaJsonFilePath: contract.qaJsonFilePath,
|
|
114
|
+
qaFile: contract.qaFile,
|
|
115
|
+
qaJsonFile: contract.qaJsonFile,
|
|
116
|
+
revisedDesignFile: contract.revisedDesignFile,
|
|
117
|
+
revisedDesignJsonFile: contract.revisedDesignJsonFile,
|
|
118
|
+
revisedPlanFile: contract.revisedPlanFile,
|
|
119
|
+
revisedPlanJsonFile: contract.revisedPlanJsonFile,
|
|
120
|
+
revisedQaFile: contract.revisedQaFile,
|
|
121
|
+
revisedQaJsonFile: contract.revisedQaJsonFile,
|
|
122
|
+
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
123
|
+
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
124
|
+
taskContextJsonFile: contract.taskContextJsonFile,
|
|
125
|
+
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
126
|
+
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
127
|
+
jiraTaskFile: contract.jiraTaskFile,
|
|
128
|
+
hasJiraAttachmentsManifestFile: contract.hasJiraAttachmentsManifestFile,
|
|
129
|
+
jiraAttachmentsManifestFilePath: contract.jiraAttachmentsManifestFilePath,
|
|
130
|
+
jiraAttachmentsManifestFile: contract.jiraAttachmentsManifestFile,
|
|
131
|
+
hasJiraAttachmentsContextFile: contract.hasJiraAttachmentsContextFile,
|
|
132
|
+
jiraAttachmentsContextFilePath: contract.jiraAttachmentsContextFilePath,
|
|
133
|
+
jiraAttachmentsContextFile: contract.jiraAttachmentsContextFile,
|
|
134
|
+
hasPlanningAnswersJsonFile: contract.hasPlanningAnswersJsonFile,
|
|
135
|
+
planningAnswersJsonFilePath: contract.planningAnswersJsonFilePath,
|
|
136
|
+
planningAnswersJsonFile: contract.planningAnswersJsonFile,
|
|
137
|
+
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
138
|
+
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
139
|
+
taskInputJsonFile: contract.taskInputJsonFile,
|
|
140
|
+
projectGuidanceFile: flowParams["projectGuidanceFile"] ?? "not provided",
|
|
141
|
+
projectGuidanceJsonFile: flowParams["projectGuidanceJsonFile"] ?? "not provided",
|
|
142
|
+
}, {
|
|
143
|
+
"params.reviewFile": contract.reviewFile,
|
|
144
|
+
"params.reviewJsonFile": contract.reviewJsonFile,
|
|
145
|
+
"params.designFile": contract.designFile,
|
|
146
|
+
"params.designJsonFile": contract.designJsonFile,
|
|
147
|
+
"params.planFile": contract.planFile,
|
|
148
|
+
"params.planJsonFile": contract.planJsonFile,
|
|
149
|
+
...(contract.qaFilePath ? { "params.qaFile": contract.qaFilePath } : {}),
|
|
150
|
+
...(contract.qaJsonFilePath ? { "params.qaJsonFile": contract.qaJsonFilePath } : {}),
|
|
151
|
+
...(contract.taskContextJsonFilePath
|
|
152
|
+
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
153
|
+
: {}),
|
|
154
|
+
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
155
|
+
...(contract.jiraAttachmentsManifestFilePath
|
|
156
|
+
? { "params.jiraAttachmentsManifestFile": contract.jiraAttachmentsManifestFilePath }
|
|
157
|
+
: {}),
|
|
158
|
+
...(contract.jiraAttachmentsContextFilePath
|
|
159
|
+
? { "params.jiraAttachmentsContextFile": contract.jiraAttachmentsContextFilePath }
|
|
160
|
+
: {}),
|
|
161
|
+
...(contract.planningAnswersJsonFilePath
|
|
162
|
+
? { "params.planningAnswersJsonFile": contract.planningAnswersJsonFilePath }
|
|
163
|
+
: {}),
|
|
164
|
+
...(contract.taskInputJsonFilePath
|
|
165
|
+
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
166
|
+
: {}),
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (flowKind === "review-flow") {
|
|
170
|
+
const taskKey = String(flowParams["taskKey"] ?? "");
|
|
171
|
+
if (!taskKey) {
|
|
172
|
+
return resolvedFlowParams;
|
|
173
|
+
}
|
|
174
|
+
const inspection = inspectReviewInputContract(taskKey);
|
|
175
|
+
if (inspection.status !== "ready") {
|
|
176
|
+
return resolvedFlowParams;
|
|
177
|
+
}
|
|
178
|
+
const { contract } = inspection;
|
|
179
|
+
return withArtifactLineageRefPaths({
|
|
180
|
+
...flowParams,
|
|
181
|
+
planningIteration: contract.planningIteration,
|
|
182
|
+
designFile: contract.designFile,
|
|
183
|
+
designJsonFile: contract.designJsonFile,
|
|
184
|
+
planFile: contract.planFile,
|
|
185
|
+
planJsonFile: contract.planJsonFile,
|
|
186
|
+
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
187
|
+
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
188
|
+
taskContextJsonFile: contract.taskContextJsonFile,
|
|
189
|
+
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
190
|
+
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
191
|
+
jiraTaskFile: contract.jiraTaskFile,
|
|
192
|
+
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
193
|
+
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
194
|
+
taskInputJsonFile: contract.taskInputJsonFile,
|
|
195
|
+
projectGuidanceFile: flowParams["projectGuidanceFile"] ?? "not provided",
|
|
196
|
+
projectGuidanceJsonFile: flowParams["projectGuidanceJsonFile"] ?? "not provided",
|
|
197
|
+
}, {
|
|
198
|
+
"params.designFile": contract.designFile,
|
|
199
|
+
"params.designJsonFile": contract.designJsonFile,
|
|
200
|
+
"params.planFile": contract.planFile,
|
|
201
|
+
"params.planJsonFile": contract.planJsonFile,
|
|
202
|
+
...(contract.taskContextJsonFilePath
|
|
203
|
+
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
204
|
+
: {}),
|
|
205
|
+
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
206
|
+
...(contract.taskInputJsonFilePath
|
|
207
|
+
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
208
|
+
: {}),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return resolvedFlowParams;
|
|
212
|
+
}
|
|
23
213
|
export const flowRunNode = {
|
|
24
214
|
kind: "flow-run",
|
|
25
215
|
version: 1,
|
|
@@ -31,179 +221,16 @@ export const flowRunNode = {
|
|
|
31
221
|
if (labelText) {
|
|
32
222
|
printInfo(String(labelText));
|
|
33
223
|
}
|
|
34
|
-
const flow = loadNamedDeclarativeFlow(fileName, context.cwd
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
designFile: contract.designFile,
|
|
45
|
-
designJsonFile: contract.designJsonFile,
|
|
46
|
-
planFile: contract.planFile,
|
|
47
|
-
planJsonFile: contract.planJsonFile,
|
|
48
|
-
hasQaArtifacts: contract.hasQaArtifacts,
|
|
49
|
-
qaFilePath: contract.qaFilePath,
|
|
50
|
-
qaJsonFilePath: contract.qaJsonFilePath,
|
|
51
|
-
qaFile: contract.qaFile,
|
|
52
|
-
qaJsonFile: contract.qaJsonFile,
|
|
53
|
-
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
54
|
-
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
55
|
-
taskContextJsonFile: contract.taskContextJsonFile,
|
|
56
|
-
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
57
|
-
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
58
|
-
jiraTaskFile: contract.jiraTaskFile,
|
|
59
|
-
hasJiraAttachmentsManifestFile: contract.hasJiraAttachmentsManifestFile,
|
|
60
|
-
jiraAttachmentsManifestFilePath: contract.jiraAttachmentsManifestFilePath,
|
|
61
|
-
jiraAttachmentsManifestFile: contract.jiraAttachmentsManifestFile,
|
|
62
|
-
hasJiraAttachmentsContextFile: contract.hasJiraAttachmentsContextFile,
|
|
63
|
-
jiraAttachmentsContextFilePath: contract.jiraAttachmentsContextFilePath,
|
|
64
|
-
jiraAttachmentsContextFile: contract.jiraAttachmentsContextFile,
|
|
65
|
-
hasPlanningAnswersJsonFile: contract.hasPlanningAnswersJsonFile,
|
|
66
|
-
planningAnswersJsonFilePath: contract.planningAnswersJsonFilePath,
|
|
67
|
-
planningAnswersJsonFile: contract.planningAnswersJsonFile,
|
|
68
|
-
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
69
|
-
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
70
|
-
taskInputJsonFile: contract.taskInputJsonFile,
|
|
71
|
-
}, {
|
|
72
|
-
"params.designFile": contract.designFile,
|
|
73
|
-
"params.designJsonFile": contract.designJsonFile,
|
|
74
|
-
"params.planFile": contract.planFile,
|
|
75
|
-
"params.planJsonFile": contract.planJsonFile,
|
|
76
|
-
...(contract.qaFilePath ? { "params.qaFile": contract.qaFilePath } : {}),
|
|
77
|
-
...(contract.qaJsonFilePath ? { "params.qaJsonFile": contract.qaJsonFilePath } : {}),
|
|
78
|
-
...(contract.taskContextJsonFilePath
|
|
79
|
-
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
80
|
-
: {}),
|
|
81
|
-
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
82
|
-
...(contract.jiraAttachmentsManifestFilePath
|
|
83
|
-
? { "params.jiraAttachmentsManifestFile": contract.jiraAttachmentsManifestFilePath }
|
|
84
|
-
: {}),
|
|
85
|
-
...(contract.jiraAttachmentsContextFilePath
|
|
86
|
-
? { "params.jiraAttachmentsContextFile": contract.jiraAttachmentsContextFilePath }
|
|
87
|
-
: {}),
|
|
88
|
-
...(contract.planningAnswersJsonFilePath
|
|
89
|
-
? { "params.planningAnswersJsonFile": contract.planningAnswersJsonFilePath }
|
|
90
|
-
: {}),
|
|
91
|
-
...(contract.taskInputJsonFilePath
|
|
92
|
-
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
93
|
-
: {}),
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
else if (flow.kind === "plan-revise-flow") {
|
|
98
|
-
const taskKey = String(flowParams["taskKey"] ?? "");
|
|
99
|
-
if (taskKey) {
|
|
100
|
-
const contract = resolvePlanReviseInputContract(taskKey);
|
|
101
|
-
resolvedFlowParams = withArtifactLineageRefPaths({
|
|
102
|
-
...flowParams,
|
|
103
|
-
reviewIteration: contract.reviewIteration,
|
|
104
|
-
reviewFile: contract.reviewFile,
|
|
105
|
-
reviewJsonFile: contract.reviewJsonFile,
|
|
106
|
-
sourcePlanningIteration: contract.sourcePlanningIteration,
|
|
107
|
-
outputIteration: contract.outputIteration,
|
|
108
|
-
designFile: contract.designFile,
|
|
109
|
-
designJsonFile: contract.designJsonFile,
|
|
110
|
-
planFile: contract.planFile,
|
|
111
|
-
planJsonFile: contract.planJsonFile,
|
|
112
|
-
hasQaArtifacts: contract.hasQaArtifacts,
|
|
113
|
-
qaFilePath: contract.qaFilePath,
|
|
114
|
-
qaJsonFilePath: contract.qaJsonFilePath,
|
|
115
|
-
qaFile: contract.qaFile,
|
|
116
|
-
qaJsonFile: contract.qaJsonFile,
|
|
117
|
-
revisedDesignFile: contract.revisedDesignFile,
|
|
118
|
-
revisedDesignJsonFile: contract.revisedDesignJsonFile,
|
|
119
|
-
revisedPlanFile: contract.revisedPlanFile,
|
|
120
|
-
revisedPlanJsonFile: contract.revisedPlanJsonFile,
|
|
121
|
-
revisedQaFile: contract.revisedQaFile,
|
|
122
|
-
revisedQaJsonFile: contract.revisedQaJsonFile,
|
|
123
|
-
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
124
|
-
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
125
|
-
taskContextJsonFile: contract.taskContextJsonFile,
|
|
126
|
-
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
127
|
-
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
128
|
-
jiraTaskFile: contract.jiraTaskFile,
|
|
129
|
-
hasJiraAttachmentsManifestFile: contract.hasJiraAttachmentsManifestFile,
|
|
130
|
-
jiraAttachmentsManifestFilePath: contract.jiraAttachmentsManifestFilePath,
|
|
131
|
-
jiraAttachmentsManifestFile: contract.jiraAttachmentsManifestFile,
|
|
132
|
-
hasJiraAttachmentsContextFile: contract.hasJiraAttachmentsContextFile,
|
|
133
|
-
jiraAttachmentsContextFilePath: contract.jiraAttachmentsContextFilePath,
|
|
134
|
-
jiraAttachmentsContextFile: contract.jiraAttachmentsContextFile,
|
|
135
|
-
hasPlanningAnswersJsonFile: contract.hasPlanningAnswersJsonFile,
|
|
136
|
-
planningAnswersJsonFilePath: contract.planningAnswersJsonFilePath,
|
|
137
|
-
planningAnswersJsonFile: contract.planningAnswersJsonFile,
|
|
138
|
-
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
139
|
-
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
140
|
-
taskInputJsonFile: contract.taskInputJsonFile,
|
|
141
|
-
}, {
|
|
142
|
-
"params.reviewFile": contract.reviewFile,
|
|
143
|
-
"params.reviewJsonFile": contract.reviewJsonFile,
|
|
144
|
-
"params.designFile": contract.designFile,
|
|
145
|
-
"params.designJsonFile": contract.designJsonFile,
|
|
146
|
-
"params.planFile": contract.planFile,
|
|
147
|
-
"params.planJsonFile": contract.planJsonFile,
|
|
148
|
-
...(contract.qaFilePath ? { "params.qaFile": contract.qaFilePath } : {}),
|
|
149
|
-
...(contract.qaJsonFilePath ? { "params.qaJsonFile": contract.qaJsonFilePath } : {}),
|
|
150
|
-
...(contract.taskContextJsonFilePath
|
|
151
|
-
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
152
|
-
: {}),
|
|
153
|
-
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
154
|
-
...(contract.jiraAttachmentsManifestFilePath
|
|
155
|
-
? { "params.jiraAttachmentsManifestFile": contract.jiraAttachmentsManifestFilePath }
|
|
156
|
-
: {}),
|
|
157
|
-
...(contract.jiraAttachmentsContextFilePath
|
|
158
|
-
? { "params.jiraAttachmentsContextFile": contract.jiraAttachmentsContextFilePath }
|
|
159
|
-
: {}),
|
|
160
|
-
...(contract.planningAnswersJsonFilePath
|
|
161
|
-
? { "params.planningAnswersJsonFile": contract.planningAnswersJsonFilePath }
|
|
162
|
-
: {}),
|
|
163
|
-
...(contract.taskInputJsonFilePath
|
|
164
|
-
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
165
|
-
: {}),
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
else if (flow.kind === "review-flow") {
|
|
170
|
-
const taskKey = String(flowParams["taskKey"] ?? "");
|
|
171
|
-
if (taskKey) {
|
|
172
|
-
const inspection = inspectReviewInputContract(taskKey);
|
|
173
|
-
if (inspection.status === "ready") {
|
|
174
|
-
const { contract } = inspection;
|
|
175
|
-
resolvedFlowParams = withArtifactLineageRefPaths({
|
|
176
|
-
...flowParams,
|
|
177
|
-
planningIteration: contract.planningIteration,
|
|
178
|
-
designFile: contract.designFile,
|
|
179
|
-
designJsonFile: contract.designJsonFile,
|
|
180
|
-
planFile: contract.planFile,
|
|
181
|
-
planJsonFile: contract.planJsonFile,
|
|
182
|
-
hasTaskContextJsonFile: contract.hasTaskContextJsonFile,
|
|
183
|
-
taskContextJsonFilePath: contract.taskContextJsonFilePath,
|
|
184
|
-
taskContextJsonFile: contract.taskContextJsonFile,
|
|
185
|
-
hasJiraTaskFile: contract.hasJiraTaskFile,
|
|
186
|
-
jiraTaskFilePath: contract.jiraTaskFilePath,
|
|
187
|
-
jiraTaskFile: contract.jiraTaskFile,
|
|
188
|
-
hasTaskInputJsonFile: contract.hasTaskInputJsonFile,
|
|
189
|
-
taskInputJsonFilePath: contract.taskInputJsonFilePath,
|
|
190
|
-
taskInputJsonFile: contract.taskInputJsonFile,
|
|
191
|
-
}, {
|
|
192
|
-
"params.designFile": contract.designFile,
|
|
193
|
-
"params.designJsonFile": contract.designJsonFile,
|
|
194
|
-
"params.planFile": contract.planFile,
|
|
195
|
-
"params.planJsonFile": contract.planJsonFile,
|
|
196
|
-
...(contract.taskContextJsonFilePath
|
|
197
|
-
? { "params.taskContextJsonFile": contract.taskContextJsonFilePath }
|
|
198
|
-
: {}),
|
|
199
|
-
...(contract.jiraTaskFilePath ? { "params.jiraTaskFile": contract.jiraTaskFilePath } : {}),
|
|
200
|
-
...(contract.taskInputJsonFilePath
|
|
201
|
-
? { "params.taskInputJsonFile": contract.taskInputJsonFilePath }
|
|
202
|
-
: {}),
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
224
|
+
const flow = await loadNamedDeclarativeFlow(fileName, context.cwd, {
|
|
225
|
+
...(context.registryContext ? { registryContext: context.registryContext } : {}),
|
|
226
|
+
});
|
|
227
|
+
const resolvedFlowParams = resolveNestedFlowParams(flow.kind, {
|
|
228
|
+
projectGuidanceFile: "not provided",
|
|
229
|
+
projectGuidanceJsonFile: "not provided",
|
|
230
|
+
repairProjectGuidanceFile: "not provided",
|
|
231
|
+
repairProjectGuidanceJsonFile: "not provided",
|
|
232
|
+
...flowParams,
|
|
233
|
+
});
|
|
207
234
|
const resumeValue = isFlowRunResumeEnvelope(context.resumeStepValue)
|
|
208
235
|
&& context.resumeStepValue.flowKind === flow.kind
|
|
209
236
|
&& context.resumeStepValue.flowVersion === flow.version
|
|
@@ -26,46 +26,28 @@ export const llmPromptNode = {
|
|
|
26
26
|
const model = params.routingGroup
|
|
27
27
|
? routedProfile?.model ?? params.model ?? fallbackProfile?.model
|
|
28
28
|
: params.model ?? fallbackProfile?.model;
|
|
29
|
-
if (!executor || !isLlmExecutorId(executor)) {
|
|
29
|
+
if (!executor || !isLlmExecutorId(executor, context.executors)) {
|
|
30
30
|
throw new TaskRunnerError(`Unsupported llm executor '${String(executor ?? params.executor ?? "undefined")}'.`);
|
|
31
31
|
}
|
|
32
|
-
if (model && !isAllowedModelForExecutor(executor, model)) {
|
|
32
|
+
if (model && !isAllowedModelForExecutor(executor, model, context.executors)) {
|
|
33
33
|
throw new TaskRunnerError(`Model '${model}' is not allowed for executor '${executor}'.`);
|
|
34
34
|
}
|
|
35
35
|
printInfo(params.labelText);
|
|
36
36
|
printPrompt(`LLM:${executor}`, params.prompt);
|
|
37
37
|
const executorContext = toExecutorContext(context);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
value
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
if (executor === "opencode") {
|
|
54
|
-
const executor = context.executors.get("opencode");
|
|
55
|
-
const value = await executor.execute(executorContext, {
|
|
56
|
-
prompt: params.prompt,
|
|
57
|
-
...(model ? { model } : {}),
|
|
58
|
-
env: { ...context.env },
|
|
59
|
-
}, executor.defaultConfig);
|
|
60
|
-
return {
|
|
61
|
-
value: {
|
|
62
|
-
...value,
|
|
63
|
-
executor: "opencode",
|
|
64
|
-
},
|
|
65
|
-
outputs: outputsForArtifacts(params.requiredArtifacts),
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
throw new TaskRunnerError(`Unsupported llm executor '${executor}'.`);
|
|
38
|
+
const resolvedExecutor = context.executors.get(executor);
|
|
39
|
+
const value = await resolvedExecutor.execute(executorContext, {
|
|
40
|
+
prompt: params.prompt,
|
|
41
|
+
...(model ? { model } : {}),
|
|
42
|
+
env: { ...context.env },
|
|
43
|
+
}, resolvedExecutor.defaultConfig);
|
|
44
|
+
return {
|
|
45
|
+
value: {
|
|
46
|
+
...value,
|
|
47
|
+
executor,
|
|
48
|
+
},
|
|
49
|
+
outputs: outputsForArtifacts(params.requiredArtifacts),
|
|
50
|
+
};
|
|
69
51
|
},
|
|
70
52
|
checks(_context, params) {
|
|
71
53
|
if (!params.requiredArtifacts || params.requiredArtifacts.length === 0) {
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildLogicalKeyForPayload } from "../../artifact-manifest.js";
|
|
4
|
+
import { loadProjectPlaybook, PLAYBOOK_DIR, PLAYBOOK_MANIFEST } from "../../runtime/playbook.js";
|
|
5
|
+
import { validateStructuredArtifactValue } from "../../structured-artifacts.js";
|
|
6
|
+
function readWriteStatus(filePath) {
|
|
7
|
+
if (!existsSync(filePath)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(readFileSync(filePath, "utf8"));
|
|
12
|
+
return typeof parsed.status === "string" ? parsed.status : null;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function writeResult(scopeKey, filePath, result) {
|
|
19
|
+
const artifact = {
|
|
20
|
+
status: result.status,
|
|
21
|
+
message: result.message,
|
|
22
|
+
written_files: result.written_files,
|
|
23
|
+
skipped_files: result.skipped_files,
|
|
24
|
+
existing_playbook_path: result.existing_playbook_path,
|
|
25
|
+
intended_files: result.intended_files,
|
|
26
|
+
blocked_paths: result.blocked_paths,
|
|
27
|
+
};
|
|
28
|
+
validateStructuredArtifactValue(artifact, "playbook-write-result/v1", filePath);
|
|
29
|
+
mkdirSync(path.dirname(filePath), { recursive: true });
|
|
30
|
+
writeFileSync(filePath, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
kind: "artifact",
|
|
34
|
+
path: filePath,
|
|
35
|
+
required: true,
|
|
36
|
+
manifest: {
|
|
37
|
+
publish: true,
|
|
38
|
+
logicalKey: buildLogicalKeyForPayload(scopeKey, filePath),
|
|
39
|
+
payloadFamily: "structured-json",
|
|
40
|
+
schemaId: "playbook-write-result/v1",
|
|
41
|
+
schemaVersion: 1,
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
export const playbookEnsureNode = {
|
|
47
|
+
kind: "playbook-ensure",
|
|
48
|
+
version: 1,
|
|
49
|
+
async run(context, params) {
|
|
50
|
+
const playbookRoot = path.join(context.cwd, PLAYBOOK_DIR);
|
|
51
|
+
const manifestPath = path.join(playbookRoot, PLAYBOOK_MANIFEST);
|
|
52
|
+
const intendedFiles = [manifestPath];
|
|
53
|
+
const priorStatus = params.verifyAfterInit ? readWriteStatus(params.writeResultJsonFile) : null;
|
|
54
|
+
if (!existsSync(manifestPath)) {
|
|
55
|
+
if (params.verifyAfterInit && priorStatus === "dry_run_written") {
|
|
56
|
+
const result = {
|
|
57
|
+
status: "dry_run_written",
|
|
58
|
+
message: "Dry-run playbook generation was accepted; manifest.yaml was not written in dry-run mode.",
|
|
59
|
+
written_files: [],
|
|
60
|
+
skipped_files: [],
|
|
61
|
+
existing_playbook_path: "",
|
|
62
|
+
intended_files: intendedFiles,
|
|
63
|
+
blocked_paths: [],
|
|
64
|
+
shouldRunPlaybookInit: false,
|
|
65
|
+
manifestPath,
|
|
66
|
+
};
|
|
67
|
+
return { value: result, outputs: writeResult(context.issueKey, params.writeResultJsonFile, result) };
|
|
68
|
+
}
|
|
69
|
+
const accepted = params.acceptPlaybookDraft === true;
|
|
70
|
+
const result = {
|
|
71
|
+
status: accepted ? "missing_playbook" : "blocked",
|
|
72
|
+
message: accepted
|
|
73
|
+
? `Playbook manifest is missing: ${manifestPath}. Running playbook-init because acceptPlaybookDraft is true.`
|
|
74
|
+
: `Playbook manifest is missing: ${manifestPath}. Run 'agentweaver playbook-init --accept-playbook-draft' first, or rerun 'agentweaver auto-common-guided --accept-playbook-draft <jira>' to explicitly accept generated playbook content before planning.`,
|
|
75
|
+
written_files: [],
|
|
76
|
+
skipped_files: [],
|
|
77
|
+
existing_playbook_path: "",
|
|
78
|
+
intended_files: intendedFiles,
|
|
79
|
+
blocked_paths: accepted ? [] : [manifestPath],
|
|
80
|
+
shouldRunPlaybookInit: accepted,
|
|
81
|
+
manifestPath,
|
|
82
|
+
};
|
|
83
|
+
return { value: result, outputs: writeResult(context.issueKey, params.writeResultJsonFile, result) };
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
loadProjectPlaybook(context.cwd);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
const result = {
|
|
90
|
+
status: "invalid_manifest",
|
|
91
|
+
message: `Invalid project playbook ${manifestPath}: ${error.message}`,
|
|
92
|
+
written_files: [],
|
|
93
|
+
skipped_files: [],
|
|
94
|
+
existing_playbook_path: "",
|
|
95
|
+
intended_files: intendedFiles,
|
|
96
|
+
blocked_paths: [manifestPath],
|
|
97
|
+
shouldRunPlaybookInit: false,
|
|
98
|
+
manifestPath,
|
|
99
|
+
};
|
|
100
|
+
return { value: result, outputs: writeResult(context.issueKey, params.writeResultJsonFile, result) };
|
|
101
|
+
}
|
|
102
|
+
const result = {
|
|
103
|
+
status: "skipped_valid_existing",
|
|
104
|
+
message: `Valid project playbook manifest exists: ${manifestPath}.`,
|
|
105
|
+
written_files: [],
|
|
106
|
+
skipped_files: [manifestPath],
|
|
107
|
+
existing_playbook_path: manifestPath,
|
|
108
|
+
intended_files: intendedFiles,
|
|
109
|
+
blocked_paths: [],
|
|
110
|
+
shouldRunPlaybookInit: false,
|
|
111
|
+
manifestPath,
|
|
112
|
+
};
|
|
113
|
+
return { value: result, outputs: writeResult(context.issueKey, params.writeResultJsonFile, result) };
|
|
114
|
+
},
|
|
115
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { buildLogicalKeyForPayload } from "../../artifact-manifest.js";
|
|
4
|
+
import { validateStructuredArtifactValue } from "../../structured-artifacts.js";
|
|
5
|
+
import { collectRepoInventory, renderRepoInventoryMarkdown } from "../../playbook/repo-inventory.js";
|
|
6
|
+
export const playbookInventoryNode = {
|
|
7
|
+
kind: "playbook-inventory",
|
|
8
|
+
version: 1,
|
|
9
|
+
async run(context, params) {
|
|
10
|
+
const inventory = collectRepoInventory(context.cwd);
|
|
11
|
+
validateStructuredArtifactValue(inventory, "repo-inventory/v1", params.outputJsonFile);
|
|
12
|
+
mkdirSync(path.dirname(params.outputJsonFile), { recursive: true });
|
|
13
|
+
mkdirSync(path.dirname(params.outputFile), { recursive: true });
|
|
14
|
+
writeFileSync(params.outputJsonFile, `${JSON.stringify(inventory, null, 2)}\n`, "utf8");
|
|
15
|
+
writeFileSync(params.outputFile, renderRepoInventoryMarkdown(inventory), "utf8");
|
|
16
|
+
return {
|
|
17
|
+
value: {
|
|
18
|
+
summary: inventory.summary,
|
|
19
|
+
outputJsonFile: params.outputJsonFile,
|
|
20
|
+
outputFile: params.outputFile,
|
|
21
|
+
evidenceCount: inventory.evidence.length,
|
|
22
|
+
},
|
|
23
|
+
outputs: [
|
|
24
|
+
{
|
|
25
|
+
kind: "artifact",
|
|
26
|
+
path: params.outputJsonFile,
|
|
27
|
+
required: true,
|
|
28
|
+
manifest: {
|
|
29
|
+
publish: true,
|
|
30
|
+
logicalKey: buildLogicalKeyForPayload(context.issueKey, params.outputJsonFile),
|
|
31
|
+
payloadFamily: "structured-json",
|
|
32
|
+
schemaId: "repo-inventory/v1",
|
|
33
|
+
schemaVersion: 1,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
kind: "artifact",
|
|
38
|
+
path: params.outputFile,
|
|
39
|
+
required: true,
|
|
40
|
+
manifest: {
|
|
41
|
+
publish: true,
|
|
42
|
+
logicalKey: buildLogicalKeyForPayload(context.issueKey, params.outputFile),
|
|
43
|
+
payloadFamily: "markdown",
|
|
44
|
+
schemaId: "markdown/v1",
|
|
45
|
+
schemaVersion: 1,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
};
|