@wrongstack/cli 0.68.0 → 0.73.1
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 +341 -104
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
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, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
|
|
2
|
+
import { color, writeErr, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderTaskGraph, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, SpecVersioning, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, 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, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
|
|
3
3
|
import * as path8 from 'path';
|
|
4
4
|
import { join } from 'path';
|
|
5
5
|
import * as fsp4 from 'fs/promises';
|
|
@@ -14,7 +14,7 @@ import { WebSocketServer, WebSocket } from 'ws';
|
|
|
14
14
|
import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
|
|
15
15
|
import { capabilitiesFor, buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';
|
|
16
16
|
import { createDefaultContainer, routeImagesForModel, readClipboardImage } from '@wrongstack/runtime';
|
|
17
|
-
import { builtinToolsPack, rememberTool, forgetTool } from '@wrongstack/tools';
|
|
17
|
+
import { builtinToolsPack, rememberTool, forgetTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes } from '@wrongstack/tools';
|
|
18
18
|
import { fileURLToPath } from 'url';
|
|
19
19
|
import * as readline from 'readline';
|
|
20
20
|
import * as fs12 from 'fs';
|
|
@@ -31,12 +31,6 @@ var __defProp = Object.defineProperty;
|
|
|
31
31
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
32
32
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
33
33
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
34
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
35
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
36
|
-
}) : x)(function(x) {
|
|
37
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
38
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
39
|
-
});
|
|
40
34
|
var __esm = (fn, res) => function __init() {
|
|
41
35
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
42
36
|
};
|
|
@@ -1936,7 +1930,7 @@ async function runWebUI(opts) {
|
|
|
1936
1930
|
);
|
|
1937
1931
|
}
|
|
1938
1932
|
}
|
|
1939
|
-
return new Promise((
|
|
1933
|
+
return new Promise((resolve5) => {
|
|
1940
1934
|
wss.on("listening", () => {
|
|
1941
1935
|
console.log(`[WebUI] WebSocket server running on ws://${host}:${port}`);
|
|
1942
1936
|
setupEvents();
|
|
@@ -2018,8 +2012,8 @@ async function runWebUI(opts) {
|
|
|
2018
2012
|
console.log("[WebUI] Client disconnected");
|
|
2019
2013
|
clients.delete(ws);
|
|
2020
2014
|
if (clients.size === 0 && pendingConfirms.size > 0) {
|
|
2021
|
-
for (const [id,
|
|
2022
|
-
|
|
2015
|
+
for (const [id, resolve6] of pendingConfirms) {
|
|
2016
|
+
resolve6("no");
|
|
2023
2017
|
pendingConfirms.delete(id);
|
|
2024
2018
|
}
|
|
2025
2019
|
}
|
|
@@ -2049,7 +2043,7 @@ async function runWebUI(opts) {
|
|
|
2049
2043
|
httpServer?.close();
|
|
2050
2044
|
wss.close(() => {
|
|
2051
2045
|
console.log("[WebUI] Server stopped");
|
|
2052
|
-
|
|
2046
|
+
resolve5();
|
|
2053
2047
|
});
|
|
2054
2048
|
}
|
|
2055
2049
|
process.on("SIGINT", shutdown);
|
|
@@ -2076,10 +2070,10 @@ async function runWebUI(opts) {
|
|
|
2076
2070
|
break;
|
|
2077
2071
|
case "tool.confirm_result": {
|
|
2078
2072
|
const { id, decision } = msg.payload;
|
|
2079
|
-
const
|
|
2080
|
-
if (
|
|
2073
|
+
const resolve5 = pendingConfirms.get(id);
|
|
2074
|
+
if (resolve5) {
|
|
2081
2075
|
pendingConfirms.delete(id);
|
|
2082
|
-
|
|
2076
|
+
resolve5(decision);
|
|
2083
2077
|
}
|
|
2084
2078
|
break;
|
|
2085
2079
|
}
|
|
@@ -2572,7 +2566,6 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
|
|
|
2572
2566
|
"recover",
|
|
2573
2567
|
"no-alt-screen",
|
|
2574
2568
|
"alt-screen",
|
|
2575
|
-
"mouse",
|
|
2576
2569
|
"output-json",
|
|
2577
2570
|
"prompt",
|
|
2578
2571
|
"metrics",
|
|
@@ -3327,6 +3320,37 @@ function buildClearCommand(opts) {
|
|
|
3327
3320
|
}
|
|
3328
3321
|
};
|
|
3329
3322
|
}
|
|
3323
|
+
function buildCodebaseReindexCommand(opts) {
|
|
3324
|
+
return {
|
|
3325
|
+
name: "codebase-reindex",
|
|
3326
|
+
aliases: ["reindex"],
|
|
3327
|
+
description: "Rebuild the codebase symbol index used by codebase-search.",
|
|
3328
|
+
argsHint: "[force]",
|
|
3329
|
+
help: [
|
|
3330
|
+
"Usage:",
|
|
3331
|
+
" /codebase-reindex Incremental reindex (only changed files).",
|
|
3332
|
+
" /codebase-reindex force Clear the index and rebuild from scratch.",
|
|
3333
|
+
"",
|
|
3334
|
+
"The index powers codebase-search. It is normally kept fresh automatically",
|
|
3335
|
+
"(at session start and as files change); use this when you want to force a",
|
|
3336
|
+
"refresh \u2014 e.g. after a large branch switch, merge, or external edit."
|
|
3337
|
+
].join("\n"),
|
|
3338
|
+
async run(args, _ctx) {
|
|
3339
|
+
const force = /\b(force|--force|-f)\b/.test(args.trim());
|
|
3340
|
+
opts.renderer.write(color.dim(`${force ? "Rebuilding" : "Reindexing"} codebase index\u2026
|
|
3341
|
+
`));
|
|
3342
|
+
try {
|
|
3343
|
+
const r = await runStartupIndex({ projectRoot: opts.projectRoot, force });
|
|
3344
|
+
const summary = `${color.green("\u2713")} codebase index ${force ? "rebuilt" : "updated"} ` + color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`) + (r.errors.length ? `
|
|
3345
|
+
${color.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
|
|
3346
|
+
return { message: summary };
|
|
3347
|
+
} catch (err) {
|
|
3348
|
+
const msg = `${color.red("Codebase reindex failed:")} ${err instanceof Error ? err.message : String(err)}`;
|
|
3349
|
+
return { message: msg };
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
};
|
|
3353
|
+
}
|
|
3330
3354
|
function buildCollabCommand(opts) {
|
|
3331
3355
|
return {
|
|
3332
3356
|
name: "collab",
|
|
@@ -4652,6 +4676,7 @@ function buildFleetCommand(opts) {
|
|
|
4652
4676
|
" /fleet terminate <subagentId> Stop a specific subagent by id",
|
|
4653
4677
|
" /fleet kill Stop all running subagents",
|
|
4654
4678
|
" /fleet usage Token and cost breakdown across the fleet",
|
|
4679
|
+
" /fleet concurrency [n] Show or set the concurrent-subagent ceiling",
|
|
4655
4680
|
" /fleet journal Show recent journal entries from /goal journal",
|
|
4656
4681
|
"",
|
|
4657
4682
|
"In the TUI, press Ctrl+F to open the graphical fleet monitor.",
|
|
@@ -4894,6 +4919,16 @@ function buildFleetCommand(opts) {
|
|
|
4894
4919
|
opts.renderer.write(msg2);
|
|
4895
4920
|
return { message: msg2 };
|
|
4896
4921
|
}
|
|
4922
|
+
if (cmd === "concurrency" || cmd === "slots" || cmd === "parallel") {
|
|
4923
|
+
if (opts.onFleet) {
|
|
4924
|
+
const n = subargs[0];
|
|
4925
|
+
const msg3 = await opts.onFleet("concurrency", n || void 0);
|
|
4926
|
+
return { message: msg3 };
|
|
4927
|
+
}
|
|
4928
|
+
const msg2 = `${color.amber("\u26A0 /fleet concurrency is not wired in this session.")}`;
|
|
4929
|
+
opts.renderer.writeWarning(msg2);
|
|
4930
|
+
return { message: msg2 };
|
|
4931
|
+
}
|
|
4897
4932
|
if (cmd === "help" || cmd === "?") {
|
|
4898
4933
|
const msg2 = [
|
|
4899
4934
|
`${color.bold("Fleet Commands")}`,
|
|
@@ -4905,12 +4940,13 @@ function buildFleetCommand(opts) {
|
|
|
4905
4940
|
` ${color.dim("/fleet terminate <subagentId>")} Stop a specific subagent by id`,
|
|
4906
4941
|
` ${color.dim("/fleet kill")} Stop all running subagents`,
|
|
4907
4942
|
` ${color.dim("/fleet usage")} Token and cost breakdown across the fleet`,
|
|
4943
|
+
` ${color.dim("/fleet concurrency [n]")} Show or set the concurrent-subagent ceiling`,
|
|
4908
4944
|
` ${color.dim("/fleet journal")} Show recent journal entries from /goal journal`
|
|
4909
4945
|
].join("\n");
|
|
4910
4946
|
opts.renderer.write(msg2);
|
|
4911
4947
|
return { message: msg2 };
|
|
4912
4948
|
}
|
|
4913
|
-
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "journal"];
|
|
4949
|
+
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "concurrency", "journal"];
|
|
4914
4950
|
const msg = `Unknown subcommand "${cmd}". Valid subcommands: ${valid.join(", ")}. Run /fleet with no args to see status, or /fleet help for usage.`;
|
|
4915
4951
|
opts.renderer.writeWarning(msg);
|
|
4916
4952
|
return { message: msg };
|
|
@@ -5364,9 +5400,9 @@ function stateBadge(state) {
|
|
|
5364
5400
|
return color.dim(state);
|
|
5365
5401
|
}
|
|
5366
5402
|
}
|
|
5367
|
-
async function readConfig(
|
|
5403
|
+
async function readConfig(path26) {
|
|
5368
5404
|
try {
|
|
5369
|
-
return JSON.parse(await fsp4.readFile(
|
|
5405
|
+
return JSON.parse(await fsp4.readFile(path26, "utf8"));
|
|
5370
5406
|
} catch {
|
|
5371
5407
|
return {};
|
|
5372
5408
|
}
|
|
@@ -5374,11 +5410,11 @@ async function readConfig(path25) {
|
|
|
5374
5410
|
function isMcpServerRecord(value) {
|
|
5375
5411
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5376
5412
|
}
|
|
5377
|
-
async function writeConfig(
|
|
5413
|
+
async function writeConfig(path26, cfg) {
|
|
5378
5414
|
const raw = JSON.stringify(cfg, null, 2);
|
|
5379
|
-
const tmp =
|
|
5415
|
+
const tmp = path26 + ".tmp";
|
|
5380
5416
|
await fsp4.writeFile(tmp, raw, "utf8");
|
|
5381
|
-
await fsp4.rename(tmp,
|
|
5417
|
+
await fsp4.rename(tmp, path26);
|
|
5382
5418
|
}
|
|
5383
5419
|
|
|
5384
5420
|
// src/slash-commands/mcp.ts
|
|
@@ -6744,6 +6780,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6744
6780
|
buildClearCommand(opts),
|
|
6745
6781
|
buildCompactCommand(opts),
|
|
6746
6782
|
buildContextCommand(opts),
|
|
6783
|
+
buildCodebaseReindexCommand(opts),
|
|
6747
6784
|
buildToolsCommand(opts),
|
|
6748
6785
|
buildPluginCommand(opts),
|
|
6749
6786
|
buildMcpSlashCommand(opts),
|
|
@@ -6881,10 +6918,10 @@ async function runProjectCheck(opts) {
|
|
|
6881
6918
|
if (answer2 === "y" || answer2 === "yes") {
|
|
6882
6919
|
try {
|
|
6883
6920
|
const { spawn: spawn3 } = await import('child_process');
|
|
6884
|
-
await new Promise((
|
|
6921
|
+
await new Promise((resolve5, reject) => {
|
|
6885
6922
|
const child = spawn3("git", ["init"], { cwd: projectRoot });
|
|
6886
6923
|
child.on("error", reject);
|
|
6887
|
-
child.on("close", (code) => code === 0 ?
|
|
6924
|
+
child.on("close", (code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`)));
|
|
6888
6925
|
});
|
|
6889
6926
|
renderer.write(` ${color.green("\u2713")} Git repository initialized
|
|
6890
6927
|
`);
|
|
@@ -6915,7 +6952,43 @@ var LaunchAbortedError = class extends Error {
|
|
|
6915
6952
|
}
|
|
6916
6953
|
};
|
|
6917
6954
|
async function runLaunchPrompts(opts) {
|
|
6918
|
-
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned } = opts;
|
|
6955
|
+
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned, lastChoices } = opts;
|
|
6956
|
+
if (modePinned !== void 0 && yoloPinned !== void 0 && directorPinned !== void 0 && autonomyPinned !== void 0) {
|
|
6957
|
+
return { mode: modePinned, yolo: yoloPinned, director: directorPinned, autonomy: autonomyPinned };
|
|
6958
|
+
}
|
|
6959
|
+
if (lastChoices) {
|
|
6960
|
+
const effective = {
|
|
6961
|
+
mode: modePinned ?? lastChoices.mode,
|
|
6962
|
+
yolo: yoloPinned ?? lastChoices.yolo,
|
|
6963
|
+
director: directorPinned ?? lastChoices.director,
|
|
6964
|
+
autonomy: autonomyPinned ?? lastChoices.autonomy
|
|
6965
|
+
};
|
|
6966
|
+
const onOff = (v) => v ? color.green("on") : color.dim("off");
|
|
6967
|
+
const modeLabel = effective.mode.toUpperCase();
|
|
6968
|
+
renderer.write(
|
|
6969
|
+
`
|
|
6970
|
+
${color.dim("Last settings:")} ${color.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Director ${onOff(effective.director)} \xB7 Autonomy ${effective.autonomy === "auto" ? color.green("auto") : color.dim("off")}
|
|
6971
|
+
`
|
|
6972
|
+
);
|
|
6973
|
+
const answer = (await reader.readLine(
|
|
6974
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
6975
|
+
)).trim().toLowerCase();
|
|
6976
|
+
if (answer === "q") {
|
|
6977
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
6978
|
+
throw new LaunchAbortedError();
|
|
6979
|
+
}
|
|
6980
|
+
if (answer !== "n" && answer !== "no") {
|
|
6981
|
+
const badges2 = buildBadges(effective);
|
|
6982
|
+
const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
|
|
6983
|
+
renderer.write(
|
|
6984
|
+
`
|
|
6985
|
+
${color.green("\u25B6")} Launching in ${color.bold(modeLabel)} mode${badgeStr2}
|
|
6986
|
+
|
|
6987
|
+
`
|
|
6988
|
+
);
|
|
6989
|
+
return effective;
|
|
6990
|
+
}
|
|
6991
|
+
}
|
|
6919
6992
|
let mode;
|
|
6920
6993
|
if (modePinned) {
|
|
6921
6994
|
mode = modePinned;
|
|
@@ -6969,10 +7042,7 @@ async function runLaunchPrompts(opts) {
|
|
|
6969
7042
|
}
|
|
6970
7043
|
autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
|
|
6971
7044
|
}
|
|
6972
|
-
const badges =
|
|
6973
|
-
if (yolo) badges.push(color.yellow("YOLO"));
|
|
6974
|
-
if (director) badges.push(color.cyan("DIRECTOR"));
|
|
6975
|
-
if (autonomy !== "off") badges.push(color.magenta(`AUTONOMY:${autonomy.toUpperCase()}`));
|
|
7045
|
+
const badges = buildBadges({ yolo, director, autonomy });
|
|
6976
7046
|
const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
|
|
6977
7047
|
renderer.write(
|
|
6978
7048
|
`
|
|
@@ -6982,6 +7052,28 @@ async function runLaunchPrompts(opts) {
|
|
|
6982
7052
|
);
|
|
6983
7053
|
return { mode, yolo, director, autonomy };
|
|
6984
7054
|
}
|
|
7055
|
+
function buildBadges(chosen) {
|
|
7056
|
+
const badges = [];
|
|
7057
|
+
if (chosen.yolo) badges.push(color.yellow("YOLO"));
|
|
7058
|
+
if (chosen.director) badges.push(color.cyan("DIRECTOR"));
|
|
7059
|
+
if (chosen.autonomy !== "off") badges.push(color.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
|
|
7060
|
+
return badges;
|
|
7061
|
+
}
|
|
7062
|
+
async function persistLaunchChoices(configPath2, choices) {
|
|
7063
|
+
let existing = {};
|
|
7064
|
+
try {
|
|
7065
|
+
const raw = await fsp4.readFile(configPath2, "utf8");
|
|
7066
|
+
existing = JSON.parse(raw);
|
|
7067
|
+
} catch {
|
|
7068
|
+
}
|
|
7069
|
+
existing.yolo = choices.yolo;
|
|
7070
|
+
existing.launch = {
|
|
7071
|
+
mode: choices.mode,
|
|
7072
|
+
director: choices.director,
|
|
7073
|
+
autonomy: choices.autonomy
|
|
7074
|
+
};
|
|
7075
|
+
await atomicWrite(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7076
|
+
}
|
|
6985
7077
|
async function bootConfig(flags) {
|
|
6986
7078
|
const opts = { flags, appLabel: "wstack" };
|
|
6987
7079
|
const { cwd, projectRoot, userHome, wpaths, pathResolver, config, vault } = await bootConfig$1(opts);
|
|
@@ -7028,32 +7120,32 @@ var ReadlineInputReader = class {
|
|
|
7028
7120
|
async readLine(prompt) {
|
|
7029
7121
|
if (this.history.length === 0) await this.loadHistory();
|
|
7030
7122
|
while (this.pending) {
|
|
7031
|
-
await new Promise((
|
|
7123
|
+
await new Promise((resolve5) => setTimeout(resolve5, 50));
|
|
7032
7124
|
}
|
|
7033
7125
|
this.pending = true;
|
|
7034
7126
|
try {
|
|
7035
7127
|
if (this.rl) {
|
|
7036
7128
|
const old = this.rl;
|
|
7037
7129
|
this.rl = void 0;
|
|
7038
|
-
await new Promise((
|
|
7130
|
+
await new Promise((resolve5) => {
|
|
7039
7131
|
if (old.closed) {
|
|
7040
|
-
|
|
7132
|
+
resolve5();
|
|
7041
7133
|
} else {
|
|
7042
|
-
old.once("close",
|
|
7134
|
+
old.once("close", resolve5);
|
|
7043
7135
|
old.close();
|
|
7044
7136
|
}
|
|
7045
7137
|
});
|
|
7046
7138
|
}
|
|
7047
7139
|
const fresh = this.ensure();
|
|
7048
|
-
return new Promise((
|
|
7140
|
+
return new Promise((resolve5) => {
|
|
7049
7141
|
fresh.question(prompt ?? "> ", (line) => {
|
|
7050
7142
|
if (line.trim()) {
|
|
7051
7143
|
this.history.push(line);
|
|
7052
7144
|
void this.saveHistory();
|
|
7053
7145
|
}
|
|
7054
|
-
|
|
7146
|
+
resolve5(line);
|
|
7055
7147
|
});
|
|
7056
|
-
fresh.once("close", () =>
|
|
7148
|
+
fresh.once("close", () => resolve5(""));
|
|
7057
7149
|
}).then((result) => {
|
|
7058
7150
|
this.rl?.close();
|
|
7059
7151
|
return result;
|
|
@@ -7064,7 +7156,7 @@ var ReadlineInputReader = class {
|
|
|
7064
7156
|
}
|
|
7065
7157
|
async readKey(prompt, options) {
|
|
7066
7158
|
writeOut(prompt);
|
|
7067
|
-
return new Promise((
|
|
7159
|
+
return new Promise((resolve5) => {
|
|
7068
7160
|
const stdin = process.stdin;
|
|
7069
7161
|
const wasRaw = stdin.isRaw;
|
|
7070
7162
|
const wasPaused = stdin.isPaused();
|
|
@@ -7075,7 +7167,7 @@ var ReadlineInputReader = class {
|
|
|
7075
7167
|
if (key === "") {
|
|
7076
7168
|
cleanup();
|
|
7077
7169
|
writeOut("\n");
|
|
7078
|
-
|
|
7170
|
+
resolve5("");
|
|
7079
7171
|
return;
|
|
7080
7172
|
}
|
|
7081
7173
|
const opt = options.find(
|
|
@@ -7085,12 +7177,12 @@ var ReadlineInputReader = class {
|
|
|
7085
7177
|
cleanup();
|
|
7086
7178
|
writeOut(`${opt.key}
|
|
7087
7179
|
`);
|
|
7088
|
-
|
|
7180
|
+
resolve5(opt.value);
|
|
7089
7181
|
}
|
|
7090
7182
|
};
|
|
7091
7183
|
const onClose = () => {
|
|
7092
7184
|
cleanup();
|
|
7093
|
-
|
|
7185
|
+
resolve5("");
|
|
7094
7186
|
};
|
|
7095
7187
|
const cleanup = () => {
|
|
7096
7188
|
stdin.off("data", onData);
|
|
@@ -7118,7 +7210,7 @@ var ReadlineInputReader = class {
|
|
|
7118
7210
|
this.rl?.close();
|
|
7119
7211
|
this.rl = void 0;
|
|
7120
7212
|
writeOut(prompt);
|
|
7121
|
-
return new Promise((
|
|
7213
|
+
return new Promise((resolve5) => {
|
|
7122
7214
|
let buf = "";
|
|
7123
7215
|
const wasRaw = stdin.isRaw;
|
|
7124
7216
|
setRawMode(stdin, true);
|
|
@@ -7136,7 +7228,7 @@ var ReadlineInputReader = class {
|
|
|
7136
7228
|
cleanup();
|
|
7137
7229
|
writeOut(` ${dim(`[${buf.length} chars]`)}
|
|
7138
7230
|
`);
|
|
7139
|
-
|
|
7231
|
+
resolve5(buf);
|
|
7140
7232
|
return;
|
|
7141
7233
|
}
|
|
7142
7234
|
if (ch === "") {
|
|
@@ -7496,21 +7588,25 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7496
7588
|
|
|
7497
7589
|
// src/picker.ts
|
|
7498
7590
|
var theme = { primary: color.amber };
|
|
7499
|
-
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ??
|
|
7591
|
+
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
7500
7592
|
try {
|
|
7501
|
-
const { atomicWrite:
|
|
7502
|
-
const
|
|
7593
|
+
const { atomicWrite: atomicWrite14 } = await import('@wrongstack/core');
|
|
7594
|
+
const fs26 = await import('fs/promises');
|
|
7503
7595
|
let existing = {};
|
|
7504
7596
|
try {
|
|
7505
|
-
const raw = await
|
|
7597
|
+
const raw = await fs26.readFile(configPath2, "utf8");
|
|
7506
7598
|
existing = JSON.parse(raw);
|
|
7507
7599
|
} catch {
|
|
7508
7600
|
}
|
|
7509
7601
|
const oldCfg = { ...existing };
|
|
7510
7602
|
existing.provider = provider;
|
|
7511
7603
|
existing.model = model;
|
|
7512
|
-
|
|
7513
|
-
|
|
7604
|
+
try {
|
|
7605
|
+
await backupCurrent(homeFn);
|
|
7606
|
+
} catch (err) {
|
|
7607
|
+
console.warn("[picker] backupCurrent failed:", err);
|
|
7608
|
+
}
|
|
7609
|
+
await atomicWrite14(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7514
7610
|
try {
|
|
7515
7611
|
await appendHistory(
|
|
7516
7612
|
oldCfg,
|
|
@@ -7521,7 +7617,8 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7521
7617
|
} catch {
|
|
7522
7618
|
}
|
|
7523
7619
|
return true;
|
|
7524
|
-
} catch {
|
|
7620
|
+
} catch (err) {
|
|
7621
|
+
console.warn("[picker] saveToGlobalConfig failed:", err instanceof Error ? err.message : String(err));
|
|
7525
7622
|
return false;
|
|
7526
7623
|
}
|
|
7527
7624
|
}
|
|
@@ -8173,14 +8270,14 @@ function summarize(value, name) {
|
|
|
8173
8270
|
if (typeof v === "object" && v !== null) {
|
|
8174
8271
|
const o = v;
|
|
8175
8272
|
if (name === "edit") {
|
|
8176
|
-
const
|
|
8273
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8177
8274
|
const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
|
|
8178
|
-
return `${
|
|
8275
|
+
return `${path26} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
|
|
8179
8276
|
}
|
|
8180
8277
|
if (name === "write") {
|
|
8181
|
-
const
|
|
8278
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8182
8279
|
const bytes = typeof o["bytes"] === "number" ? o["bytes"] : void 0;
|
|
8183
|
-
return bytes !== void 0 ? `${
|
|
8280
|
+
return bytes !== void 0 ? `${path26} ${bytes}B` : path26;
|
|
8184
8281
|
}
|
|
8185
8282
|
if (typeof o["count"] === "number") {
|
|
8186
8283
|
return `${o["count"]} match${o["count"] === 1 ? "" : "es"}`;
|
|
@@ -9040,7 +9137,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9040
9137
|
deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
|
|
9041
9138
|
`);
|
|
9042
9139
|
try {
|
|
9043
|
-
const result = await new Promise((
|
|
9140
|
+
const result = await new Promise((resolve5, reject) => {
|
|
9044
9141
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
9045
9142
|
const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
|
|
9046
9143
|
cwd,
|
|
@@ -9051,7 +9148,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9051
9148
|
_stderr += d;
|
|
9052
9149
|
});
|
|
9053
9150
|
child.on("error", reject);
|
|
9054
|
-
child.on("close", (code) =>
|
|
9151
|
+
child.on("close", (code) => resolve5({ code: code ?? 0 }));
|
|
9055
9152
|
});
|
|
9056
9153
|
if (result.code === 0) {
|
|
9057
9154
|
deps.renderer.write(`
|
|
@@ -9487,8 +9584,8 @@ async function serveMcpStdio(deps) {
|
|
|
9487
9584
|
log(
|
|
9488
9585
|
`wrongstack MCP server ready at ${handle2.url} \u2014 exposing ${allowed.length} tool(s) (${mode})${token ? " [token auth]" : ""}.`
|
|
9489
9586
|
);
|
|
9490
|
-
await new Promise((
|
|
9491
|
-
const stop = () =>
|
|
9587
|
+
await new Promise((resolve5) => {
|
|
9588
|
+
const stop = () => resolve5();
|
|
9492
9589
|
process.once("SIGINT", stop);
|
|
9493
9590
|
process.once("SIGTERM", stop);
|
|
9494
9591
|
});
|
|
@@ -10757,10 +10854,10 @@ var auditCmd = async (args, deps) => {
|
|
|
10757
10854
|
return verify.ok ? 0 : 1;
|
|
10758
10855
|
};
|
|
10759
10856
|
async function listAudits(log, dir, deps) {
|
|
10760
|
-
const
|
|
10857
|
+
const fs26 = await import('fs/promises');
|
|
10761
10858
|
let entries;
|
|
10762
10859
|
try {
|
|
10763
|
-
entries = await
|
|
10860
|
+
entries = await fs26.readdir(dir);
|
|
10764
10861
|
} catch {
|
|
10765
10862
|
deps.renderer.write(
|
|
10766
10863
|
color.dim(`No sessions dir found at ${dir}. Run a session first.`) + "\n"
|
|
@@ -10911,22 +11008,22 @@ function fmtDuration(ms) {
|
|
|
10911
11008
|
const remMin = m - h * 60;
|
|
10912
11009
|
return `${h}h${remMin}m`;
|
|
10913
11010
|
}
|
|
10914
|
-
function fmtTaskResultLine(r,
|
|
11011
|
+
function fmtTaskResultLine(r, color49) {
|
|
10915
11012
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
10916
11013
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
10917
11014
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
10918
11015
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
10919
|
-
const errKindChip = errKind ?
|
|
10920
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
11016
|
+
const errKindChip = errKind ? color49.dim(` [${errKind}]`) : "";
|
|
11017
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color49.dim(errTail)}` : "";
|
|
10921
11018
|
switch (r.status) {
|
|
10922
11019
|
case "success":
|
|
10923
|
-
return { mark:
|
|
11020
|
+
return { mark: color49.green("\u2713"), stats, tail: "" };
|
|
10924
11021
|
case "timeout":
|
|
10925
|
-
return { mark:
|
|
11022
|
+
return { mark: color49.yellow("\u23F1"), stats: `${color49.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
10926
11023
|
case "stopped":
|
|
10927
|
-
return { mark:
|
|
11024
|
+
return { mark: color49.dim("\u2298"), stats: `${color49.dim("stopped")} ${stats}`, tail: errSnip };
|
|
10928
11025
|
case "failed":
|
|
10929
|
-
return { mark:
|
|
11026
|
+
return { mark: color49.red("\u2717"), stats: `${color49.red("failed")} ${stats}`, tail: errSnip };
|
|
10930
11027
|
}
|
|
10931
11028
|
}
|
|
10932
11029
|
|
|
@@ -11050,20 +11147,51 @@ async function boot(argv) {
|
|
|
11050
11147
|
const modelFlag = typeof flags["model"] === "string" ? flags["model"] : void 0;
|
|
11051
11148
|
if (!(!!providerFlag && !!modelFlag)) {
|
|
11052
11149
|
if (isStdinTTY()) {
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11150
|
+
let picked;
|
|
11151
|
+
let skipPicker = false;
|
|
11152
|
+
const savedProvider = config.provider;
|
|
11153
|
+
const savedModel = config.model;
|
|
11154
|
+
if (savedProvider && savedModel) {
|
|
11155
|
+
renderer.write(
|
|
11156
|
+
`
|
|
11157
|
+
${color.dim("Last settings:")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11158
|
+
`
|
|
11159
|
+
);
|
|
11160
|
+
const answer = (await reader.readLine(
|
|
11161
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
11162
|
+
)).trim().toLowerCase();
|
|
11163
|
+
if (answer === "q") {
|
|
11164
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
11165
|
+
await reader.close();
|
|
11166
|
+
return 0;
|
|
11167
|
+
}
|
|
11168
|
+
if (answer !== "n" && answer !== "no") {
|
|
11169
|
+
skipPicker = true;
|
|
11170
|
+
renderer.write(
|
|
11171
|
+
`
|
|
11172
|
+
${color.green("\u25B6")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11173
|
+
|
|
11174
|
+
`
|
|
11175
|
+
);
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11178
|
+
if (!skipPicker) {
|
|
11179
|
+
picked = await runPicker({
|
|
11180
|
+
modelsRegistry,
|
|
11181
|
+
renderer,
|
|
11182
|
+
reader,
|
|
11183
|
+
config,
|
|
11184
|
+
defaultProvider: providerFlag ?? config.provider,
|
|
11185
|
+
defaultModel: modelFlag ?? config.model
|
|
11186
|
+
});
|
|
11187
|
+
}
|
|
11188
|
+
if (!picked && !skipPicker) {
|
|
11062
11189
|
if (!config.provider || !config.model) {
|
|
11063
11190
|
await reader.close();
|
|
11064
11191
|
return 2;
|
|
11065
11192
|
}
|
|
11066
|
-
}
|
|
11193
|
+
}
|
|
11194
|
+
if (picked) {
|
|
11067
11195
|
const prevProvider = config.provider;
|
|
11068
11196
|
const prevModel = config.model;
|
|
11069
11197
|
config = patchConfig(config, { provider: picked.provider, model: picked.model });
|
|
@@ -11073,8 +11201,15 @@ async function boot(argv) {
|
|
|
11073
11201
|
picked.provider,
|
|
11074
11202
|
picked.model
|
|
11075
11203
|
);
|
|
11076
|
-
if (saved)
|
|
11204
|
+
if (saved) {
|
|
11205
|
+
renderer.writeInfo(`Saved ${picked.provider}/${picked.model} as default.
|
|
11077
11206
|
`);
|
|
11207
|
+
} else {
|
|
11208
|
+
renderer.writeWarning(
|
|
11209
|
+
`Could not save ${picked.provider}/${picked.model} to config. Check permissions or disk space.
|
|
11210
|
+
`
|
|
11211
|
+
);
|
|
11212
|
+
}
|
|
11078
11213
|
}
|
|
11079
11214
|
}
|
|
11080
11215
|
} else if (!config.provider || !config.model) {
|
|
@@ -11107,6 +11242,12 @@ async function boot(argv) {
|
|
|
11107
11242
|
} else if (flags["autonomy"] === true) {
|
|
11108
11243
|
autonomyPinned = "auto";
|
|
11109
11244
|
}
|
|
11245
|
+
const lastChoices = config.launch ? {
|
|
11246
|
+
mode: config.launch.mode ?? "tui",
|
|
11247
|
+
yolo: config.yolo ?? true,
|
|
11248
|
+
director: config.launch.director ?? true,
|
|
11249
|
+
autonomy: config.launch.autonomy ?? "auto"
|
|
11250
|
+
} : void 0;
|
|
11110
11251
|
let choices;
|
|
11111
11252
|
try {
|
|
11112
11253
|
choices = await runLaunchPrompts({
|
|
@@ -11115,7 +11256,8 @@ async function boot(argv) {
|
|
|
11115
11256
|
modePinned,
|
|
11116
11257
|
yoloPinned,
|
|
11117
11258
|
directorPinned,
|
|
11118
|
-
autonomyPinned
|
|
11259
|
+
autonomyPinned,
|
|
11260
|
+
lastChoices
|
|
11119
11261
|
});
|
|
11120
11262
|
} catch (err) {
|
|
11121
11263
|
if (err instanceof LaunchAbortedError) {
|
|
@@ -11134,6 +11276,10 @@ async function boot(argv) {
|
|
|
11134
11276
|
if (choices.yolo !== config.yolo) config = patchConfig(config, { yolo: choices.yolo });
|
|
11135
11277
|
if (choices.director) flags["director"] = true;
|
|
11136
11278
|
flags["autonomy"] = choices.autonomy;
|
|
11279
|
+
try {
|
|
11280
|
+
await persistLaunchChoices(wpaths.globalConfig, choices);
|
|
11281
|
+
} catch {
|
|
11282
|
+
}
|
|
11137
11283
|
printLaunchHints(renderer, flags, {
|
|
11138
11284
|
cursorFile: path8.join(wpaths.cacheDir, "hint-cursor")
|
|
11139
11285
|
});
|
|
@@ -11527,7 +11673,7 @@ async function runRepl(opts) {
|
|
|
11527
11673
|
`[eternal] ${err instanceof Error ? err.message : String(err)}`
|
|
11528
11674
|
);
|
|
11529
11675
|
}
|
|
11530
|
-
await new Promise((
|
|
11676
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11531
11677
|
continue;
|
|
11532
11678
|
}
|
|
11533
11679
|
} else if (opts.getAutonomy?.() === "eternal-parallel") {
|
|
@@ -11573,7 +11719,7 @@ async function runRepl(opts) {
|
|
|
11573
11719
|
`[parallel] ${err instanceof Error ? err.message : String(err)}`
|
|
11574
11720
|
);
|
|
11575
11721
|
}
|
|
11576
|
-
await new Promise((
|
|
11722
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11577
11723
|
continue;
|
|
11578
11724
|
}
|
|
11579
11725
|
}
|
|
@@ -12341,15 +12487,10 @@ async function execute(deps) {
|
|
|
12341
12487
|
},
|
|
12342
12488
|
effectiveMaxContext,
|
|
12343
12489
|
// Default OFF so the terminal's native scrollback works for chat
|
|
12344
|
-
// history out of the box
|
|
12345
|
-
//
|
|
12346
|
-
// `--
|
|
12490
|
+
// history out of the box. Users who hit resize/overlay-leak
|
|
12491
|
+
// artifacts can opt back into alt-screen with `--alt-screen`.
|
|
12492
|
+
// `--no-alt-screen` still wins when both are passed.
|
|
12347
12493
|
altScreen: flags["alt-screen"] === true && flags["no-alt-screen"] !== true,
|
|
12348
|
-
// Mouse mode is DISABLED. It was unreliable on Windows consoles
|
|
12349
|
-
// (freezes / constant repaint in the managed viewport) and is not
|
|
12350
|
-
// wanted, so `--mouse` is intentionally ignored and never engages —
|
|
12351
|
-
// the TUI stays keyboard-only. Do not re-wire `flags.mouse` here.
|
|
12352
|
-
mouse: false,
|
|
12353
12494
|
director,
|
|
12354
12495
|
fleetRoster,
|
|
12355
12496
|
onAfterExit: () => {
|
|
@@ -12712,8 +12853,10 @@ var MultiAgentHost = class {
|
|
|
12712
12853
|
// meaningless to a single delegated subtask.
|
|
12713
12854
|
subagent: true
|
|
12714
12855
|
});
|
|
12715
|
-
|
|
12716
|
-
|
|
12856
|
+
baseSystem.unshift({ type: "text", text: DEFAULT_SUBAGENT_BASELINE });
|
|
12857
|
+
const rolePrompt = subCfg.systemPromptOverride ?? (subCfg.role ? FLEET_ROSTER[subCfg.role]?.prompt : void 0);
|
|
12858
|
+
if (rolePrompt) {
|
|
12859
|
+
baseSystem.push({ type: "text", text: rolePrompt });
|
|
12717
12860
|
}
|
|
12718
12861
|
let subSession;
|
|
12719
12862
|
if (this.sessionFactory) {
|
|
@@ -13243,11 +13386,11 @@ var SessionStats = class {
|
|
|
13243
13386
|
if (e.name === "bash") this.bashCommands++;
|
|
13244
13387
|
else if (e.name === "fetch") this.fetches++;
|
|
13245
13388
|
if (!e.ok) return;
|
|
13246
|
-
const
|
|
13247
|
-
if (e.name === "read" &&
|
|
13248
|
-
else if (e.name === "edit" &&
|
|
13249
|
-
else if (e.name === "write" &&
|
|
13250
|
-
this.writtenPaths.add(
|
|
13389
|
+
const path26 = typeof input?.path === "string" ? input.path : void 0;
|
|
13390
|
+
if (e.name === "read" && path26) this.readPaths.add(path26);
|
|
13391
|
+
else if (e.name === "edit" && path26) this.editedPaths.add(path26);
|
|
13392
|
+
else if (e.name === "write" && path26) {
|
|
13393
|
+
this.writtenPaths.add(path26);
|
|
13251
13394
|
const content = typeof input?.content === "string" ? input.content : "";
|
|
13252
13395
|
this.bytesWritten += Buffer.byteLength(content, "utf8");
|
|
13253
13396
|
}
|
|
@@ -13353,7 +13496,7 @@ function samplePaths(set) {
|
|
|
13353
13496
|
}
|
|
13354
13497
|
var WORKTREE_PHASE_CONCURRENCY = 4;
|
|
13355
13498
|
function gitText(args, cwd) {
|
|
13356
|
-
return new Promise((
|
|
13499
|
+
return new Promise((resolve5) => {
|
|
13357
13500
|
let out = "";
|
|
13358
13501
|
const child = spawn("git", args, {
|
|
13359
13502
|
cwd,
|
|
@@ -13366,8 +13509,8 @@ function gitText(args, cwd) {
|
|
|
13366
13509
|
child.stderr?.on("data", (c) => {
|
|
13367
13510
|
out += c.toString();
|
|
13368
13511
|
});
|
|
13369
|
-
child.on("error", () =>
|
|
13370
|
-
child.on("close", (code) =>
|
|
13512
|
+
child.on("error", () => resolve5({ code: 1, out }));
|
|
13513
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13371
13514
|
});
|
|
13372
13515
|
}
|
|
13373
13516
|
async function isGitRepo(cwd) {
|
|
@@ -13375,7 +13518,7 @@ async function isGitRepo(cwd) {
|
|
|
13375
13518
|
return code === 0 && out.trim() === "true";
|
|
13376
13519
|
}
|
|
13377
13520
|
function runCmd(cmd, args, cwd, shell = false) {
|
|
13378
|
-
return new Promise((
|
|
13521
|
+
return new Promise((resolve5) => {
|
|
13379
13522
|
let out = "";
|
|
13380
13523
|
const child = spawn(cmd, args, {
|
|
13381
13524
|
cwd,
|
|
@@ -13389,8 +13532,8 @@ function runCmd(cmd, args, cwd, shell = false) {
|
|
|
13389
13532
|
child.stderr?.on("data", (c) => {
|
|
13390
13533
|
out += c.toString();
|
|
13391
13534
|
});
|
|
13392
|
-
child.on("error", (e) =>
|
|
13393
|
-
child.on("close", (code) =>
|
|
13535
|
+
child.on("error", (e) => resolve5({ code: 1, out: `${out}${String(e)}` }));
|
|
13536
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13394
13537
|
});
|
|
13395
13538
|
}
|
|
13396
13539
|
function detectPackageManager2(root) {
|
|
@@ -14084,6 +14227,91 @@ function setupMetrics(params) {
|
|
|
14084
14227
|
}
|
|
14085
14228
|
return { metricsSink, healthRegistry, metricsServerHandle };
|
|
14086
14229
|
}
|
|
14230
|
+
var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "multi-edit", "notebook-edit"]);
|
|
14231
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
14232
|
+
"node_modules",
|
|
14233
|
+
".git",
|
|
14234
|
+
"dist",
|
|
14235
|
+
"build",
|
|
14236
|
+
".next",
|
|
14237
|
+
"coverage",
|
|
14238
|
+
".turbo",
|
|
14239
|
+
"__snapshots__",
|
|
14240
|
+
".nyc_output"
|
|
14241
|
+
]);
|
|
14242
|
+
function isIgnored(rel) {
|
|
14243
|
+
return rel.split(/[/\\]/).some((seg) => IGNORE_DIRS.has(seg));
|
|
14244
|
+
}
|
|
14245
|
+
async function setupCodebaseIndexing(deps) {
|
|
14246
|
+
const { config, pipelines, projectRoot, logger } = deps;
|
|
14247
|
+
const idx = config.indexing;
|
|
14248
|
+
if (!idx) return () => {
|
|
14249
|
+
};
|
|
14250
|
+
const debounceMs = idx.debounceMs ?? 400;
|
|
14251
|
+
const onError = (err) => logger.debug(`codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14252
|
+
if (idx.onSessionStart) {
|
|
14253
|
+
void runStartupIndex({ projectRoot }).then((r) => {
|
|
14254
|
+
const summary = `${color.green("\u2713")} codebase index ready ${color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`)}`;
|
|
14255
|
+
process.stderr.write(`
|
|
14256
|
+
${summary}
|
|
14257
|
+
`);
|
|
14258
|
+
}).catch((err) => {
|
|
14259
|
+
logger.warn(
|
|
14260
|
+
`codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
14261
|
+
);
|
|
14262
|
+
});
|
|
14263
|
+
}
|
|
14264
|
+
if (idx.onEdit) {
|
|
14265
|
+
pipelines.toolCall.use({
|
|
14266
|
+
name: "CodebaseAutoIndex",
|
|
14267
|
+
// Non-core owner → the pipeline error boundary swallows failures instead
|
|
14268
|
+
// of failing the turn (see wiring/pipeline.ts).
|
|
14269
|
+
owner: "codebase-index",
|
|
14270
|
+
handler: async (payload, next) => {
|
|
14271
|
+
try {
|
|
14272
|
+
const tool = payload.tool;
|
|
14273
|
+
if (tool?.mutating && FILE_EDIT_TOOLS.has(tool.name)) {
|
|
14274
|
+
const fp = payload.toolUse.input?.file_path;
|
|
14275
|
+
if (typeof fp === "string" && fp.length > 0) {
|
|
14276
|
+
const abs = path8.resolve(payload.ctx.cwd, fp);
|
|
14277
|
+
if (isIndexableFile(abs)) {
|
|
14278
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14279
|
+
}
|
|
14280
|
+
}
|
|
14281
|
+
}
|
|
14282
|
+
} catch {
|
|
14283
|
+
}
|
|
14284
|
+
return next(payload);
|
|
14285
|
+
}
|
|
14286
|
+
});
|
|
14287
|
+
}
|
|
14288
|
+
let watcher;
|
|
14289
|
+
if (idx.watchExternal) {
|
|
14290
|
+
try {
|
|
14291
|
+
watcher = fs12.watch(projectRoot, { recursive: true }, (_event, filename) => {
|
|
14292
|
+
if (!filename) return;
|
|
14293
|
+
const rel = filename.toString();
|
|
14294
|
+
if (isIgnored(rel)) return;
|
|
14295
|
+
const abs = path8.resolve(projectRoot, rel);
|
|
14296
|
+
if (!isIndexableFile(abs)) return;
|
|
14297
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14298
|
+
});
|
|
14299
|
+
watcher.on("error", (err) => logger.debug(`codebase index watcher error: ${err}`));
|
|
14300
|
+
watcher.unref?.();
|
|
14301
|
+
} catch (err) {
|
|
14302
|
+
logger.debug(
|
|
14303
|
+
`codebase index watcher unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
14304
|
+
);
|
|
14305
|
+
}
|
|
14306
|
+
}
|
|
14307
|
+
return () => {
|
|
14308
|
+
try {
|
|
14309
|
+
watcher?.close();
|
|
14310
|
+
} catch {
|
|
14311
|
+
}
|
|
14312
|
+
cancelPendingReindexes();
|
|
14313
|
+
};
|
|
14314
|
+
}
|
|
14087
14315
|
function createApi(ownerName, base) {
|
|
14088
14316
|
return new DefaultPluginAPI({ ownerName, ...base });
|
|
14089
14317
|
}
|
|
@@ -14892,7 +15120,8 @@ async function main(argv) {
|
|
|
14892
15120
|
const directorMode = flags["director"] === true || typeof flags["resume"] === "string";
|
|
14893
15121
|
const maxConcurrentFromFlag = typeof flags["max-concurrent"] === "string" ? Number.parseInt(flags["max-concurrent"], 10) : void 0;
|
|
14894
15122
|
const maxConcurrentFromEnv = typeof process.env["WRONGSTACK_MAX_CONCURRENT"] === "string" ? Number.parseInt(process.env["WRONGSTACK_MAX_CONCURRENT"], 10) : void 0;
|
|
14895
|
-
const
|
|
15123
|
+
const maxConcurrentFromConfig = typeof config.maxConcurrent === "number" && config.maxConcurrent > 0 ? config.maxConcurrent : void 0;
|
|
15124
|
+
const maxConcurrent = Number.isFinite(maxConcurrentFromFlag) && maxConcurrentFromFlag > 0 ? maxConcurrentFromFlag : Number.isFinite(maxConcurrentFromEnv) && maxConcurrentFromEnv > 0 ? maxConcurrentFromEnv : Number.isFinite(maxConcurrentFromConfig) && maxConcurrentFromConfig > 0 ? maxConcurrentFromConfig : void 0;
|
|
14896
15125
|
let director = null;
|
|
14897
15126
|
let autonomyMode = (() => {
|
|
14898
15127
|
const v = flags["autonomy"];
|
|
@@ -15222,6 +15451,7 @@ async function main(argv) {
|
|
|
15222
15451
|
}
|
|
15223
15452
|
try {
|
|
15224
15453
|
multiAgentHost.setMaxConcurrent(n);
|
|
15454
|
+
events.emit("concurrency.changed", { n });
|
|
15225
15455
|
} catch (err) {
|
|
15226
15456
|
return err instanceof Error ? err.message : String(err);
|
|
15227
15457
|
}
|
|
@@ -15590,7 +15820,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15590
15820
|
const { spawn: spawn3 } = await import('child_process');
|
|
15591
15821
|
const cwd2 = projectRoot;
|
|
15592
15822
|
const statusResult = await new Promise(
|
|
15593
|
-
(
|
|
15823
|
+
(resolve5, reject) => {
|
|
15594
15824
|
const child = spawn3("git", ["status", "--porcelain"], {
|
|
15595
15825
|
cwd: cwd2,
|
|
15596
15826
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -15600,7 +15830,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15600
15830
|
stdout += d;
|
|
15601
15831
|
});
|
|
15602
15832
|
child.on("error", reject);
|
|
15603
|
-
child.on("close", (code) =>
|
|
15833
|
+
child.on("close", (code) => resolve5({ stdout, code: code ?? 0 }));
|
|
15604
15834
|
}
|
|
15605
15835
|
);
|
|
15606
15836
|
if (statusResult.stdout.trim().length > 0) {
|
|
@@ -15726,6 +15956,13 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15726
15956
|
if (eternalFlag.length > 0) {
|
|
15727
15957
|
autonomyMode = "eternal";
|
|
15728
15958
|
}
|
|
15959
|
+
const disposeIndexing = await setupCodebaseIndexing({
|
|
15960
|
+
config,
|
|
15961
|
+
pipelines,
|
|
15962
|
+
projectRoot,
|
|
15963
|
+
logger
|
|
15964
|
+
});
|
|
15965
|
+
process.once("exit", disposeIndexing);
|
|
15729
15966
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
15730
15967
|
return execute({
|
|
15731
15968
|
agent,
|