iosm-cli 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/README.md +447 -285
- package/dist/core/agent-profiles.d.ts +1 -0
- package/dist/core/agent-profiles.d.ts.map +1 -1
- package/dist/core/agent-profiles.js +10 -6
- package/dist/core/agent-profiles.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +6 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agent-teams.d.ts.map +1 -1
- package/dist/core/agent-teams.js +90 -19
- package/dist/core/agent-teams.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +6 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +9 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/parallel-task-agent.d.ts +23 -1
- package/dist/core/parallel-task-agent.d.ts.map +1 -1
- package/dist/core/parallel-task-agent.js +110 -20
- package/dist/core/parallel-task-agent.js.map +1 -1
- package/dist/core/shared-memory.d.ts +16 -2
- package/dist/core/shared-memory.d.ts.map +1 -1
- package/dist/core/shared-memory.js +283 -91
- package/dist/core/shared-memory.js.map +1 -1
- package/dist/core/singular.d.ts.map +1 -1
- package/dist/core/singular.js +3 -1
- package/dist/core/singular.js.map +1 -1
- package/dist/core/subagents.d.ts +1 -1
- package/dist/core/subagents.d.ts.map +1 -1
- package/dist/core/subagents.js +11 -3
- package/dist/core/subagents.js.map +1 -1
- package/dist/core/swarm/planner.d.ts.map +1 -1
- package/dist/core/swarm/planner.js +200 -12
- package/dist/core/swarm/planner.js.map +1 -1
- package/dist/core/swarm/scheduler.d.ts +2 -0
- package/dist/core/swarm/scheduler.d.ts.map +1 -1
- package/dist/core/swarm/scheduler.js +87 -6
- package/dist/core/swarm/scheduler.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ast-grep.d.ts.map +1 -1
- package/dist/core/tools/ast-grep.js +2 -0
- package/dist/core/tools/ast-grep.js.map +1 -1
- package/dist/core/tools/shared-memory.d.ts.map +1 -1
- package/dist/core/tools/shared-memory.js +79 -11
- package/dist/core/tools/shared-memory.js.map +1 -1
- package/dist/core/tools/task.d.ts +12 -1
- package/dist/core/tools/task.d.ts.map +1 -1
- package/dist/core/tools/task.js +1023 -76
- package/dist/core/tools/task.js.map +1 -1
- package/dist/core/tools/yq.d.ts.map +1 -1
- package/dist/core/tools/yq.js +2 -0
- package/dist/core/tools/yq.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +2 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +881 -74
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/cli-reference.md +4 -0
- package/docs/interactive-mode.md +2 -0
- package/docs/orchestration-and-subagents.md +5 -0
- 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 =
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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(
|
|
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 =
|
|
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
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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;
|
|
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
|
-
|
|
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
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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 ?? []) {
|