@wrongstack/cli 0.1.8 → 0.1.9
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 +95 -39
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { color, DefaultLogger, DefaultModelsRegistry, Container, DefaultConfigStore, TOKENS, DefaultSecretScrubber, DefaultRetryPolicy, DefaultErrorHandler, DefaultTokenCounter, DefaultModeStore, DefaultSessionStore, DefaultMemoryStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultPermissionPolicy, HybridCompactor, ProviderRegistry, ToolRegistry, createContextManagerTool, EventBus, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, createDefaultPipelines, AutoCompactionMiddleware, Agent, SlashCommandRegistry, loadPlugins, DefaultPathResolver, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader,
|
|
2
|
+
import { color, DefaultLogger, DefaultModelsRegistry, Container, DefaultConfigStore, TOKENS, DefaultSecretScrubber, DefaultRetryPolicy, DefaultErrorHandler, DefaultTokenCounter, DefaultModeStore, DefaultSessionStore, DefaultMemoryStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultPermissionPolicy, HybridCompactor, ProviderRegistry, ToolRegistry, createContextManagerTool, EventBus, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, createDefaultPipelines, AutoCompactionMiddleware, Agent, SlashCommandRegistry, loadPlugins, FLEET_ROSTER, DefaultPathResolver, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, makeDirectorSessionFactory, makeAgentSubagentRunner, Director, DefaultMultiAgentCoordinator, InputBuilder, DefaultPluginAPI, atomicWrite, DefaultSessionReader, decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core';
|
|
3
3
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
4
4
|
import * as fs6 from 'fs/promises';
|
|
5
5
|
import { writeFileSync } from 'fs';
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
|
-
import * as
|
|
7
|
+
import * as path6 from 'path';
|
|
8
8
|
import { MCPRegistry } from '@wrongstack/mcp';
|
|
9
9
|
import { buildProviderFactoriesFromRegistry, makeProviderFromConfig, capabilitiesFor } from '@wrongstack/providers';
|
|
10
10
|
import { rememberTool, forgetTool } from '@wrongstack/tools';
|
|
@@ -541,7 +541,7 @@ var ReadlineInputReader = class {
|
|
|
541
541
|
history = [];
|
|
542
542
|
pending = false;
|
|
543
543
|
constructor(opts = {}) {
|
|
544
|
-
this.historyFile = opts.historyFile ??
|
|
544
|
+
this.historyFile = opts.historyFile ?? path6.join(os3.homedir(), ".wrongstack", "history");
|
|
545
545
|
}
|
|
546
546
|
async loadHistory() {
|
|
547
547
|
try {
|
|
@@ -553,7 +553,7 @@ var ReadlineInputReader = class {
|
|
|
553
553
|
}
|
|
554
554
|
async saveHistory() {
|
|
555
555
|
try {
|
|
556
|
-
await fs6.mkdir(
|
|
556
|
+
await fs6.mkdir(path6.dirname(this.historyFile), { recursive: true });
|
|
557
557
|
await fs6.writeFile(this.historyFile, this.history.slice(-1e3).join("\n"));
|
|
558
558
|
} catch {
|
|
559
559
|
}
|
|
@@ -1168,8 +1168,8 @@ function initCommand(opts) {
|
|
|
1168
1168
|
description: "Scaffold .wrongstack/AGENTS.md in the current project.",
|
|
1169
1169
|
async run(args, ctx) {
|
|
1170
1170
|
const force = args.trim() === "--force";
|
|
1171
|
-
const dir =
|
|
1172
|
-
const file =
|
|
1171
|
+
const dir = path6.join(ctx.projectRoot, ".wrongstack");
|
|
1172
|
+
const file = path6.join(dir, "AGENTS.md");
|
|
1173
1173
|
try {
|
|
1174
1174
|
await fs6.access(file);
|
|
1175
1175
|
if (!force) {
|
|
@@ -1200,7 +1200,7 @@ No project type auto-detected. Edit the file to add build/test commands and conv
|
|
|
1200
1200
|
async function detectProjectFacts(root) {
|
|
1201
1201
|
const facts = { hints: [] };
|
|
1202
1202
|
try {
|
|
1203
|
-
const pkg = JSON.parse(await fs6.readFile(
|
|
1203
|
+
const pkg = JSON.parse(await fs6.readFile(path6.join(root, "package.json"), "utf8"));
|
|
1204
1204
|
const scripts = pkg.scripts ?? {};
|
|
1205
1205
|
const pm = (pkg.packageManager ?? "npm").split("@")[0] ?? "npm";
|
|
1206
1206
|
if (scripts["build"]) facts.build = `${pm} run build`;
|
|
@@ -1211,28 +1211,28 @@ async function detectProjectFacts(root) {
|
|
|
1211
1211
|
} catch {
|
|
1212
1212
|
}
|
|
1213
1213
|
try {
|
|
1214
|
-
await fs6.access(
|
|
1214
|
+
await fs6.access(path6.join(root, "pyproject.toml"));
|
|
1215
1215
|
facts.test ??= "pytest";
|
|
1216
1216
|
facts.lint ??= "ruff check .";
|
|
1217
1217
|
facts.hints.push("pyproject.toml");
|
|
1218
1218
|
} catch {
|
|
1219
1219
|
}
|
|
1220
1220
|
try {
|
|
1221
|
-
await fs6.access(
|
|
1221
|
+
await fs6.access(path6.join(root, "go.mod"));
|
|
1222
1222
|
facts.build ??= "go build ./...";
|
|
1223
1223
|
facts.test ??= "go test ./...";
|
|
1224
1224
|
facts.hints.push("go.mod");
|
|
1225
1225
|
} catch {
|
|
1226
1226
|
}
|
|
1227
1227
|
try {
|
|
1228
|
-
await fs6.access(
|
|
1228
|
+
await fs6.access(path6.join(root, "Cargo.toml"));
|
|
1229
1229
|
facts.build ??= "cargo build";
|
|
1230
1230
|
facts.test ??= "cargo test";
|
|
1231
1231
|
facts.hints.push("Cargo.toml");
|
|
1232
1232
|
} catch {
|
|
1233
1233
|
}
|
|
1234
1234
|
try {
|
|
1235
|
-
await fs6.access(
|
|
1235
|
+
await fs6.access(path6.join(root, "Makefile"));
|
|
1236
1236
|
facts.build ??= "make";
|
|
1237
1237
|
facts.test ??= "make test";
|
|
1238
1238
|
facts.hints.push("Makefile");
|
|
@@ -1808,13 +1808,13 @@ var MANIFESTS = [
|
|
|
1808
1808
|
];
|
|
1809
1809
|
async function detectProjectKind(projectRoot) {
|
|
1810
1810
|
try {
|
|
1811
|
-
await fs6.access(
|
|
1811
|
+
await fs6.access(path6.join(projectRoot, ".wrongstack", "AGENTS.md"));
|
|
1812
1812
|
return "initialized";
|
|
1813
1813
|
} catch {
|
|
1814
1814
|
}
|
|
1815
1815
|
for (const m of MANIFESTS) {
|
|
1816
1816
|
try {
|
|
1817
|
-
await fs6.access(
|
|
1817
|
+
await fs6.access(path6.join(projectRoot, m));
|
|
1818
1818
|
return "project";
|
|
1819
1819
|
} catch {
|
|
1820
1820
|
}
|
|
@@ -1822,8 +1822,8 @@ async function detectProjectKind(projectRoot) {
|
|
|
1822
1822
|
return "empty";
|
|
1823
1823
|
}
|
|
1824
1824
|
async function scaffoldAgentsMd(projectRoot) {
|
|
1825
|
-
const dir =
|
|
1826
|
-
const file =
|
|
1825
|
+
const dir = path6.join(projectRoot, ".wrongstack");
|
|
1826
|
+
const file = path6.join(dir, "AGENTS.md");
|
|
1827
1827
|
const facts = await detectProjectFacts(projectRoot);
|
|
1828
1828
|
const body = renderAgentsTemplate(facts);
|
|
1829
1829
|
await fs6.mkdir(dir, { recursive: true });
|
|
@@ -1836,7 +1836,7 @@ async function runProjectCheck(opts) {
|
|
|
1836
1836
|
if (kind === "initialized") {
|
|
1837
1837
|
renderer.write(
|
|
1838
1838
|
`
|
|
1839
|
-
${color.green("\u2713")} Project initialized ${color.dim(`(${
|
|
1839
|
+
${color.green("\u2713")} Project initialized ${color.dim(`(${path6.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
|
|
1840
1840
|
`
|
|
1841
1841
|
);
|
|
1842
1842
|
return true;
|
|
@@ -2498,7 +2498,7 @@ function renderProgress2(ratio, width) {
|
|
|
2498
2498
|
return FILLED2.repeat(capped) + EMPTY2.repeat(width - capped);
|
|
2499
2499
|
}
|
|
2500
2500
|
async function bootConfig(flags) {
|
|
2501
|
-
const cwd = typeof flags["cwd"] === "string" ?
|
|
2501
|
+
const cwd = typeof flags["cwd"] === "string" ? path6.resolve(flags["cwd"]) : process.cwd();
|
|
2502
2502
|
const pathResolver = new DefaultPathResolver(cwd);
|
|
2503
2503
|
const projectRoot = pathResolver.projectRoot;
|
|
2504
2504
|
const userHome = os3.homedir();
|
|
@@ -2570,12 +2570,35 @@ var MultiAgentHost = class {
|
|
|
2570
2570
|
* coordinator; the host's `coordinator` field still points at it so
|
|
2571
2571
|
* the rest of the methods don't need to branch. */
|
|
2572
2572
|
director;
|
|
2573
|
+
/** Lazily built alongside the director — produces per-subagent JSONL
|
|
2574
|
+
* writers under `<sessionsRoot>/<runId>/`. Null in non-director mode. */
|
|
2575
|
+
sessionFactory;
|
|
2573
2576
|
pending = /* @__PURE__ */ new Map();
|
|
2574
2577
|
results = [];
|
|
2575
2578
|
opts;
|
|
2579
|
+
/**
|
|
2580
|
+
* Force the lazy build path to run *now* and return the live Director,
|
|
2581
|
+
* or null when director mode is off. Used by the CLI to register the
|
|
2582
|
+
* fleet's LLM-callable orchestration tools (spawn_subagent,
|
|
2583
|
+
* assign_task, await_tasks, ask_subagent, roll_up, terminate_subagent,
|
|
2584
|
+
* fleet_status, fleet_usage) into the leader's ToolRegistry before the
|
|
2585
|
+
* agent starts — without this, the leader literally cannot see the
|
|
2586
|
+
* orchestration tools and `--director` becomes a no-op.
|
|
2587
|
+
*/
|
|
2588
|
+
async ensureDirector() {
|
|
2589
|
+
if (!this.opts.directorMode) return null;
|
|
2590
|
+
await this.ensureCoordinator();
|
|
2591
|
+
return this.director ?? null;
|
|
2592
|
+
}
|
|
2576
2593
|
async ensureCoordinator() {
|
|
2577
2594
|
if (this.coordinator) return this.coordinator;
|
|
2578
2595
|
const config = this.deps.configStore.get();
|
|
2596
|
+
if (this.opts.directorMode && this.opts.sessionsRoot && !this.sessionFactory) {
|
|
2597
|
+
this.sessionFactory = makeDirectorSessionFactory({
|
|
2598
|
+
sessionsRoot: this.opts.sessionsRoot,
|
|
2599
|
+
directorRunId: this.opts.directorRunId
|
|
2600
|
+
});
|
|
2601
|
+
}
|
|
2579
2602
|
const factory = async (subCfg) => {
|
|
2580
2603
|
const events = new EventBus();
|
|
2581
2604
|
const provider = await this.buildSubagentProvider(config, subCfg.provider);
|
|
@@ -2586,11 +2609,22 @@ var MultiAgentHost = class {
|
|
|
2586
2609
|
model: subCfg.model ?? config.model,
|
|
2587
2610
|
provider: subCfg.provider ?? config.provider
|
|
2588
2611
|
});
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
id
|
|
2592
|
-
|
|
2593
|
-
|
|
2612
|
+
let subSession;
|
|
2613
|
+
if (this.sessionFactory) {
|
|
2614
|
+
const subagentName = subCfg.name ?? subCfg.id ?? `sub_${randomUUID().slice(0, 8)}`;
|
|
2615
|
+
subSession = await this.sessionFactory.createSubagentSession({
|
|
2616
|
+
subagentId: subagentName,
|
|
2617
|
+
provider: subCfg.provider ?? config.provider,
|
|
2618
|
+
model: subCfg.model ?? config.model,
|
|
2619
|
+
title: `subagent: ${subagentName}`
|
|
2620
|
+
});
|
|
2621
|
+
} else {
|
|
2622
|
+
const parentSession = this.deps.session;
|
|
2623
|
+
subSession = {
|
|
2624
|
+
id: parentSession.id,
|
|
2625
|
+
append: (ev) => parentSession.append({ ...ev })
|
|
2626
|
+
};
|
|
2627
|
+
}
|
|
2594
2628
|
const ctx = new Context({
|
|
2595
2629
|
systemPrompt: baseSystem,
|
|
2596
2630
|
provider,
|
|
@@ -2628,7 +2662,8 @@ var MultiAgentHost = class {
|
|
|
2628
2662
|
this.director = new Director({
|
|
2629
2663
|
config: coordinatorConfig,
|
|
2630
2664
|
runner,
|
|
2631
|
-
manifestPath: this.opts.manifestPath
|
|
2665
|
+
manifestPath: this.opts.manifestPath,
|
|
2666
|
+
sharedScratchpadPath: this.opts.sharedScratchpadPath
|
|
2632
2667
|
});
|
|
2633
2668
|
this.director.on("task.completed", ({ task, result }) => {
|
|
2634
2669
|
this.results.push(result);
|
|
@@ -3577,8 +3612,8 @@ async function initCmd(_args, deps) {
|
|
|
3577
3612
|
};
|
|
3578
3613
|
if (apiKey) config.apiKey = apiKey;
|
|
3579
3614
|
await atomicWrite(deps.paths.globalConfig, JSON.stringify(config, null, 2));
|
|
3580
|
-
await fs6.mkdir(
|
|
3581
|
-
const agentsFile =
|
|
3615
|
+
await fs6.mkdir(path6.join(deps.projectRoot, ".wrongstack"), { recursive: true });
|
|
3616
|
+
const agentsFile = path6.join(deps.projectRoot, ".wrongstack", "AGENTS.md");
|
|
3582
3617
|
try {
|
|
3583
3618
|
await fs6.access(agentsFile);
|
|
3584
3619
|
} catch {
|
|
@@ -3986,7 +4021,7 @@ async function doctorCmd(_args, deps) {
|
|
|
3986
4021
|
}
|
|
3987
4022
|
try {
|
|
3988
4023
|
await fs6.mkdir(deps.paths.projectSessions, { recursive: true });
|
|
3989
|
-
const probe =
|
|
4024
|
+
const probe = path6.join(deps.paths.projectSessions, `.probe-${Date.now()}`);
|
|
3990
4025
|
await fs6.writeFile(probe, "");
|
|
3991
4026
|
await fs6.unlink(probe);
|
|
3992
4027
|
checks.push({ name: "sessions writable", status: "ok", detail: deps.paths.projectSessions });
|
|
@@ -4089,8 +4124,8 @@ async function exportCmd(args, deps) {
|
|
|
4089
4124
|
return 1;
|
|
4090
4125
|
}
|
|
4091
4126
|
if (output) {
|
|
4092
|
-
await fs6.mkdir(
|
|
4093
|
-
await fs6.writeFile(
|
|
4127
|
+
await fs6.mkdir(path6.dirname(path6.resolve(deps.cwd, output)), { recursive: true });
|
|
4128
|
+
await fs6.writeFile(path6.resolve(deps.cwd, output), rendered, "utf8");
|
|
4094
4129
|
deps.renderer.write(`Wrote ${rendered.length} bytes to ${output}
|
|
4095
4130
|
`);
|
|
4096
4131
|
} else {
|
|
@@ -4150,7 +4185,7 @@ async function helpCmd(_args, deps) {
|
|
|
4150
4185
|
return 0;
|
|
4151
4186
|
}
|
|
4152
4187
|
async function projectsCmd(_args, deps) {
|
|
4153
|
-
const projectsRoot =
|
|
4188
|
+
const projectsRoot = path6.join(deps.paths.globalRoot, "projects");
|
|
4154
4189
|
try {
|
|
4155
4190
|
const entries = await fs6.readdir(projectsRoot);
|
|
4156
4191
|
if (entries.length === 0) {
|
|
@@ -4160,7 +4195,7 @@ async function projectsCmd(_args, deps) {
|
|
|
4160
4195
|
for (const hash of entries) {
|
|
4161
4196
|
try {
|
|
4162
4197
|
const meta = JSON.parse(
|
|
4163
|
-
await fs6.readFile(
|
|
4198
|
+
await fs6.readFile(path6.join(projectsRoot, hash, "meta.json"), "utf8")
|
|
4164
4199
|
);
|
|
4165
4200
|
deps.renderer.write(
|
|
4166
4201
|
` ${color.dim(hash)} ${color.dim(meta.lastSeen ?? "")} ${meta.root ?? "?"}
|
|
@@ -4251,7 +4286,7 @@ function resolveBundledSkillsDir() {
|
|
|
4251
4286
|
try {
|
|
4252
4287
|
const req2 = createRequire(import.meta.url);
|
|
4253
4288
|
const corePkg = req2.resolve("@wrongstack/core/package.json");
|
|
4254
|
-
return
|
|
4289
|
+
return path6.join(path6.dirname(corePkg), "skills");
|
|
4255
4290
|
} catch {
|
|
4256
4291
|
return void 0;
|
|
4257
4292
|
}
|
|
@@ -4520,7 +4555,7 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
4520
4555
|
const dumpMetrics = () => {
|
|
4521
4556
|
if (!metricsSink) return;
|
|
4522
4557
|
try {
|
|
4523
|
-
const out =
|
|
4558
|
+
const out = path6.join(wpaths.projectSessions, "metrics.json");
|
|
4524
4559
|
const snap = metricsSink.snapshot();
|
|
4525
4560
|
writeFileSync(out, JSON.stringify(snap, null, 2));
|
|
4526
4561
|
} catch {
|
|
@@ -4677,10 +4712,10 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
4677
4712
|
}
|
|
4678
4713
|
await recoveryLock.write(session.id).catch(() => void 0);
|
|
4679
4714
|
const attachments = new DefaultAttachmentStore({
|
|
4680
|
-
spoolDir:
|
|
4715
|
+
spoolDir: path6.join(wpaths.projectSessions, session.id, "attachments")
|
|
4681
4716
|
});
|
|
4682
4717
|
const queueStore = new QueueStore({
|
|
4683
|
-
dir:
|
|
4718
|
+
dir: path6.join(wpaths.projectSessions, session.id)
|
|
4684
4719
|
});
|
|
4685
4720
|
const tokenCounter = container.resolve(TOKENS.TokenCounter);
|
|
4686
4721
|
const stats = new SessionStats(events, tokenCounter);
|
|
@@ -4889,7 +4924,10 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
4889
4924
|
}
|
|
4890
4925
|
};
|
|
4891
4926
|
const directorMode = flags["director"] === true;
|
|
4892
|
-
const
|
|
4927
|
+
const fleetRoot = directorMode ? path6.join(wpaths.projectSessions, session.id) : void 0;
|
|
4928
|
+
const manifestPath = directorMode ? typeof process.env["WRONGSTACK_FLEET_MANIFEST"] === "string" ? process.env["WRONGSTACK_FLEET_MANIFEST"] : path6.join(fleetRoot, "fleet.json") : void 0;
|
|
4929
|
+
const sharedScratchpadPath = directorMode ? path6.join(fleetRoot, "shared") : void 0;
|
|
4930
|
+
const subagentSessionsRoot = directorMode ? path6.join(fleetRoot, "subagents") : void 0;
|
|
4893
4931
|
const multiAgentHost = new MultiAgentHost({
|
|
4894
4932
|
container,
|
|
4895
4933
|
toolRegistry,
|
|
@@ -4901,9 +4939,27 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
4901
4939
|
tokenCounter,
|
|
4902
4940
|
projectRoot,
|
|
4903
4941
|
cwd
|
|
4904
|
-
}, {
|
|
4942
|
+
}, {
|
|
4943
|
+
directorMode,
|
|
4944
|
+
manifestPath,
|
|
4945
|
+
sharedScratchpadPath,
|
|
4946
|
+
sessionsRoot: subagentSessionsRoot,
|
|
4947
|
+
directorRunId: session.id
|
|
4948
|
+
});
|
|
4905
4949
|
if (directorMode) {
|
|
4906
|
-
|
|
4950
|
+
const director = await multiAgentHost.ensureDirector();
|
|
4951
|
+
if (director) {
|
|
4952
|
+
for (const tool of director.tools(FLEET_ROSTER)) {
|
|
4953
|
+
toolRegistry.register(tool);
|
|
4954
|
+
}
|
|
4955
|
+
renderer.writeInfo(`Director mode enabled. Roster: ${Object.keys(FLEET_ROSTER).join(", ")}`);
|
|
4956
|
+
renderer.writeInfo(` fleet root \u2192 ${fleetRoot}`);
|
|
4957
|
+
renderer.writeInfo(` manifest \u2192 ${manifestPath}`);
|
|
4958
|
+
renderer.writeInfo(` scratchpad \u2192 ${sharedScratchpadPath}`);
|
|
4959
|
+
renderer.writeInfo(` subagents \u2192 ${subagentSessionsRoot}`);
|
|
4960
|
+
} else {
|
|
4961
|
+
renderer.writeInfo(`Director mode enabled. Fleet manifest \u2192 ${manifestPath}`);
|
|
4962
|
+
}
|
|
4907
4963
|
}
|
|
4908
4964
|
const slashCmds = buildBuiltinSlashCommands({
|
|
4909
4965
|
registry: slashRegistry,
|
|
@@ -5157,7 +5213,7 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
5157
5213
|
tokenCounter,
|
|
5158
5214
|
attachments,
|
|
5159
5215
|
effectiveMaxContext,
|
|
5160
|
-
projectName:
|
|
5216
|
+
projectName: path6.basename(projectRoot) || void 0
|
|
5161
5217
|
});
|
|
5162
5218
|
await webuiPromise;
|
|
5163
5219
|
} else {
|
|
@@ -5169,7 +5225,7 @@ Try \`wstack models refresh\` once you have network access, or run with --no-fea
|
|
|
5169
5225
|
tokenCounter,
|
|
5170
5226
|
attachments,
|
|
5171
5227
|
effectiveMaxContext,
|
|
5172
|
-
projectName:
|
|
5228
|
+
projectName: path6.basename(projectRoot) || void 0
|
|
5173
5229
|
});
|
|
5174
5230
|
}
|
|
5175
5231
|
} finally {
|