iosm-cli 0.2.4 → 0.2.5

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 (65) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +23 -17
  3. package/dist/core/agent-profiles.d.ts +1 -0
  4. package/dist/core/agent-profiles.d.ts.map +1 -1
  5. package/dist/core/agent-profiles.js +10 -6
  6. package/dist/core/agent-profiles.js.map +1 -1
  7. package/dist/core/agent-session.d.ts +1 -1
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +6 -2
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/agent-teams.d.ts.map +1 -1
  12. package/dist/core/agent-teams.js +90 -19
  13. package/dist/core/agent-teams.js.map +1 -1
  14. package/dist/core/footer-data-provider.d.ts +6 -1
  15. package/dist/core/footer-data-provider.d.ts.map +1 -1
  16. package/dist/core/footer-data-provider.js +9 -0
  17. package/dist/core/footer-data-provider.js.map +1 -1
  18. package/dist/core/parallel-task-agent.d.ts +23 -1
  19. package/dist/core/parallel-task-agent.d.ts.map +1 -1
  20. package/dist/core/parallel-task-agent.js +110 -20
  21. package/dist/core/parallel-task-agent.js.map +1 -1
  22. package/dist/core/shared-memory.d.ts +2 -2
  23. package/dist/core/shared-memory.d.ts.map +1 -1
  24. package/dist/core/shared-memory.js +220 -91
  25. package/dist/core/shared-memory.js.map +1 -1
  26. package/dist/core/singular.d.ts.map +1 -1
  27. package/dist/core/singular.js +3 -1
  28. package/dist/core/singular.js.map +1 -1
  29. package/dist/core/subagents.d.ts +1 -1
  30. package/dist/core/subagents.d.ts.map +1 -1
  31. package/dist/core/subagents.js +11 -3
  32. package/dist/core/subagents.js.map +1 -1
  33. package/dist/core/swarm/planner.d.ts.map +1 -1
  34. package/dist/core/swarm/planner.js +200 -12
  35. package/dist/core/swarm/planner.js.map +1 -1
  36. package/dist/core/swarm/scheduler.d.ts +2 -0
  37. package/dist/core/swarm/scheduler.d.ts.map +1 -1
  38. package/dist/core/swarm/scheduler.js +87 -6
  39. package/dist/core/swarm/scheduler.js.map +1 -1
  40. package/dist/core/system-prompt.d.ts.map +1 -1
  41. package/dist/core/system-prompt.js +1 -0
  42. package/dist/core/system-prompt.js.map +1 -1
  43. package/dist/core/tools/ast-grep.d.ts.map +1 -1
  44. package/dist/core/tools/ast-grep.js +2 -0
  45. package/dist/core/tools/ast-grep.js.map +1 -1
  46. package/dist/core/tools/shared-memory.d.ts.map +1 -1
  47. package/dist/core/tools/shared-memory.js +34 -6
  48. package/dist/core/tools/shared-memory.js.map +1 -1
  49. package/dist/core/tools/task.d.ts.map +1 -1
  50. package/dist/core/tools/task.js +464 -73
  51. package/dist/core/tools/task.js.map +1 -1
  52. package/dist/core/tools/yq.d.ts.map +1 -1
  53. package/dist/core/tools/yq.js +2 -0
  54. package/dist/core/tools/yq.js.map +1 -1
  55. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  56. package/dist/modes/interactive/components/footer.js +2 -1
  57. package/dist/modes/interactive/components/footer.js.map +1 -1
  58. package/dist/modes/interactive/interactive-mode.d.ts +13 -0
  59. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  60. package/dist/modes/interactive/interactive-mode.js +756 -74
  61. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  62. package/docs/cli-reference.md +4 -0
  63. package/docs/interactive-mode.md +2 -0
  64. package/docs/orchestration-and-subagents.md +5 -0
  65. package/package.json +1 -1
@@ -37,6 +37,110 @@ function spreadTouches(touches, index) {
37
37
  }
38
38
  return compact(result);
39
39
  }
40
+ const CODE_LIKE_EXTENSIONS = /\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|json|ya?ml|toml|sql|css|scss|html)$/i;
41
+ const DOC_EXTENSIONS = /\.(?:md|markdown|txt|rst|adoc)$/i;
42
+ function touchPriority(path) {
43
+ const normalized = path.trim().replace(/\\/g, "/").replace(/^\.\//, "").toLowerCase();
44
+ let score = 0;
45
+ if (/^(?:src|app|packages|lib|server|client|services|api)\//.test(normalized))
46
+ score += 4;
47
+ if (/^(?:test|tests|__tests__)\//.test(normalized))
48
+ score += 3;
49
+ if (/\.(?:test|spec)\./.test(normalized))
50
+ score += 2;
51
+ if (CODE_LIKE_EXTENSIONS.test(normalized))
52
+ score += 2;
53
+ if (DOC_EXTENSIONS.test(normalized))
54
+ score -= 3;
55
+ if (/^(?:docs|assets)\//.test(normalized))
56
+ score -= 2;
57
+ return score;
58
+ }
59
+ function prioritizeTouches(paths) {
60
+ const compacted = compact(paths);
61
+ if (compacted.length <= 1)
62
+ return compacted;
63
+ const ranked = compacted
64
+ .map((path) => ({ path, score: touchPriority(path) }))
65
+ .sort((a, b) => b.score - a.score || a.path.localeCompare(b.path))
66
+ .map((item) => item.path);
67
+ const hasCodeLike = ranked.some((path) => touchPriority(path) > 0);
68
+ return hasCodeLike ? ranked : compacted;
69
+ }
70
+ function deriveWorkstreamCount(request, touches) {
71
+ const normalized = request.toLowerCase();
72
+ const words = request
73
+ .trim()
74
+ .split(/\s+/)
75
+ .filter((token) => token.length > 0).length;
76
+ const conjunctions = (normalized.match(/\b(?:and|и|plus|also|then)\b/g)?.length ?? 0) +
77
+ (normalized.match(/[;,/]/g)?.length ?? 0);
78
+ const complexitySignal = /(audit|security|refactor|rewrite|migrat|hardening|parallel|orchestr|multi|complex|reliability|performance)/.test(normalized);
79
+ let workstreams = 1;
80
+ if (touches.length >= 6)
81
+ workstreams = 2;
82
+ if (touches.length >= 10)
83
+ workstreams = 3;
84
+ if (touches.length >= 14)
85
+ workstreams = 4;
86
+ if (conjunctions >= 2)
87
+ workstreams = Math.max(workstreams, 2);
88
+ if (complexitySignal && words >= 2)
89
+ workstreams = Math.max(workstreams, 2);
90
+ if (complexitySignal && touches.length >= 8)
91
+ workstreams = Math.max(workstreams, 3);
92
+ // Keep fan-out bounded for predictable scheduler behavior.
93
+ return Math.max(1, Math.min(4, workstreams));
94
+ }
95
+ function clusterTouchKey(touch) {
96
+ const normalized = touch.trim().replace(/\\/g, "/").replace(/^\.\//, "");
97
+ if (!normalized)
98
+ return "root";
99
+ const parts = normalized.split("/").filter((part) => part.length > 0);
100
+ if (parts.length === 0)
101
+ return "root";
102
+ if (parts.length === 1)
103
+ return parts[0];
104
+ return `${parts[0]}/${parts[1]}`;
105
+ }
106
+ function partitionTouchesForWorkstreams(touches, requestedStreams) {
107
+ const normalizedTouches = compact(touches);
108
+ if (requestedStreams <= 1)
109
+ return [normalizedTouches];
110
+ const streamCount = Math.max(1, Math.min(requestedStreams, normalizedTouches.length > 0 ? normalizedTouches.length : requestedStreams));
111
+ if (streamCount <= 1)
112
+ return [normalizedTouches];
113
+ const groupsByKey = new Map();
114
+ for (const touch of normalizedTouches) {
115
+ const key = clusterTouchKey(touch);
116
+ const existing = groupsByKey.get(key);
117
+ if (existing) {
118
+ existing.push(touch);
119
+ }
120
+ else {
121
+ groupsByKey.set(key, [touch]);
122
+ }
123
+ }
124
+ const groups = [...groupsByKey.values()].sort((a, b) => b.length - a.length || a[0].localeCompare(b[0]));
125
+ const streams = Array.from({ length: streamCount }, () => []);
126
+ if (groups.length === 0) {
127
+ return streams;
128
+ }
129
+ if (groups.length <= streamCount) {
130
+ groups.forEach((group, index) => {
131
+ streams[index] = compact(group);
132
+ });
133
+ }
134
+ else {
135
+ groups.forEach((group, index) => {
136
+ const targetIndex = index < streamCount
137
+ ? index
138
+ : streams.reduce((bestIndex, current, currentIndex) => (current.length < streams[bestIndex].length ? currentIndex : bestIndex), 0);
139
+ streams[targetIndex] = compact([...streams[targetIndex], ...group]);
140
+ });
141
+ }
142
+ return streams.map((stream, index) => (stream.length > 0 ? stream : spreadTouches(normalizedTouches, index))).map((stream) => compact(stream));
143
+ }
40
144
  function deriveDiffPredictionTouches(index, querySeeds, limit = 12) {
41
145
  const touches = [];
42
146
  for (const seed of querySeeds) {
@@ -75,15 +179,33 @@ export function buildSwarmPlanFromTask(input) {
75
179
  `refactor ${input.request}`,
76
180
  `verify ${input.request}`,
77
181
  ]);
78
- const touches = compact([...matches.map((entry) => entry.path), ...diffPredictionTouches]).slice(0, 12);
182
+ const touches = prioritizeTouches([...matches.map((entry) => entry.path), ...diffPredictionTouches]).slice(0, 12);
79
183
  const scopes = deriveScopes(input.contract, touches.length > 0 ? touches : ["src/**", "test/**"]);
80
- const tasks = [
81
- buildTask(0, `Map scope and baseline risks for: ${input.request}`, spreadTouches(touches, 0), scopes, [], "low"),
82
- buildTask(1, `Implement change for: ${input.request}`, spreadTouches(touches, 1), scopes, [toTaskId(0)], "high"),
83
- buildTask(2, `Verify behavior and quality gates for: ${input.request}`, spreadTouches(touches, 2), scopes, [toTaskId(1)], "medium"),
84
- ];
184
+ const workstreamCount = deriveWorkstreamCount(input.request, touches);
185
+ const workstreamTouches = partitionTouchesForWorkstreams(touches, workstreamCount);
186
+ const tasks = [];
187
+ const analysisTask = buildTask(0, `Map scope and baseline risks for: ${input.request}`, spreadTouches(touches, 0), scopes, [], "low");
188
+ tasks.push(analysisTask);
189
+ const workstreamTaskIds = [];
190
+ const runWorkstreamsInParallel = workstreamTouches.length > 1;
191
+ const isAuditRequest = /\b(?:audit|review|analy[sz]e|scan|security|assessment)\b/i.test(input.request);
192
+ for (const streamTouches of workstreamTouches) {
193
+ const streamIndex = workstreamTaskIds.length + 1;
194
+ const brief = isAuditRequest
195
+ ? `Audit workstream ${streamIndex}/${workstreamTouches.length} for: ${input.request}`
196
+ : `Execute workstream ${streamIndex}/${workstreamTouches.length} for: ${input.request}`;
197
+ const task = buildTask(tasks.length, brief, streamTouches, scopes, runWorkstreamsInParallel ? [] : [analysisTask.id], "high");
198
+ tasks.push(task);
199
+ workstreamTaskIds.push(task.id);
200
+ }
201
+ const verificationDependsOn = compact([
202
+ ...(workstreamTaskIds.length > 0 ? workstreamTaskIds : [analysisTask.id]),
203
+ analysisTask.id,
204
+ ]);
205
+ const verificationTask = buildTask(tasks.length, `Verify behavior and quality gates for: ${input.request}`, spreadTouches(touches, tasks.length), scopes, verificationDependsOn, "medium");
206
+ tasks.push(verificationTask);
85
207
  if ((input.contract.definition_of_done ?? []).length > 0 || (input.contract.quality_gates ?? []).length > 0) {
86
- tasks.push(buildTask(3, "Finalize integration report and contract gate checklist.", spreadTouches(touches, 3), scopes, [toTaskId(2)], "medium"));
208
+ tasks.push(buildTask(tasks.length, "Finalize integration report and contract gate checklist.", spreadTouches(touches, tasks.length), scopes, [verificationTask.id], "medium"));
87
209
  }
88
210
  return {
89
211
  source: "plain",
@@ -93,6 +215,7 @@ export function buildSwarmPlanFromTask(input) {
93
215
  "Plan built from plain-language task and Project Index signals.",
94
216
  `candidate_files=${touches.length}`,
95
217
  `diff_prediction_candidates=${diffPredictionTouches.length}`,
218
+ `workstreams=${workstreamTouches.length}`,
96
219
  ],
97
220
  };
98
221
  }
@@ -107,15 +230,79 @@ export function buildSwarmPlanFromSingular(input) {
107
230
  ...input.option.pros.slice(0, 3),
108
231
  ...input.option.cons.slice(0, 3),
109
232
  ], 14);
110
- const touches = compact([
233
+ const touches = prioritizeTouches([
111
234
  ...(optionTouches.length > 0 ? optionTouches : fallbackTouches),
112
235
  ...diffPredictionTouches,
113
236
  ]).slice(0, 14);
114
237
  const scopes = deriveScopes(input.contract, touches.length > 0 ? touches : ["src/**", "test/**"]);
115
- const steps = input.option.plan.length > 0
116
- ? input.option.plan
117
- : [`Implement option ${input.option.id}: ${input.option.title}`];
118
- const tasks = steps.map((step, index) => buildTask(index, step, spreadTouches(touches, index), scopes, index === 0 ? [] : [toTaskId(index - 1)], index === 0 ? "medium" : index === steps.length - 1 ? "medium" : "high"));
238
+ const workstreamSignal = [
239
+ input.analysis.request,
240
+ input.option.title,
241
+ input.option.summary,
242
+ ...input.option.plan.slice(0, 6),
243
+ ].join(" ");
244
+ const workstreamCount = deriveWorkstreamCount(workstreamSignal, touches);
245
+ const touchStreams = partitionTouchesForWorkstreams(touches, workstreamCount);
246
+ const steps = input.option.plan.length > 0 ? input.option.plan : [`Implement option ${input.option.id}: ${input.option.title}`];
247
+ const tasks = [];
248
+ if (steps.length === 1) {
249
+ const targetStreams = Math.max(1, Math.min(4, touchStreams.length));
250
+ if (targetStreams <= 1) {
251
+ tasks.push(buildTask(0, steps[0], spreadTouches(touches, 0), scopes, [], "high"));
252
+ }
253
+ else {
254
+ tasks.push(buildTask(0, `Prepare execution baseline for option ${input.option.id}: ${input.option.title}`, spreadTouches(touches, 0), scopes, [], "medium"));
255
+ const setupTaskId = tasks[0].id;
256
+ const streamTaskIds = [];
257
+ for (let streamIndex = 0; streamIndex < targetStreams; streamIndex += 1) {
258
+ const streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);
259
+ const streamTask = buildTask(tasks.length, `Implementation slice ${streamIndex + 1}/${targetStreams} for option ${input.option.id}: ${input.option.title}`, streamTouches, scopes, [setupTaskId], "high");
260
+ tasks.push(streamTask);
261
+ streamTaskIds.push(streamTask.id);
262
+ }
263
+ tasks.push(buildTask(tasks.length, steps[0], spreadTouches(touches, tasks.length), scopes, streamTaskIds, "medium"));
264
+ }
265
+ }
266
+ else if (steps.length === 2) {
267
+ const targetStreams = Math.max(1, Math.min(4, touchStreams.length));
268
+ tasks.push(buildTask(0, steps[0], spreadTouches(touches, 0), scopes, [], "medium"));
269
+ if (targetStreams <= 1) {
270
+ tasks.push(buildTask(1, steps[1], spreadTouches(touches, 1), scopes, [tasks[0].id], "high"));
271
+ }
272
+ else {
273
+ const setupTaskId = tasks[0].id;
274
+ const streamTaskIds = [];
275
+ for (let streamIndex = 0; streamIndex < targetStreams; streamIndex += 1) {
276
+ const streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);
277
+ const streamTask = buildTask(tasks.length, `Implementation slice ${streamIndex + 1}/${targetStreams} for option ${input.option.id}: ${input.option.title}`, streamTouches, scopes, [setupTaskId], "high");
278
+ tasks.push(streamTask);
279
+ streamTaskIds.push(streamTask.id);
280
+ }
281
+ tasks.push(buildTask(tasks.length, steps[1], spreadTouches(touches, tasks.length), scopes, streamTaskIds, "medium"));
282
+ }
283
+ }
284
+ else {
285
+ // For richer singular options, preserve an initial setup step, run middle slices in parallel,
286
+ // then converge into a final synthesis/verification step.
287
+ tasks.push(buildTask(0, steps[0], spreadTouches(touches, 0), scopes, [], "medium"));
288
+ const setupTaskId = tasks[0].id;
289
+ const middleSteps = steps.slice(1, -1);
290
+ const middleTaskIds = [];
291
+ for (const step of middleSteps) {
292
+ const task = buildTask(tasks.length, step, spreadTouches(touches, tasks.length), scopes, [setupTaskId], "high");
293
+ tasks.push(task);
294
+ middleTaskIds.push(task.id);
295
+ }
296
+ const targetParallelSlices = Math.max(middleSteps.length, Math.max(1, Math.min(4, touchStreams.length)));
297
+ for (let streamIndex = middleSteps.length; streamIndex < targetParallelSlices; streamIndex += 1) {
298
+ const streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);
299
+ const task = buildTask(tasks.length, `Parallel slice ${streamIndex + 1}/${targetParallelSlices} for option ${input.option.id}: ${input.option.title}`, streamTouches, scopes, [setupTaskId], "high");
300
+ tasks.push(task);
301
+ middleTaskIds.push(task.id);
302
+ }
303
+ const finalStepDependsOn = middleTaskIds.length > 0 ? middleTaskIds : [setupTaskId];
304
+ tasks.push(buildTask(tasks.length, steps[steps.length - 1], spreadTouches(touches, tasks.length), scopes, finalStepDependsOn, "medium"));
305
+ }
119
306
  if (tasks.length === 0) {
120
307
  tasks.push(buildTask(0, `Execute selected singular option: ${input.option.title}`, touches, scopes, [], "high"));
121
308
  }
@@ -131,6 +318,7 @@ export function buildSwarmPlanFromSingular(input) {
131
318
  `option_title=${input.option.title}`,
132
319
  `final_task_id=${finalTaskId}`,
133
320
  `diff_prediction_candidates=${diffPredictionTouches.length}`,
321
+ `workstreams=${touchStreams.length}`,
134
322
  ],
135
323
  };
136
324
  }
@@ -1 +1 @@
1
- {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/core/swarm/planner.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EngineeringContract } from \"../contract.js\";\nimport type { SingularAnalysisResult, SingularOption } from \"../singular.js\";\nimport type { ProjectIndex } from \"../project-index/types.js\";\nimport { queryProjectIndex } from \"../project-index/index.js\";\nimport type { SwarmPlan, SwarmTaskPlan } from \"./types.js\";\n\nfunction toTaskId(index: number): string {\n\treturn `task_${index + 1}`;\n}\n\nfunction compact(values: string[]): string[] {\n\treturn [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];\n}\n\nfunction inferConcurrencyClass(brief: string, touches: string[]): SwarmTaskPlan[\"concurrency_class\"] {\n\tconst lower = `${brief} ${touches.join(\" \")}`.toLowerCase();\n\tif (/(test|spec|verification|verify|qa)/.test(lower)) return \"verification\";\n\tif (/(doc|readme|changelog)/.test(lower)) return \"docs\";\n\tif (/(analysis|audit|map|scope)/.test(lower)) return \"analysis\";\n\tif (/(implement|refactor|patch|change|rewrite)/.test(lower)) return \"implementation\";\n\treturn \"default\";\n}\n\nfunction deriveScopes(contract: EngineeringContract, touches: string[]): string[] {\n\tif ((contract.scope_include ?? []).length > 0) {\n\t\treturn compact(contract.scope_include ?? []);\n\t}\n\tconst scopes = touches\n\t\t.map((touch) => touch.replace(/^\\.\\//, \"\").split(\"/\").slice(0, 2).join(\"/\"))\n\t\t.filter((value) => value.length > 0)\n\t\t.map((value) => `${value}/**`);\n\treturn compact(scopes).slice(0, 8);\n}\n\nfunction spreadTouches(touches: string[], index: number): string[] {\n\tif (touches.length === 0) return [];\n\tconst start = index % touches.length;\n\tconst result: string[] = [];\n\tfor (let offset = 0; offset < Math.min(3, touches.length); offset += 1) {\n\t\tresult.push(touches[(start + offset) % touches.length] ?? touches[0]!);\n\t}\n\treturn compact(result);\n}\n\nfunction deriveDiffPredictionTouches(index: ProjectIndex, querySeeds: string[], limit = 12): string[] {\n\tconst touches: string[] = [];\n\tfor (const seed of querySeeds) {\n\t\tif (!seed || seed.trim().length === 0) continue;\n\t\tconst matches = queryProjectIndex(index, seed, Math.max(4, Math.floor(limit / 2))).matches;\n\t\tfor (const entry of matches) {\n\t\t\ttouches.push(entry.path);\n\t\t\tif (touches.length >= limit) {\n\t\t\t\treturn compact(touches).slice(0, limit);\n\t\t\t}\n\t\t}\n\t}\n\treturn compact(touches).slice(0, limit);\n}\n\nfunction buildTask(\n\tindex: number,\n\tbrief: string,\n\ttouches: string[],\n\tscopes: string[],\n\tdependsOn: string[],\n\tseverity: SwarmTaskPlan[\"severity\"] = \"medium\",\n): SwarmTaskPlan {\n\tconst taskTouches = compact(touches).slice(0, 8);\n\treturn {\n\t\tid: toTaskId(index),\n\t\tbrief,\n\t\tdepends_on: compact(dependsOn),\n\t\tscopes: compact(scopes),\n\t\ttouches: taskTouches,\n\t\tconcurrency_class: inferConcurrencyClass(brief, taskTouches),\n\t\tseverity,\n\t\tneeds_user_input: false,\n\t\tmodel_hint: \"default\",\n\t\tspawn_policy: severity === \"high\" ? \"manual_high_risk\" : \"allow\",\n\t};\n}\n\nexport function buildSwarmPlanFromTask(input: {\n\trequest: string;\n\tcontract: EngineeringContract;\n\tindex: ProjectIndex;\n}): SwarmPlan {\n\tconst matches = queryProjectIndex(input.index, input.request, 12).matches;\n\tconst diffPredictionTouches = deriveDiffPredictionTouches(input.index, [\n\t\tinput.request,\n\t\t`implement ${input.request}`,\n\t\t`refactor ${input.request}`,\n\t\t`verify ${input.request}`,\n\t]);\n\tconst touches = compact([...matches.map((entry) => entry.path), ...diffPredictionTouches]).slice(0, 12);\n\tconst scopes = deriveScopes(input.contract, touches.length > 0 ? touches : [\"src/**\", \"test/**\"]);\n\n\tconst tasks: SwarmTaskPlan[] = [\n\t\tbuildTask(0, `Map scope and baseline risks for: ${input.request}`, spreadTouches(touches, 0), scopes, [], \"low\"),\n\t\tbuildTask(1, `Implement change for: ${input.request}`, spreadTouches(touches, 1), scopes, [toTaskId(0)], \"high\"),\n\t\tbuildTask(2, `Verify behavior and quality gates for: ${input.request}`, spreadTouches(touches, 2), scopes, [toTaskId(1)], \"medium\"),\n\t];\n\n\tif ((input.contract.definition_of_done ?? []).length > 0 || (input.contract.quality_gates ?? []).length > 0) {\n\t\ttasks.push(\n\t\t\tbuildTask(\n\t\t\t\t3,\n\t\t\t\t\"Finalize integration report and contract gate checklist.\",\n\t\t\t\tspreadTouches(touches, 3),\n\t\t\t\tscopes,\n\t\t\t\t[toTaskId(2)],\n\t\t\t\t\"medium\",\n\t\t\t),\n\t\t);\n\t}\n\n\treturn {\n\t\tsource: \"plain\",\n\t\trequest: input.request,\n\t\ttasks,\n\t\tnotes: [\n\t\t\t\"Plan built from plain-language task and Project Index signals.\",\n\t\t\t`candidate_files=${touches.length}`,\n\t\t\t`diff_prediction_candidates=${diffPredictionTouches.length}`,\n\t\t],\n\t};\n}\n\nexport function buildSwarmPlanFromSingular(input: {\n\tanalysis: SingularAnalysisResult;\n\toption: SingularOption;\n\tcontract: EngineeringContract;\n\tindex: ProjectIndex;\n}): SwarmPlan {\n\tconst optionTouches = compact(input.option.suggested_files);\n\tconst fallbackTouches = queryProjectIndex(input.index, `${input.analysis.request} ${input.option.title}`, 12).matches.map(\n\t\t(entry) => entry.path,\n\t);\n\tconst diffPredictionTouches = deriveDiffPredictionTouches(\n\t\tinput.index,\n\t\t[\n\t\t\tinput.analysis.request,\n\t\t\tinput.option.title,\n\t\t\tinput.option.summary,\n\t\t\t...input.option.plan.slice(0, 6),\n\t\t\t...input.option.pros.slice(0, 3),\n\t\t\t...input.option.cons.slice(0, 3),\n\t\t],\n\t\t14,\n\t);\n\tconst touches = compact([\n\t\t...(optionTouches.length > 0 ? optionTouches : fallbackTouches),\n\t\t...diffPredictionTouches,\n\t]).slice(0, 14);\n\tconst scopes = deriveScopes(input.contract, touches.length > 0 ? touches : [\"src/**\", \"test/**\"]);\n\n\tconst steps = input.option.plan.length > 0\n\t\t? input.option.plan\n\t\t: [`Implement option ${input.option.id}: ${input.option.title}`];\n\n\tconst tasks: SwarmTaskPlan[] = steps.map((step, index) =>\n\t\tbuildTask(\n\t\t\tindex,\n\t\t\tstep,\n\t\t\tspreadTouches(touches, index),\n\t\t\tscopes,\n\t\t\tindex === 0 ? [] : [toTaskId(index - 1)],\n\t\t\tindex === 0 ? \"medium\" : index === steps.length - 1 ? \"medium\" : \"high\",\n\t\t),\n\t);\n\n\tif (tasks.length === 0) {\n\t\ttasks.push(buildTask(0, `Execute selected singular option: ${input.option.title}`, touches, scopes, [], \"high\"));\n\t}\n\n\tconst finalTaskId = toTaskId(tasks.length);\n\ttasks.push(\n\t\tbuildTask(\n\t\t\ttasks.length,\n\t\t\t\"Run final task gates and prepare integration handoff artifact.\",\n\t\t\tspreadTouches(touches, tasks.length),\n\t\t\tscopes,\n\t\t\t[tasks[tasks.length - 1]!.id],\n\t\t\t\"medium\",\n\t\t),\n\t);\n\n\treturn {\n\t\tsource: \"singular\",\n\t\trequest: input.analysis.request,\n\t\ttasks,\n\t\tnotes: [\n\t\t\t`singular_run_id=${input.analysis.runId}`,\n\t\t\t`option=${input.option.id}`,\n\t\t\t`option_title=${input.option.title}`,\n\t\t\t`final_task_id=${finalTaskId}`,\n\t\t\t`diff_prediction_candidates=${diffPredictionTouches.length}`,\n\t\t],\n\t};\n}\n"]}
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/core/swarm/planner.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EngineeringContract } from \"../contract.js\";\nimport type { SingularAnalysisResult, SingularOption } from \"../singular.js\";\nimport type { ProjectIndex } from \"../project-index/types.js\";\nimport { queryProjectIndex } from \"../project-index/index.js\";\nimport type { SwarmPlan, SwarmTaskPlan } from \"./types.js\";\n\nfunction toTaskId(index: number): string {\n\treturn `task_${index + 1}`;\n}\n\nfunction compact(values: string[]): string[] {\n\treturn [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];\n}\n\nfunction inferConcurrencyClass(brief: string, touches: string[]): SwarmTaskPlan[\"concurrency_class\"] {\n\tconst lower = `${brief} ${touches.join(\" \")}`.toLowerCase();\n\tif (/(test|spec|verification|verify|qa)/.test(lower)) return \"verification\";\n\tif (/(doc|readme|changelog)/.test(lower)) return \"docs\";\n\tif (/(analysis|audit|map|scope)/.test(lower)) return \"analysis\";\n\tif (/(implement|refactor|patch|change|rewrite)/.test(lower)) return \"implementation\";\n\treturn \"default\";\n}\n\nfunction deriveScopes(contract: EngineeringContract, touches: string[]): string[] {\n\tif ((contract.scope_include ?? []).length > 0) {\n\t\treturn compact(contract.scope_include ?? []);\n\t}\n\tconst scopes = touches\n\t\t.map((touch) => touch.replace(/^\\.\\//, \"\").split(\"/\").slice(0, 2).join(\"/\"))\n\t\t.filter((value) => value.length > 0)\n\t\t.map((value) => `${value}/**`);\n\treturn compact(scopes).slice(0, 8);\n}\n\nfunction spreadTouches(touches: string[], index: number): string[] {\n\tif (touches.length === 0) return [];\n\tconst start = index % touches.length;\n\tconst result: string[] = [];\n\tfor (let offset = 0; offset < Math.min(3, touches.length); offset += 1) {\n\t\tresult.push(touches[(start + offset) % touches.length] ?? touches[0]!);\n\t}\n\treturn compact(result);\n}\n\nconst CODE_LIKE_EXTENSIONS = /\\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|kt|swift|json|ya?ml|toml|sql|css|scss|html)$/i;\nconst DOC_EXTENSIONS = /\\.(?:md|markdown|txt|rst|adoc)$/i;\n\nfunction touchPriority(path: string): number {\n\tconst normalized = path.trim().replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\").toLowerCase();\n\tlet score = 0;\n\tif (/^(?:src|app|packages|lib|server|client|services|api)\\//.test(normalized)) score += 4;\n\tif (/^(?:test|tests|__tests__)\\//.test(normalized)) score += 3;\n\tif (/\\.(?:test|spec)\\./.test(normalized)) score += 2;\n\tif (CODE_LIKE_EXTENSIONS.test(normalized)) score += 2;\n\tif (DOC_EXTENSIONS.test(normalized)) score -= 3;\n\tif (/^(?:docs|assets)\\//.test(normalized)) score -= 2;\n\treturn score;\n}\n\nfunction prioritizeTouches(paths: string[]): string[] {\n\tconst compacted = compact(paths);\n\tif (compacted.length <= 1) return compacted;\n\tconst ranked = compacted\n\t\t.map((path) => ({ path, score: touchPriority(path) }))\n\t\t.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path))\n\t\t.map((item) => item.path);\n\tconst hasCodeLike = ranked.some((path) => touchPriority(path) > 0);\n\treturn hasCodeLike ? ranked : compacted;\n}\n\nfunction deriveWorkstreamCount(request: string, touches: string[]): number {\n\tconst normalized = request.toLowerCase();\n\tconst words = request\n\t\t.trim()\n\t\t.split(/\\s+/)\n\t\t.filter((token) => token.length > 0).length;\n\tconst conjunctions =\n\t\t(normalized.match(/\\b(?:and|и|plus|also|then)\\b/g)?.length ?? 0) +\n\t\t(normalized.match(/[;,/]/g)?.length ?? 0);\n\tconst complexitySignal = /(audit|security|refactor|rewrite|migrat|hardening|parallel|orchestr|multi|complex|reliability|performance)/.test(\n\t\tnormalized,\n\t);\n\n\tlet workstreams = 1;\n\tif (touches.length >= 6) workstreams = 2;\n\tif (touches.length >= 10) workstreams = 3;\n\tif (touches.length >= 14) workstreams = 4;\n\tif (conjunctions >= 2) workstreams = Math.max(workstreams, 2);\n\tif (complexitySignal && words >= 2) workstreams = Math.max(workstreams, 2);\n\tif (complexitySignal && touches.length >= 8) workstreams = Math.max(workstreams, 3);\n\n\t// Keep fan-out bounded for predictable scheduler behavior.\n\treturn Math.max(1, Math.min(4, workstreams));\n}\n\nfunction clusterTouchKey(touch: string): string {\n\tconst normalized = touch.trim().replace(/\\\\/g, \"/\").replace(/^\\.\\//, \"\");\n\tif (!normalized) return \"root\";\n\tconst parts = normalized.split(\"/\").filter((part) => part.length > 0);\n\tif (parts.length === 0) return \"root\";\n\tif (parts.length === 1) return parts[0]!;\n\treturn `${parts[0]}/${parts[1]}`;\n}\n\nfunction partitionTouchesForWorkstreams(touches: string[], requestedStreams: number): string[][] {\n\tconst normalizedTouches = compact(touches);\n\tif (requestedStreams <= 1) return [normalizedTouches];\n\tconst streamCount = Math.max(\n\t\t1,\n\t\tMath.min(requestedStreams, normalizedTouches.length > 0 ? normalizedTouches.length : requestedStreams),\n\t);\n\tif (streamCount <= 1) return [normalizedTouches];\n\n\tconst groupsByKey = new Map<string, string[]>();\n\tfor (const touch of normalizedTouches) {\n\t\tconst key = clusterTouchKey(touch);\n\t\tconst existing = groupsByKey.get(key);\n\t\tif (existing) {\n\t\t\texisting.push(touch);\n\t\t} else {\n\t\t\tgroupsByKey.set(key, [touch]);\n\t\t}\n\t}\n\n\tconst groups = [...groupsByKey.values()].sort((a, b) => b.length - a.length || a[0]!.localeCompare(b[0]!));\n\tconst streams: string[][] = Array.from({ length: streamCount }, () => []);\n\n\tif (groups.length === 0) {\n\t\treturn streams;\n\t}\n\n\tif (groups.length <= streamCount) {\n\t\tgroups.forEach((group, index) => {\n\t\t\tstreams[index] = compact(group);\n\t\t});\n\t} else {\n\t\tgroups.forEach((group, index) => {\n\t\t\tconst targetIndex =\n\t\t\t\tindex < streamCount\n\t\t\t\t\t? index\n\t\t\t\t\t: streams.reduce(\n\t\t\t\t\t\t\t(bestIndex, current, currentIndex) => (current.length < streams[bestIndex]!.length ? currentIndex : bestIndex),\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t);\n\t\t\tstreams[targetIndex] = compact([...streams[targetIndex]!, ...group]);\n\t\t});\n\t}\n\n\treturn streams.map((stream, index) => (stream.length > 0 ? stream : spreadTouches(normalizedTouches, index))).map((stream) => compact(stream));\n}\n\nfunction deriveDiffPredictionTouches(index: ProjectIndex, querySeeds: string[], limit = 12): string[] {\n\tconst touches: string[] = [];\n\tfor (const seed of querySeeds) {\n\t\tif (!seed || seed.trim().length === 0) continue;\n\t\tconst matches = queryProjectIndex(index, seed, Math.max(4, Math.floor(limit / 2))).matches;\n\t\tfor (const entry of matches) {\n\t\t\ttouches.push(entry.path);\n\t\t\tif (touches.length >= limit) {\n\t\t\t\treturn compact(touches).slice(0, limit);\n\t\t\t}\n\t\t}\n\t}\n\treturn compact(touches).slice(0, limit);\n}\n\nfunction buildTask(\n\tindex: number,\n\tbrief: string,\n\ttouches: string[],\n\tscopes: string[],\n\tdependsOn: string[],\n\tseverity: SwarmTaskPlan[\"severity\"] = \"medium\",\n): SwarmTaskPlan {\n\tconst taskTouches = compact(touches).slice(0, 8);\n\treturn {\n\t\tid: toTaskId(index),\n\t\tbrief,\n\t\tdepends_on: compact(dependsOn),\n\t\tscopes: compact(scopes),\n\t\ttouches: taskTouches,\n\t\tconcurrency_class: inferConcurrencyClass(brief, taskTouches),\n\t\tseverity,\n\t\tneeds_user_input: false,\n\t\tmodel_hint: \"default\",\n\t\tspawn_policy: severity === \"high\" ? \"manual_high_risk\" : \"allow\",\n\t};\n}\n\nexport function buildSwarmPlanFromTask(input: {\n\trequest: string;\n\tcontract: EngineeringContract;\n\tindex: ProjectIndex;\n}): SwarmPlan {\n\tconst matches = queryProjectIndex(input.index, input.request, 12).matches;\n\tconst diffPredictionTouches = deriveDiffPredictionTouches(input.index, [\n\t\tinput.request,\n\t\t`implement ${input.request}`,\n\t\t`refactor ${input.request}`,\n\t\t`verify ${input.request}`,\n\t]);\n\tconst touches = prioritizeTouches([...matches.map((entry) => entry.path), ...diffPredictionTouches]).slice(0, 12);\n\tconst scopes = deriveScopes(input.contract, touches.length > 0 ? touches : [\"src/**\", \"test/**\"]);\n\tconst workstreamCount = deriveWorkstreamCount(input.request, touches);\n\tconst workstreamTouches = partitionTouchesForWorkstreams(touches, workstreamCount);\n\n\tconst tasks: SwarmTaskPlan[] = [];\n\tconst analysisTask = buildTask(0, `Map scope and baseline risks for: ${input.request}`, spreadTouches(touches, 0), scopes, [], \"low\");\n\ttasks.push(analysisTask);\n\n\tconst workstreamTaskIds: string[] = [];\n\tconst runWorkstreamsInParallel = workstreamTouches.length > 1;\n\tconst isAuditRequest = /\\b(?:audit|review|analy[sz]e|scan|security|assessment)\\b/i.test(input.request);\n\tfor (const streamTouches of workstreamTouches) {\n\t\tconst streamIndex = workstreamTaskIds.length + 1;\n\t\tconst brief = isAuditRequest\n\t\t\t? `Audit workstream ${streamIndex}/${workstreamTouches.length} for: ${input.request}`\n\t\t\t: `Execute workstream ${streamIndex}/${workstreamTouches.length} for: ${input.request}`;\n\t\tconst task = buildTask(\n\t\t\ttasks.length,\n\t\t\tbrief,\n\t\t\tstreamTouches,\n\t\t\tscopes,\n\t\t\trunWorkstreamsInParallel ? [] : [analysisTask.id],\n\t\t\t\"high\",\n\t\t);\n\t\ttasks.push(task);\n\t\tworkstreamTaskIds.push(task.id);\n\t}\n\tconst verificationDependsOn = compact([\n\t\t...(workstreamTaskIds.length > 0 ? workstreamTaskIds : [analysisTask.id]),\n\t\tanalysisTask.id,\n\t]);\n\n\tconst verificationTask = buildTask(\n\t\ttasks.length,\n\t\t`Verify behavior and quality gates for: ${input.request}`,\n\t\tspreadTouches(touches, tasks.length),\n\t\tscopes,\n\t\tverificationDependsOn,\n\t\t\"medium\",\n\t);\n\ttasks.push(verificationTask);\n\n\tif ((input.contract.definition_of_done ?? []).length > 0 || (input.contract.quality_gates ?? []).length > 0) {\n\t\ttasks.push(\n\t\t\tbuildTask(\n\t\t\t\ttasks.length,\n\t\t\t\t\"Finalize integration report and contract gate checklist.\",\n\t\t\t\tspreadTouches(touches, tasks.length),\n\t\t\t\tscopes,\n\t\t\t\t[verificationTask.id],\n\t\t\t\t\"medium\",\n\t\t\t),\n\t\t);\n\t}\n\n\treturn {\n\t\tsource: \"plain\",\n\t\trequest: input.request,\n\t\ttasks,\n\t\tnotes: [\n\t\t\t\"Plan built from plain-language task and Project Index signals.\",\n\t\t\t`candidate_files=${touches.length}`,\n\t\t\t`diff_prediction_candidates=${diffPredictionTouches.length}`,\n\t\t\t`workstreams=${workstreamTouches.length}`,\n\t\t],\n\t};\n}\n\nexport function buildSwarmPlanFromSingular(input: {\n\tanalysis: SingularAnalysisResult;\n\toption: SingularOption;\n\tcontract: EngineeringContract;\n\tindex: ProjectIndex;\n}): SwarmPlan {\n\tconst optionTouches = compact(input.option.suggested_files);\n\tconst fallbackTouches = queryProjectIndex(input.index, `${input.analysis.request} ${input.option.title}`, 12).matches.map(\n\t\t(entry) => entry.path,\n\t);\n\tconst diffPredictionTouches = deriveDiffPredictionTouches(\n\t\tinput.index,\n\t\t[\n\t\t\tinput.analysis.request,\n\t\t\tinput.option.title,\n\t\t\tinput.option.summary,\n\t\t\t...input.option.plan.slice(0, 6),\n\t\t\t...input.option.pros.slice(0, 3),\n\t\t\t...input.option.cons.slice(0, 3),\n\t\t],\n\t\t14,\n\t);\n\tconst touches = prioritizeTouches([\n\t\t...(optionTouches.length > 0 ? optionTouches : fallbackTouches),\n\t\t...diffPredictionTouches,\n\t]).slice(0, 14);\n\tconst scopes = deriveScopes(input.contract, touches.length > 0 ? touches : [\"src/**\", \"test/**\"]);\n\tconst workstreamSignal = [\n\t\tinput.analysis.request,\n\t\tinput.option.title,\n\t\tinput.option.summary,\n\t\t...input.option.plan.slice(0, 6),\n\t].join(\" \");\n\tconst workstreamCount = deriveWorkstreamCount(workstreamSignal, touches);\n\tconst touchStreams = partitionTouchesForWorkstreams(touches, workstreamCount);\n\n\tconst steps =\n\t\tinput.option.plan.length > 0 ? input.option.plan : [`Implement option ${input.option.id}: ${input.option.title}`];\n\n\tconst tasks: SwarmTaskPlan[] = [];\n\tif (steps.length === 1) {\n\t\tconst targetStreams = Math.max(1, Math.min(4, touchStreams.length));\n\t\tif (targetStreams <= 1) {\n\t\t\ttasks.push(buildTask(0, steps[0]!, spreadTouches(touches, 0), scopes, [], \"high\"));\n\t\t} else {\n\t\t\ttasks.push(\n\t\t\t\tbuildTask(\n\t\t\t\t\t0,\n\t\t\t\t\t`Prepare execution baseline for option ${input.option.id}: ${input.option.title}`,\n\t\t\t\t\tspreadTouches(touches, 0),\n\t\t\t\t\tscopes,\n\t\t\t\t\t[],\n\t\t\t\t\t\"medium\",\n\t\t\t\t),\n\t\t\t);\n\t\t\tconst setupTaskId = tasks[0]!.id;\n\t\t\tconst streamTaskIds: string[] = [];\n\t\t\tfor (let streamIndex = 0; streamIndex < targetStreams; streamIndex += 1) {\n\t\t\t\tconst streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);\n\t\t\t\tconst streamTask = buildTask(\n\t\t\t\t\ttasks.length,\n\t\t\t\t\t`Implementation slice ${streamIndex + 1}/${targetStreams} for option ${input.option.id}: ${input.option.title}`,\n\t\t\t\t\tstreamTouches,\n\t\t\t\t\tscopes,\n\t\t\t\t\t[setupTaskId],\n\t\t\t\t\t\"high\",\n\t\t\t\t);\n\t\t\t\ttasks.push(streamTask);\n\t\t\t\tstreamTaskIds.push(streamTask.id);\n\t\t\t}\n\t\t\ttasks.push(\n\t\t\t\tbuildTask(\n\t\t\t\t\ttasks.length,\n\t\t\t\t\tsteps[0]!,\n\t\t\t\t\tspreadTouches(touches, tasks.length),\n\t\t\t\t\tscopes,\n\t\t\t\t\tstreamTaskIds,\n\t\t\t\t\t\"medium\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t} else if (steps.length === 2) {\n\t\tconst targetStreams = Math.max(1, Math.min(4, touchStreams.length));\n\t\ttasks.push(buildTask(0, steps[0]!, spreadTouches(touches, 0), scopes, [], \"medium\"));\n\t\tif (targetStreams <= 1) {\n\t\t\ttasks.push(buildTask(1, steps[1]!, spreadTouches(touches, 1), scopes, [tasks[0]!.id], \"high\"));\n\t\t} else {\n\t\t\tconst setupTaskId = tasks[0]!.id;\n\t\t\tconst streamTaskIds: string[] = [];\n\t\t\tfor (let streamIndex = 0; streamIndex < targetStreams; streamIndex += 1) {\n\t\t\t\tconst streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);\n\t\t\t\tconst streamTask = buildTask(\n\t\t\t\t\ttasks.length,\n\t\t\t\t\t`Implementation slice ${streamIndex + 1}/${targetStreams} for option ${input.option.id}: ${input.option.title}`,\n\t\t\t\t\tstreamTouches,\n\t\t\t\t\tscopes,\n\t\t\t\t\t[setupTaskId],\n\t\t\t\t\t\"high\",\n\t\t\t\t);\n\t\t\t\ttasks.push(streamTask);\n\t\t\t\tstreamTaskIds.push(streamTask.id);\n\t\t\t}\n\t\t\ttasks.push(\n\t\t\t\tbuildTask(\n\t\t\t\t\ttasks.length,\n\t\t\t\t\tsteps[1]!,\n\t\t\t\t\tspreadTouches(touches, tasks.length),\n\t\t\t\t\tscopes,\n\t\t\t\t\tstreamTaskIds,\n\t\t\t\t\t\"medium\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t} else {\n\t\t// For richer singular options, preserve an initial setup step, run middle slices in parallel,\n\t\t// then converge into a final synthesis/verification step.\n\t\ttasks.push(buildTask(0, steps[0]!, spreadTouches(touches, 0), scopes, [], \"medium\"));\n\t\tconst setupTaskId = tasks[0]!.id;\n\t\tconst middleSteps = steps.slice(1, -1);\n\t\tconst middleTaskIds: string[] = [];\n\t\tfor (const step of middleSteps) {\n\t\t\tconst task = buildTask(tasks.length, step, spreadTouches(touches, tasks.length), scopes, [setupTaskId], \"high\");\n\t\t\ttasks.push(task);\n\t\t\tmiddleTaskIds.push(task.id);\n\t\t}\n\t\tconst targetParallelSlices = Math.max(middleSteps.length, Math.max(1, Math.min(4, touchStreams.length)));\n\t\tfor (let streamIndex = middleSteps.length; streamIndex < targetParallelSlices; streamIndex += 1) {\n\t\t\tconst streamTouches = touchStreams[streamIndex] ?? spreadTouches(touches, streamIndex + 1);\n\t\t\tconst task = buildTask(\n\t\t\t\ttasks.length,\n\t\t\t\t`Parallel slice ${streamIndex + 1}/${targetParallelSlices} for option ${input.option.id}: ${input.option.title}`,\n\t\t\t\tstreamTouches,\n\t\t\t\tscopes,\n\t\t\t\t[setupTaskId],\n\t\t\t\t\"high\",\n\t\t\t);\n\t\t\ttasks.push(task);\n\t\t\tmiddleTaskIds.push(task.id);\n\t\t}\n\t\tconst finalStepDependsOn = middleTaskIds.length > 0 ? middleTaskIds : [setupTaskId];\n\t\ttasks.push(\n\t\t\tbuildTask(\n\t\t\t\ttasks.length,\n\t\t\t\tsteps[steps.length - 1]!,\n\t\t\t\tspreadTouches(touches, tasks.length),\n\t\t\t\tscopes,\n\t\t\t\tfinalStepDependsOn,\n\t\t\t\t\"medium\",\n\t\t\t),\n\t\t);\n\t}\n\n\tif (tasks.length === 0) {\n\t\ttasks.push(buildTask(0, `Execute selected singular option: ${input.option.title}`, touches, scopes, [], \"high\"));\n\t}\n\n\tconst finalTaskId = toTaskId(tasks.length);\n\ttasks.push(\n\t\tbuildTask(\n\t\t\ttasks.length,\n\t\t\t\"Run final task gates and prepare integration handoff artifact.\",\n\t\t\tspreadTouches(touches, tasks.length),\n\t\t\tscopes,\n\t\t\t[tasks[tasks.length - 1]!.id],\n\t\t\t\"medium\",\n\t\t),\n\t);\n\n\treturn {\n\t\tsource: \"singular\",\n\t\trequest: input.analysis.request,\n\t\ttasks,\n\t\tnotes: [\n\t\t\t`singular_run_id=${input.analysis.runId}`,\n\t\t\t`option=${input.option.id}`,\n\t\t\t`option_title=${input.option.title}`,\n\t\t\t`final_task_id=${finalTaskId}`,\n\t\t\t`diff_prediction_candidates=${diffPredictionTouches.length}`,\n\t\t\t`workstreams=${touchStreams.length}`,\n\t\t],\n\t};\n}\n"]}
@@ -9,6 +9,8 @@ export interface RunSwarmSchedulerOptions {
9
9
  budgetUsd?: number;
10
10
  existingState?: SwarmRuntimeState;
11
11
  retryPolicy?: SwarmRetryPolicy;
12
+ /** Max time for a single dispatch call in milliseconds. Defaults to IOSM_SWARM_DISPATCH_TIMEOUT_MS or 180000. */
13
+ dispatchTimeoutMs?: number;
12
14
  noProgressTickLimit?: number;
13
15
  spawnCap?: number;
14
16
  progressHeuristic?: {
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../src/core/swarm/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,OAAO,EAAqC,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEtF,OAAO,KAAK,EACX,mBAAmB,EACnB,UAAU,EAEV,SAAS,EAET,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAyOpB,MAAM,WAAW,wBAAwB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,4BAA4B,CAAC,EAAE,MAAM,CAAC;QACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,oBAAoB,CAAC,EAAE;QACtB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;QACtB,SAAS,EAAE,WAAW,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACvE,UAAU,EAAE,aAAa,CAAC;QAC1B,iBAAiB,EAAE,qBAAqB,CAAC;QACzC,KAAK,EAAE,iBAAiB,CAAC;KACzB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,YAAY,EAAE,CAAC,KAAK,EAAE;QACrB,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,qBAAqB,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;KACb,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,+BAAgC,SAAQ,oBAAoB;IAC5E,YAAY,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpG;AAED,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,+BAA+B,CAAC,CAsY1C"}
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../../src/core/swarm/scheduler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG1D,OAAO,EAAqC,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEtF,OAAO,KAAK,EACX,mBAAmB,EACnB,UAAU,EAEV,SAAS,EAET,iBAAiB,EACjB,oBAAoB,EACpB,aAAa,EACb,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAoRpB,MAAM,WAAW,wBAAwB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iHAAiH;IACjH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,4BAA4B,CAAC,EAAE,MAAM,CAAC;QACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,oBAAoB,CAAC,EAAE;QACtB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,WAAW,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE;QACtB,SAAS,EAAE,WAAW,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACvE,UAAU,EAAE,aAAa,CAAC;QAC1B,iBAAiB,EAAE,qBAAqB,CAAC;QACzC,KAAK,EAAE,iBAAiB,CAAC;KACzB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,YAAY,EAAE,CAAC,KAAK,EAAE;QACrB,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,qBAAqB,CAAC;QAC/B,IAAI,EAAE,MAAM,CAAC;KACb,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAChE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,+BAAgC,SAAQ,oBAAoB;IAC5E,YAAY,EAAE,KAAK,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpG;AAED,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,+BAA+B,CAAC,CA2b1C"}
@@ -3,9 +3,21 @@ import { evaluateRunGates, evaluateTaskGates } from "./gates.js";
3
3
  import { DEFAULT_RETRY_POLICY, shouldRetry } from "./retry.js";
4
4
  import { SwarmSpawnQueue } from "./spawn.js";
5
5
  const TERMINAL_STATUSES = new Set(["done", "error", "cancelled", "blocked"]);
6
+ const FAILURE_STATUSES = new Set(["error", "cancelled"]);
6
7
  function nowIso() {
7
8
  return new Date().toISOString();
8
9
  }
10
+ function parseBoundedInt(raw, fallback, min, max) {
11
+ const parsed = raw ? Number.parseInt(raw, 10) : fallback;
12
+ if (!Number.isInteger(parsed))
13
+ return fallback;
14
+ return Math.max(min, Math.min(max, parsed));
15
+ }
16
+ function clampBoundedInt(value, fallback, min, max) {
17
+ if (typeof value !== "number" || !Number.isFinite(value))
18
+ return fallback;
19
+ return Math.max(min, Math.min(max, Math.floor(value)));
20
+ }
9
21
  function compact(values) {
10
22
  return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];
11
23
  }
@@ -99,6 +111,32 @@ function collectReadyTasks(state, planById) {
99
111
  }
100
112
  return ready;
101
113
  }
114
+ function blockDependentsOfFailure(input) {
115
+ const blocked = [];
116
+ const queue = [input.failedTaskId];
117
+ const seen = new Set(queue);
118
+ while (queue.length > 0) {
119
+ const failedId = queue.shift();
120
+ if (!failedId)
121
+ break;
122
+ for (const [taskId, runtime] of Object.entries(input.state.tasks)) {
123
+ if (runtime.status !== "pending" && runtime.status !== "ready")
124
+ continue;
125
+ const plan = input.planById.get(taskId);
126
+ if (!plan || !plan.depends_on.includes(failedId))
127
+ continue;
128
+ runtime.status = "blocked";
129
+ runtime.completedAt = nowIso();
130
+ runtime.lastError = `Dependency failed: ${failedId}`;
131
+ blocked.push(taskId);
132
+ if (!seen.has(taskId)) {
133
+ seen.add(taskId);
134
+ queue.push(taskId);
135
+ }
136
+ }
137
+ }
138
+ return blocked;
139
+ }
102
140
  function selectBatch(input) {
103
141
  const sorted = [...input.readyTaskIds].sort((a, b) => {
104
142
  const taskA = input.planById.get(a);
@@ -210,6 +248,8 @@ export async function runSwarmScheduler(options) {
210
248
  const planById = new Map(options.plan.tasks.map((task) => [task.id, task]));
211
249
  const dependents = collectDependents(options.plan);
212
250
  const retryPolicy = options.retryPolicy ?? DEFAULT_RETRY_POLICY;
251
+ const envDispatchTimeoutMs = parseBoundedInt(process.env.IOSM_SWARM_DISPATCH_TIMEOUT_MS, 180_000, 1_000, 1_800_000);
252
+ const dispatchTimeoutMs = clampBoundedInt(options.dispatchTimeoutMs, envDispatchTimeoutMs, 1_000, 1_800_000);
213
253
  const noProgressLimit = Math.max(3, options.noProgressTickLimit ?? 8);
214
254
  const spawnCap = Math.max(1, options.spawnCap ?? 30);
215
255
  const progressHeuristicEnabled = options.progressHeuristic?.enabled !== false;
@@ -403,11 +443,34 @@ export async function runSwarmScheduler(options) {
403
443
  const dispatchResults = await Promise.all(dispatchContexts.map(async ({ taskId, plan, runtime }) => {
404
444
  let result;
405
445
  try {
406
- result = await options.dispatchTask({
446
+ const dispatchPromise = options.dispatchTask({
407
447
  task: plan,
408
448
  runtime,
409
449
  tick: state.tick,
410
450
  });
451
+ // Prevent unhandled rejections when timeout wins the race.
452
+ void dispatchPromise.catch(() => {
453
+ // handled by timeout race path
454
+ });
455
+ let timeoutHandle;
456
+ const timeoutPromise = new Promise((resolve) => {
457
+ timeoutHandle = setTimeout(() => {
458
+ resolve({
459
+ taskId,
460
+ status: "error",
461
+ error: `Dispatch timed out after ${dispatchTimeoutMs}ms.`,
462
+ failureCause: "timeout",
463
+ });
464
+ }, dispatchTimeoutMs);
465
+ });
466
+ try {
467
+ result = await Promise.race([dispatchPromise, timeoutPromise]);
468
+ }
469
+ finally {
470
+ if (timeoutHandle) {
471
+ clearTimeout(timeoutHandle);
472
+ }
473
+ }
411
474
  }
412
475
  catch (error) {
413
476
  result = {
@@ -443,16 +506,20 @@ export async function runSwarmScheduler(options) {
443
506
  else if (result.status === "blocked") {
444
507
  runtime.status = "blocked";
445
508
  runtime.lastError = result.error ?? "Task blocked by user input or policy.";
509
+ runtime.completedAt = nowIso();
446
510
  emit("task_blocked", runtime.lastError, undefined, taskId);
447
511
  }
448
512
  else {
449
513
  const errorMessage = result.error ?? "Unknown task failure.";
450
514
  const currentRetries = state.retries[taskId] ?? 0;
451
- const retryDecision = shouldRetry({
452
- errorMessage,
453
- currentRetries,
454
- policy: retryPolicy,
455
- });
515
+ const nonRetryableFailure = result.failureCause === "protocol_violation" || result.failureCause === "interrupted";
516
+ const retryDecision = nonRetryableFailure
517
+ ? { retry: false, bucket: "unknown", max: 0 }
518
+ : shouldRetry({
519
+ errorMessage,
520
+ currentRetries,
521
+ policy: retryPolicy,
522
+ });
456
523
  if (retryDecision.retry) {
457
524
  state.retries[taskId] = currentRetries + 1;
458
525
  runtime.status = "ready";
@@ -468,6 +535,20 @@ export async function runSwarmScheduler(options) {
468
535
  runtime.completedAt = nowIso();
469
536
  runtime.lastError = errorMessage;
470
537
  emit("task_error", errorMessage, { bucket: retryDecision.bucket, failureCause: result.failureCause ?? retryDecision.bucket }, taskId);
538
+ if (FAILURE_STATUSES.has(runtime.status)) {
539
+ const blockedDependents = blockDependentsOfFailure({
540
+ failedTaskId: taskId,
541
+ state,
542
+ planById,
543
+ });
544
+ for (const blockedTaskId of blockedDependents) {
545
+ const blockedRuntime = state.tasks[blockedTaskId];
546
+ emit("task_blocked", blockedRuntime?.lastError ?? `Dependency failed: ${taskId}`, { dependency: taskId }, blockedTaskId);
547
+ }
548
+ if (blockedDependents.length > 0) {
549
+ progressThisTick = true;
550
+ }
551
+ }
471
552
  }
472
553
  }
473
554
  for (const candidate of result.spawnCandidates ?? []) {