@wrongstack/cli 0.119.1 → 0.141.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/index.js +91 -32
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, DefaultPathResolver, EventBus, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, atomicWrite, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, loadTasks, emptyTaskFile, saveTasks, formatTaskProgress, formatTaskList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, InputBuilder, FsError } from '@wrongstack/core';
|
|
2
|
+
import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, DefaultPathResolver, EventBus, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, atomicWrite, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, loadTasks, emptyTaskFile, saveTasks, formatTaskProgress, formatTaskList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, InputBuilder, FsError, estimateMessageTokens } from '@wrongstack/core';
|
|
3
3
|
import * as fsp4 from 'fs/promises';
|
|
4
4
|
import { DefaultSecretVault, decryptConfigSecrets, encryptConfigSecrets, isSecretField } from '@wrongstack/core/security';
|
|
5
5
|
import * as path9 from 'path';
|
|
@@ -2083,8 +2083,7 @@ async function runWebUI(opts) {
|
|
|
2083
2083
|
ws.close();
|
|
2084
2084
|
}
|
|
2085
2085
|
clients.clear();
|
|
2086
|
-
void unregisterInstance(process.pid, registryBaseDir).catch(() => {
|
|
2087
|
-
});
|
|
2086
|
+
void unregisterInstance(process.pid, registryBaseDir).catch((err) => console.debug(`[webui-server] unregister failed: ${err}`));
|
|
2088
2087
|
httpServer?.close();
|
|
2089
2088
|
wss.close(() => {
|
|
2090
2089
|
console.log("[WebUI] Server stopped");
|
|
@@ -2160,6 +2159,15 @@ async function runWebUI(opts) {
|
|
|
2160
2159
|
await handleProviderRemove(ws, m.payload.providerId);
|
|
2161
2160
|
break;
|
|
2162
2161
|
}
|
|
2162
|
+
default:
|
|
2163
|
+
send(ws, {
|
|
2164
|
+
type: "error",
|
|
2165
|
+
payload: {
|
|
2166
|
+
phase: "ws.dispatch",
|
|
2167
|
+
message: `Unknown message type: ${String(msg.type)}`
|
|
2168
|
+
}
|
|
2169
|
+
});
|
|
2170
|
+
break;
|
|
2163
2171
|
}
|
|
2164
2172
|
}
|
|
2165
2173
|
async function handleUserMessage(ws, _client, content) {
|
|
@@ -2873,20 +2881,7 @@ function countToolResults(messages) {
|
|
|
2873
2881
|
return count;
|
|
2874
2882
|
}
|
|
2875
2883
|
function estimateTokens(messages) {
|
|
2876
|
-
|
|
2877
|
-
for (const m of messages) {
|
|
2878
|
-
const content = m.content;
|
|
2879
|
-
if (typeof content === "string") {
|
|
2880
|
-
total += Math.ceil(content.length / 4);
|
|
2881
|
-
} else if (Array.isArray(content)) {
|
|
2882
|
-
for (const b of content) {
|
|
2883
|
-
if (b.type === "text") total += Math.ceil(b.text.length / 4);
|
|
2884
|
-
else if (b.type === "tool_use" || b.type === "tool_result")
|
|
2885
|
-
total += Math.ceil(JSON.stringify(b).length / 4);
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
}
|
|
2889
|
-
return total;
|
|
2884
|
+
return estimateMessageTokens(messages);
|
|
2890
2885
|
}
|
|
2891
2886
|
|
|
2892
2887
|
// src/slash-commands/auth.ts
|
|
@@ -3187,6 +3182,7 @@ function buildAutoPhaseCommand(opts) {
|
|
|
3187
3182
|
};
|
|
3188
3183
|
}
|
|
3189
3184
|
}
|
|
3185
|
+
return { message: `Unknown subcommand "${sub}". Run \`/autophase\` for usage.` };
|
|
3190
3186
|
}
|
|
3191
3187
|
};
|
|
3192
3188
|
}
|
|
@@ -3874,7 +3870,7 @@ ${formatContextWindowModeList(active)}`;
|
|
|
3874
3870
|
const lines = [
|
|
3875
3871
|
`${color.bold("Context Window")}`,
|
|
3876
3872
|
` messages: ${messages.length} total (${countTurnPairs(messages)} user+assistant pairs)`,
|
|
3877
|
-
` tokens (est): ${estimateTokens(messages).toLocaleString()} (chars
|
|
3873
|
+
` tokens (est): ${estimateTokens(messages).toLocaleString()} (\u2248 chars/3.5)`,
|
|
3878
3874
|
` mode: ${policy ? `${policy.id} (${policy.name})` : "balanced"}`,
|
|
3879
3875
|
` limit: ${formatLimit(readEffectiveLimit(ctx, opts))}`,
|
|
3880
3876
|
` system prompt: ${ctx.systemPrompt.length} block${ctx.systemPrompt.length !== 1 ? "s" : ""}`,
|
|
@@ -4137,7 +4133,7 @@ async function persistTelegramConfig(deps, mutator) {
|
|
|
4137
4133
|
decrypted.extensions = extensions;
|
|
4138
4134
|
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
4139
4135
|
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
4140
|
-
deps.configStore.update({ extensions
|
|
4136
|
+
deps.configStore.update({ extensions });
|
|
4141
4137
|
}
|
|
4142
4138
|
|
|
4143
4139
|
// src/slash-commands/enhance.ts
|
|
@@ -5605,6 +5601,7 @@ ${formatGoal(updated)}` };
|
|
|
5605
5601
|
} catch {
|
|
5606
5602
|
}
|
|
5607
5603
|
if (opts.onEternalStop) opts.onEternalStop();
|
|
5604
|
+
if (opts.onAutonomy) opts.onAutonomy("off");
|
|
5608
5605
|
const msg = `${color.amber("Goal cleared.")} Previous goal marked abandoned; eternal mode will stop.`;
|
|
5609
5606
|
opts.renderer.write(msg);
|
|
5610
5607
|
return { message: msg };
|
|
@@ -8823,7 +8820,10 @@ var ReadlineInputReader = class {
|
|
|
8823
8820
|
const fresh = this.ensure();
|
|
8824
8821
|
this.installPromptGuard(fresh);
|
|
8825
8822
|
return new Promise((resolve5) => {
|
|
8823
|
+
let settled = false;
|
|
8826
8824
|
const settle = (line) => {
|
|
8825
|
+
if (settled) return;
|
|
8826
|
+
settled = true;
|
|
8827
8827
|
setOutputLineGuard(null);
|
|
8828
8828
|
resolve5(line);
|
|
8829
8829
|
};
|
|
@@ -8835,6 +8835,7 @@ var ReadlineInputReader = class {
|
|
|
8835
8835
|
settle(line);
|
|
8836
8836
|
});
|
|
8837
8837
|
fresh.once("close", () => settle(""));
|
|
8838
|
+
fresh.on && fresh.on("error", (_e) => settle(""));
|
|
8838
8839
|
}).then((result) => {
|
|
8839
8840
|
this.rl?.close();
|
|
8840
8841
|
return result;
|
|
@@ -13040,10 +13041,10 @@ function roleCat(role) {
|
|
|
13040
13041
|
function createProviderForId(providerId, cfg) {
|
|
13041
13042
|
const savedCfg = cfg.providers?.[providerId];
|
|
13042
13043
|
const resolvedProviderId = savedCfg?.type ?? providerId;
|
|
13043
|
-
const cfgWithType =
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13044
|
+
const cfgWithType = Object.assign(
|
|
13045
|
+
{ type: resolvedProviderId },
|
|
13046
|
+
savedCfg ?? { apiKey: cfg.apiKey, baseUrl: cfg.baseUrl }
|
|
13047
|
+
);
|
|
13047
13048
|
try {
|
|
13048
13049
|
return makeProviderFromConfig(resolvedProviderId, cfgWithType);
|
|
13049
13050
|
} catch {
|
|
@@ -13288,10 +13289,17 @@ var modeldiagCmd = async (args, deps) => {
|
|
|
13288
13289
|
const providersEqIdx = benchArgs.findIndex((a) => a.startsWith("--providers="));
|
|
13289
13290
|
let providerFilter;
|
|
13290
13291
|
if (providersEqIdx >= 0) {
|
|
13291
|
-
|
|
13292
|
-
|
|
13292
|
+
const rawFilter = benchArgs[providersEqIdx]?.replace("--providers=", "").split(",");
|
|
13293
|
+
if (rawFilter) {
|
|
13294
|
+
providerFilter = rawFilter.map((s) => s.trim()).filter(Boolean);
|
|
13295
|
+
benchArgs.splice(providersEqIdx, 1);
|
|
13296
|
+
}
|
|
13293
13297
|
}
|
|
13294
13298
|
const benchRole = benchArgs[0];
|
|
13299
|
+
if (!benchRole) {
|
|
13300
|
+
writeLine(`${color.amber("No benchmark role specified")}. Usage: wstack diag bench <role> [prompt]`);
|
|
13301
|
+
return 1;
|
|
13302
|
+
}
|
|
13295
13303
|
const benchPrompt = benchArgs.slice(1).join(" ");
|
|
13296
13304
|
const cat = roleCat(benchRole);
|
|
13297
13305
|
const candidates = rankModels(providers, hasKey, cat, 5);
|
|
@@ -14431,6 +14439,28 @@ async function runRepl(opts) {
|
|
|
14431
14439
|
`
|
|
14432
14440
|
);
|
|
14433
14441
|
}
|
|
14442
|
+
if (engine.currentState === "stopped") {
|
|
14443
|
+
const goal = await loadGoalSafe(opts);
|
|
14444
|
+
if (goal?.goalState === "completed") {
|
|
14445
|
+
const u = goal.journal.length > 0 ? summarizeUsage(goal) : null;
|
|
14446
|
+
const costLine = u && u.iterationsWithUsage > 0 ? color.dim(` \u2014 ${u.totalCostUsd.toFixed(4)} \xB7 ${u.totalInputTokens} in / ${u.totalOutputTokens} out \xB7 ${goal.iterations} iterations`) : goal.iterations > 0 ? color.dim(` \u2014 ${goal.iterations} iterations`) : "";
|
|
14447
|
+
opts.renderer.write(
|
|
14448
|
+
color.green(`
|
|
14449
|
+
\u{1F3AF} Goal completed!${costLine}
|
|
14450
|
+
|
|
14451
|
+
`) + color.dim(" Goal cleared. Use /goal set <mission> to create a new goal.\n")
|
|
14452
|
+
);
|
|
14453
|
+
if (opts.projectRoot) {
|
|
14454
|
+
try {
|
|
14455
|
+
const { unlink: unlink4 } = await import('fs/promises');
|
|
14456
|
+
await unlink4(goalFilePath(opts.projectRoot));
|
|
14457
|
+
} catch {
|
|
14458
|
+
}
|
|
14459
|
+
}
|
|
14460
|
+
}
|
|
14461
|
+
opts.onAutonomy?.("off");
|
|
14462
|
+
continue;
|
|
14463
|
+
}
|
|
14434
14464
|
} catch (err) {
|
|
14435
14465
|
opts.renderer.writeError(
|
|
14436
14466
|
`[eternal] ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -14477,6 +14507,28 @@ async function runRepl(opts) {
|
|
|
14477
14507
|
`
|
|
14478
14508
|
);
|
|
14479
14509
|
}
|
|
14510
|
+
if (engine.currentState === "stopped") {
|
|
14511
|
+
const goal = await loadGoalSafe(opts);
|
|
14512
|
+
if (goal?.goalState === "completed") {
|
|
14513
|
+
const u = goal.journal.length > 0 ? summarizeUsage(goal) : null;
|
|
14514
|
+
const costLine = u && u.iterationsWithUsage > 0 ? color.dim(` \u2014 ${u.totalCostUsd.toFixed(4)} \xB7 ${u.totalInputTokens} in / ${u.totalOutputTokens} out \xB7 ${goal.iterations} iterations`) : goal.iterations > 0 ? color.dim(` \u2014 ${goal.iterations} iterations`) : "";
|
|
14515
|
+
opts.renderer.write(
|
|
14516
|
+
color.green(`
|
|
14517
|
+
\u{1F3AF} Goal completed!${costLine}
|
|
14518
|
+
|
|
14519
|
+
`) + color.dim(" Goal cleared. Use /goal set <mission> to create a new goal.\n")
|
|
14520
|
+
);
|
|
14521
|
+
if (opts.projectRoot) {
|
|
14522
|
+
try {
|
|
14523
|
+
const { unlink: unlink4 } = await import('fs/promises');
|
|
14524
|
+
await unlink4(goalFilePath(opts.projectRoot));
|
|
14525
|
+
} catch {
|
|
14526
|
+
}
|
|
14527
|
+
}
|
|
14528
|
+
}
|
|
14529
|
+
opts.onAutonomy?.("off");
|
|
14530
|
+
continue;
|
|
14531
|
+
}
|
|
14480
14532
|
} catch (err) {
|
|
14481
14533
|
opts.renderer.writeError(
|
|
14482
14534
|
`[parallel] ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -15337,8 +15389,7 @@ async function execute(deps) {
|
|
|
15337
15389
|
const toWrite = targetPath === wpaths.globalConfig ? decrypted : filterSafeForProject(decrypted);
|
|
15338
15390
|
const encrypted = encryptConfigSecrets$1(toWrite, vault);
|
|
15339
15391
|
if (targetPath !== wpaths.globalConfig) {
|
|
15340
|
-
await fsp4.mkdir(path9.dirname(targetPath), { recursive: true }).catch(() => {
|
|
15341
|
-
});
|
|
15392
|
+
await fsp4.mkdir(path9.dirname(targetPath), { recursive: true }).catch((err) => console.debug(`[execution] mkdir failed: ${err}`));
|
|
15342
15393
|
}
|
|
15343
15394
|
await atomicWrite(targetPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
15344
15395
|
configStore.update({
|
|
@@ -15428,13 +15479,15 @@ async function execute(deps) {
|
|
|
15428
15479
|
return typeof metaMode === "string" ? metaMode : modeId ?? "default";
|
|
15429
15480
|
},
|
|
15430
15481
|
registerDebugStreamCallback: (cb) => {
|
|
15431
|
-
void import('@wrongstack/providers').then(
|
|
15432
|
-
(
|
|
15482
|
+
void import('@wrongstack/providers').then(({ setDebugStreamCallback }) => setDebugStreamCallback(cb)).catch(
|
|
15483
|
+
(err) => console.error("[execution] failed to register debug stream callback:", err)
|
|
15433
15484
|
);
|
|
15434
15485
|
},
|
|
15435
15486
|
restoreDebugStreamCallback: () => {
|
|
15436
15487
|
void import('@wrongstack/providers').then(
|
|
15437
15488
|
({ setDebugStreamCallback, defaultDebugStreamCallback }) => setDebugStreamCallback(defaultDebugStreamCallback)
|
|
15489
|
+
).catch(
|
|
15490
|
+
(err) => console.error("[execution] failed to restore debug stream callback:", err)
|
|
15438
15491
|
);
|
|
15439
15492
|
}
|
|
15440
15493
|
});
|
|
@@ -15481,7 +15534,7 @@ async function execute(deps) {
|
|
|
15481
15534
|
onAgentIterationComplete: director ? (tokens) => director.setLeaderContextPressure(tokens) : void 0
|
|
15482
15535
|
});
|
|
15483
15536
|
} finally {
|
|
15484
|
-
await webuiPromise.catch(() =>
|
|
15537
|
+
await webuiPromise.catch((err) => console.debug(`[execution] webui shutdown failed: ${err}`));
|
|
15485
15538
|
}
|
|
15486
15539
|
} else {
|
|
15487
15540
|
code = await runRepl({
|
|
@@ -16885,7 +16938,12 @@ async function setupCompaction(params) {
|
|
|
16885
16938
|
effectiveMaxContext,
|
|
16886
16939
|
// Calibrated estimator: recordActualUsage() is called after each API
|
|
16887
16940
|
// response so this converges on real token counts for compaction decisions.
|
|
16888
|
-
(ctx) => estimateRequestTokensCalibrated(
|
|
16941
|
+
(ctx) => estimateRequestTokensCalibrated(
|
|
16942
|
+
ctx.messages,
|
|
16943
|
+
ctx.systemPrompt,
|
|
16944
|
+
ctx.tools ?? [],
|
|
16945
|
+
`${ctx.provider?.id ?? "unknown"}/${ctx.model}`
|
|
16946
|
+
).total,
|
|
16889
16947
|
initialPolicy.thresholds,
|
|
16890
16948
|
{
|
|
16891
16949
|
aggressiveOn: initialPolicy.aggressiveOn,
|
|
@@ -17443,7 +17501,7 @@ async function setupSession(params) {
|
|
|
17443
17501
|
} = params;
|
|
17444
17502
|
sessionStore.prune(DEFAULT_SESSION_PRUNE_DAYS).then((count) => {
|
|
17445
17503
|
if (count > 0) renderer.writeInfo(`Pruned ${count} old session${count === 1 ? "" : "s"}.`);
|
|
17446
|
-
}).catch(() =>
|
|
17504
|
+
}).catch((err) => console.debug(`[session] prune failed: ${err}`));
|
|
17447
17505
|
let resumeId = typeof flags["resume"] === "string" ? flags["resume"] : void 0;
|
|
17448
17506
|
const recoveryLock = new RecoveryLock({ dir: wpaths.projectSessions, sessionStore });
|
|
17449
17507
|
if (!resumeId && !flags["no-recovery"]) {
|
|
@@ -18866,6 +18924,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
18866
18924
|
message: `\u26A0 ${color.yellow(`${lines.length} uncommitted change${lines.length > 1 ? "s" : ""}`)} \u2014 session ended without commit`
|
|
18867
18925
|
};
|
|
18868
18926
|
}
|
|
18927
|
+
return void 0;
|
|
18869
18928
|
},
|
|
18870
18929
|
onClear: () => {
|
|
18871
18930
|
if (flags.tui && !flags["no-tui"]) return;
|