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.
Files changed (74) hide show
  1. package/README.md +148 -27
  2. package/dist/artifacts.js +114 -3
  3. package/dist/doctor/checks/executors.js +2 -2
  4. package/dist/flow-state.js +138 -1
  5. package/dist/index.js +421 -82
  6. package/dist/interactive/controller.js +305 -36
  7. package/dist/interactive/ink/index.js +24 -3
  8. package/dist/interactive/state.js +1 -0
  9. package/dist/interactive/tree.js +2 -2
  10. package/dist/interactive/web/index.js +179 -0
  11. package/dist/interactive/web/protocol.js +154 -0
  12. package/dist/interactive/web/server.js +575 -0
  13. package/dist/interactive/web/static/app.js +709 -0
  14. package/dist/interactive/web/static/index.html +77 -0
  15. package/dist/interactive/web/static/styles.css +2 -0
  16. package/dist/interactive/web/static/styles.input.css +469 -0
  17. package/dist/pipeline/auto-flow.js +9 -6
  18. package/dist/pipeline/context.js +6 -5
  19. package/dist/pipeline/declarative-flows.js +39 -20
  20. package/dist/pipeline/flow-catalog.js +40 -14
  21. package/dist/pipeline/flow-specs/auto-common-guided.json +313 -0
  22. package/dist/pipeline/flow-specs/auto-common.json +4 -1
  23. package/dist/pipeline/flow-specs/auto-golang.json +27 -1
  24. package/dist/pipeline/flow-specs/design-review/design-review-loop.json +15 -1
  25. package/dist/pipeline/flow-specs/design-review.json +2 -0
  26. package/dist/pipeline/flow-specs/implement.json +3 -1
  27. package/dist/pipeline/flow-specs/plan.json +8 -2
  28. package/dist/pipeline/flow-specs/playbook-init.json +199 -0
  29. package/dist/pipeline/flow-specs/review/review-fix.json +3 -1
  30. package/dist/pipeline/flow-specs/review/review-loop.json +4 -0
  31. package/dist/pipeline/flow-specs/review/review.json +2 -0
  32. package/dist/pipeline/launch-profile-config.js +30 -18
  33. package/dist/pipeline/node-contract.js +1 -0
  34. package/dist/pipeline/node-registry.js +119 -5
  35. package/dist/pipeline/nodes/flow-run-node.js +200 -173
  36. package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
  37. package/dist/pipeline/nodes/playbook-ensure-node.js +115 -0
  38. package/dist/pipeline/nodes/playbook-inventory-node.js +51 -0
  39. package/dist/pipeline/nodes/playbook-questions-form-node.js +166 -0
  40. package/dist/pipeline/nodes/playbook-write-node.js +243 -0
  41. package/dist/pipeline/nodes/project-guidance-node.js +69 -0
  42. package/dist/pipeline/plugin-loader.js +389 -0
  43. package/dist/pipeline/plugin-types.js +1 -0
  44. package/dist/pipeline/prompt-registry.js +4 -1
  45. package/dist/pipeline/prompt-runtime.js +6 -2
  46. package/dist/pipeline/registry.js +71 -4
  47. package/dist/pipeline/spec-compiler.js +1 -0
  48. package/dist/pipeline/spec-loader.js +14 -0
  49. package/dist/pipeline/spec-types.js +19 -0
  50. package/dist/pipeline/spec-validator.js +6 -0
  51. package/dist/pipeline/value-resolver.js +41 -2
  52. package/dist/playbook/practice-candidates.js +12 -0
  53. package/dist/playbook/repo-inventory.js +208 -0
  54. package/dist/plugin-sdk.js +1 -0
  55. package/dist/prompts.js +31 -0
  56. package/dist/runtime/artifact-registry.js +3 -0
  57. package/dist/runtime/execution-routing.js +25 -19
  58. package/dist/runtime/interactive-execution-routing.js +66 -57
  59. package/dist/runtime/playbook.js +485 -0
  60. package/dist/runtime/project-guidance.js +339 -0
  61. package/dist/structured-artifact-schema-registry.js +8 -0
  62. package/dist/structured-artifact-schemas.json +235 -0
  63. package/dist/structured-artifacts.js +7 -1
  64. package/docs/declarative-workflows.md +565 -0
  65. package/docs/example/.flows/examples/claude-example.json +50 -0
  66. package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
  67. package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
  68. package/docs/examples/.flows/claude-example.json +50 -0
  69. package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
  70. package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
  71. package/docs/features.md +77 -0
  72. package/docs/playbook.md +327 -0
  73. package/docs/plugin-sdk.md +731 -0
  74. 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
- let resolvedFlowParams = withCanonicalReviewLoopParams(flow.kind, flowParams);
36
- if (flow.kind === "design-review-flow") {
37
- const taskKey = String(flowParams["taskKey"] ?? "");
38
- if (taskKey) {
39
- const contract = resolveDesignReviewInputContract(taskKey);
40
- resolvedFlowParams = withArtifactLineageRefPaths({
41
- ...flowParams,
42
- iteration: contract.planningIteration,
43
- planningIteration: contract.planningIteration,
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
- if (executor === "codex") {
39
- const executor = context.executors.get("codex");
40
- const value = await executor.execute(executorContext, {
41
- prompt: params.prompt,
42
- ...(model ? { model } : {}),
43
- env: { ...context.env },
44
- }, executor.defaultConfig);
45
- return {
46
- value: {
47
- ...value,
48
- executor: "codex",
49
- },
50
- outputs: outputsForArtifacts(params.requiredArtifacts),
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
+ };