iosm-cli 0.2.0 → 0.2.2

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 (111) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +64 -52
  3. package/dist/core/agent-teams.d.ts.map +1 -1
  4. package/dist/core/agent-teams.js +38 -11
  5. package/dist/core/agent-teams.js.map +1 -1
  6. package/dist/core/failure-retrospective.d.ts +12 -0
  7. package/dist/core/failure-retrospective.d.ts.map +1 -0
  8. package/dist/core/failure-retrospective.js +115 -0
  9. package/dist/core/failure-retrospective.js.map +1 -0
  10. package/dist/core/model-registry.d.ts.map +1 -1
  11. package/dist/core/model-registry.js +2 -3
  12. package/dist/core/model-registry.js.map +1 -1
  13. package/dist/core/models-dev-provider-catalog.d.ts +30 -0
  14. package/dist/core/models-dev-provider-catalog.d.ts.map +1 -0
  15. package/dist/core/models-dev-provider-catalog.js +118 -0
  16. package/dist/core/models-dev-provider-catalog.js.map +1 -0
  17. package/dist/core/models-dev-providers.d.ts +12 -0
  18. package/dist/core/models-dev-providers.d.ts.map +1 -0
  19. package/dist/core/models-dev-providers.js +736 -0
  20. package/dist/core/models-dev-providers.js.map +1 -0
  21. package/dist/core/project-index/index.d.ts +17 -0
  22. package/dist/core/project-index/index.d.ts.map +1 -0
  23. package/dist/core/project-index/index.js +323 -0
  24. package/dist/core/project-index/index.js.map +1 -0
  25. package/dist/core/project-index/types.d.ts +34 -0
  26. package/dist/core/project-index/types.d.ts.map +1 -0
  27. package/dist/core/project-index/types.js +2 -0
  28. package/dist/core/project-index/types.js.map +1 -0
  29. package/dist/core/sdk.d.ts.map +1 -1
  30. package/dist/core/sdk.js +8 -0
  31. package/dist/core/sdk.js.map +1 -1
  32. package/dist/core/shared-memory.d.ts +46 -0
  33. package/dist/core/shared-memory.d.ts.map +1 -0
  34. package/dist/core/shared-memory.js +253 -0
  35. package/dist/core/shared-memory.js.map +1 -0
  36. package/dist/core/slash-commands.d.ts.map +1 -1
  37. package/dist/core/slash-commands.js +5 -1
  38. package/dist/core/slash-commands.js.map +1 -1
  39. package/dist/core/subagents.js +1 -1
  40. package/dist/core/subagents.js.map +1 -1
  41. package/dist/core/swarm/gates.d.ts +9 -0
  42. package/dist/core/swarm/gates.d.ts.map +1 -0
  43. package/dist/core/swarm/gates.js +65 -0
  44. package/dist/core/swarm/gates.js.map +1 -0
  45. package/dist/core/swarm/index.d.ts +9 -0
  46. package/dist/core/swarm/index.d.ts.map +1 -0
  47. package/dist/core/swarm/index.js +9 -0
  48. package/dist/core/swarm/index.js.map +1 -0
  49. package/dist/core/swarm/locks.d.ts +21 -0
  50. package/dist/core/swarm/locks.d.ts.map +1 -0
  51. package/dist/core/swarm/locks.js +93 -0
  52. package/dist/core/swarm/locks.js.map +1 -0
  53. package/dist/core/swarm/planner.d.ts +16 -0
  54. package/dist/core/swarm/planner.d.ts.map +1 -0
  55. package/dist/core/swarm/planner.js +137 -0
  56. package/dist/core/swarm/planner.js.map +1 -0
  57. package/dist/core/swarm/retry.d.ts +16 -0
  58. package/dist/core/swarm/retry.d.ts.map +1 -0
  59. package/dist/core/swarm/retry.js +32 -0
  60. package/dist/core/swarm/retry.js.map +1 -0
  61. package/dist/core/swarm/scheduler.d.ts +48 -0
  62. package/dist/core/swarm/scheduler.d.ts.map +1 -0
  63. package/dist/core/swarm/scheduler.js +554 -0
  64. package/dist/core/swarm/scheduler.js.map +1 -0
  65. package/dist/core/swarm/spawn.d.ts +16 -0
  66. package/dist/core/swarm/spawn.d.ts.map +1 -0
  67. package/dist/core/swarm/spawn.js +42 -0
  68. package/dist/core/swarm/spawn.js.map +1 -0
  69. package/dist/core/swarm/state-store.d.ts +35 -0
  70. package/dist/core/swarm/state-store.d.ts.map +1 -0
  71. package/dist/core/swarm/state-store.js +106 -0
  72. package/dist/core/swarm/state-store.js.map +1 -0
  73. package/dist/core/swarm/types.d.ts +116 -0
  74. package/dist/core/swarm/types.d.ts.map +1 -0
  75. package/dist/core/swarm/types.js +2 -0
  76. package/dist/core/swarm/types.js.map +1 -0
  77. package/dist/core/system-prompt.d.ts.map +1 -1
  78. package/dist/core/system-prompt.js +3 -2
  79. package/dist/core/system-prompt.js.map +1 -1
  80. package/dist/core/tools/shared-memory.d.ts +23 -0
  81. package/dist/core/tools/shared-memory.d.ts.map +1 -0
  82. package/dist/core/tools/shared-memory.js +134 -0
  83. package/dist/core/tools/shared-memory.js.map +1 -0
  84. package/dist/core/tools/task.d.ts +8 -1
  85. package/dist/core/tools/task.d.ts.map +1 -1
  86. package/dist/core/tools/task.js +664 -123
  87. package/dist/core/tools/task.js.map +1 -1
  88. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  89. package/dist/modes/interactive/components/footer.js +3 -11
  90. package/dist/modes/interactive/components/footer.js.map +1 -1
  91. package/dist/modes/interactive/components/login-dialog.d.ts +1 -0
  92. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  93. package/dist/modes/interactive/components/login-dialog.js +27 -4
  94. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  95. package/dist/modes/interactive/components/oauth-selector.d.ts +13 -1
  96. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  97. package/dist/modes/interactive/components/oauth-selector.js +89 -27
  98. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  99. package/dist/modes/interactive/components/subagent-message.d.ts.map +1 -1
  100. package/dist/modes/interactive/components/subagent-message.js +14 -0
  101. package/dist/modes/interactive/components/subagent-message.js.map +1 -1
  102. package/dist/modes/interactive/interactive-mode.d.ts +50 -0
  103. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  104. package/dist/modes/interactive/interactive-mode.js +1594 -51
  105. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  106. package/docs/cli-reference.md +11 -1
  107. package/docs/configuration.md +4 -1
  108. package/docs/getting-started.md +2 -2
  109. package/docs/interactive-mode.md +43 -4
  110. package/docs/orchestration-and-subagents.md +96 -169
  111. package/package.json +5 -4
@@ -0,0 +1,554 @@
1
+ import { touchesConflict, HierarchicalLockManager } from "./locks.js";
2
+ import { evaluateRunGates, evaluateTaskGates } from "./gates.js";
3
+ import { DEFAULT_RETRY_POLICY, shouldRetry } from "./retry.js";
4
+ import { SwarmSpawnQueue } from "./spawn.js";
5
+ const TERMINAL_STATUSES = new Set(["done", "error", "cancelled", "blocked"]);
6
+ function nowIso() {
7
+ return new Date().toISOString();
8
+ }
9
+ function compact(values) {
10
+ return [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];
11
+ }
12
+ function isTerminal(status) {
13
+ return TERMINAL_STATUSES.has(status);
14
+ }
15
+ function severityWeight(task) {
16
+ if (task.severity === "high")
17
+ return 3;
18
+ if (task.severity === "medium")
19
+ return 2;
20
+ return 1;
21
+ }
22
+ function collectDependents(plan) {
23
+ const result = new Map();
24
+ for (const task of plan.tasks) {
25
+ for (const dep of task.depends_on) {
26
+ result.set(dep, (result.get(dep) ?? 0) + 1);
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ function createTaskRuntimeState(task) {
32
+ return {
33
+ id: task.id,
34
+ status: task.depends_on.length === 0 ? "ready" : "pending",
35
+ attempts: 0,
36
+ depends_on: [...task.depends_on],
37
+ touches: [...task.touches],
38
+ scopes: [...task.scopes],
39
+ };
40
+ }
41
+ function buildInitialState(input) {
42
+ if (input.existingState) {
43
+ return {
44
+ ...input.existingState,
45
+ updatedAt: nowIso(),
46
+ status: input.existingState.status === "completed" ? "running" : input.existingState.status,
47
+ };
48
+ }
49
+ const tasks = {};
50
+ for (const task of input.plan.tasks) {
51
+ tasks[task.id] = createTaskRuntimeState(task);
52
+ }
53
+ return {
54
+ runId: input.runId,
55
+ status: "running",
56
+ createdAt: nowIso(),
57
+ updatedAt: nowIso(),
58
+ tick: 0,
59
+ noProgressTicks: 0,
60
+ readyQueue: Object.values(tasks)
61
+ .filter((task) => task.status === "ready")
62
+ .map((task) => task.id),
63
+ blockedTasks: [],
64
+ tasks,
65
+ locks: {},
66
+ retries: {},
67
+ budget: {
68
+ limitUsd: input.budgetUsd,
69
+ spentUsd: 0,
70
+ warned80: false,
71
+ hardStopped: false,
72
+ },
73
+ };
74
+ }
75
+ function runHasOnlyBlockedTasks(state) {
76
+ const tasks = Object.values(state.tasks);
77
+ const unfinished = tasks.filter((task) => !isTerminal(task.status));
78
+ if (unfinished.length > 0)
79
+ return false;
80
+ return tasks.length > 0 && tasks.some((task) => task.status === "blocked");
81
+ }
82
+ function collectReadyTasks(state, planById) {
83
+ const ready = [];
84
+ for (const [taskId, runtime] of Object.entries(state.tasks)) {
85
+ if (runtime.status !== "pending" && runtime.status !== "ready")
86
+ continue;
87
+ const plan = planById.get(taskId);
88
+ if (!plan)
89
+ continue;
90
+ const depsDone = plan.depends_on.every((dep) => state.tasks[dep]?.status === "done");
91
+ if (!depsDone) {
92
+ runtime.status = "pending";
93
+ continue;
94
+ }
95
+ if (runtime.status !== "ready") {
96
+ runtime.status = "ready";
97
+ }
98
+ ready.push(taskId);
99
+ }
100
+ return ready;
101
+ }
102
+ function selectBatch(input) {
103
+ const sorted = [...input.readyTaskIds].sort((a, b) => {
104
+ const taskA = input.planById.get(a);
105
+ const taskB = input.planById.get(b);
106
+ if (!taskA || !taskB)
107
+ return a.localeCompare(b);
108
+ const severityDelta = severityWeight(taskB) - severityWeight(taskA);
109
+ if (severityDelta !== 0)
110
+ return severityDelta;
111
+ const dependentDelta = (input.dependents.get(b) ?? 0) - (input.dependents.get(a) ?? 0);
112
+ if (dependentDelta !== 0)
113
+ return dependentDelta;
114
+ return a.localeCompare(b);
115
+ });
116
+ const selected = [];
117
+ for (const taskId of sorted) {
118
+ const plan = input.planById.get(taskId);
119
+ if (!plan)
120
+ continue;
121
+ const hasConflictWithSelected = selected.some((existingId) => {
122
+ const existing = input.planById.get(existingId);
123
+ if (!existing)
124
+ return false;
125
+ return touchesConflict(existing.touches, plan.touches);
126
+ });
127
+ if (hasConflictWithSelected)
128
+ continue;
129
+ selected.push(taskId);
130
+ if (selected.length >= Math.max(1, input.maxParallel))
131
+ break;
132
+ }
133
+ return selected;
134
+ }
135
+ function progressScore(task, dependents) {
136
+ const dependentWeight = dependents.get(task.id) ?? 0;
137
+ const touchWeight = Math.min(3, Math.max(1, task.touches.length));
138
+ return severityWeight(task) * 3 + dependentWeight * 2 + touchWeight;
139
+ }
140
+ function applyProgressHeuristic(input) {
141
+ if (input.readyTaskIds.length <= 1)
142
+ return input.readyTaskIds;
143
+ if (input.state.noProgressTicks < input.activateAfterNoProgressTicks)
144
+ return input.readyTaskIds;
145
+ const scored = input.readyTaskIds
146
+ .map((taskId) => {
147
+ const plan = input.planById.get(taskId);
148
+ if (!plan)
149
+ return undefined;
150
+ return { taskId, score: progressScore(plan, input.dependents), severity: plan.severity };
151
+ })
152
+ .filter((item) => item !== undefined)
153
+ .sort((a, b) => b.score - a.score || a.taskId.localeCompare(b.taskId));
154
+ if (scored.length === 0)
155
+ return input.readyTaskIds;
156
+ const topScore = scored[0].score;
157
+ const threshold = Math.max(input.minScore, topScore - 2);
158
+ const filtered = scored
159
+ .filter((item) => item.score >= threshold || item.severity === "high")
160
+ .map((item) => item.taskId);
161
+ return filtered.length > 0 ? filtered : [scored[0].taskId];
162
+ }
163
+ function conflictDensity(input) {
164
+ const count = input.taskIds.length;
165
+ if (count < 2)
166
+ return 0;
167
+ let conflictingPairs = 0;
168
+ let totalPairs = 0;
169
+ for (let i = 0; i < count; i += 1) {
170
+ const a = input.planById.get(input.taskIds[i]);
171
+ if (!a)
172
+ continue;
173
+ for (let j = i + 1; j < count; j += 1) {
174
+ const b = input.planById.get(input.taskIds[j]);
175
+ if (!b)
176
+ continue;
177
+ totalPairs += 1;
178
+ if (touchesConflict(a.touches, b.touches)) {
179
+ conflictingPairs += 1;
180
+ }
181
+ }
182
+ }
183
+ return totalPairs > 0 ? conflictingPairs / totalPairs : 0;
184
+ }
185
+ function applyConflictDensityGuard(input) {
186
+ const density = conflictDensity({ taskIds: input.readyTaskIds, planById: input.planById });
187
+ if (density < input.threshold) {
188
+ return { effectiveMaxParallel: input.maxParallel, density };
189
+ }
190
+ const scaled = Math.max(input.minParallel, Math.floor(input.maxParallel * Math.max(0.2, 1 - density)));
191
+ return {
192
+ effectiveMaxParallel: Math.max(1, Math.min(input.maxParallel, scaled)),
193
+ density,
194
+ };
195
+ }
196
+ function shouldStopForBudget(state) {
197
+ const limit = state.budget.limitUsd;
198
+ if (limit === undefined || limit <= 0)
199
+ return false;
200
+ if (!state.budget.warned80 && state.budget.spentUsd >= limit * 0.8) {
201
+ state.budget.warned80 = true;
202
+ }
203
+ if (state.budget.spentUsd >= limit) {
204
+ state.budget.hardStopped = true;
205
+ return true;
206
+ }
207
+ return false;
208
+ }
209
+ export async function runSwarmScheduler(options) {
210
+ const planById = new Map(options.plan.tasks.map((task) => [task.id, task]));
211
+ const dependents = collectDependents(options.plan);
212
+ const retryPolicy = options.retryPolicy ?? DEFAULT_RETRY_POLICY;
213
+ const noProgressLimit = Math.max(3, options.noProgressTickLimit ?? 8);
214
+ const spawnCap = Math.max(1, options.spawnCap ?? 30);
215
+ const progressHeuristicEnabled = options.progressHeuristic?.enabled !== false;
216
+ const progressHeuristicActivateAfter = Math.max(1, options.progressHeuristic?.activateAfterNoProgressTicks ?? 2);
217
+ const progressHeuristicMinScore = Math.max(1, options.progressHeuristic?.minScore ?? 4);
218
+ const conflictGuardEnabled = options.conflictDensityGuard?.enabled !== false;
219
+ const conflictGuardThreshold = Math.min(1, Math.max(0, options.conflictDensityGuard?.threshold ?? 0.45));
220
+ const conflictGuardMinParallel = Math.max(1, options.conflictDensityGuard?.minParallel ?? 1);
221
+ const state = buildInitialState({
222
+ runId: options.runId,
223
+ plan: options.plan,
224
+ budgetUsd: options.budgetUsd,
225
+ existingState: options.existingState,
226
+ });
227
+ const lockManager = new HierarchicalLockManager();
228
+ const taskGateByTaskId = new Map();
229
+ const spawned = new SwarmSpawnQueue();
230
+ const events = [];
231
+ for (const [taskId, taskState] of Object.entries(state.tasks)) {
232
+ if (taskState.status === "running") {
233
+ taskState.status = "pending";
234
+ taskState.startedAt = undefined;
235
+ }
236
+ if (taskState.status === "done") {
237
+ const plan = planById.get(taskId);
238
+ if (plan) {
239
+ taskGateByTaskId.set(taskId, evaluateTaskGates({ ...plan, touches: taskState.touches }, options.contract));
240
+ }
241
+ }
242
+ }
243
+ const emit = (type, message, payload, taskId) => {
244
+ const event = {
245
+ type,
246
+ timestamp: nowIso(),
247
+ runId: options.runId,
248
+ tick: state.tick,
249
+ message,
250
+ payload,
251
+ ...(taskId ? { taskId } : {}),
252
+ };
253
+ events.push(event);
254
+ options.onEvent?.(event, state);
255
+ };
256
+ emit("run_started", `Swarm run ${options.runId} started`, {
257
+ tasks: options.plan.tasks.length,
258
+ maxParallel: options.maxParallel,
259
+ budgetUsd: options.budgetUsd,
260
+ });
261
+ options.onStateChanged?.(state);
262
+ while (true) {
263
+ if (options.shouldStop?.()) {
264
+ state.status = "stopped";
265
+ state.lastError = "Run interrupted by user.";
266
+ emit("run_stopped", state.lastError);
267
+ break;
268
+ }
269
+ state.tick += 1;
270
+ state.updatedAt = nowIso();
271
+ emit("tick", `scheduler_tick=${state.tick}`);
272
+ if (shouldStopForBudget(state)) {
273
+ state.status = "stopped";
274
+ state.lastError = "Budget hard-stop reached.";
275
+ emit("run_stopped", state.lastError, {
276
+ budgetLimitUsd: state.budget.limitUsd,
277
+ spentUsd: state.budget.spentUsd,
278
+ });
279
+ options.onStateChanged?.(state);
280
+ break;
281
+ }
282
+ const readyTaskIds = collectReadyTasks(state, planById);
283
+ state.readyQueue = [...readyTaskIds];
284
+ state.blockedTasks = Object.values(state.tasks)
285
+ .filter((task) => task.status === "blocked")
286
+ .map((task) => task.id)
287
+ .sort((a, b) => a.localeCompare(b));
288
+ if (readyTaskIds.length === 0) {
289
+ const allTerminal = Object.values(state.tasks).every((task) => isTerminal(task.status));
290
+ if (allTerminal) {
291
+ const runGate = evaluateRunGates({
292
+ taskStates: state.tasks,
293
+ taskGateResults: [...taskGateByTaskId.values()],
294
+ contract: options.contract,
295
+ });
296
+ emit("gate_run", runGate.pass ? "run_gates_passed" : "run_gates_failed", {
297
+ warnings: runGate.warnings,
298
+ failures: runGate.failures,
299
+ });
300
+ if (runGate.pass && Object.values(state.tasks).every((task) => task.status === "done" || task.status === "blocked")) {
301
+ state.status = runHasOnlyBlockedTasks(state) ? "blocked" : "completed";
302
+ emit(state.status === "completed" ? "run_completed" : "run_blocked", `Swarm run ${state.status}`);
303
+ }
304
+ else {
305
+ state.status = "failed";
306
+ state.lastError = runGate.failures.join(" | ") || "Run gates failed.";
307
+ emit("run_failed", state.lastError);
308
+ }
309
+ options.onStateChanged?.(state);
310
+ break;
311
+ }
312
+ state.noProgressTicks += 1;
313
+ if (state.noProgressTicks >= noProgressLimit) {
314
+ state.status = "blocked";
315
+ state.lastError = "No progress threshold reached.";
316
+ emit("run_blocked", state.lastError, { noProgressTicks: state.noProgressTicks });
317
+ options.onStateChanged?.(state);
318
+ break;
319
+ }
320
+ options.onStateChanged?.(state);
321
+ continue;
322
+ }
323
+ const progressReady = progressHeuristicEnabled
324
+ ? applyProgressHeuristic({
325
+ readyTaskIds,
326
+ planById,
327
+ dependents,
328
+ state,
329
+ activateAfterNoProgressTicks: progressHeuristicActivateAfter,
330
+ minScore: progressHeuristicMinScore,
331
+ })
332
+ : readyTaskIds;
333
+ const guard = conflictGuardEnabled
334
+ ? applyConflictDensityGuard({
335
+ readyTaskIds: progressReady,
336
+ planById,
337
+ maxParallel: options.maxParallel,
338
+ threshold: conflictGuardThreshold,
339
+ minParallel: conflictGuardMinParallel,
340
+ })
341
+ : { effectiveMaxParallel: options.maxParallel, density: conflictDensity({ taskIds: progressReady, planById }) };
342
+ emit("tick", "scheduler_guards", {
343
+ ready: readyTaskIds.length,
344
+ progress_candidates: progressReady.length,
345
+ conflict_density: Number(guard.density.toFixed(3)),
346
+ effective_max_parallel: guard.effectiveMaxParallel,
347
+ no_progress_ticks: state.noProgressTicks,
348
+ });
349
+ const preselected = selectBatch({
350
+ readyTaskIds: progressReady,
351
+ planById,
352
+ maxParallel: guard.effectiveMaxParallel,
353
+ dependents,
354
+ });
355
+ const selected = [];
356
+ for (const taskId of preselected) {
357
+ const plan = planById.get(taskId);
358
+ if (!plan)
359
+ continue;
360
+ const lockCheck = lockManager.canAcquire(taskId, plan.touches);
361
+ if (!lockCheck.ok) {
362
+ const runtime = state.tasks[taskId];
363
+ if (runtime) {
364
+ runtime.status = "blocked";
365
+ runtime.lastError = `Lock conflict: ${lockCheck.conflicts
366
+ .map((conflict) => `${conflict.touch}<->${conflict.conflictingTouch}`)
367
+ .join(", ")}`;
368
+ emit("task_blocked", runtime.lastError, { conflicts: lockCheck.conflicts }, taskId);
369
+ }
370
+ continue;
371
+ }
372
+ selected.push(taskId);
373
+ }
374
+ if (selected.length === 0) {
375
+ state.noProgressTicks += 1;
376
+ if (state.noProgressTicks >= noProgressLimit) {
377
+ state.status = "blocked";
378
+ state.lastError = "No dispatch candidates after lock/budget filters.";
379
+ emit("run_blocked", state.lastError, { ready: readyTaskIds });
380
+ options.onStateChanged?.(state);
381
+ break;
382
+ }
383
+ options.onStateChanged?.(state);
384
+ continue;
385
+ }
386
+ let progressThisTick = false;
387
+ const dispatchContexts = [];
388
+ for (const taskId of selected) {
389
+ const plan = planById.get(taskId);
390
+ const runtime = state.tasks[taskId];
391
+ if (!plan || !runtime)
392
+ continue;
393
+ lockManager.acquire(taskId, runtime.touches.length > 0 ? runtime.touches : plan.touches);
394
+ state.locks = lockManager.snapshot();
395
+ emit("lock_acquired", `lock acquired for ${taskId}`, { touches: runtime.touches }, taskId);
396
+ runtime.status = "running";
397
+ runtime.attempts += 1;
398
+ runtime.startedAt = nowIso();
399
+ emit("task_running", `task ${taskId} running`, { attempt: runtime.attempts }, taskId);
400
+ dispatchContexts.push({ taskId, plan, runtime });
401
+ }
402
+ options.onStateChanged?.(state);
403
+ const dispatchResults = await Promise.all(dispatchContexts.map(async ({ taskId, plan, runtime }) => {
404
+ let result;
405
+ try {
406
+ result = await options.dispatchTask({
407
+ task: plan,
408
+ runtime,
409
+ tick: state.tick,
410
+ });
411
+ }
412
+ catch (error) {
413
+ result = {
414
+ taskId,
415
+ status: "error",
416
+ error: error instanceof Error ? error.message : String(error),
417
+ };
418
+ }
419
+ return { taskId, plan, runtime, result };
420
+ }));
421
+ for (const { taskId, plan, runtime, result } of dispatchResults) {
422
+ if (result.touchesRefined && result.touchesRefined.length > 0) {
423
+ runtime.touches = compact(result.touchesRefined);
424
+ lockManager.downgrade(taskId, runtime.touches);
425
+ state.locks = lockManager.snapshot();
426
+ }
427
+ if (typeof result.costUsd === "number" && Number.isFinite(result.costUsd) && result.costUsd > 0) {
428
+ state.budget.spentUsd += result.costUsd;
429
+ }
430
+ if (result.status === "done") {
431
+ runtime.status = "done";
432
+ runtime.completedAt = nowIso();
433
+ runtime.lastError = undefined;
434
+ progressThisTick = true;
435
+ emit("task_done", `task ${taskId} done`, undefined, taskId);
436
+ const gateResult = evaluateTaskGates({ ...plan, touches: runtime.touches }, options.contract);
437
+ taskGateByTaskId.set(taskId, gateResult);
438
+ emit("gate_task", gateResult.pass ? "task_gates_passed" : "task_gates_failed", {
439
+ warnings: gateResult.warnings,
440
+ failures: gateResult.failures,
441
+ }, taskId);
442
+ }
443
+ else if (result.status === "blocked") {
444
+ runtime.status = "blocked";
445
+ runtime.lastError = result.error ?? "Task blocked by user input or policy.";
446
+ emit("task_blocked", runtime.lastError, undefined, taskId);
447
+ }
448
+ else {
449
+ const errorMessage = result.error ?? "Unknown task failure.";
450
+ const currentRetries = state.retries[taskId] ?? 0;
451
+ const retryDecision = shouldRetry({
452
+ errorMessage,
453
+ currentRetries,
454
+ policy: retryPolicy,
455
+ });
456
+ if (retryDecision.retry) {
457
+ state.retries[taskId] = currentRetries + 1;
458
+ runtime.status = "ready";
459
+ runtime.lastError = errorMessage;
460
+ emit("task_retry", `retry ${state.retries[taskId]}/${retryDecision.max} for ${taskId} (${retryDecision.bucket})`, {
461
+ error: errorMessage,
462
+ bucket: retryDecision.bucket,
463
+ failureCause: result.failureCause ?? retryDecision.bucket,
464
+ }, taskId);
465
+ }
466
+ else {
467
+ runtime.status = "error";
468
+ runtime.completedAt = nowIso();
469
+ runtime.lastError = errorMessage;
470
+ emit("task_error", errorMessage, { bucket: retryDecision.bucket, failureCause: result.failureCause ?? retryDecision.bucket }, taskId);
471
+ }
472
+ }
473
+ for (const candidate of result.spawnCandidates ?? []) {
474
+ if (spawned.size() >= spawnCap)
475
+ break;
476
+ const requiresConfirmation = candidate.severity === "high" || plan.spawn_policy === "manual_high_risk";
477
+ if (requiresConfirmation && options.confirmSpawn) {
478
+ const approved = await options.confirmSpawn({
479
+ candidate,
480
+ parentTask: plan,
481
+ parentTaskRuntime: runtime,
482
+ state,
483
+ });
484
+ if (!approved) {
485
+ emit("spawn_rejected", `spawn rejected from ${taskId}`, {
486
+ description: candidate.description,
487
+ path: candidate.path,
488
+ changeType: candidate.changeType,
489
+ severity: candidate.severity,
490
+ }, taskId);
491
+ continue;
492
+ }
493
+ }
494
+ const queued = spawned.enqueue(candidate);
495
+ if (!queued.accepted)
496
+ continue;
497
+ emit("spawn_enqueued", `spawn queued from ${taskId}`, {
498
+ fingerprint: queued.fingerprint,
499
+ description: candidate.description,
500
+ path: candidate.path,
501
+ changeType: candidate.changeType,
502
+ severity: candidate.severity,
503
+ }, taskId);
504
+ }
505
+ lockManager.release(taskId);
506
+ state.locks = lockManager.snapshot();
507
+ emit("lock_released", `lock released for ${taskId}`, undefined, taskId);
508
+ options.onStateChanged?.(state);
509
+ }
510
+ if (shouldStopForBudget(state)) {
511
+ state.status = "stopped";
512
+ state.lastError = "Budget hard-stop reached.";
513
+ emit("run_stopped", state.lastError, {
514
+ budgetLimitUsd: state.budget.limitUsd,
515
+ spentUsd: state.budget.spentUsd,
516
+ });
517
+ options.onStateChanged?.(state);
518
+ break;
519
+ }
520
+ state.noProgressTicks = progressThisTick ? 0 : state.noProgressTicks + 1;
521
+ options.onStateChanged?.(state);
522
+ if (!progressThisTick && state.noProgressTicks >= noProgressLimit) {
523
+ state.status = "blocked";
524
+ state.lastError = "No measurable progress within scheduler threshold.";
525
+ emit("run_blocked", state.lastError, { noProgressTicks: state.noProgressTicks });
526
+ options.onStateChanged?.(state);
527
+ break;
528
+ }
529
+ }
530
+ const runGate = evaluateRunGates({
531
+ taskStates: state.tasks,
532
+ taskGateResults: [...taskGateByTaskId.values()],
533
+ contract: options.contract,
534
+ });
535
+ if (state.status === "completed" && !runGate.pass) {
536
+ state.status = "failed";
537
+ state.lastError = runGate.failures.join(" | ") || "Run gates failed.";
538
+ emit("run_failed", state.lastError);
539
+ }
540
+ const drainedSpawn = spawned.drain(spawnCap).map(({ fingerprint, candidate }) => ({
541
+ fingerprint,
542
+ description: candidate.description,
543
+ path: candidate.path,
544
+ changeType: candidate.changeType,
545
+ }));
546
+ return {
547
+ state,
548
+ taskGates: [...taskGateByTaskId.values()],
549
+ runGate,
550
+ events,
551
+ spawnBacklog: drainedSpawn,
552
+ };
553
+ }
554
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../../src/core/swarm/scheduler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { EngineeringContract } from \"../contract.js\";\nimport { touchesConflict, HierarchicalLockManager } from \"./locks.js\";\nimport { evaluateRunGates, evaluateTaskGates } from \"./gates.js\";\nimport { DEFAULT_RETRY_POLICY, shouldRetry, type SwarmRetryPolicy } from \"./retry.js\";\nimport { SwarmSpawnQueue } from \"./spawn.js\";\nimport type {\n\tSwarmDispatchResult,\n\tSwarmEvent,\n\tSwarmGateResult,\n\tSwarmPlan,\n\tSwarmRunGateResult,\n\tSwarmRuntimeState,\n\tSwarmSchedulerResult,\n\tSwarmTaskPlan,\n\tSwarmTaskRuntimeState,\n} from \"./types.js\";\n\nconst TERMINAL_STATUSES = new Set<SwarmTaskRuntimeState[\"status\"]>([\"done\", \"error\", \"cancelled\", \"blocked\"]);\n\nfunction nowIso(): string {\n\treturn new Date().toISOString();\n}\n\nfunction compact(values: string[]): string[] {\n\treturn [...new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))];\n}\n\nfunction isTerminal(status: SwarmTaskRuntimeState[\"status\"]): boolean {\n\treturn TERMINAL_STATUSES.has(status);\n}\n\nfunction severityWeight(task: SwarmTaskPlan): number {\n\tif (task.severity === \"high\") return 3;\n\tif (task.severity === \"medium\") return 2;\n\treturn 1;\n}\n\nfunction collectDependents(plan: SwarmPlan): Map<string, number> {\n\tconst result = new Map<string, number>();\n\tfor (const task of plan.tasks) {\n\t\tfor (const dep of task.depends_on) {\n\t\t\tresult.set(dep, (result.get(dep) ?? 0) + 1);\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction createTaskRuntimeState(task: SwarmTaskPlan): SwarmTaskRuntimeState {\n\treturn {\n\t\tid: task.id,\n\t\tstatus: task.depends_on.length === 0 ? \"ready\" : \"pending\",\n\t\tattempts: 0,\n\t\tdepends_on: [...task.depends_on],\n\t\ttouches: [...task.touches],\n\t\tscopes: [...task.scopes],\n\t};\n}\n\nfunction buildInitialState(input: {\n\trunId: string;\n\tplan: SwarmPlan;\n\tbudgetUsd?: number;\n\texistingState?: SwarmRuntimeState;\n}): SwarmRuntimeState {\n\tif (input.existingState) {\n\t\treturn {\n\t\t\t...input.existingState,\n\t\t\tupdatedAt: nowIso(),\n\t\t\tstatus: input.existingState.status === \"completed\" ? \"running\" : input.existingState.status,\n\t\t};\n\t}\n\n\tconst tasks: Record<string, SwarmTaskRuntimeState> = {};\n\tfor (const task of input.plan.tasks) {\n\t\ttasks[task.id] = createTaskRuntimeState(task);\n\t}\n\n\treturn {\n\t\trunId: input.runId,\n\t\tstatus: \"running\",\n\t\tcreatedAt: nowIso(),\n\t\tupdatedAt: nowIso(),\n\t\ttick: 0,\n\t\tnoProgressTicks: 0,\n\t\treadyQueue: Object.values(tasks)\n\t\t\t.filter((task) => task.status === \"ready\")\n\t\t\t.map((task) => task.id),\n\t\tblockedTasks: [],\n\t\ttasks,\n\t\tlocks: {},\n\t\tretries: {},\n\t\tbudget: {\n\t\t\tlimitUsd: input.budgetUsd,\n\t\t\tspentUsd: 0,\n\t\t\twarned80: false,\n\t\t\thardStopped: false,\n\t\t},\n\t};\n}\n\nfunction runHasOnlyBlockedTasks(state: SwarmRuntimeState): boolean {\n\tconst tasks = Object.values(state.tasks);\n\tconst unfinished = tasks.filter((task) => !isTerminal(task.status));\n\tif (unfinished.length > 0) return false;\n\treturn tasks.length > 0 && tasks.some((task) => task.status === \"blocked\");\n}\n\nfunction collectReadyTasks(state: SwarmRuntimeState, planById: Map<string, SwarmTaskPlan>): string[] {\n\tconst ready: string[] = [];\n\tfor (const [taskId, runtime] of Object.entries(state.tasks)) {\n\t\tif (runtime.status !== \"pending\" && runtime.status !== \"ready\") continue;\n\t\tconst plan = planById.get(taskId);\n\t\tif (!plan) continue;\n\t\tconst depsDone = plan.depends_on.every((dep) => state.tasks[dep]?.status === \"done\");\n\t\tif (!depsDone) {\n\t\t\truntime.status = \"pending\";\n\t\t\tcontinue;\n\t\t}\n\t\tif (runtime.status !== \"ready\") {\n\t\t\truntime.status = \"ready\";\n\t\t}\n\t\tready.push(taskId);\n\t}\n\treturn ready;\n}\n\nfunction selectBatch(input: {\n\treadyTaskIds: string[];\n\tplanById: Map<string, SwarmTaskPlan>;\n\tmaxParallel: number;\n\tdependents: Map<string, number>;\n}): string[] {\n\tconst sorted = [...input.readyTaskIds].sort((a, b) => {\n\t\tconst taskA = input.planById.get(a);\n\t\tconst taskB = input.planById.get(b);\n\t\tif (!taskA || !taskB) return a.localeCompare(b);\n\t\tconst severityDelta = severityWeight(taskB) - severityWeight(taskA);\n\t\tif (severityDelta !== 0) return severityDelta;\n\t\tconst dependentDelta = (input.dependents.get(b) ?? 0) - (input.dependents.get(a) ?? 0);\n\t\tif (dependentDelta !== 0) return dependentDelta;\n\t\treturn a.localeCompare(b);\n\t});\n\n\tconst selected: string[] = [];\n\tfor (const taskId of sorted) {\n\t\tconst plan = input.planById.get(taskId);\n\t\tif (!plan) continue;\n\t\tconst hasConflictWithSelected = selected.some((existingId) => {\n\t\t\tconst existing = input.planById.get(existingId);\n\t\t\tif (!existing) return false;\n\t\t\treturn touchesConflict(existing.touches, plan.touches);\n\t\t});\n\t\tif (hasConflictWithSelected) continue;\n\t\tselected.push(taskId);\n\t\tif (selected.length >= Math.max(1, input.maxParallel)) break;\n\t}\n\treturn selected;\n}\n\nfunction progressScore(task: SwarmTaskPlan, dependents: Map<string, number>): number {\n\tconst dependentWeight = dependents.get(task.id) ?? 0;\n\tconst touchWeight = Math.min(3, Math.max(1, task.touches.length));\n\treturn severityWeight(task) * 3 + dependentWeight * 2 + touchWeight;\n}\n\nfunction applyProgressHeuristic(input: {\n\treadyTaskIds: string[];\n\tplanById: Map<string, SwarmTaskPlan>;\n\tdependents: Map<string, number>;\n\tstate: SwarmRuntimeState;\n\tactivateAfterNoProgressTicks: number;\n\tminScore: number;\n}): string[] {\n\tif (input.readyTaskIds.length <= 1) return input.readyTaskIds;\n\tif (input.state.noProgressTicks < input.activateAfterNoProgressTicks) return input.readyTaskIds;\n\n\tconst scored = input.readyTaskIds\n\t\t.map((taskId) => {\n\t\t\tconst plan = input.planById.get(taskId);\n\t\t\tif (!plan) return undefined;\n\t\t\treturn { taskId, score: progressScore(plan, input.dependents), severity: plan.severity };\n\t\t})\n\t\t.filter((item): item is { taskId: string; score: number; severity: SwarmTaskPlan[\"severity\"] } => item !== undefined)\n\t\t.sort((a, b) => b.score - a.score || a.taskId.localeCompare(b.taskId));\n\tif (scored.length === 0) return input.readyTaskIds;\n\n\tconst topScore = scored[0]!.score;\n\tconst threshold = Math.max(input.minScore, topScore - 2);\n\tconst filtered = scored\n\t\t.filter((item) => item.score >= threshold || item.severity === \"high\")\n\t\t.map((item) => item.taskId);\n\treturn filtered.length > 0 ? filtered : [scored[0]!.taskId];\n}\n\nfunction conflictDensity(input: { taskIds: string[]; planById: Map<string, SwarmTaskPlan> }): number {\n\tconst count = input.taskIds.length;\n\tif (count < 2) return 0;\n\tlet conflictingPairs = 0;\n\tlet totalPairs = 0;\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst a = input.planById.get(input.taskIds[i]!);\n\t\tif (!a) continue;\n\t\tfor (let j = i + 1; j < count; j += 1) {\n\t\t\tconst b = input.planById.get(input.taskIds[j]!);\n\t\t\tif (!b) continue;\n\t\t\ttotalPairs += 1;\n\t\t\tif (touchesConflict(a.touches, b.touches)) {\n\t\t\t\tconflictingPairs += 1;\n\t\t\t}\n\t\t}\n\t}\n\treturn totalPairs > 0 ? conflictingPairs / totalPairs : 0;\n}\n\nfunction applyConflictDensityGuard(input: {\n\treadyTaskIds: string[];\n\tplanById: Map<string, SwarmTaskPlan>;\n\tmaxParallel: number;\n\tthreshold: number;\n\tminParallel: number;\n}): { effectiveMaxParallel: number; density: number } {\n\tconst density = conflictDensity({ taskIds: input.readyTaskIds, planById: input.planById });\n\tif (density < input.threshold) {\n\t\treturn { effectiveMaxParallel: input.maxParallel, density };\n\t}\n\tconst scaled = Math.max(\n\t\tinput.minParallel,\n\t\tMath.floor(input.maxParallel * Math.max(0.2, 1 - density)),\n\t);\n\treturn {\n\t\teffectiveMaxParallel: Math.max(1, Math.min(input.maxParallel, scaled)),\n\t\tdensity,\n\t};\n}\n\nfunction shouldStopForBudget(state: SwarmRuntimeState): boolean {\n\tconst limit = state.budget.limitUsd;\n\tif (limit === undefined || limit <= 0) return false;\n\tif (!state.budget.warned80 && state.budget.spentUsd >= limit * 0.8) {\n\t\tstate.budget.warned80 = true;\n\t}\n\tif (state.budget.spentUsd >= limit) {\n\t\tstate.budget.hardStopped = true;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nexport interface RunSwarmSchedulerOptions {\n\trunId: string;\n\tplan: SwarmPlan;\n\tcontract: EngineeringContract;\n\tmaxParallel: number;\n\tbudgetUsd?: number;\n\texistingState?: SwarmRuntimeState;\n\tretryPolicy?: SwarmRetryPolicy;\n\tnoProgressTickLimit?: number;\n\tspawnCap?: number;\n\tprogressHeuristic?: {\n\t\tenabled?: boolean;\n\t\tactivateAfterNoProgressTicks?: number;\n\t\tminScore?: number;\n\t};\n\tconflictDensityGuard?: {\n\t\tenabled?: boolean;\n\t\tthreshold?: number;\n\t\tminParallel?: number;\n\t};\n\tconfirmSpawn?: (input: {\n\t\tcandidate: NonNullable<SwarmDispatchResult[\"spawnCandidates\"]>[number];\n\t\tparentTask: SwarmTaskPlan;\n\t\tparentTaskRuntime: SwarmTaskRuntimeState;\n\t\tstate: SwarmRuntimeState;\n\t}) => Promise<boolean>;\n\tdispatchTask: (input: {\n\t\ttask: SwarmTaskPlan;\n\t\truntime: SwarmTaskRuntimeState;\n\t\ttick: number;\n\t}) => Promise<SwarmDispatchResult>;\n\tonEvent?: (event: SwarmEvent, state: SwarmRuntimeState) => void;\n\tonStateChanged?: (state: SwarmRuntimeState) => void;\n\tshouldStop?: () => boolean;\n}\n\nexport interface RunSwarmSchedulerExtendedResult extends SwarmSchedulerResult {\n\tspawnBacklog: Array<{ fingerprint: string; description: string; path: string; changeType: string }>;\n}\n\nexport async function runSwarmScheduler(\n\toptions: RunSwarmSchedulerOptions,\n): Promise<RunSwarmSchedulerExtendedResult> {\n\tconst planById = new Map(options.plan.tasks.map((task) => [task.id, task]));\n\tconst dependents = collectDependents(options.plan);\n\tconst retryPolicy = options.retryPolicy ?? DEFAULT_RETRY_POLICY;\n\tconst noProgressLimit = Math.max(3, options.noProgressTickLimit ?? 8);\n\tconst spawnCap = Math.max(1, options.spawnCap ?? 30);\n\tconst progressHeuristicEnabled = options.progressHeuristic?.enabled !== false;\n\tconst progressHeuristicActivateAfter = Math.max(1, options.progressHeuristic?.activateAfterNoProgressTicks ?? 2);\n\tconst progressHeuristicMinScore = Math.max(1, options.progressHeuristic?.minScore ?? 4);\n\tconst conflictGuardEnabled = options.conflictDensityGuard?.enabled !== false;\n\tconst conflictGuardThreshold = Math.min(1, Math.max(0, options.conflictDensityGuard?.threshold ?? 0.45));\n\tconst conflictGuardMinParallel = Math.max(1, options.conflictDensityGuard?.minParallel ?? 1);\n\n\tconst state = buildInitialState({\n\t\trunId: options.runId,\n\t\tplan: options.plan,\n\t\tbudgetUsd: options.budgetUsd,\n\t\texistingState: options.existingState,\n\t});\n\tconst lockManager = new HierarchicalLockManager();\n\tconst taskGateByTaskId = new Map<string, SwarmGateResult>();\n\tconst spawned = new SwarmSpawnQueue();\n\tconst events: SwarmEvent[] = [];\n\n\tfor (const [taskId, taskState] of Object.entries(state.tasks)) {\n\t\tif (taskState.status === \"running\") {\n\t\t\ttaskState.status = \"pending\";\n\t\t\ttaskState.startedAt = undefined;\n\t\t}\n\t\tif (taskState.status === \"done\") {\n\t\t\tconst plan = planById.get(taskId);\n\t\t\tif (plan) {\n\t\t\t\ttaskGateByTaskId.set(taskId, evaluateTaskGates({ ...plan, touches: taskState.touches }, options.contract));\n\t\t\t}\n\t\t}\n\t}\n\n\tconst emit = (type: SwarmEvent[\"type\"], message: string, payload?: Record<string, unknown>, taskId?: string): void => {\n\t\tconst event: SwarmEvent = {\n\t\t\ttype,\n\t\t\ttimestamp: nowIso(),\n\t\t\trunId: options.runId,\n\t\t\ttick: state.tick,\n\t\t\tmessage,\n\t\t\tpayload,\n\t\t\t...(taskId ? { taskId } : {}),\n\t\t};\n\t\tevents.push(event);\n\t\toptions.onEvent?.(event, state);\n\t};\n\n\temit(\"run_started\", `Swarm run ${options.runId} started`, {\n\t\ttasks: options.plan.tasks.length,\n\t\tmaxParallel: options.maxParallel,\n\t\tbudgetUsd: options.budgetUsd,\n\t});\n\toptions.onStateChanged?.(state);\n\n\twhile (true) {\n\t\tif (options.shouldStop?.()) {\n\t\t\tstate.status = \"stopped\";\n\t\t\tstate.lastError = \"Run interrupted by user.\";\n\t\t\temit(\"run_stopped\", state.lastError);\n\t\t\tbreak;\n\t\t}\n\n\t\tstate.tick += 1;\n\t\tstate.updatedAt = nowIso();\n\t\temit(\"tick\", `scheduler_tick=${state.tick}`);\n\n\t\tif (shouldStopForBudget(state)) {\n\t\t\tstate.status = \"stopped\";\n\t\t\tstate.lastError = \"Budget hard-stop reached.\";\n\t\t\temit(\"run_stopped\", state.lastError, {\n\t\t\t\tbudgetLimitUsd: state.budget.limitUsd,\n\t\t\t\tspentUsd: state.budget.spentUsd,\n\t\t\t});\n\t\t\toptions.onStateChanged?.(state);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst readyTaskIds = collectReadyTasks(state, planById);\n\t\tstate.readyQueue = [...readyTaskIds];\n\t\tstate.blockedTasks = Object.values(state.tasks)\n\t\t\t.filter((task) => task.status === \"blocked\")\n\t\t\t.map((task) => task.id)\n\t\t\t.sort((a, b) => a.localeCompare(b));\n\n\t\tif (readyTaskIds.length === 0) {\n\t\t\tconst allTerminal = Object.values(state.tasks).every((task) => isTerminal(task.status));\n\t\t\tif (allTerminal) {\n\t\t\t\tconst runGate = evaluateRunGates({\n\t\t\t\t\ttaskStates: state.tasks,\n\t\t\t\t\ttaskGateResults: [...taskGateByTaskId.values()],\n\t\t\t\t\tcontract: options.contract,\n\t\t\t\t});\n\t\t\t\temit(\"gate_run\", runGate.pass ? \"run_gates_passed\" : \"run_gates_failed\", {\n\t\t\t\t\twarnings: runGate.warnings,\n\t\t\t\t\tfailures: runGate.failures,\n\t\t\t\t});\n\t\t\t\tif (runGate.pass && Object.values(state.tasks).every((task) => task.status === \"done\" || task.status === \"blocked\")) {\n\t\t\t\t\tstate.status = runHasOnlyBlockedTasks(state) ? \"blocked\" : \"completed\";\n\t\t\t\t\temit(state.status === \"completed\" ? \"run_completed\" : \"run_blocked\", `Swarm run ${state.status}`);\n\t\t\t\t} else {\n\t\t\t\t\tstate.status = \"failed\";\n\t\t\t\t\tstate.lastError = runGate.failures.join(\" | \") || \"Run gates failed.\";\n\t\t\t\t\temit(\"run_failed\", state.lastError);\n\t\t\t\t}\n\t\t\t\toptions.onStateChanged?.(state);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tstate.noProgressTicks += 1;\n\t\t\tif (state.noProgressTicks >= noProgressLimit) {\n\t\t\t\tstate.status = \"blocked\";\n\t\t\t\tstate.lastError = \"No progress threshold reached.\";\n\t\t\t\temit(\"run_blocked\", state.lastError, { noProgressTicks: state.noProgressTicks });\n\t\t\t\toptions.onStateChanged?.(state);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\toptions.onStateChanged?.(state);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst progressReady = progressHeuristicEnabled\n\t\t\t? applyProgressHeuristic({\n\t\t\t\treadyTaskIds,\n\t\t\t\tplanById,\n\t\t\t\tdependents,\n\t\t\t\tstate,\n\t\t\t\tactivateAfterNoProgressTicks: progressHeuristicActivateAfter,\n\t\t\t\tminScore: progressHeuristicMinScore,\n\t\t\t})\n\t\t\t: readyTaskIds;\n\n\t\tconst guard = conflictGuardEnabled\n\t\t\t? applyConflictDensityGuard({\n\t\t\t\treadyTaskIds: progressReady,\n\t\t\t\tplanById,\n\t\t\t\tmaxParallel: options.maxParallel,\n\t\t\t\tthreshold: conflictGuardThreshold,\n\t\t\t\tminParallel: conflictGuardMinParallel,\n\t\t\t})\n\t\t\t: { effectiveMaxParallel: options.maxParallel, density: conflictDensity({ taskIds: progressReady, planById }) };\n\t\temit(\"tick\", \"scheduler_guards\", {\n\t\t\tready: readyTaskIds.length,\n\t\t\tprogress_candidates: progressReady.length,\n\t\t\tconflict_density: Number(guard.density.toFixed(3)),\n\t\t\teffective_max_parallel: guard.effectiveMaxParallel,\n\t\t\tno_progress_ticks: state.noProgressTicks,\n\t\t});\n\n\t\tconst preselected = selectBatch({\n\t\t\treadyTaskIds: progressReady,\n\t\t\tplanById,\n\t\t\tmaxParallel: guard.effectiveMaxParallel,\n\t\t\tdependents,\n\t\t});\n\n\t\tconst selected: string[] = [];\n\t\tfor (const taskId of preselected) {\n\t\t\tconst plan = planById.get(taskId);\n\t\t\tif (!plan) continue;\n\t\t\tconst lockCheck = lockManager.canAcquire(taskId, plan.touches);\n\t\t\tif (!lockCheck.ok) {\n\t\t\t\tconst runtime = state.tasks[taskId];\n\t\t\t\tif (runtime) {\n\t\t\t\t\truntime.status = \"blocked\";\n\t\t\t\t\truntime.lastError = `Lock conflict: ${lockCheck.conflicts\n\t\t\t\t\t\t.map((conflict) => `${conflict.touch}<->${conflict.conflictingTouch}`)\n\t\t\t\t\t\t.join(\", \")}`;\n\t\t\t\t\temit(\"task_blocked\", runtime.lastError, { conflicts: lockCheck.conflicts }, taskId);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tselected.push(taskId);\n\t\t}\n\n\t\tif (selected.length === 0) {\n\t\t\tstate.noProgressTicks += 1;\n\t\t\tif (state.noProgressTicks >= noProgressLimit) {\n\t\t\t\tstate.status = \"blocked\";\n\t\t\t\tstate.lastError = \"No dispatch candidates after lock/budget filters.\";\n\t\t\t\temit(\"run_blocked\", state.lastError, { ready: readyTaskIds });\n\t\t\t\toptions.onStateChanged?.(state);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\toptions.onStateChanged?.(state);\n\t\t\tcontinue;\n\t\t}\n\n\t\t\tlet progressThisTick = false;\n\t\t\tconst dispatchContexts: Array<{ taskId: string; plan: SwarmTaskPlan; runtime: SwarmTaskRuntimeState }> = [];\n\t\t\tfor (const taskId of selected) {\n\t\t\t\tconst plan = planById.get(taskId);\n\t\t\t\tconst runtime = state.tasks[taskId];\n\t\t\t\tif (!plan || !runtime) continue;\n\t\t\t\tlockManager.acquire(taskId, runtime.touches.length > 0 ? runtime.touches : plan.touches);\n\t\t\t\tstate.locks = lockManager.snapshot();\n\t\t\t\temit(\"lock_acquired\", `lock acquired for ${taskId}`, { touches: runtime.touches }, taskId);\n\n\t\t\t\truntime.status = \"running\";\n\t\t\t\truntime.attempts += 1;\n\t\t\t\truntime.startedAt = nowIso();\n\t\t\t\temit(\"task_running\", `task ${taskId} running`, { attempt: runtime.attempts }, taskId);\n\t\t\t\tdispatchContexts.push({ taskId, plan, runtime });\n\t\t\t}\n\t\t\toptions.onStateChanged?.(state);\n\n\t\t\tconst dispatchResults = await Promise.all(\n\t\t\t\tdispatchContexts.map(async ({ taskId, plan, runtime }) => {\n\t\t\t\t\tlet result: SwarmDispatchResult;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tresult = await options.dispatchTask({\n\t\t\t\t\t\t\ttask: plan,\n\t\t\t\t\t\t\truntime,\n\t\t\t\t\t\t\ttick: state.tick,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tresult = {\n\t\t\t\t\t\t\ttaskId,\n\t\t\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn { taskId, plan, runtime, result };\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tfor (const { taskId, plan, runtime, result } of dispatchResults) {\n\t\t\t\tif (result.touchesRefined && result.touchesRefined.length > 0) {\n\t\t\t\t\truntime.touches = compact(result.touchesRefined);\n\t\t\t\t\tlockManager.downgrade(taskId, runtime.touches);\n\t\t\t\t\tstate.locks = lockManager.snapshot();\n\t\t\t\t}\n\n\t\t\t\tif (typeof result.costUsd === \"number\" && Number.isFinite(result.costUsd) && result.costUsd > 0) {\n\t\t\t\t\tstate.budget.spentUsd += result.costUsd;\n\t\t\t\t}\n\n\t\t\t\tif (result.status === \"done\") {\n\t\t\t\t\truntime.status = \"done\";\n\t\t\t\t\truntime.completedAt = nowIso();\n\t\t\t\t\truntime.lastError = undefined;\n\t\t\t\t\tprogressThisTick = true;\n\t\t\t\t\temit(\"task_done\", `task ${taskId} done`, undefined, taskId);\n\n\t\t\t\t\tconst gateResult = evaluateTaskGates({ ...plan, touches: runtime.touches }, options.contract);\n\t\t\t\t\ttaskGateByTaskId.set(taskId, gateResult);\n\t\t\t\t\temit(\n\t\t\t\t\t\t\"gate_task\",\n\t\t\t\t\t\tgateResult.pass ? \"task_gates_passed\" : \"task_gates_failed\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\twarnings: gateResult.warnings,\n\t\t\t\t\t\t\tfailures: gateResult.failures,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttaskId,\n\t\t\t\t\t);\n\t\t\t\t} else if (result.status === \"blocked\") {\n\t\t\t\t\truntime.status = \"blocked\";\n\t\t\t\t\truntime.lastError = result.error ?? \"Task blocked by user input or policy.\";\n\t\t\t\t\temit(\"task_blocked\", runtime.lastError, undefined, taskId);\n\t\t\t\t} else {\n\t\t\t\t\tconst errorMessage = result.error ?? \"Unknown task failure.\";\n\t\t\t\t\tconst currentRetries = state.retries[taskId] ?? 0;\n\t\t\t\t\t\tconst retryDecision = shouldRetry({\n\t\t\t\t\t\t\terrorMessage,\n\t\t\t\t\t\t\tcurrentRetries,\n\t\t\t\t\t\t\tpolicy: retryPolicy,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (retryDecision.retry) {\n\t\t\t\t\t\t\tstate.retries[taskId] = currentRetries + 1;\n\t\t\t\t\t\t\truntime.status = \"ready\";\n\t\t\t\t\t\t\truntime.lastError = errorMessage;\n\t\t\t\t\t\t\temit(\n\t\t\t\t\t\t\t\t\"task_retry\",\n\t\t\t\t\t\t\t\t`retry ${state.retries[taskId]}/${retryDecision.max} for ${taskId} (${retryDecision.bucket})`,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\terror: errorMessage,\n\t\t\t\t\t\t\t\t\tbucket: retryDecision.bucket,\n\t\t\t\t\t\t\t\t\tfailureCause: result.failureCause ?? retryDecision.bucket,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttaskId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\truntime.status = \"error\";\n\t\t\t\t\t\t\truntime.completedAt = nowIso();\n\t\t\t\t\t\t\truntime.lastError = errorMessage;\n\t\t\t\t\t\t\temit(\n\t\t\t\t\t\t\t\t\"task_error\",\n\t\t\t\t\t\t\t\terrorMessage,\n\t\t\t\t\t\t\t\t{ bucket: retryDecision.bucket, failureCause: result.failureCause ?? retryDecision.bucket },\n\t\t\t\t\t\t\t\ttaskId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\tfor (const candidate of result.spawnCandidates ?? []) {\n\t\t\t\t\tif (spawned.size() >= spawnCap) break;\n\t\t\t\t\tconst requiresConfirmation = candidate.severity === \"high\" || plan.spawn_policy === \"manual_high_risk\";\n\t\t\t\t\tif (requiresConfirmation && options.confirmSpawn) {\n\t\t\t\t\t\tconst approved = await options.confirmSpawn({\n\t\t\t\t\t\t\tcandidate,\n\t\t\t\t\t\t\tparentTask: plan,\n\t\t\t\t\t\t\tparentTaskRuntime: runtime,\n\t\t\t\t\t\t\tstate,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tif (!approved) {\n\t\t\t\t\t\t\temit(\n\t\t\t\t\t\t\t\t\"spawn_rejected\",\n\t\t\t\t\t\t\t\t`spawn rejected from ${taskId}`,\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tdescription: candidate.description,\n\t\t\t\t\t\t\t\t\tpath: candidate.path,\n\t\t\t\t\t\t\t\t\tchangeType: candidate.changeType,\n\t\t\t\t\t\t\t\t\tseverity: candidate.severity,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\ttaskId,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst queued = spawned.enqueue(candidate);\n\t\t\t\t\tif (!queued.accepted) continue;\n\t\t\t\t\temit(\n\t\t\t\t\t\t\"spawn_enqueued\",\n\t\t\t\t\t\t`spawn queued from ${taskId}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfingerprint: queued.fingerprint,\n\t\t\t\t\t\t\tdescription: candidate.description,\n\t\t\t\t\t\t\tpath: candidate.path,\n\t\t\t\t\t\t\tchangeType: candidate.changeType,\n\t\t\t\t\t\t\tseverity: candidate.severity,\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttaskId,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tlockManager.release(taskId);\n\t\t\t\tstate.locks = lockManager.snapshot();\n\t\t\t\temit(\"lock_released\", `lock released for ${taskId}`, undefined, taskId);\n\t\t\t\toptions.onStateChanged?.(state);\n\t\t\t}\n\n\t\tif (shouldStopForBudget(state)) {\n\t\t\tstate.status = \"stopped\";\n\t\t\tstate.lastError = \"Budget hard-stop reached.\";\n\t\t\temit(\"run_stopped\", state.lastError, {\n\t\t\t\tbudgetLimitUsd: state.budget.limitUsd,\n\t\t\t\tspentUsd: state.budget.spentUsd,\n\t\t\t});\n\t\t\toptions.onStateChanged?.(state);\n\t\t\tbreak;\n\t\t}\n\n\t\tstate.noProgressTicks = progressThisTick ? 0 : state.noProgressTicks + 1;\n\t\toptions.onStateChanged?.(state);\n\t\tif (!progressThisTick && state.noProgressTicks >= noProgressLimit) {\n\t\t\tstate.status = \"blocked\";\n\t\t\tstate.lastError = \"No measurable progress within scheduler threshold.\";\n\t\t\temit(\"run_blocked\", state.lastError, { noProgressTicks: state.noProgressTicks });\n\t\t\toptions.onStateChanged?.(state);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst runGate: SwarmRunGateResult = evaluateRunGates({\n\t\ttaskStates: state.tasks,\n\t\ttaskGateResults: [...taskGateByTaskId.values()],\n\t\tcontract: options.contract,\n\t});\n\tif (state.status === \"completed\" && !runGate.pass) {\n\t\tstate.status = \"failed\";\n\t\tstate.lastError = runGate.failures.join(\" | \") || \"Run gates failed.\";\n\t\temit(\"run_failed\", state.lastError);\n\t}\n\n\tconst drainedSpawn = spawned.drain(spawnCap).map(({ fingerprint, candidate }) => ({\n\t\tfingerprint,\n\t\tdescription: candidate.description,\n\t\tpath: candidate.path,\n\t\tchangeType: candidate.changeType,\n\t}));\n\n\treturn {\n\t\tstate,\n\t\ttaskGates: [...taskGateByTaskId.values()],\n\t\trunGate,\n\t\tevents,\n\t\tspawnBacklog: drainedSpawn,\n\t};\n}\n"]}