@wrongstack/cli 0.5.6 → 0.5.7
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/index.js +106 -144
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as path21 from 'path';
|
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
import * as fsp2 from 'fs/promises';
|
|
5
5
|
import { readdir, readFile } from 'fs/promises';
|
|
6
|
-
import { color, allServers, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, ToolRegistry, createContextManagerTool, EventBus, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, SlashCommandRegistry, loadPlugins, createDelegateTool, FLEET_ROSTER, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, makeDirectorSessionFactory, Director,
|
|
6
|
+
import { color, allServers, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, ToolRegistry, createContextManagerTool, EventBus, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, SlashCommandRegistry, loadPlugins, createDelegateTool, FLEET_ROSTER, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, FleetManager, makeDirectorSessionFactory, Director, makeAgentSubagentRunner, NULL_FLEET_BUS, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, AutoApprovePermissionPolicy, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, SpecVersioning, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, InputBuilder, projectHash, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, DefaultPluginAPI } from '@wrongstack/core';
|
|
7
7
|
import { createRequire } from 'module';
|
|
8
8
|
import * as os6 from 'os';
|
|
9
9
|
import os6__default from 'os';
|
|
@@ -7339,6 +7339,8 @@ async function execute(deps) {
|
|
|
7339
7339
|
result = await agent.run(query, { signal: ctrl.signal });
|
|
7340
7340
|
} finally {
|
|
7341
7341
|
process.off("SIGINT", onSigint);
|
|
7342
|
+
const { getProcessRegistry } = await import('@wrongstack/tools');
|
|
7343
|
+
getProcessRegistry().killAll();
|
|
7342
7344
|
}
|
|
7343
7345
|
const after = tokenCounter.total();
|
|
7344
7346
|
const costAfter = tokenCounter.estimateCost().total;
|
|
@@ -7537,22 +7539,18 @@ var MultiAgentHost = class {
|
|
|
7537
7539
|
this.opts = opts;
|
|
7538
7540
|
}
|
|
7539
7541
|
deps;
|
|
7540
|
-
coordinator;
|
|
7541
|
-
/** Lazily built when `opts.directorMode` is set. Owns its own internal
|
|
7542
|
-
* coordinator; the host's `coordinator` field still points at it so
|
|
7543
|
-
* the rest of the methods don't need to branch. */
|
|
7544
7542
|
director;
|
|
7543
|
+
/** Own FleetManager — created in buildDirector(), used for pending task
|
|
7544
|
+
* tracking so status() can show descriptions without host-side state. */
|
|
7545
|
+
fleetManager;
|
|
7545
7546
|
/** Lazily built alongside the director — produces per-subagent JSONL
|
|
7546
|
-
* writers under `<sessionsRoot>/<runId>/`. Null
|
|
7547
|
+
* writers under `<sessionsRoot>/<runId>/`. Null without sessionsRoot. */
|
|
7547
7548
|
sessionFactory;
|
|
7548
|
-
pending = /* @__PURE__ */ new Map();
|
|
7549
|
-
results = [];
|
|
7550
7549
|
opts;
|
|
7551
7550
|
/**
|
|
7552
|
-
* Populated by `promoteToDirector` when it refuses to promote
|
|
7553
|
-
* because a non-director coordinator is already running). The delegate
|
|
7551
|
+
* Populated by `promoteToDirector` when it refuses to promote. The delegate
|
|
7554
7552
|
* tool reads this through `getPromotionBlockReason` to render an
|
|
7555
|
-
* actionable error instead of a generic "could not
|
|
7553
|
+
* actionable error instead of a generic "Director could not be activated".
|
|
7556
7554
|
*/
|
|
7557
7555
|
promotionBlockReason = null;
|
|
7558
7556
|
/**
|
|
@@ -7565,14 +7563,34 @@ var MultiAgentHost = class {
|
|
|
7565
7563
|
* orchestration tools and `--director` becomes a no-op.
|
|
7566
7564
|
*/
|
|
7567
7565
|
async ensureDirector() {
|
|
7566
|
+
if (this.director) return this.director;
|
|
7568
7567
|
if (!this.opts.directorMode) return null;
|
|
7569
|
-
await this.
|
|
7568
|
+
await this.buildDirector();
|
|
7570
7569
|
return this.director ?? null;
|
|
7571
7570
|
}
|
|
7572
|
-
|
|
7573
|
-
|
|
7571
|
+
/** Access the Director's internal coordinator. Returns the concrete
|
|
7572
|
+
* `DefaultMultiAgentCoordinator` so callers can use class-only surface
|
|
7573
|
+
* (`on`, `setRunner`) that isn't part of the `MultiAgentCoordinator`
|
|
7574
|
+
* interface. */
|
|
7575
|
+
getCoordinator() {
|
|
7576
|
+
return this.director.coordinator;
|
|
7577
|
+
}
|
|
7578
|
+
async buildDirector() {
|
|
7579
|
+
if (this.director) return;
|
|
7574
7580
|
const config = this.deps.configStore.get();
|
|
7575
|
-
|
|
7581
|
+
const fleetManager = new FleetManager({
|
|
7582
|
+
manifestPath: this.opts.manifestPath,
|
|
7583
|
+
sessionsRoot: this.opts.sessionsRoot,
|
|
7584
|
+
directorRunId: this.opts.directorRunId,
|
|
7585
|
+
stateCheckpointPath: this.opts.stateCheckpointPath,
|
|
7586
|
+
sessionWriter: this.opts.sessionWriter,
|
|
7587
|
+
directorBudget: this.opts.directorBudget,
|
|
7588
|
+
manifestDebounceMs: 2e3,
|
|
7589
|
+
checkpointDebounceMs: this.opts.checkpointDebounceMs ?? 250,
|
|
7590
|
+
maxSpawnDepth: 5
|
|
7591
|
+
});
|
|
7592
|
+
this.fleetManager = fleetManager;
|
|
7593
|
+
if (this.opts.sessionsRoot && !this.sessionFactory) {
|
|
7576
7594
|
this.sessionFactory = makeDirectorSessionFactory({
|
|
7577
7595
|
sessionsRoot: this.opts.sessionsRoot,
|
|
7578
7596
|
directorRunId: this.opts.directorRunId
|
|
@@ -7582,75 +7600,45 @@ var MultiAgentHost = class {
|
|
|
7582
7600
|
coordinatorId: randomUUID(),
|
|
7583
7601
|
doneCondition: { type: "all_tasks_done" },
|
|
7584
7602
|
maxConcurrent: 8
|
|
7585
|
-
// No defaultBudget. Caps land on a subagent ONLY when the
|
|
7586
|
-
// orchestrator (delegate-tool / spawn_subagent) or the user
|
|
7587
|
-
// (CLI flag) sets them explicitly. The prior defaults
|
|
7588
|
-
// (1000 tools / 200 iter / 4h) silently killed long autonomous
|
|
7589
|
-
// runs; for a "work until done" director we want no implicit
|
|
7590
|
-
// ceilings. The orchestrator can still cap a single subagent
|
|
7591
|
-
// by passing maxToolCalls/maxIterations through the spawn tool.
|
|
7592
7603
|
};
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7604
|
+
const defaultScratchpad = this.opts.sharedScratchpadPath || (this.opts.sessionsRoot && this.opts.directorRunId ? path21.join(this.opts.sessionsRoot, this.opts.directorRunId, "shared") : void 0);
|
|
7605
|
+
this.director = new Director({
|
|
7606
|
+
config: coordinatorConfig,
|
|
7607
|
+
manifestPath: this.opts.manifestPath,
|
|
7608
|
+
sharedScratchpadPath: defaultScratchpad,
|
|
7609
|
+
stateCheckpointPath: this.opts.stateCheckpointPath,
|
|
7610
|
+
sessionWriter: this.opts.sessionWriter,
|
|
7611
|
+
directorBudget: this.opts.directorBudget,
|
|
7612
|
+
maxBudgetExtensions: this.opts.maxBudgetExtensions,
|
|
7613
|
+
checkpointDebounceMs: this.opts.checkpointDebounceMs,
|
|
7614
|
+
sessionsRoot: this.opts.sessionsRoot,
|
|
7615
|
+
directorRunId: this.opts.directorRunId,
|
|
7616
|
+
maxSpawnDepth: 5,
|
|
7617
|
+
fleetManager
|
|
7618
|
+
// pass so director.fleetManager is never undefined
|
|
7619
|
+
});
|
|
7620
|
+
this.director.on("task.completed", ({ task, result }) => {
|
|
7621
|
+
this.fleetManager?.removePendingTask(task.id);
|
|
7622
|
+
this.emitLifecycleCompleted(task.id, result);
|
|
7623
|
+
});
|
|
7624
|
+
this.director.fleet.filter("budget.threshold_reached", (e) => {
|
|
7625
|
+
const payload = e.payload;
|
|
7626
|
+
this.deps.events.emit("subagent.budget_warning", {
|
|
7627
|
+
subagentId: e.subagentId,
|
|
7628
|
+
kind: payload.kind,
|
|
7629
|
+
used: payload.used,
|
|
7630
|
+
limit: payload.limit
|
|
7618
7631
|
});
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
limit: payload.limit
|
|
7626
|
-
});
|
|
7632
|
+
});
|
|
7633
|
+
this.getCoordinator().on("task.assigned", ({ task, subagentId }) => {
|
|
7634
|
+
this.deps.events.emit("subagent.task_started", {
|
|
7635
|
+
subagentId,
|
|
7636
|
+
taskId: task.id,
|
|
7637
|
+
description: task.description
|
|
7627
7638
|
});
|
|
7628
|
-
|
|
7629
|
-
} else {
|
|
7630
|
-
this.coordinator = new DefaultMultiAgentCoordinator(coordinatorConfig, {});
|
|
7631
|
-
this.coordinator.on(
|
|
7632
|
-
"task.completed",
|
|
7633
|
-
({ task, result }) => {
|
|
7634
|
-
this.results.push(result);
|
|
7635
|
-
this.pending.delete(task.id);
|
|
7636
|
-
this.emitLifecycleCompleted(task.id, result);
|
|
7637
|
-
}
|
|
7638
|
-
);
|
|
7639
|
-
}
|
|
7640
|
-
this.coordinator.on(
|
|
7641
|
-
"task.assigned",
|
|
7642
|
-
({ task, subagentId }) => {
|
|
7643
|
-
this.deps.events.emit("subagent.task_started", {
|
|
7644
|
-
subagentId,
|
|
7645
|
-
taskId: task.id,
|
|
7646
|
-
description: task.description
|
|
7647
|
-
});
|
|
7648
|
-
}
|
|
7649
|
-
);
|
|
7639
|
+
});
|
|
7650
7640
|
const runner = this.buildSubagentRunner(config);
|
|
7651
|
-
|
|
7652
|
-
innerCoord.setRunner(runner);
|
|
7653
|
-
return this.coordinator;
|
|
7641
|
+
this.getCoordinator().setRunner(runner);
|
|
7654
7642
|
}
|
|
7655
7643
|
/**
|
|
7656
7644
|
* Build the per-subagent runner: agent factory → runner. Extracted so
|
|
@@ -7732,7 +7720,7 @@ var MultiAgentHost = class {
|
|
|
7732
7720
|
};
|
|
7733
7721
|
return { agent, events, dispose };
|
|
7734
7722
|
};
|
|
7735
|
-
return makeAgentSubagentRunner({ factory, fleetBus: this.director?.fleet });
|
|
7723
|
+
return makeAgentSubagentRunner({ factory, fleetBus: this.director?.fleet ?? NULL_FLEET_BUS });
|
|
7736
7724
|
}
|
|
7737
7725
|
/**
|
|
7738
7726
|
* Build a Provider for a subagent. When `overrideId` is supplied (from
|
|
@@ -7778,7 +7766,7 @@ var MultiAgentHost = class {
|
|
|
7778
7766
|
* the full tool registry.
|
|
7779
7767
|
*/
|
|
7780
7768
|
async spawn(description, opts) {
|
|
7781
|
-
await this.
|
|
7769
|
+
await this.buildDirector();
|
|
7782
7770
|
const subagentConfig = {
|
|
7783
7771
|
name: opts?.name ?? "adhoc",
|
|
7784
7772
|
role: "general",
|
|
@@ -7787,34 +7775,10 @@ var MultiAgentHost = class {
|
|
|
7787
7775
|
tools: opts?.tools
|
|
7788
7776
|
};
|
|
7789
7777
|
const transcriptPath = this.sessionFactory ? path21.join(this.sessionFactory.dir, `${subagentConfig.name}.jsonl`) : void 0;
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
const taskId2 = randomUUID();
|
|
7793
|
-
this.pending.set(taskId2, { description, subagentId });
|
|
7794
|
-
this.deps.events.emit("subagent.spawned", {
|
|
7795
|
-
subagentId,
|
|
7796
|
-
taskId: taskId2,
|
|
7797
|
-
name: subagentConfig.name,
|
|
7798
|
-
provider: opts?.provider,
|
|
7799
|
-
model: opts?.model,
|
|
7800
|
-
description,
|
|
7801
|
-
transcriptPath
|
|
7802
|
-
});
|
|
7803
|
-
await this.director.assign({
|
|
7804
|
-
id: taskId2,
|
|
7805
|
-
description,
|
|
7806
|
-
subagentId
|
|
7807
|
-
// No maxToolCalls — same reasoning as the spawn config above.
|
|
7808
|
-
// The director / orchestrator owns the budget decision.
|
|
7809
|
-
});
|
|
7810
|
-
return { subagentId, taskId: taskId2 };
|
|
7811
|
-
}
|
|
7812
|
-
const coord = this.coordinator;
|
|
7813
|
-
const spawned = await coord.spawn(subagentConfig);
|
|
7814
|
-
const taskId = randomUUID();
|
|
7815
|
-
this.pending.set(taskId, { description, subagentId: spawned.subagentId });
|
|
7778
|
+
const { subagentId, taskId } = await this._spawnAndAssign(subagentConfig);
|
|
7779
|
+
this.fleetManager?.addPendingTask(taskId, subagentId, description);
|
|
7816
7780
|
this.deps.events.emit("subagent.spawned", {
|
|
7817
|
-
subagentId
|
|
7781
|
+
subagentId,
|
|
7818
7782
|
taskId,
|
|
7819
7783
|
name: subagentConfig.name,
|
|
7820
7784
|
provider: opts?.provider,
|
|
@@ -7822,13 +7786,22 @@ var MultiAgentHost = class {
|
|
|
7822
7786
|
description,
|
|
7823
7787
|
transcriptPath
|
|
7824
7788
|
});
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7789
|
+
return { subagentId, taskId };
|
|
7790
|
+
}
|
|
7791
|
+
/**
|
|
7792
|
+
* Common spawn + assign logic shared by both director mode and raw
|
|
7793
|
+
* coordinator mode. Extracts the identical body from the two branches
|
|
7794
|
+
* in `spawn()` so future changes (e.g. adding a new field to both
|
|
7795
|
+
* paths) are made in one place.
|
|
7796
|
+
*
|
|
7797
|
+
* Returns `{ subagentId, taskId }`. Caller holds `pending` tracking
|
|
7798
|
+
* and event emission — the helper only talks to the coordinator.
|
|
7799
|
+
*/
|
|
7800
|
+
async _spawnAndAssign(subagentConfig) {
|
|
7801
|
+
const taskId = randomUUID();
|
|
7802
|
+
const subagentId = await this.director.spawn(subagentConfig);
|
|
7803
|
+
await this.director.assign({ id: taskId, description: "", subagentId });
|
|
7804
|
+
return { subagentId, taskId };
|
|
7832
7805
|
}
|
|
7833
7806
|
/**
|
|
7834
7807
|
* Relay a `task.completed` notification (from either the Director or
|
|
@@ -7851,29 +7824,24 @@ var MultiAgentHost = class {
|
|
|
7851
7824
|
}
|
|
7852
7825
|
status() {
|
|
7853
7826
|
const activeSubagentIds = /* @__PURE__ */ new Set();
|
|
7854
|
-
|
|
7855
|
-
|
|
7827
|
+
const live = [];
|
|
7828
|
+
if (this.director) {
|
|
7829
|
+
const coord = this.getCoordinator();
|
|
7830
|
+
const s = coord.getStatus();
|
|
7856
7831
|
for (const a of s.subagents) {
|
|
7857
7832
|
if (a.status === "running" || a.status === "idle") {
|
|
7858
7833
|
activeSubagentIds.add(a.id);
|
|
7859
7834
|
}
|
|
7860
|
-
}
|
|
7861
|
-
}
|
|
7862
|
-
const pending = Array.from(this.pending.entries()).filter(([, v]) => activeSubagentIds.has(v.subagentId)).map(([taskId, v]) => ({
|
|
7863
|
-
taskId,
|
|
7864
|
-
description: v.description,
|
|
7865
|
-
subagentId: v.subagentId
|
|
7866
|
-
}));
|
|
7867
|
-
const live = [];
|
|
7868
|
-
if (this.coordinator) {
|
|
7869
|
-
const s = this.coordinator.getStatus();
|
|
7870
|
-
for (const a of s.subagents) {
|
|
7871
7835
|
live.push({ subagentId: a.id, status: a.status, task: a.currentTask });
|
|
7872
7836
|
}
|
|
7873
7837
|
}
|
|
7838
|
+
const fleetStatus = this.fleetManager?.getFleetStatus() ?? { pending: []};
|
|
7839
|
+
const pending = fleetStatus.pending.filter((p) => activeSubagentIds.has(p.subagentId));
|
|
7840
|
+
const completed = this.director ? this.director.completedResults() : [];
|
|
7841
|
+
const completedCount = completed.length;
|
|
7874
7842
|
const liveCount = live.filter((s) => s.status === "running" || s.status === "idle").length;
|
|
7875
|
-
const summary = !this.
|
|
7876
|
-
return { pending, completed
|
|
7843
|
+
const summary = !this.director ? "No subagents have been spawned." : liveCount > 0 ? `${pending.length} pending, ${liveCount} active, ${completedCount} completed.` : `${pending.length} pending, ${completedCount} completed.`;
|
|
7844
|
+
return { pending, completed, live, summary };
|
|
7877
7845
|
}
|
|
7878
7846
|
/**
|
|
7879
7847
|
* Roll up per-subagent runtime cost from completed TaskResults. We don't
|
|
@@ -7886,8 +7854,9 @@ var MultiAgentHost = class {
|
|
|
7886
7854
|
* the table renders the most interesting subagent at the top.
|
|
7887
7855
|
*/
|
|
7888
7856
|
usage() {
|
|
7857
|
+
const completed = this.director ? this.director.completedResults() : [];
|
|
7889
7858
|
const bySubagent = /* @__PURE__ */ new Map();
|
|
7890
|
-
for (const r of
|
|
7859
|
+
for (const r of completed) {
|
|
7891
7860
|
const cur = bySubagent.get(r.subagentId) ?? {
|
|
7892
7861
|
tasks: 0,
|
|
7893
7862
|
iterations: 0,
|
|
@@ -7933,7 +7902,7 @@ var MultiAgentHost = class {
|
|
|
7933
7902
|
*/
|
|
7934
7903
|
async manifest() {
|
|
7935
7904
|
if (!this.director) return null;
|
|
7936
|
-
return this.director.writeManifest();
|
|
7905
|
+
return await this.director.fleetManager?.writeManifest() ?? null;
|
|
7937
7906
|
}
|
|
7938
7907
|
/**
|
|
7939
7908
|
* Promote a non-director session to director mode at runtime. Only
|
|
@@ -7946,13 +7915,6 @@ var MultiAgentHost = class {
|
|
|
7946
7915
|
*/
|
|
7947
7916
|
async promoteToDirector() {
|
|
7948
7917
|
if (this.director) return this.director;
|
|
7949
|
-
if (this.coordinator) {
|
|
7950
|
-
const status = this.coordinator.getStatus();
|
|
7951
|
-
const running = status.subagents.filter((s) => s.status === "running").length;
|
|
7952
|
-
const idle = status.subagents.filter((s) => s.status === "idle").length;
|
|
7953
|
-
this.promotionBlockReason = `Cannot promote to director: a non-director coordinator is already in use (${running} running, ${idle} idle, ${status.pendingTasks} pending tasks). Stop the existing subagents with /fleet kill <id> or wait for them to finish, then retry \u2014 or restart wstack with --director to start in director mode.`;
|
|
7954
|
-
return null;
|
|
7955
|
-
}
|
|
7956
7918
|
this.opts.directorMode = true;
|
|
7957
7919
|
if (this.opts.fleetRoot && !this.opts.manifestPath) {
|
|
7958
7920
|
this.opts.manifestPath = path21.join(this.opts.fleetRoot, "fleet.json");
|
|
@@ -7994,13 +7956,13 @@ var MultiAgentHost = class {
|
|
|
7994
7956
|
* called /fleet kill before any /spawn, and there's nothing to do.
|
|
7995
7957
|
*/
|
|
7996
7958
|
async kill(subagentId) {
|
|
7997
|
-
if (!this.
|
|
7998
|
-
await this.
|
|
7959
|
+
if (!this.director) return false;
|
|
7960
|
+
await this.getCoordinator().stop(subagentId);
|
|
7999
7961
|
return true;
|
|
8000
7962
|
}
|
|
8001
7963
|
async stopAll() {
|
|
8002
|
-
if (this.
|
|
8003
|
-
await this.
|
|
7964
|
+
if (this.director) {
|
|
7965
|
+
await this.getCoordinator().stopAll();
|
|
8004
7966
|
}
|
|
8005
7967
|
}
|
|
8006
7968
|
};
|