@copilot-swarm/core 0.0.0

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 (58) hide show
  1. package/defaults/swarm.config.yaml +62 -0
  2. package/dist/config.d.ts +19 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +124 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/constants.d.ts +22 -0
  7. package/dist/constants.d.ts.map +1 -0
  8. package/dist/constants.js +32 -0
  9. package/dist/constants.js.map +1 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +25 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/logger.d.ts +15 -0
  15. package/dist/logger.d.ts.map +1 -0
  16. package/dist/logger.js +36 -0
  17. package/dist/logger.js.map +1 -0
  18. package/dist/messages.d.ts +47 -0
  19. package/dist/messages.d.ts.map +1 -0
  20. package/dist/messages.js +57 -0
  21. package/dist/messages.js.map +1 -0
  22. package/dist/orchestrator.d.ts +14 -0
  23. package/dist/orchestrator.d.ts.map +1 -0
  24. package/dist/orchestrator.js +19 -0
  25. package/dist/orchestrator.js.map +1 -0
  26. package/dist/pipeline-config.d.ts +8 -0
  27. package/dist/pipeline-config.d.ts.map +1 -0
  28. package/dist/pipeline-config.js +230 -0
  29. package/dist/pipeline-config.js.map +1 -0
  30. package/dist/pipeline-config.test.d.ts +2 -0
  31. package/dist/pipeline-config.test.d.ts.map +1 -0
  32. package/dist/pipeline-config.test.js +132 -0
  33. package/dist/pipeline-config.test.js.map +1 -0
  34. package/dist/pipeline-engine.d.ts +20 -0
  35. package/dist/pipeline-engine.d.ts.map +1 -0
  36. package/dist/pipeline-engine.js +230 -0
  37. package/dist/pipeline-engine.js.map +1 -0
  38. package/dist/pipeline-types.d.ts +67 -0
  39. package/dist/pipeline-types.d.ts.map +1 -0
  40. package/dist/pipeline-types.js +7 -0
  41. package/dist/pipeline-types.js.map +1 -0
  42. package/dist/planning-engine.d.ts +15 -0
  43. package/dist/planning-engine.d.ts.map +1 -0
  44. package/dist/planning-engine.js +129 -0
  45. package/dist/planning-engine.js.map +1 -0
  46. package/dist/session.d.ts +26 -0
  47. package/dist/session.d.ts.map +1 -0
  48. package/dist/session.js +110 -0
  49. package/dist/session.js.map +1 -0
  50. package/dist/utils.d.ts +12 -0
  51. package/dist/utils.d.ts.map +1 -0
  52. package/dist/utils.js +40 -0
  53. package/dist/utils.js.map +1 -0
  54. package/dist/utils.test.d.ts +2 -0
  55. package/dist/utils.test.d.ts.map +1 -0
  56. package/dist/utils.test.js +66 -0
  57. package/dist/utils.test.js.map +1 -0
  58. package/package.json +44 -0
@@ -0,0 +1,230 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
+ const VALID_PHASES = new Set(["spec", "decompose", "design", "implement", "cross-model-review"]);
5
+ const CONFIG_FILE_NAME = "swarm.config.yaml";
6
+ function fail(msg) {
7
+ throw new Error(`Pipeline config error: ${msg}`);
8
+ }
9
+ function requireString(obj, key, context) {
10
+ const val = obj[key];
11
+ if (typeof val !== "string" || val === "") {
12
+ fail(`"${key}" must be a non-empty string in ${context}`);
13
+ }
14
+ return val;
15
+ }
16
+ function requirePositiveInt(obj, key, context) {
17
+ const val = obj[key];
18
+ if (typeof val !== "number" || !Number.isInteger(val) || val <= 0) {
19
+ fail(`"${key}" must be a positive integer in ${context}`);
20
+ }
21
+ return val;
22
+ }
23
+ function optionalString(obj, key) {
24
+ const val = obj[key];
25
+ if (val === undefined || val === null)
26
+ return undefined;
27
+ if (typeof val !== "string")
28
+ fail(`"${key}" must be a string if provided`);
29
+ return val;
30
+ }
31
+ function validateReviewStep(raw, context) {
32
+ if (typeof raw !== "object" || raw === null)
33
+ fail(`review step must be an object in ${context}`);
34
+ const obj = raw;
35
+ return {
36
+ agent: requireString(obj, "agent", context),
37
+ maxIterations: requirePositiveInt(obj, "maxIterations", context),
38
+ approvalKeyword: requireString(obj, "approvalKeyword", context),
39
+ clarificationKeyword: optionalString(obj, "clarificationKeyword"),
40
+ clarificationAgent: optionalString(obj, "clarificationAgent"),
41
+ };
42
+ }
43
+ function validateReviews(raw, context) {
44
+ if (!Array.isArray(raw))
45
+ fail(`"reviews" must be an array in ${context}`);
46
+ return raw.map((item, i) => validateReviewStep(item, `${context}.reviews[${i}]`));
47
+ }
48
+ function validateQa(raw, context) {
49
+ if (typeof raw !== "object" || raw === null)
50
+ fail(`"qa" must be an object in ${context}`);
51
+ const obj = raw;
52
+ return {
53
+ agent: requireString(obj, "agent", context),
54
+ maxIterations: requirePositiveInt(obj, "maxIterations", context),
55
+ approvalKeyword: requireString(obj, "approvalKeyword", context),
56
+ };
57
+ }
58
+ function validatePhase(raw, index) {
59
+ if (typeof raw !== "object" || raw === null)
60
+ fail(`pipeline[${index}] must be an object`);
61
+ const obj = raw;
62
+ const phase = requireString(obj, "phase", `pipeline[${index}]`);
63
+ if (!VALID_PHASES.has(phase)) {
64
+ fail(`Unknown phase type "${phase}" in pipeline[${index}]. Valid: ${[...VALID_PHASES].join(", ")}`);
65
+ }
66
+ const ctx = `pipeline[${index}] (phase: ${phase})`;
67
+ switch (phase) {
68
+ case "spec": {
69
+ return {
70
+ phase: "spec",
71
+ agent: requireString(obj, "agent", ctx),
72
+ reviews: validateReviews(obj.reviews, ctx),
73
+ };
74
+ }
75
+ case "decompose": {
76
+ return {
77
+ phase: "decompose",
78
+ agent: requireString(obj, "agent", ctx),
79
+ frontendMarker: requireString(obj, "frontendMarker", ctx),
80
+ };
81
+ }
82
+ case "design": {
83
+ return {
84
+ phase: "design",
85
+ condition: optionalString(obj, "condition"),
86
+ agent: requireString(obj, "agent", ctx),
87
+ clarificationAgent: optionalString(obj, "clarificationAgent"),
88
+ reviews: validateReviews(obj.reviews, ctx),
89
+ };
90
+ }
91
+ case "implement": {
92
+ const parallel = obj.parallel;
93
+ if (typeof parallel !== "boolean")
94
+ fail(`"parallel" must be a boolean in ${ctx}`);
95
+ return {
96
+ phase: "implement",
97
+ parallel,
98
+ agent: requireString(obj, "agent", ctx),
99
+ reviews: validateReviews(obj.reviews, ctx),
100
+ qa: obj.qa !== undefined ? validateQa(obj.qa, ctx) : undefined,
101
+ };
102
+ }
103
+ case "cross-model-review": {
104
+ return {
105
+ phase: "cross-model-review",
106
+ condition: optionalString(obj, "condition"),
107
+ agent: requireString(obj, "agent", ctx),
108
+ fixAgent: requireString(obj, "fixAgent", ctx),
109
+ maxIterations: requirePositiveInt(obj, "maxIterations", ctx),
110
+ approvalKeyword: requireString(obj, "approvalKeyword", ctx),
111
+ };
112
+ }
113
+ default:
114
+ fail(`Unhandled phase type "${phase}"`);
115
+ }
116
+ }
117
+ function validateAgents(raw) {
118
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
119
+ fail('"agents" must be an object mapping agent names to instruction sources');
120
+ }
121
+ const result = {};
122
+ for (const [key, value] of Object.entries(raw)) {
123
+ if (typeof value !== "string" || value === "") {
124
+ fail(`Agent "${key}" must have a non-empty string source (e.g. "builtin:pm" or a file path)`);
125
+ }
126
+ result[key] = value;
127
+ }
128
+ return result;
129
+ }
130
+ function validatePipeline(raw) {
131
+ if (!Array.isArray(raw) || raw.length === 0) {
132
+ fail('"pipeline" must be a non-empty array of phase definitions');
133
+ }
134
+ return raw.map((item, i) => validatePhase(item, i));
135
+ }
136
+ /** Cross-validate that every agent referenced in the pipeline is defined in agents. */
137
+ function validateAgentReferences(config) {
138
+ const defined = new Set(Object.keys(config.agents));
139
+ function check(agentName, context) {
140
+ if (!defined.has(agentName)) {
141
+ fail(`Agent "${agentName}" referenced in ${context} is not defined in "agents"`);
142
+ }
143
+ }
144
+ for (const phase of config.pipeline) {
145
+ const ctx = `phase "${phase.phase}"`;
146
+ switch (phase.phase) {
147
+ case "spec":
148
+ check(phase.agent, ctx);
149
+ for (const r of phase.reviews)
150
+ check(r.agent, `${ctx} review`);
151
+ break;
152
+ case "decompose":
153
+ check(phase.agent, ctx);
154
+ break;
155
+ case "design":
156
+ check(phase.agent, ctx);
157
+ if (phase.clarificationAgent)
158
+ check(phase.clarificationAgent, ctx);
159
+ for (const r of phase.reviews) {
160
+ check(r.agent, `${ctx} review`);
161
+ if (r.clarificationAgent)
162
+ check(r.clarificationAgent, `${ctx} review clarification`);
163
+ }
164
+ break;
165
+ case "implement":
166
+ check(phase.agent, ctx);
167
+ for (const r of phase.reviews)
168
+ check(r.agent, `${ctx} review`);
169
+ if (phase.qa)
170
+ check(phase.qa.agent, `${ctx} qa`);
171
+ break;
172
+ case "cross-model-review":
173
+ check(phase.agent, ctx);
174
+ check(phase.fixAgent, `${ctx} fixAgent`);
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ export function parsePipelineConfig(raw) {
180
+ if (typeof raw !== "object" || raw === null) {
181
+ fail("Config must be a YAML object");
182
+ }
183
+ const obj = raw;
184
+ const config = {
185
+ primaryModel: typeof obj.primaryModel === "string" ? obj.primaryModel : "claude-opus-4-6-fast",
186
+ reviewModel: typeof obj.reviewModel === "string" ? obj.reviewModel : "gpt-5.2-codex",
187
+ agents: validateAgents(obj.agents),
188
+ pipeline: validatePipeline(obj.pipeline),
189
+ };
190
+ validateAgentReferences(config);
191
+ return config;
192
+ }
193
+ /**
194
+ * Load pipeline config from the repo root, falling back to the built-in default.
195
+ * Env vars PRIMARY_MODEL and REVIEW_MODEL override the YAML values.
196
+ */
197
+ export function loadPipelineConfig(repoRoot) {
198
+ const repoConfigPath = path.join(repoRoot, CONFIG_FILE_NAME);
199
+ const defaultConfigPath = path.join(import.meta.dirname, "..", "defaults", CONFIG_FILE_NAME);
200
+ let yamlContent;
201
+ let source;
202
+ if (fs.existsSync(repoConfigPath)) {
203
+ yamlContent = fs.readFileSync(repoConfigPath, "utf-8");
204
+ source = repoConfigPath;
205
+ }
206
+ else if (fs.existsSync(defaultConfigPath)) {
207
+ yamlContent = fs.readFileSync(defaultConfigPath, "utf-8");
208
+ source = defaultConfigPath;
209
+ }
210
+ else {
211
+ fail(`No ${CONFIG_FILE_NAME} found in repo root or package defaults`);
212
+ }
213
+ let parsed;
214
+ try {
215
+ parsed = parseYaml(yamlContent);
216
+ }
217
+ catch (err) {
218
+ fail(`Failed to parse ${source}: ${err instanceof Error ? err.message : String(err)}`);
219
+ }
220
+ const config = parsePipelineConfig(parsed);
221
+ // Env var overrides for models
222
+ const envPrimary = process.env.PRIMARY_MODEL;
223
+ const envReview = process.env.REVIEW_MODEL;
224
+ return {
225
+ ...config,
226
+ primaryModel: envPrimary && envPrimary !== "" ? envPrimary : config.primaryModel,
227
+ reviewModel: envReview && envReview !== "" ? envReview : config.reviewModel,
228
+ };
229
+ }
230
+ //# sourceMappingURL=pipeline-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-config.js","sourceRoot":"","sources":["../src/pipeline-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAa1C,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC;AACjG,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAE7C,SAAS,IAAI,CAAC,GAAW;IACvB,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,aAAa,CAAC,GAA4B,EAAE,GAAW,EAAE,OAAe;IAC/E,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,GAAG,mCAAmC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,kBAAkB,CAAC,GAA4B,EAAE,GAAW,EAAE,OAAe;IACpF,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,mCAAmC,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,GAA4B,EAAE,GAAW;IAC/D,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACrB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACxD,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,IAAI,CAAC,IAAI,GAAG,gCAAgC,CAAC,CAAC;IAC3E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAY,EAAE,OAAe;IACvD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,IAAI,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC;IACjG,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO;QACL,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAC3C,aAAa,EAAE,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC;QAChE,eAAe,EAAE,aAAa,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,CAAC;QAC/D,oBAAoB,EAAE,cAAc,CAAC,GAAG,EAAE,sBAAsB,CAAC;QACjE,kBAAkB,EAAE,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAY,EAAE,OAAe;IACpD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,IAAI,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;IAC1E,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,GAAG,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,UAAU,CAAC,GAAY,EAAE,OAAe;IAC/C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,IAAI,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;IAC1F,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO;QACL,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC;QAC3C,aAAa,EAAE,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC;QAChE,eAAe,EAAE,aAAa,CAAC,GAAG,EAAE,iBAAiB,EAAE,OAAO,CAAC;KAChE,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAY,EAAE,KAAa;IAChD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,IAAI,CAAC,YAAY,KAAK,qBAAqB,CAAC,CAAC;IAC1F,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,KAAK,GAAG,CAAC,CAAC;IAEhE,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,uBAAuB,KAAK,iBAAiB,KAAK,aAAa,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,KAAK,aAAa,KAAK,GAAG,CAAC;IAEnD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,OAAO;gBACL,KAAK,EAAE,MAAM;gBACb,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC;gBACvC,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;aACjB,CAAC;QAC9B,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,OAAO;gBACL,KAAK,EAAE,WAAW;gBAClB,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC;gBACvC,cAAc,EAAE,aAAa,CAAC,GAAG,EAAE,gBAAgB,EAAE,GAAG,CAAC;aAC3B,CAAC;QACnC,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,OAAO;gBACL,KAAK,EAAE,QAAQ;gBACf,SAAS,EAAE,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC;gBAC3C,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC;gBACvC,kBAAkB,EAAE,cAAc,CAAC,GAAG,EAAE,oBAAoB,CAAC;gBAC7D,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;aACf,CAAC;QAChC,CAAC;QACD,KAAK,WAAW,CAAC,CAAC,CAAC;YACjB,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;YAC9B,IAAI,OAAO,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,mCAAmC,GAAG,EAAE,CAAC,CAAC;YAClF,OAAO;gBACL,KAAK,EAAE,WAAW;gBAClB,QAAQ;gBACR,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC;gBACvC,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;gBAC1C,EAAE,EAAE,GAAG,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;aAChC,CAAC;QACnC,CAAC;QACD,KAAK,oBAAoB,CAAC,CAAC,CAAC;YAC1B,OAAO;gBACL,KAAK,EAAE,oBAAoB;gBAC3B,SAAS,EAAE,cAAc,CAAC,GAAG,EAAE,WAAW,CAAC;gBAC3C,KAAK,EAAE,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC;gBACvC,QAAQ,EAAE,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC;gBAC7C,aAAa,EAAE,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,CAAC;gBAC5D,eAAe,EAAE,aAAa,CAAC,GAAG,EAAE,iBAAiB,EAAE,GAAG,CAAC;aACtB,CAAC;QAC1C,CAAC;QACD;YACE,IAAI,CAAC,yBAAyB,KAAK,GAAG,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,uEAAuE,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC,EAAE,CAAC;QAC1E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC9C,IAAI,CAAC,UAAU,GAAG,0EAA0E,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAY;IACpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,2DAA2D,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,uFAAuF;AACvF,SAAS,uBAAuB,CAAC,MAAsB;IACrD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpD,SAAS,KAAK,CAAC,SAAiB,EAAE,OAAe;QAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,UAAU,SAAS,mBAAmB,OAAO,6BAA6B,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,UAAU,KAAK,CAAC,KAAK,GAAG,CAAC;QACrC,QAAQ,KAAK,CAAC,KAAK,EAAE,CAAC;YACpB,KAAK,MAAM;gBACT,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACxB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO;oBAAE,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;gBAC/D,MAAM;YACR,KAAK,WAAW;gBACd,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACxB,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACxB,IAAI,KAAK,CAAC,kBAAkB;oBAAE,KAAK,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;gBACnE,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAC9B,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;oBAChC,IAAI,CAAC,CAAC,kBAAkB;wBAAE,KAAK,CAAC,CAAC,CAAC,kBAAkB,EAAE,GAAG,GAAG,uBAAuB,CAAC,CAAC;gBACvF,CAAC;gBACD,MAAM;YACR,KAAK,WAAW;gBACd,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACxB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,OAAO;oBAAE,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC,CAAC;gBAC/D,IAAI,KAAK,CAAC,EAAE;oBAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;gBACjD,MAAM;YACR,KAAK,oBAAoB;gBACvB,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBACxB,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,WAAW,CAAC,CAAC;gBACzC,MAAM;QACV,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACvC,CAAC;IACD,MAAM,GAAG,GAAG,GAA8B,CAAC;IAE3C,MAAM,MAAM,GAAmB;QAC7B,YAAY,EAAE,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,sBAAsB;QAC9F,WAAW,EAAE,OAAO,GAAG,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe;QACpF,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAClC,QAAQ,EAAE,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;KACzC,CAAC;IAEF,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAC7D,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC;IAE7F,IAAI,WAAmB,CAAC;IACxB,IAAI,MAAc,CAAC;IAEnB,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAClC,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;QACvD,MAAM,GAAG,cAAc,CAAC;IAC1B,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;QAC5C,WAAW,GAAG,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAC;QAC1D,MAAM,GAAG,iBAAiB,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,MAAM,gBAAgB,yCAAyC,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,mBAAmB,MAAM,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE3C,+BAA+B;IAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC7C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC3C,OAAO;QACL,GAAG,MAAM;QACT,YAAY,EAAE,UAAU,IAAI,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY;QAChF,WAAW,EAAE,SAAS,IAAI,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW;KAC5E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pipeline-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-config.test.d.ts","sourceRoot":"","sources":["../src/pipeline-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,132 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parsePipelineConfig } from "./pipeline-config.js";
3
+ const validAgents = {
4
+ pm: "builtin:pm",
5
+ reviewer: "builtin:pm-reviewer",
6
+ engineer: "builtin:engineer",
7
+ "code-reviewer": "builtin:eng-code-reviewer",
8
+ tester: "builtin:tester",
9
+ cross: "builtin:cross-model-reviewer",
10
+ };
11
+ function makeConfig(overrides = {}) {
12
+ return {
13
+ primaryModel: "test-model",
14
+ reviewModel: "test-review",
15
+ agents: validAgents,
16
+ pipeline: [
17
+ {
18
+ phase: "spec",
19
+ agent: "pm",
20
+ reviews: [{ agent: "reviewer", maxIterations: 2, approvalKeyword: "APPROVED" }],
21
+ },
22
+ { phase: "decompose", agent: "pm", frontendMarker: "[FRONTEND]" },
23
+ {
24
+ phase: "implement",
25
+ parallel: true,
26
+ agent: "engineer",
27
+ reviews: [{ agent: "code-reviewer", maxIterations: 3, approvalKeyword: "APPROVED" }],
28
+ qa: { agent: "tester", maxIterations: 5, approvalKeyword: "ALL_PASSED" },
29
+ },
30
+ ],
31
+ ...overrides,
32
+ };
33
+ }
34
+ describe("parsePipelineConfig", () => {
35
+ it("parses a valid config", () => {
36
+ const config = parsePipelineConfig(makeConfig());
37
+ expect(config.primaryModel).toBe("test-model");
38
+ expect(config.reviewModel).toBe("test-review");
39
+ expect(config.pipeline).toHaveLength(3);
40
+ expect(config.pipeline[0].phase).toBe("spec");
41
+ });
42
+ it("defaults models when not provided", () => {
43
+ const raw = makeConfig();
44
+ delete raw.primaryModel;
45
+ delete raw.reviewModel;
46
+ const config = parsePipelineConfig(raw);
47
+ expect(config.primaryModel).toBe("claude-opus-4-6-fast");
48
+ expect(config.reviewModel).toBe("gpt-5.2-codex");
49
+ });
50
+ it("rejects missing agents map", () => {
51
+ expect(() => parsePipelineConfig(makeConfig({ agents: null }))).toThrow("agents");
52
+ });
53
+ it("rejects empty pipeline", () => {
54
+ expect(() => parsePipelineConfig(makeConfig({ pipeline: [] }))).toThrow("non-empty array");
55
+ });
56
+ it("rejects unknown phase type", () => {
57
+ expect(() => parsePipelineConfig(makeConfig({ pipeline: [{ phase: "unknown", agent: "pm" }] }))).toThrow("Unknown phase type");
58
+ });
59
+ it("rejects agent reference not defined in agents map", () => {
60
+ expect(() => parsePipelineConfig(makeConfig({
61
+ pipeline: [
62
+ {
63
+ phase: "spec",
64
+ agent: "nonexistent",
65
+ reviews: [],
66
+ },
67
+ ],
68
+ }))).toThrow('Agent "nonexistent"');
69
+ });
70
+ it("rejects review step with missing maxIterations", () => {
71
+ expect(() => parsePipelineConfig(makeConfig({
72
+ pipeline: [
73
+ {
74
+ phase: "spec",
75
+ agent: "pm",
76
+ reviews: [{ agent: "reviewer", approvalKeyword: "APPROVED" }],
77
+ },
78
+ ],
79
+ }))).toThrow("maxIterations");
80
+ });
81
+ it("rejects non-boolean parallel in implement phase", () => {
82
+ expect(() => parsePipelineConfig(makeConfig({
83
+ pipeline: [
84
+ {
85
+ phase: "implement",
86
+ parallel: "yes",
87
+ agent: "engineer",
88
+ reviews: [],
89
+ },
90
+ ],
91
+ }))).toThrow("parallel");
92
+ });
93
+ it("validates cross-model-review phase", () => {
94
+ const config = parsePipelineConfig(makeConfig({
95
+ pipeline: [
96
+ {
97
+ phase: "cross-model-review",
98
+ agent: "cross",
99
+ fixAgent: "engineer",
100
+ maxIterations: 3,
101
+ approvalKeyword: "APPROVED",
102
+ },
103
+ ],
104
+ }));
105
+ expect(config.pipeline[0].phase).toBe("cross-model-review");
106
+ });
107
+ it("validates design phase with condition", () => {
108
+ const agents = { ...validAgents, designer: "builtin:designer", "design-reviewer": "builtin:design-reviewer" };
109
+ const config = parsePipelineConfig({
110
+ agents,
111
+ pipeline: [
112
+ {
113
+ phase: "design",
114
+ condition: "hasFrontendTasks",
115
+ agent: "designer",
116
+ clarificationAgent: "pm",
117
+ reviews: [{ agent: "design-reviewer", maxIterations: 3, approvalKeyword: "APPROVED" }],
118
+ },
119
+ ],
120
+ });
121
+ const phase = config.pipeline[0];
122
+ expect(phase.phase).toBe("design");
123
+ if (phase.phase === "design") {
124
+ expect(phase.condition).toBe("hasFrontendTasks");
125
+ }
126
+ });
127
+ it("rejects non-object input", () => {
128
+ expect(() => parsePipelineConfig("not an object")).toThrow("YAML object");
129
+ expect(() => parsePipelineConfig(null)).toThrow("YAML object");
130
+ });
131
+ });
132
+ //# sourceMappingURL=pipeline-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-config.test.js","sourceRoot":"","sources":["../src/pipeline-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { SwarmConfig } from "./config.js";
2
+ import type { Logger } from "./logger.js";
3
+ import type { PipelineConfig } from "./pipeline-types.js";
4
+ export declare class PipelineEngine {
5
+ private readonly config;
6
+ private readonly pipeline;
7
+ private readonly logger;
8
+ private readonly sessions;
9
+ constructor(config: SwarmConfig, pipeline: PipelineConfig, logger: Logger);
10
+ start(): Promise<void>;
11
+ stop(): Promise<void>;
12
+ execute(): Promise<void>;
13
+ private executeSpec;
14
+ private executeDecompose;
15
+ private executeDesign;
16
+ private executeImplement;
17
+ private executeCrossModelReview;
18
+ private runReviewLoop;
19
+ }
20
+ //# sourceMappingURL=pipeline-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-engine.d.ts","sourceRoot":"","sources":["../src/pipeline-engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAKV,cAAc,EAGf,MAAM,qBAAqB,CAAC;AAY7B,qBAAa,cAAc;IAIvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;gBAGvB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM;IAK3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAIrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAsChB,WAAW;YAiBX,gBAAgB;YAoBhB,aAAa;YAmEb,gBAAgB;YAqEhB,uBAAuB;YAgDvB,aAAa;CAwB5B"}
@@ -0,0 +1,230 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { msg } from "./messages.js";
4
+ import { SessionManager } from "./session.js";
5
+ import { hasFrontendWork, isFrontendTask, parseJsonArray, responseContains, writeRoleSummary } from "./utils.js";
6
+ export class PipelineEngine {
7
+ config;
8
+ pipeline;
9
+ logger;
10
+ sessions;
11
+ constructor(config, pipeline, logger) {
12
+ this.config = config;
13
+ this.pipeline = pipeline;
14
+ this.logger = logger;
15
+ this.sessions = new SessionManager(config, pipeline, logger);
16
+ }
17
+ async start() {
18
+ await this.sessions.start();
19
+ }
20
+ async stop() {
21
+ await this.sessions.stop();
22
+ }
23
+ async execute() {
24
+ this.logger.info(msg.configLoaded(this.pipeline.primaryModel, this.pipeline.reviewModel, this.config.verbose));
25
+ const ctx = { spec: "", tasks: [], designSpec: "", streamResults: [] };
26
+ for (const phase of this.pipeline.pipeline) {
27
+ switch (phase.phase) {
28
+ case "spec":
29
+ ctx.spec = await this.executeSpec(phase);
30
+ break;
31
+ case "decompose":
32
+ ctx.tasks = await this.executeDecompose(phase, ctx);
33
+ break;
34
+ case "design":
35
+ ctx.designSpec = await this.executeDesign(phase, ctx);
36
+ break;
37
+ case "implement":
38
+ ctx.streamResults = await this.executeImplement(phase, ctx);
39
+ break;
40
+ case "cross-model-review":
41
+ ctx.streamResults = await this.executeCrossModelReview(phase, ctx);
42
+ break;
43
+ }
44
+ }
45
+ // Final summary
46
+ this.logger.info(msg.swarmComplete);
47
+ const timestamp = new Date().toISOString();
48
+ const summary = `# Swarm Run Summary\n\n**Timestamp:** ${timestamp}\n**Tasks:** ${ctx.tasks.length}\n\n` +
49
+ `${ctx.streamResults.map((r, i) => `## Stream ${i + 1}\n\n${r}`).join("\n\n---\n\n")}\n`;
50
+ const docPath = path.join(this.config.repoRoot, this.config.docDir);
51
+ await fs.mkdir(docPath, { recursive: true });
52
+ await fs.writeFile(path.join(docPath, this.config.summaryFileName), summary);
53
+ }
54
+ // --- SPEC PHASE ---
55
+ async executeSpec(phase) {
56
+ this.logger.info(msg.pmPhaseStart);
57
+ this.logger.info(msg.pmDrafting);
58
+ let spec = await this.sessions.callIsolated(phase.agent, this.config.issueBody);
59
+ for (const review of phase.reviews) {
60
+ this.logger.info(msg.reviewPhase(review.agent));
61
+ spec = await this.runReviewLoop(review, spec, phase.agent, (content) => `Review this specification:\n${content}`);
62
+ }
63
+ await writeRoleSummary(this.config, phase.agent, `## Final Specification\n\n${spec}`);
64
+ return spec;
65
+ }
66
+ // --- DECOMPOSE PHASE ---
67
+ async executeDecompose(phase, ctx) {
68
+ this.logger.info(msg.taskDecomposition);
69
+ const marker = phase.frontendMarker;
70
+ const prompt = `Break this spec into 2-3 independent JSON tasks. Mark frontend tasks with ${marker}. ` +
71
+ `Respond with ONLY a JSON array, no other text. Format: ["${marker} Task 1", "Task 2"]\nSpec:\n${ctx.spec}`;
72
+ const raw = await this.sessions.callIsolated(phase.agent, prompt);
73
+ const tasks = parseJsonArray(raw);
74
+ this.logger.info(msg.tasksResult(tasks));
75
+ await writeRoleSummary(this.config, `${phase.agent}-tasks`, `## Decomposed Tasks\n\n${tasks.map((t, i) => `${i + 1}. ${t}`).join("\n")}`);
76
+ return tasks;
77
+ }
78
+ // --- DESIGN PHASE ---
79
+ async executeDesign(phase, ctx) {
80
+ if (phase.condition === "hasFrontendTasks" && !hasFrontendWork(ctx.tasks)) {
81
+ return ctx.designSpec;
82
+ }
83
+ this.logger.info(msg.designPhaseStart);
84
+ const session = await this.sessions.createAgentSession(phase.agent);
85
+ try {
86
+ this.logger.info(msg.designPhase);
87
+ let design = await this.sessions.send(session, `Create a detailed UI/UX design specification based on this spec:\n${ctx.spec}\n\n` +
88
+ `Include: component hierarchy, layout, interactions, states, and accessibility considerations.`);
89
+ if (phase.clarificationAgent && responseContains(design, "CLARIFICATION_NEEDED")) {
90
+ this.logger.info(msg.designerClarification);
91
+ const clarification = await this.sessions.callIsolated(phase.clarificationAgent, `The designer needs clarification:\n${design}`);
92
+ design = await this.sessions.send(session, `PM Clarification:\n${clarification}\n\nRevise the design.`);
93
+ }
94
+ for (const review of phase.reviews) {
95
+ this.logger.info(msg.reviewPhase(review.agent));
96
+ const maxIter = review.maxIterations;
97
+ for (let i = 1; i <= maxIter; i++) {
98
+ this.logger.info(msg.reviewIteration(i, maxIter));
99
+ const feedback = await this.sessions.callIsolated(review.agent, `Review this design specification:\n${design}`);
100
+ if (responseContains(feedback, review.approvalKeyword)) {
101
+ this.logger.info(msg.approved(review.agent));
102
+ break;
103
+ }
104
+ if (review.clarificationKeyword && responseContains(feedback, review.clarificationKeyword)) {
105
+ const clarAgent = review.clarificationAgent ?? phase.clarificationAgent;
106
+ if (clarAgent) {
107
+ this.logger.info(msg.reviewerClarification);
108
+ const clar = await this.sessions.callIsolated(clarAgent, `The design reviewer needs clarification:\n${feedback}`);
109
+ design = await this.sessions.send(session, `Review feedback:\n${feedback}\n\nPM Clarification:\n${clar}\n\nRevise the design.`);
110
+ }
111
+ }
112
+ else {
113
+ this.logger.info(msg.codeFeedback(feedback.substring(0, 80)));
114
+ design = await this.sessions.send(session, `Review feedback:\n${feedback}\n\nRevise the design.`);
115
+ }
116
+ }
117
+ }
118
+ await writeRoleSummary(this.config, phase.agent, design);
119
+ return design;
120
+ }
121
+ finally {
122
+ await session.destroy();
123
+ }
124
+ }
125
+ // --- IMPLEMENT PHASE ---
126
+ async executeImplement(phase, ctx) {
127
+ this.logger.info(msg.launchingStreams(ctx.tasks.length));
128
+ const runStream = async (task, idx) => {
129
+ const label = msg.streamLabel(idx);
130
+ this.logger.info(msg.streamStart(label, task));
131
+ const session = await this.sessions.createAgentSession(phase.agent);
132
+ try {
133
+ this.logger.info(msg.streamEngineering(label));
134
+ const engineeringPrompt = isFrontendTask(task)
135
+ ? `Spec:\n${ctx.spec}\n\nDesign:\n${ctx.designSpec}\n\nTask:\n${task}\n\nImplement this task.`
136
+ : `Spec:\n${ctx.spec}\n\nTask:\n${task}\n\nImplement this task.`;
137
+ let code = await this.sessions.send(session, engineeringPrompt);
138
+ // Reviews
139
+ for (const review of phase.reviews) {
140
+ this.logger.info(msg.streamCodeReview(label, review.agent));
141
+ const maxIter = review.maxIterations;
142
+ for (let i = 1; i <= maxIter; i++) {
143
+ this.logger.info(msg.reviewIteration(i, maxIter));
144
+ const feedback = await this.sessions.callIsolated(review.agent, `Review this implementation:\n${code}`);
145
+ if (responseContains(feedback, review.approvalKeyword)) {
146
+ this.logger.info(msg.codeApproved);
147
+ break;
148
+ }
149
+ this.logger.info(msg.codeFeedback(feedback.substring(0, 80)));
150
+ code = await this.sessions.send(session, `Code review feedback:\n${feedback}\n\nFix all issues.`);
151
+ }
152
+ }
153
+ // QA
154
+ if (phase.qa) {
155
+ this.logger.info(msg.streamQa(label));
156
+ const maxQa = phase.qa.maxIterations;
157
+ for (let i = 1; i <= maxQa; i++) {
158
+ this.logger.info(msg.qaIteration(i, maxQa));
159
+ const testReport = await this.sessions.callIsolated(phase.qa.agent, `Spec:\n${ctx.spec}\n\nImplementation:\n${code}\n\nValidate the implementation against the spec.`);
160
+ if (responseContains(testReport, phase.qa.approvalKeyword)) {
161
+ this.logger.info(msg.allTestsPassed);
162
+ break;
163
+ }
164
+ this.logger.info(msg.defectsFound);
165
+ code = await this.sessions.send(session, `QA Report:\n${testReport}\n\nFix all reported issues.`);
166
+ }
167
+ }
168
+ await writeRoleSummary(this.config, `engineer-stream-${idx + 1}`, code);
169
+ return code;
170
+ }
171
+ finally {
172
+ await session.destroy();
173
+ }
174
+ };
175
+ if (phase.parallel) {
176
+ return Promise.all(ctx.tasks.map((task, idx) => runStream(task, idx)));
177
+ }
178
+ const results = [];
179
+ for (let i = 0; i < ctx.tasks.length; i++) {
180
+ results.push(await runStream(ctx.tasks[i], i));
181
+ }
182
+ return results;
183
+ }
184
+ // --- CROSS-MODEL REVIEW ---
185
+ async executeCrossModelReview(phase, ctx) {
186
+ if (phase.condition === "differentReviewModel" && this.pipeline.reviewModel === this.pipeline.primaryModel) {
187
+ this.logger.info(msg.crossModelSkipped);
188
+ return ctx.streamResults;
189
+ }
190
+ this.logger.info(msg.crossModelStart(this.pipeline.reviewModel));
191
+ const maxIter = phase.maxIterations;
192
+ const reviewed = await Promise.all(ctx.streamResults.map(async (code, idx) => {
193
+ const label = msg.streamLabel(idx);
194
+ this.logger.info(msg.crossModelStreamReview(label));
195
+ let current = code;
196
+ for (let i = 1; i <= maxIter; i++) {
197
+ this.logger.info(msg.crossModelIteration(i, maxIter, this.pipeline.reviewModel));
198
+ const feedback = await this.sessions.callIsolated(phase.agent, `Spec:\n${ctx.spec}\n\nReview this implementation from scratch. ` +
199
+ `You are using a different model than the one that wrote this code — look for blind spots.\n\n` +
200
+ `Implementation:\n${current}`, this.pipeline.reviewModel);
201
+ if (responseContains(feedback, phase.approvalKeyword)) {
202
+ this.logger.info(msg.crossModelApproved);
203
+ break;
204
+ }
205
+ this.logger.info(msg.crossModelIssues);
206
+ current = await this.sessions.callIsolated(phase.fixAgent, `Cross-model review feedback:\n${feedback}\n\nOriginal implementation:\n${current}\n\nFix all reported issues.`);
207
+ }
208
+ return current;
209
+ }));
210
+ await writeRoleSummary(this.config, "cross-model-review", reviewed.map((r, i) => `## Stream ${i + 1}\n\n${r}`).join("\n\n---\n\n"));
211
+ return reviewed;
212
+ }
213
+ // --- GENERIC REVIEW LOOP ---
214
+ async runReviewLoop(review, content, authorAgent, buildPrompt) {
215
+ const maxIter = review.maxIterations;
216
+ let current = content;
217
+ for (let i = 1; i <= maxIter; i++) {
218
+ this.logger.info(msg.reviewIteration(i, maxIter));
219
+ const feedback = await this.sessions.callIsolated(review.agent, buildPrompt(current));
220
+ if (responseContains(feedback, review.approvalKeyword)) {
221
+ this.logger.info(msg.approved(review.agent));
222
+ break;
223
+ }
224
+ this.logger.info(msg.feedbackReceived(feedback.substring(0, 80)));
225
+ current = await this.sessions.callIsolated(authorAgent, `Previous content:\n${current}\n\nReview feedback:\n${feedback}\n\nRevise accordingly.`);
226
+ }
227
+ return current;
228
+ }
229
+ }
230
+ //# sourceMappingURL=pipeline-engine.js.map