@soleri/core 9.4.0 → 9.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude-code-adapter.d.ts +27 -0
- package/dist/adapters/claude-code-adapter.d.ts.map +1 -0
- package/dist/adapters/claude-code-adapter.js +111 -0
- package/dist/adapters/claude-code-adapter.js.map +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +10 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/registry.d.ts +21 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +44 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/types.d.ts +93 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +10 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/brain/brain.d.ts +12 -1
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +106 -44
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +36 -30
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/chat/agent-loop.js +1 -1
- package/dist/chat/agent-loop.js.map +1 -1
- package/dist/chat/notifications.d.ts.map +1 -1
- package/dist/chat/notifications.js +4 -0
- package/dist/chat/notifications.js.map +1 -1
- package/dist/control/intent-router.d.ts +1 -0
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +11 -5
- package/dist/control/intent-router.js.map +1 -1
- package/dist/curator/curator.d.ts +4 -0
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +141 -27
- package/dist/curator/curator.js.map +1 -1
- package/dist/hooks/candidate-scorer.d.ts +28 -0
- package/dist/hooks/candidate-scorer.d.ts.map +1 -0
- package/dist/hooks/candidate-scorer.js +20 -0
- package/dist/hooks/candidate-scorer.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +1 -0
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/packs/index.d.ts +3 -2
- package/dist/packs/index.d.ts.map +1 -1
- package/dist/packs/index.js +3 -2
- package/dist/packs/index.js.map +1 -1
- package/dist/packs/lockfile.d.ts +23 -1
- package/dist/packs/lockfile.d.ts.map +1 -1
- package/dist/packs/lockfile.js +50 -4
- package/dist/packs/lockfile.js.map +1 -1
- package/dist/packs/pack-installer.d.ts +10 -0
- package/dist/packs/pack-installer.d.ts.map +1 -1
- package/dist/packs/pack-installer.js +69 -2
- package/dist/packs/pack-installer.js.map +1 -1
- package/dist/packs/pack-lifecycle.d.ts +50 -0
- package/dist/packs/pack-lifecycle.d.ts.map +1 -0
- package/dist/packs/pack-lifecycle.js +91 -0
- package/dist/packs/pack-lifecycle.js.map +1 -0
- package/dist/packs/types.d.ts +64 -44
- package/dist/packs/types.d.ts.map +1 -1
- package/dist/packs/types.js +9 -0
- package/dist/packs/types.js.map +1 -1
- package/dist/persistence/sqlite-provider.d.ts +5 -1
- package/dist/persistence/sqlite-provider.d.ts.map +1 -1
- package/dist/persistence/sqlite-provider.js +22 -2
- package/dist/persistence/sqlite-provider.js.map +1 -1
- package/dist/planning/github-projection.d.ts +8 -8
- package/dist/planning/github-projection.d.ts.map +1 -1
- package/dist/planning/github-projection.js +42 -42
- package/dist/planning/github-projection.js.map +1 -1
- package/dist/planning/plan-lifecycle.d.ts.map +1 -1
- package/dist/planning/plan-lifecycle.js +6 -1
- package/dist/planning/plan-lifecycle.js.map +1 -1
- package/dist/plugins/types.d.ts +21 -21
- package/dist/queue/pipeline-runner.d.ts.map +1 -1
- package/dist/queue/pipeline-runner.js +4 -0
- package/dist/queue/pipeline-runner.js.map +1 -1
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
- package/dist/runtime/curator-extra-ops.js +9 -1
- package/dist/runtime/curator-extra-ops.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +169 -0
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +133 -4
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +128 -90
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +44 -11
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/shutdown-registry.d.ts +36 -0
- package/dist/runtime/shutdown-registry.d.ts.map +1 -0
- package/dist/runtime/shutdown-registry.js +74 -0
- package/dist/runtime/shutdown-registry.js.map +1 -0
- package/dist/runtime/types.d.ts +10 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/subagent/concurrency-manager.d.ts +29 -0
- package/dist/subagent/concurrency-manager.d.ts.map +1 -0
- package/dist/subagent/concurrency-manager.js +73 -0
- package/dist/subagent/concurrency-manager.js.map +1 -0
- package/dist/subagent/dispatcher.d.ts +41 -0
- package/dist/subagent/dispatcher.d.ts.map +1 -0
- package/dist/subagent/dispatcher.js +259 -0
- package/dist/subagent/dispatcher.js.map +1 -0
- package/dist/subagent/index.d.ts +14 -0
- package/dist/subagent/index.d.ts.map +1 -0
- package/dist/subagent/index.js +15 -0
- package/dist/subagent/index.js.map +1 -0
- package/dist/subagent/orphan-reaper.d.ts +37 -0
- package/dist/subagent/orphan-reaper.d.ts.map +1 -0
- package/dist/subagent/orphan-reaper.js +71 -0
- package/dist/subagent/orphan-reaper.js.map +1 -0
- package/dist/subagent/result-aggregator.d.ts +7 -0
- package/dist/subagent/result-aggregator.d.ts.map +1 -0
- package/dist/subagent/result-aggregator.js +57 -0
- package/dist/subagent/result-aggregator.js.map +1 -0
- package/dist/subagent/task-checkout.d.ts +36 -0
- package/dist/subagent/task-checkout.d.ts.map +1 -0
- package/dist/subagent/task-checkout.js +52 -0
- package/dist/subagent/task-checkout.js.map +1 -0
- package/dist/subagent/types.d.ts +114 -0
- package/dist/subagent/types.d.ts.map +1 -0
- package/dist/subagent/types.js +9 -0
- package/dist/subagent/types.js.map +1 -0
- package/dist/subagent/workspace-resolver.d.ts +35 -0
- package/dist/subagent/workspace-resolver.d.ts.map +1 -0
- package/dist/subagent/workspace-resolver.js +99 -0
- package/dist/subagent/workspace-resolver.js.map +1 -0
- package/dist/transport/http-server.d.ts.map +1 -1
- package/dist/transport/http-server.js +49 -3
- package/dist/transport/http-server.js.map +1 -1
- package/dist/transport/ws-server.d.ts.map +1 -1
- package/dist/transport/ws-server.js +7 -0
- package/dist/transport/ws-server.js.map +1 -1
- package/dist/vault/linking.d.ts +3 -4
- package/dist/vault/linking.d.ts.map +1 -1
- package/dist/vault/linking.js +79 -32
- package/dist/vault/linking.js.map +1 -1
- package/dist/vault/vault-maintenance.d.ts.map +1 -1
- package/dist/vault/vault-maintenance.js +7 -14
- package/dist/vault/vault-maintenance.js.map +1 -1
- package/dist/vault/vault-memories.d.ts.map +1 -1
- package/dist/vault/vault-memories.js +19 -9
- package/dist/vault/vault-memories.js.map +1 -1
- package/dist/vault/vault-schema.d.ts +1 -0
- package/dist/vault/vault-schema.d.ts.map +1 -1
- package/dist/vault/vault-schema.js +20 -0
- package/dist/vault/vault-schema.js.map +1 -1
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +7 -3
- package/dist/vault/vault.js.map +1 -1
- package/package.json +8 -2
- package/src/__tests__/adapters/claude-code-adapter.test.ts +167 -0
- package/src/__tests__/adapters/registry.test.ts +100 -0
- package/src/__tests__/packs/pack-lifecycle.test.ts +379 -0
- package/src/__tests__/subagent/concurrency-manager.test.ts +132 -0
- package/src/__tests__/subagent/dispatcher.test.ts +195 -0
- package/src/__tests__/subagent/orphan-reaper.test.ts +141 -0
- package/src/__tests__/subagent/result-aggregator.test.ts +141 -0
- package/src/__tests__/subagent/task-checkout.test.ts +86 -0
- package/src/__tests__/subagent/workspace-resolver.test.ts +138 -0
- package/src/adapters/claude-code-adapter.ts +163 -0
- package/src/adapters/index.ts +22 -0
- package/src/adapters/registry.ts +53 -0
- package/src/adapters/types.ts +114 -0
- package/src/brain/brain.ts +120 -46
- package/src/brain/intelligence.ts +42 -34
- package/src/chat/agent-loop.ts +1 -1
- package/src/chat/notifications.ts +4 -0
- package/src/control/intent-router.ts +10 -8
- package/src/curator/curator.ts +146 -29
- package/src/hooks/candidate-scorer.test.ts +76 -0
- package/src/hooks/candidate-scorer.ts +39 -0
- package/src/index.ts +40 -1
- package/src/llm/llm-client.ts +1 -0
- package/src/packs/index.ts +5 -1
- package/src/packs/lockfile.ts +70 -5
- package/src/packs/pack-installer.ts +78 -2
- package/src/packs/pack-lifecycle.ts +115 -0
- package/src/packs/pack-lockfile.test.ts +1 -1
- package/src/packs/pack-system.test.ts +1 -1
- package/src/packs/types.ts +40 -2
- package/src/persistence/sqlite-provider.ts +27 -2
- package/src/planning/github-projection.ts +48 -44
- package/src/planning/plan-lifecycle.ts +14 -1
- package/src/queue/pipeline-runner.ts +4 -0
- package/src/runtime/admin-setup-ops.test.ts +9 -4
- package/src/runtime/curator-extra-ops.test.ts +7 -0
- package/src/runtime/curator-extra-ops.ts +10 -1
- package/src/runtime/facades/curator-facade.test.ts +7 -0
- package/src/runtime/facades/memory-facade.ts +187 -0
- package/src/runtime/orchestrate-ops.ts +156 -4
- package/src/runtime/runtime.test.ts +50 -2
- package/src/runtime/runtime.ts +132 -89
- package/src/runtime/session-briefing.test.ts +94 -2
- package/src/runtime/session-briefing.ts +48 -12
- package/src/runtime/shutdown-registry.test.ts +151 -0
- package/src/runtime/shutdown-registry.ts +85 -0
- package/src/runtime/types.ts +10 -1
- package/src/subagent/concurrency-manager.ts +89 -0
- package/src/subagent/dispatcher.ts +326 -0
- package/src/subagent/index.ts +28 -0
- package/src/subagent/orphan-reaper.ts +82 -0
- package/src/subagent/result-aggregator.ts +66 -0
- package/src/subagent/task-checkout.ts +60 -0
- package/src/subagent/types.ts +138 -0
- package/src/subagent/workspace-resolver.ts +117 -0
- package/src/transport/http-server.ts +50 -3
- package/src/transport/ws-server.ts +8 -0
- package/src/vault/linking.test.ts +12 -0
- package/src/vault/linking.ts +90 -44
- package/src/vault/vault-maintenance.ts +11 -18
- package/src/vault/vault-memories.ts +21 -13
- package/src/vault/vault-scaling.test.ts +3 -2
- package/src/vault/vault-schema.ts +21 -0
- package/src/vault/vault.ts +8 -3
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency-manager.d.ts","sourceRoot":"","sources":["../../src/subagent/concurrency-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAqC;IAElD;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,GAAE,MAA+B,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB1F;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAY3B,qEAAqE;IACrE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAI/B,uEAAuE;IACvE,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIhC,kEAAkE;IAClE,KAAK,IAAI,IAAI;IAab,OAAO,CAAC,WAAW;CAQpB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-agent-type semaphore for controlling concurrent subagent runs.
|
|
3
|
+
*
|
|
4
|
+
* Pure promise-based — zero external deps. FIFO ordering guarantees
|
|
5
|
+
* the first waiter is the first to acquire a slot when one frees up.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_MAX_CONCURRENT = 3;
|
|
8
|
+
export class ConcurrencyManager {
|
|
9
|
+
state = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Acquire a concurrency slot for the given adapter type.
|
|
12
|
+
* Resolves immediately if a slot is available, otherwise queues
|
|
13
|
+
* and resolves when a slot frees up (FIFO).
|
|
14
|
+
*/
|
|
15
|
+
async acquire(type, maxConcurrent = DEFAULT_MAX_CONCURRENT) {
|
|
16
|
+
const entry = this.getOrCreate(type);
|
|
17
|
+
if (entry.active < maxConcurrent) {
|
|
18
|
+
entry.active++;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// At capacity — park until a slot opens.
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
entry.waiters.push(() => {
|
|
24
|
+
entry.active++;
|
|
25
|
+
resolve();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Release a concurrency slot for the given adapter type.
|
|
31
|
+
* If waiters exist, the first one (FIFO) is unblocked.
|
|
32
|
+
* No-op if the type is not tracked.
|
|
33
|
+
*/
|
|
34
|
+
release(type) {
|
|
35
|
+
const entry = this.state.get(type);
|
|
36
|
+
if (!entry)
|
|
37
|
+
return;
|
|
38
|
+
entry.active = Math.max(0, entry.active - 1);
|
|
39
|
+
if (entry.waiters.length > 0) {
|
|
40
|
+
const next = entry.waiters.shift();
|
|
41
|
+
next();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Return the number of active slots for a type (0 if untracked). */
|
|
45
|
+
getActive(type) {
|
|
46
|
+
return this.state.get(type)?.active ?? 0;
|
|
47
|
+
}
|
|
48
|
+
/** Return the number of waiters queued for a type (0 if untracked). */
|
|
49
|
+
getWaiting(type) {
|
|
50
|
+
return this.state.get(type)?.waiters.length ?? 0;
|
|
51
|
+
}
|
|
52
|
+
/** Clear all state, resolving any pending waiters immediately. */
|
|
53
|
+
reset() {
|
|
54
|
+
for (const entry of this.state.values()) {
|
|
55
|
+
for (const waiter of entry.waiters) {
|
|
56
|
+
waiter();
|
|
57
|
+
}
|
|
58
|
+
entry.waiters.length = 0;
|
|
59
|
+
entry.active = 0;
|
|
60
|
+
}
|
|
61
|
+
this.state.clear();
|
|
62
|
+
}
|
|
63
|
+
// ── internal ──────────────────────────────────────────────────────
|
|
64
|
+
getOrCreate(type) {
|
|
65
|
+
let entry = this.state.get(type);
|
|
66
|
+
if (!entry) {
|
|
67
|
+
entry = { active: 0, waiters: [] };
|
|
68
|
+
this.state.set(type, entry);
|
|
69
|
+
}
|
|
70
|
+
return entry;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=concurrency-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency-manager.js","sourceRoot":"","sources":["../../src/subagent/concurrency-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,MAAM,OAAO,kBAAkB;IACrB,KAAK,GAA2B,IAAI,GAAG,EAAE,CAAC;IAElD;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,gBAAwB,sBAAsB;QACxE,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,KAAK,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;YACjC,KAAK,CAAC,MAAM,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,yCAAyC;QACzC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE;gBACtB,KAAK,CAAC,MAAM,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,IAAY;QAClB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE7C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAG,CAAC;YACpC,IAAI,EAAE,CAAC;QACT,CAAC;IACH,CAAC;IAED,qEAAqE;IACrE,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,uEAAuE;IACvE,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,kEAAkE;IAClE,KAAK;QACH,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACnC,MAAM,EAAE,CAAC;YACX,CAAC;YACD,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;YACzB,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,qEAAqE;IAE7D,WAAW,CAAC,IAAY;QAC9B,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentDispatcher — the core orchestrator for subagent execution.
|
|
3
|
+
*
|
|
4
|
+
* Composes: TaskCheckout, WorkspaceResolver, ConcurrencyManager,
|
|
5
|
+
* OrphanReaper, and RuntimeAdapterRegistry to dispatch tasks to
|
|
6
|
+
* child agent processes.
|
|
7
|
+
*/
|
|
8
|
+
import type { RuntimeAdapterRegistry } from '../adapters/registry.js';
|
|
9
|
+
import type { SubagentTask, SubagentResult, DispatchOptions, AggregatedResult } from './types.js';
|
|
10
|
+
export interface SubagentDispatcherConfig {
|
|
11
|
+
/** RuntimeAdapterRegistry for looking up adapters by type */
|
|
12
|
+
adapterRegistry: RuntimeAdapterRegistry;
|
|
13
|
+
/** Base directory for git worktree isolation */
|
|
14
|
+
baseDir?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class SubagentDispatcher {
|
|
17
|
+
private readonly checkout;
|
|
18
|
+
private readonly workspace;
|
|
19
|
+
private readonly concurrency;
|
|
20
|
+
private readonly reaper;
|
|
21
|
+
private readonly adapterRegistry;
|
|
22
|
+
constructor(config: SubagentDispatcherConfig);
|
|
23
|
+
/**
|
|
24
|
+
* Dispatch one or more tasks to subagents.
|
|
25
|
+
*
|
|
26
|
+
* Tasks run in parallel by default (controlled by options.parallel).
|
|
27
|
+
* Each task goes through: claim → resolve workspace → acquire slot →
|
|
28
|
+
* execute via adapter → collect result.
|
|
29
|
+
*/
|
|
30
|
+
dispatch(tasks: SubagentTask[], options?: DispatchOptions): Promise<AggregatedResult>;
|
|
31
|
+
/** Clean up all resources (worktrees, claims, concurrency) */
|
|
32
|
+
cleanup(): void;
|
|
33
|
+
/** Run orphan detection and cleanup */
|
|
34
|
+
reapOrphans(): SubagentResult[];
|
|
35
|
+
private dispatchParallel;
|
|
36
|
+
private executeTask;
|
|
37
|
+
/** Topological sort by dependencies (stable — preserves input order for equal deps) */
|
|
38
|
+
private resolveDependencies;
|
|
39
|
+
private getDefaultAdapterType;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=dispatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/subagent/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EAEd,eAAe,EACf,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAUpB,MAAM,WAAW,wBAAwB;IACvC,6DAA6D;IAC7D,eAAe,EAAE,sBAAsB,CAAC;IACxC,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4B;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;gBAE7C,MAAM,EAAE,wBAAwB;IAU5C;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2C/F,8DAA8D;IAC9D,OAAO,IAAI,IAAI;IAOf,uCAAuC;IACvC,WAAW,IAAI,cAAc,EAAE;YAcjB,gBAAgB;YAuFhB,WAAW;IA+EzB,uFAAuF;IACvF,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,qBAAqB;CAO9B"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SubagentDispatcher — the core orchestrator for subagent execution.
|
|
3
|
+
*
|
|
4
|
+
* Composes: TaskCheckout, WorkspaceResolver, ConcurrencyManager,
|
|
5
|
+
* OrphanReaper, and RuntimeAdapterRegistry to dispatch tasks to
|
|
6
|
+
* child agent processes.
|
|
7
|
+
*/
|
|
8
|
+
import { TaskCheckout } from './task-checkout.js';
|
|
9
|
+
import { WorkspaceResolver } from './workspace-resolver.js';
|
|
10
|
+
import { ConcurrencyManager } from './concurrency-manager.js';
|
|
11
|
+
import { OrphanReaper } from './orphan-reaper.js';
|
|
12
|
+
import { aggregate } from './result-aggregator.js';
|
|
13
|
+
const DEFAULT_TIMEOUT = 300_000; // 5 minutes
|
|
14
|
+
const DEFAULT_MAX_CONCURRENT = 3;
|
|
15
|
+
export class SubagentDispatcher {
|
|
16
|
+
checkout = new TaskCheckout();
|
|
17
|
+
workspace;
|
|
18
|
+
concurrency = new ConcurrencyManager();
|
|
19
|
+
reaper;
|
|
20
|
+
adapterRegistry;
|
|
21
|
+
constructor(config) {
|
|
22
|
+
this.adapterRegistry = config.adapterRegistry;
|
|
23
|
+
this.workspace = new WorkspaceResolver(config.baseDir ?? process.cwd());
|
|
24
|
+
this.reaper = new OrphanReaper((taskId) => {
|
|
25
|
+
// On orphan: release the task claim and clean up workspace
|
|
26
|
+
this.checkout.release(taskId);
|
|
27
|
+
this.workspace.cleanup(taskId);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dispatch one or more tasks to subagents.
|
|
32
|
+
*
|
|
33
|
+
* Tasks run in parallel by default (controlled by options.parallel).
|
|
34
|
+
* Each task goes through: claim → resolve workspace → acquire slot →
|
|
35
|
+
* execute via adapter → collect result.
|
|
36
|
+
*/
|
|
37
|
+
async dispatch(tasks, options = {}) {
|
|
38
|
+
const { parallel = true, maxConcurrent = DEFAULT_MAX_CONCURRENT, worktreeIsolation = false, timeout = DEFAULT_TIMEOUT, onTaskUpdate, } = options;
|
|
39
|
+
if (tasks.length === 0) {
|
|
40
|
+
return aggregate([]);
|
|
41
|
+
}
|
|
42
|
+
// Resolve dependency order
|
|
43
|
+
const ordered = this.resolveDependencies(tasks);
|
|
44
|
+
if (parallel) {
|
|
45
|
+
// Run independent tasks in parallel, respecting dependencies
|
|
46
|
+
const results = await this.dispatchParallel(ordered, {
|
|
47
|
+
maxConcurrent,
|
|
48
|
+
worktreeIsolation,
|
|
49
|
+
timeout,
|
|
50
|
+
onTaskUpdate,
|
|
51
|
+
});
|
|
52
|
+
return aggregate(results);
|
|
53
|
+
}
|
|
54
|
+
// Sequential dispatch — await in loop is intentional (tasks must run one at a time)
|
|
55
|
+
const results = [];
|
|
56
|
+
for (const task of ordered) {
|
|
57
|
+
// eslint-disable-line no-await-in-loop
|
|
58
|
+
onTaskUpdate?.(task.taskId, 'running');
|
|
59
|
+
const result = await this.executeTask(task, worktreeIsolation, timeout);
|
|
60
|
+
results.push(result);
|
|
61
|
+
onTaskUpdate?.(task.taskId, result.status);
|
|
62
|
+
// Stop on failure in sequential mode
|
|
63
|
+
if (result.exitCode !== 0)
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
return aggregate(results);
|
|
67
|
+
}
|
|
68
|
+
/** Clean up all resources (worktrees, claims, concurrency) */
|
|
69
|
+
cleanup() {
|
|
70
|
+
this.workspace.cleanupAll();
|
|
71
|
+
this.checkout.releaseAll();
|
|
72
|
+
this.concurrency.reset();
|
|
73
|
+
this.reaper.clear();
|
|
74
|
+
}
|
|
75
|
+
/** Run orphan detection and cleanup */
|
|
76
|
+
reapOrphans() {
|
|
77
|
+
const orphaned = this.reaper.reap();
|
|
78
|
+
return orphaned.map((p) => ({
|
|
79
|
+
taskId: p.taskId,
|
|
80
|
+
status: 'orphaned',
|
|
81
|
+
exitCode: 1,
|
|
82
|
+
error: `Process ${p.pid} died unexpectedly`,
|
|
83
|
+
durationMs: Date.now() - p.registeredAt,
|
|
84
|
+
pid: p.pid,
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
// ── Internal ──────────────────────────────────────────────────────
|
|
88
|
+
async dispatchParallel(tasks, opts) {
|
|
89
|
+
const results = new Map();
|
|
90
|
+
const pending = new Map();
|
|
91
|
+
const completed = new Set();
|
|
92
|
+
// Initialize all tasks as pending
|
|
93
|
+
for (const task of tasks) {
|
|
94
|
+
pending.set(task.taskId, task);
|
|
95
|
+
}
|
|
96
|
+
// Process in waves until all done
|
|
97
|
+
while (pending.size > 0) {
|
|
98
|
+
// Find tasks whose dependencies are all completed
|
|
99
|
+
const ready = [];
|
|
100
|
+
for (const [_id, task] of pending) {
|
|
101
|
+
const deps = task.dependencies ?? [];
|
|
102
|
+
if (deps.every((d) => completed.has(d))) {
|
|
103
|
+
ready.push(task);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (ready.length === 0 && pending.size > 0) {
|
|
107
|
+
// Deadlock — remaining tasks have unmet dependencies
|
|
108
|
+
for (const [deadId, task] of pending) {
|
|
109
|
+
results.set(deadId, {
|
|
110
|
+
taskId: deadId,
|
|
111
|
+
status: 'failed',
|
|
112
|
+
exitCode: 1,
|
|
113
|
+
error: `Unresolvable dependencies: ${(task.dependencies ?? []).filter((d) => !completed.has(d)).join(', ')}`,
|
|
114
|
+
durationMs: 0,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
// Dispatch ready tasks in parallel with concurrency control
|
|
120
|
+
// eslint-disable-next-line no-await-in-loop -- waves must complete before next wave
|
|
121
|
+
const waveResults = await Promise.allSettled(ready.map(async (task) => {
|
|
122
|
+
opts.onTaskUpdate?.(task.taskId, 'running');
|
|
123
|
+
await this.concurrency.acquire(task.runtime ?? 'default', opts.maxConcurrent);
|
|
124
|
+
try {
|
|
125
|
+
return await this.executeTask(task, opts.worktreeIsolation, task.timeout ?? opts.timeout);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
this.concurrency.release(task.runtime ?? 'default');
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
131
|
+
// Collect results
|
|
132
|
+
for (let i = 0; i < ready.length; i++) {
|
|
133
|
+
const task = ready[i];
|
|
134
|
+
const settled = waveResults[i];
|
|
135
|
+
const result = settled.status === 'fulfilled'
|
|
136
|
+
? settled.value
|
|
137
|
+
: {
|
|
138
|
+
taskId: task.taskId,
|
|
139
|
+
status: 'failed',
|
|
140
|
+
exitCode: 1,
|
|
141
|
+
error: settled.reason?.message ?? 'Unknown error',
|
|
142
|
+
durationMs: 0,
|
|
143
|
+
};
|
|
144
|
+
results.set(task.taskId, result);
|
|
145
|
+
completed.add(task.taskId);
|
|
146
|
+
pending.delete(task.taskId);
|
|
147
|
+
opts.onTaskUpdate?.(task.taskId, result.status);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Return in original task order
|
|
151
|
+
return tasks.map((t) => results.get(t.taskId));
|
|
152
|
+
}
|
|
153
|
+
async executeTask(task, worktreeIsolation, timeout) {
|
|
154
|
+
const startTime = Date.now();
|
|
155
|
+
// 1. Claim the task
|
|
156
|
+
const claimed = this.checkout.claim(task.taskId, 'dispatcher');
|
|
157
|
+
if (!claimed) {
|
|
158
|
+
return {
|
|
159
|
+
taskId: task.taskId,
|
|
160
|
+
status: 'failed',
|
|
161
|
+
exitCode: 1,
|
|
162
|
+
error: 'Task already claimed by another process',
|
|
163
|
+
durationMs: Date.now() - startTime,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// 2. Resolve workspace
|
|
167
|
+
const workspace = this.workspace.resolve(task.taskId, task.workspace, worktreeIsolation);
|
|
168
|
+
// 3. Get adapter
|
|
169
|
+
const adapterType = task.runtime ?? this.getDefaultAdapterType();
|
|
170
|
+
let adapter;
|
|
171
|
+
try {
|
|
172
|
+
adapter = this.adapterRegistry.get(adapterType);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
this.checkout.release(task.taskId);
|
|
176
|
+
return {
|
|
177
|
+
taskId: task.taskId,
|
|
178
|
+
status: 'failed',
|
|
179
|
+
exitCode: 1,
|
|
180
|
+
error: `Adapter '${adapterType}' not found in registry`,
|
|
181
|
+
durationMs: Date.now() - startTime,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// 4. Execute with timeout
|
|
185
|
+
try {
|
|
186
|
+
const resultPromise = adapter.execute({
|
|
187
|
+
runId: `subagent-${task.taskId}-${Date.now()}`,
|
|
188
|
+
prompt: task.prompt,
|
|
189
|
+
workspace,
|
|
190
|
+
config: { ...task.config, timeout },
|
|
191
|
+
});
|
|
192
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
193
|
+
setTimeout(() => reject(new Error('Task timed out')), timeout);
|
|
194
|
+
});
|
|
195
|
+
const adapterResult = await Promise.race([resultPromise, timeoutPromise]);
|
|
196
|
+
return {
|
|
197
|
+
taskId: task.taskId,
|
|
198
|
+
status: adapterResult.exitCode === 0 ? 'completed' : 'failed',
|
|
199
|
+
exitCode: adapterResult.exitCode,
|
|
200
|
+
summary: adapterResult.summary,
|
|
201
|
+
usage: adapterResult.usage,
|
|
202
|
+
sessionState: adapterResult.sessionState,
|
|
203
|
+
durationMs: Date.now() - startTime,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
return {
|
|
208
|
+
taskId: task.taskId,
|
|
209
|
+
status: 'failed',
|
|
210
|
+
exitCode: 1,
|
|
211
|
+
error: err instanceof Error ? err.message : String(err),
|
|
212
|
+
durationMs: Date.now() - startTime,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
// Cleanup
|
|
217
|
+
this.checkout.release(task.taskId);
|
|
218
|
+
if (worktreeIsolation) {
|
|
219
|
+
this.workspace.cleanup(task.taskId);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/** Topological sort by dependencies (stable — preserves input order for equal deps) */
|
|
224
|
+
resolveDependencies(tasks) {
|
|
225
|
+
const taskMap = new Map(tasks.map((t) => [t.taskId, t]));
|
|
226
|
+
const sorted = [];
|
|
227
|
+
const visited = new Set();
|
|
228
|
+
const visiting = new Set();
|
|
229
|
+
const visit = (id) => {
|
|
230
|
+
if (visited.has(id))
|
|
231
|
+
return;
|
|
232
|
+
if (visiting.has(id))
|
|
233
|
+
return; // cycle — skip
|
|
234
|
+
visiting.add(id);
|
|
235
|
+
const task = taskMap.get(id);
|
|
236
|
+
if (task) {
|
|
237
|
+
for (const dep of task.dependencies ?? []) {
|
|
238
|
+
visit(dep);
|
|
239
|
+
}
|
|
240
|
+
visited.add(id);
|
|
241
|
+
visiting.delete(id);
|
|
242
|
+
sorted.push(task);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
for (const task of tasks) {
|
|
246
|
+
visit(task.taskId);
|
|
247
|
+
}
|
|
248
|
+
return sorted;
|
|
249
|
+
}
|
|
250
|
+
getDefaultAdapterType() {
|
|
251
|
+
try {
|
|
252
|
+
return this.adapterRegistry.getDefault().type;
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return 'claude-code';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=dispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../../src/subagent/dispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent runtime engine — spawn, manage, and aggregate results
|
|
3
|
+
* from child agent processes.
|
|
4
|
+
*
|
|
5
|
+
* @module subagent
|
|
6
|
+
*/
|
|
7
|
+
export type { SubagentTask, SubagentStatus, SubagentResult, DispatchOptions, AggregatedResult, ClaimInfo, WorktreeInfo, TrackedProcess, } from './types.js';
|
|
8
|
+
export { TaskCheckout } from './task-checkout.js';
|
|
9
|
+
export { WorkspaceResolver } from './workspace-resolver.js';
|
|
10
|
+
export { ConcurrencyManager } from './concurrency-manager.js';
|
|
11
|
+
export { OrphanReaper } from './orphan-reaper.js';
|
|
12
|
+
export { aggregate as aggregateResults } from './result-aggregator.js';
|
|
13
|
+
export { SubagentDispatcher } from './dispatcher.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/subagent/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,YAAY,EACZ,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAGvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent runtime engine — spawn, manage, and aggregate results
|
|
3
|
+
* from child agent processes.
|
|
4
|
+
*
|
|
5
|
+
* @module subagent
|
|
6
|
+
*/
|
|
7
|
+
// Components
|
|
8
|
+
export { TaskCheckout } from './task-checkout.js';
|
|
9
|
+
export { WorkspaceResolver } from './workspace-resolver.js';
|
|
10
|
+
export { ConcurrencyManager } from './concurrency-manager.js';
|
|
11
|
+
export { OrphanReaper } from './orphan-reaper.js';
|
|
12
|
+
export { aggregate as aggregateResults } from './result-aggregator.js';
|
|
13
|
+
// Dispatcher
|
|
14
|
+
export { SubagentDispatcher } from './dispatcher.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/subagent/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,aAAa;AACb,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAEvE,aAAa;AACb,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrphanReaper — tracks spawned child processes and detects dead/orphaned ones.
|
|
3
|
+
*
|
|
4
|
+
* Uses `process.kill(pid, 0)` (signal 0) as an existence check:
|
|
5
|
+
* - No error → process is alive
|
|
6
|
+
* - ESRCH → process is dead (reap it)
|
|
7
|
+
* - EPERM → process is alive but we lack permission to signal it
|
|
8
|
+
*/
|
|
9
|
+
import type { TrackedProcess } from './types.js';
|
|
10
|
+
export declare class OrphanReaper {
|
|
11
|
+
private readonly tracked;
|
|
12
|
+
private readonly onOrphan?;
|
|
13
|
+
constructor(onOrphan?: (taskId: string, pid: number) => void);
|
|
14
|
+
/** Start tracking a process. */
|
|
15
|
+
register(pid: number, taskId: string): void;
|
|
16
|
+
/** Stop tracking a process (called on normal completion). */
|
|
17
|
+
unregister(pid: number): void;
|
|
18
|
+
/**
|
|
19
|
+
* Check each tracked PID for liveness. Dead processes are removed from
|
|
20
|
+
* tracking, the onOrphan callback is invoked, and they are returned.
|
|
21
|
+
*/
|
|
22
|
+
reap(): TrackedProcess[];
|
|
23
|
+
/** Return all currently tracked processes. */
|
|
24
|
+
listTracked(): TrackedProcess[];
|
|
25
|
+
/** Check if a PID is currently tracked. */
|
|
26
|
+
isTracked(pid: number): boolean;
|
|
27
|
+
/** Clear all tracked processes without killing them. */
|
|
28
|
+
clear(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Signal-0 existence check.
|
|
31
|
+
* - No error → alive
|
|
32
|
+
* - EPERM → alive (exists but we can't signal it)
|
|
33
|
+
* - ESRCH → dead
|
|
34
|
+
*/
|
|
35
|
+
private isAlive;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=orphan-reaper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphan-reaper.d.ts","sourceRoot":"","sources":["../../src/subagent/orphan-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAwC;gBAEtD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI;IAI5D,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3C,6DAA6D;IAC7D,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI7B;;;OAGG;IACH,IAAI,IAAI,cAAc,EAAE;IAcxB,8CAA8C;IAC9C,WAAW,IAAI,cAAc,EAAE;IAI/B,2CAA2C;IAC3C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI/B,wDAAwD;IACxD,KAAK,IAAI,IAAI;IAMb;;;;;OAKG;IACH,OAAO,CAAC,OAAO;CAWhB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OrphanReaper — tracks spawned child processes and detects dead/orphaned ones.
|
|
3
|
+
*
|
|
4
|
+
* Uses `process.kill(pid, 0)` (signal 0) as an existence check:
|
|
5
|
+
* - No error → process is alive
|
|
6
|
+
* - ESRCH → process is dead (reap it)
|
|
7
|
+
* - EPERM → process is alive but we lack permission to signal it
|
|
8
|
+
*/
|
|
9
|
+
export class OrphanReaper {
|
|
10
|
+
tracked = new Map();
|
|
11
|
+
onOrphan;
|
|
12
|
+
constructor(onOrphan) {
|
|
13
|
+
this.onOrphan = onOrphan;
|
|
14
|
+
}
|
|
15
|
+
/** Start tracking a process. */
|
|
16
|
+
register(pid, taskId) {
|
|
17
|
+
this.tracked.set(pid, { pid, taskId, registeredAt: Date.now() });
|
|
18
|
+
}
|
|
19
|
+
/** Stop tracking a process (called on normal completion). */
|
|
20
|
+
unregister(pid) {
|
|
21
|
+
this.tracked.delete(pid);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check each tracked PID for liveness. Dead processes are removed from
|
|
25
|
+
* tracking, the onOrphan callback is invoked, and they are returned.
|
|
26
|
+
*/
|
|
27
|
+
reap() {
|
|
28
|
+
const reaped = [];
|
|
29
|
+
for (const [pid, entry] of this.tracked) {
|
|
30
|
+
if (!this.isAlive(pid)) {
|
|
31
|
+
this.tracked.delete(pid);
|
|
32
|
+
this.onOrphan?.(entry.taskId, pid);
|
|
33
|
+
reaped.push(entry);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return reaped;
|
|
37
|
+
}
|
|
38
|
+
/** Return all currently tracked processes. */
|
|
39
|
+
listTracked() {
|
|
40
|
+
return [...this.tracked.values()];
|
|
41
|
+
}
|
|
42
|
+
/** Check if a PID is currently tracked. */
|
|
43
|
+
isTracked(pid) {
|
|
44
|
+
return this.tracked.has(pid);
|
|
45
|
+
}
|
|
46
|
+
/** Clear all tracked processes without killing them. */
|
|
47
|
+
clear() {
|
|
48
|
+
this.tracked.clear();
|
|
49
|
+
}
|
|
50
|
+
// ── internals ──────────────────────────────────────────────────────
|
|
51
|
+
/**
|
|
52
|
+
* Signal-0 existence check.
|
|
53
|
+
* - No error → alive
|
|
54
|
+
* - EPERM → alive (exists but we can't signal it)
|
|
55
|
+
* - ESRCH → dead
|
|
56
|
+
*/
|
|
57
|
+
isAlive(pid) {
|
|
58
|
+
try {
|
|
59
|
+
process.kill(pid, 0);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
const code = err.code;
|
|
64
|
+
if (code === 'EPERM')
|
|
65
|
+
return true;
|
|
66
|
+
// ESRCH or any other error → treat as dead
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=orphan-reaper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orphan-reaper.js","sourceRoot":"","sources":["../../src/subagent/orphan-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,OAAO,YAAY;IACN,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC5C,QAAQ,CAAyC;IAElE,YAAY,QAAgD;QAC1D,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,gCAAgC;IAChC,QAAQ,CAAC,GAAW,EAAE,MAAc;QAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,6DAA6D;IAC7D,UAAU,CAAC,GAAW;QACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,MAAM,MAAM,GAAqB,EAAE,CAAC;QAEpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACvB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBACnC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,8CAA8C;IAC9C,WAAW;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,2CAA2C;IAC3C,SAAS,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,wDAAwD;IACxD,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,sEAAsE;IAEtE;;;;;OAKG;IACK,OAAO,CAAC,GAAW;QACzB,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;YACrB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,OAAO;gBAAE,OAAO,IAAI,CAAC;YAClC,2CAA2C;YAC3C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result aggregator — merges results from multiple parallel subagent
|
|
3
|
+
* executions into a single summary.
|
|
4
|
+
*/
|
|
5
|
+
import type { AggregatedResult, SubagentResult } from './types.js';
|
|
6
|
+
export declare function aggregate(results: SubagentResult[]): AggregatedResult;
|
|
7
|
+
//# sourceMappingURL=result-aggregator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-aggregator.d.ts","sourceRoot":"","sources":["../../src/subagent/result-aggregator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnE,wBAAgB,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,gBAAgB,CA0DrE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Result aggregator — merges results from multiple parallel subagent
|
|
3
|
+
* executions into a single summary.
|
|
4
|
+
*/
|
|
5
|
+
export function aggregate(results) {
|
|
6
|
+
if (results.length === 0) {
|
|
7
|
+
return {
|
|
8
|
+
status: 'all-passed',
|
|
9
|
+
totalTasks: 0,
|
|
10
|
+
completed: 0,
|
|
11
|
+
failed: 0,
|
|
12
|
+
totalUsage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
|
|
13
|
+
filesChanged: [],
|
|
14
|
+
combinedSummary: '',
|
|
15
|
+
durationMs: 0,
|
|
16
|
+
results: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
const completed = results.filter((r) => r.exitCode === 0).length;
|
|
20
|
+
const failed = results.length - completed;
|
|
21
|
+
const status = failed === 0 ? 'all-passed' : completed === 0 ? 'all-failed' : 'partial';
|
|
22
|
+
const totalUsage = {
|
|
23
|
+
inputTokens: 0,
|
|
24
|
+
outputTokens: 0,
|
|
25
|
+
totalTokens: 0,
|
|
26
|
+
};
|
|
27
|
+
for (const r of results) {
|
|
28
|
+
totalUsage.inputTokens += r.usage?.inputTokens ?? 0;
|
|
29
|
+
totalUsage.outputTokens += r.usage?.outputTokens ?? 0;
|
|
30
|
+
totalUsage.totalTokens += r.usage?.totalTokens ?? 0;
|
|
31
|
+
}
|
|
32
|
+
const fileSet = new Set();
|
|
33
|
+
for (const r of results) {
|
|
34
|
+
if (r.filesChanged) {
|
|
35
|
+
for (const f of r.filesChanged)
|
|
36
|
+
fileSet.add(f);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const combinedSummary = results
|
|
40
|
+
.filter((r) => r.summary)
|
|
41
|
+
.map((r) => `[${r.taskId}] ${r.summary}`)
|
|
42
|
+
.join('\n');
|
|
43
|
+
// Parallel wall-clock: max of all durations
|
|
44
|
+
const durationMs = Math.max(...results.map((r) => r.durationMs));
|
|
45
|
+
return {
|
|
46
|
+
status,
|
|
47
|
+
totalTasks: results.length,
|
|
48
|
+
completed,
|
|
49
|
+
failed,
|
|
50
|
+
totalUsage,
|
|
51
|
+
filesChanged: [...fileSet],
|
|
52
|
+
combinedSummary,
|
|
53
|
+
durationMs,
|
|
54
|
+
results,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=result-aggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result-aggregator.js","sourceRoot":"","sources":["../../src/subagent/result-aggregator.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,UAAU,SAAS,CAAC,OAAyB;IACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,MAAM,EAAE,YAAY;YACpB,UAAU,EAAE,CAAC;YACb,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,UAAU,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE;YAC/D,YAAY,EAAE,EAAE;YAChB,eAAe,EAAE,EAAE;YACnB,UAAU,EAAE,CAAC;YACb,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAE1C,MAAM,MAAM,GACV,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IAE3E,MAAM,UAAU,GAAG;QACjB,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;KACf,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,UAAU,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,CAAC;QACpD,UAAU,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;QACtD,UAAU,CAAC,WAAW,IAAI,CAAC,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;YACnB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,MAAM,eAAe,GAAG,OAAO;SAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACxB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;SACxC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,4CAA4C;IAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAEjE,OAAO;QACL,MAAM;QACN,UAAU,EAAE,OAAO,CAAC,MAAM;QAC1B,SAAS;QACT,MAAM;QACN,UAAU;QACV,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC;QAC1B,eAAe;QACf,UAAU;QACV,OAAO;KACR,CAAC;AACJ,CAAC"}
|