@wrongstack/cli 0.68.0 → 0.77.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 +840 -171
- package/dist/index.js.map +1 -1
- package/package.json +12 -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,
|
|
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, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$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, 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",
|
|
@@ -3812,6 +3836,141 @@ function buildStatsCommand(opts) {
|
|
|
3812
3836
|
}
|
|
3813
3837
|
};
|
|
3814
3838
|
}
|
|
3839
|
+
async function persistAutonomySetting(deps, mutator) {
|
|
3840
|
+
let raw;
|
|
3841
|
+
let fileExists = true;
|
|
3842
|
+
try {
|
|
3843
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
3844
|
+
} catch (err) {
|
|
3845
|
+
if (err.code !== "ENOENT") {
|
|
3846
|
+
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
3847
|
+
}
|
|
3848
|
+
fileExists = false;
|
|
3849
|
+
raw = "{}";
|
|
3850
|
+
}
|
|
3851
|
+
let parsed;
|
|
3852
|
+
try {
|
|
3853
|
+
parsed = JSON.parse(raw);
|
|
3854
|
+
} catch (err) {
|
|
3855
|
+
if (fileExists) {
|
|
3856
|
+
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
3857
|
+
}
|
|
3858
|
+
parsed = {};
|
|
3859
|
+
}
|
|
3860
|
+
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
3861
|
+
const autonomy = decrypted.autonomy ?? {};
|
|
3862
|
+
mutator(autonomy);
|
|
3863
|
+
decrypted.autonomy = autonomy;
|
|
3864
|
+
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
3865
|
+
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3866
|
+
deps.configStore.update({ autonomy: decrypted.autonomy });
|
|
3867
|
+
}
|
|
3868
|
+
async function persistTelegramConfig(deps, mutator) {
|
|
3869
|
+
let raw;
|
|
3870
|
+
let fileExists = true;
|
|
3871
|
+
try {
|
|
3872
|
+
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
3873
|
+
} catch (err) {
|
|
3874
|
+
if (err.code !== "ENOENT") {
|
|
3875
|
+
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
3876
|
+
}
|
|
3877
|
+
fileExists = false;
|
|
3878
|
+
raw = "{}";
|
|
3879
|
+
}
|
|
3880
|
+
let parsed;
|
|
3881
|
+
try {
|
|
3882
|
+
parsed = JSON.parse(raw);
|
|
3883
|
+
} catch (err) {
|
|
3884
|
+
if (fileExists) {
|
|
3885
|
+
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
3886
|
+
}
|
|
3887
|
+
parsed = {};
|
|
3888
|
+
}
|
|
3889
|
+
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
3890
|
+
const extensions = decrypted.extensions ?? {};
|
|
3891
|
+
const telegram = extensions.telegram ?? {};
|
|
3892
|
+
mutator(telegram);
|
|
3893
|
+
extensions.telegram = telegram;
|
|
3894
|
+
decrypted.extensions = extensions;
|
|
3895
|
+
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
3896
|
+
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3897
|
+
deps.configStore.update({ extensions: decrypted.extensions });
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
// src/slash-commands/enhance.ts
|
|
3901
|
+
var noOpVault = {
|
|
3902
|
+
encrypt: (v) => v,
|
|
3903
|
+
decrypt: (v) => v,
|
|
3904
|
+
isEncrypted: () => false
|
|
3905
|
+
};
|
|
3906
|
+
function buildEnhanceCommand(opts) {
|
|
3907
|
+
const controller = opts.enhanceController;
|
|
3908
|
+
return {
|
|
3909
|
+
name: "enhance",
|
|
3910
|
+
description: 'Toggle prompt refinement ("did you mean this?") before sending.',
|
|
3911
|
+
help: [
|
|
3912
|
+
"Usage:",
|
|
3913
|
+
" /enhance Show current prompt-refinement status",
|
|
3914
|
+
" /enhance on Enable \u2014 refine free-text prompts before sending",
|
|
3915
|
+
" /enhance off Disable \u2014 send prompts verbatim",
|
|
3916
|
+
" /enhance toggle Flip the current state",
|
|
3917
|
+
"",
|
|
3918
|
+
"When on, each free-text message is rewritten into a clearer instruction",
|
|
3919
|
+
"by a separate LLM call and briefly previewed (auto-sends after a short",
|
|
3920
|
+
"countdown; Enter sends now, Esc keeps your original, e edits). Persisted",
|
|
3921
|
+
"to ~/.wrongstack/config.json (autonomy.enhance)."
|
|
3922
|
+
].join("\n"),
|
|
3923
|
+
async run(args) {
|
|
3924
|
+
if (!controller) {
|
|
3925
|
+
const msg2 = "Prompt refinement is not available in this session.";
|
|
3926
|
+
opts.renderer.writeWarning(msg2);
|
|
3927
|
+
return { message: msg2 };
|
|
3928
|
+
}
|
|
3929
|
+
const arg = args.trim().toLowerCase();
|
|
3930
|
+
if (!arg) {
|
|
3931
|
+
const status = controller.enabled ? `${color.cyan("ON")} ${color.dim("(prompts are refined before sending)")}` : `${color.green("OFF")} ${color.dim("(prompts are sent verbatim)")}`;
|
|
3932
|
+
const msg2 = `Prompt refinement: ${status}`;
|
|
3933
|
+
opts.renderer.write(msg2);
|
|
3934
|
+
return { message: msg2 };
|
|
3935
|
+
}
|
|
3936
|
+
let newState;
|
|
3937
|
+
if (arg === "on" || arg === "enable" || arg === "true" || arg === "1") {
|
|
3938
|
+
newState = true;
|
|
3939
|
+
} else if (arg === "off" || arg === "disable" || arg === "false" || arg === "0") {
|
|
3940
|
+
newState = false;
|
|
3941
|
+
} else if (arg === "toggle") {
|
|
3942
|
+
newState = !controller.enabled;
|
|
3943
|
+
} else {
|
|
3944
|
+
const msg2 = `Unknown argument: ${arg}. Use /enhance on, /enhance off, or /enhance toggle.`;
|
|
3945
|
+
opts.renderer.writeWarning(msg2);
|
|
3946
|
+
return { message: msg2 };
|
|
3947
|
+
}
|
|
3948
|
+
controller.setEnabled(newState);
|
|
3949
|
+
if (opts.configStore && opts.paths) {
|
|
3950
|
+
try {
|
|
3951
|
+
await persistAutonomySetting(
|
|
3952
|
+
{
|
|
3953
|
+
configStore: opts.configStore,
|
|
3954
|
+
globalConfigPath: opts.paths.globalConfig,
|
|
3955
|
+
vault: noOpVault
|
|
3956
|
+
},
|
|
3957
|
+
(autonomy) => {
|
|
3958
|
+
autonomy.enhance = newState;
|
|
3959
|
+
}
|
|
3960
|
+
);
|
|
3961
|
+
} catch (err) {
|
|
3962
|
+
opts.renderer.writeWarning(
|
|
3963
|
+
`Toggle applied for this session but could not be saved: ${err.message}`
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
const label = newState ? `${color.cyan("ENABLED")} \u2014 free-text prompts will be refined before sending` : `${color.green("DISABLED")} \u2014 prompts are sent verbatim`;
|
|
3968
|
+
const msg = `Prompt refinement: ${label}`;
|
|
3969
|
+
opts.renderer.write(msg);
|
|
3970
|
+
return { message: msg };
|
|
3971
|
+
}
|
|
3972
|
+
};
|
|
3973
|
+
}
|
|
3815
3974
|
|
|
3816
3975
|
// src/slash-commands/fix-classifier.ts
|
|
3817
3976
|
var TS = ["typescript-strict"];
|
|
@@ -4652,6 +4811,7 @@ function buildFleetCommand(opts) {
|
|
|
4652
4811
|
" /fleet terminate <subagentId> Stop a specific subagent by id",
|
|
4653
4812
|
" /fleet kill Stop all running subagents",
|
|
4654
4813
|
" /fleet usage Token and cost breakdown across the fleet",
|
|
4814
|
+
" /fleet concurrency [n] Show or set the concurrent-subagent ceiling",
|
|
4655
4815
|
" /fleet journal Show recent journal entries from /goal journal",
|
|
4656
4816
|
"",
|
|
4657
4817
|
"In the TUI, press Ctrl+F to open the graphical fleet monitor.",
|
|
@@ -4894,6 +5054,16 @@ function buildFleetCommand(opts) {
|
|
|
4894
5054
|
opts.renderer.write(msg2);
|
|
4895
5055
|
return { message: msg2 };
|
|
4896
5056
|
}
|
|
5057
|
+
if (cmd === "concurrency" || cmd === "slots" || cmd === "parallel") {
|
|
5058
|
+
if (opts.onFleet) {
|
|
5059
|
+
const n = subargs[0];
|
|
5060
|
+
const msg3 = await opts.onFleet("concurrency", n || void 0);
|
|
5061
|
+
return { message: msg3 };
|
|
5062
|
+
}
|
|
5063
|
+
const msg2 = `${color.amber("\u26A0 /fleet concurrency is not wired in this session.")}`;
|
|
5064
|
+
opts.renderer.writeWarning(msg2);
|
|
5065
|
+
return { message: msg2 };
|
|
5066
|
+
}
|
|
4897
5067
|
if (cmd === "help" || cmd === "?") {
|
|
4898
5068
|
const msg2 = [
|
|
4899
5069
|
`${color.bold("Fleet Commands")}`,
|
|
@@ -4905,12 +5075,13 @@ function buildFleetCommand(opts) {
|
|
|
4905
5075
|
` ${color.dim("/fleet terminate <subagentId>")} Stop a specific subagent by id`,
|
|
4906
5076
|
` ${color.dim("/fleet kill")} Stop all running subagents`,
|
|
4907
5077
|
` ${color.dim("/fleet usage")} Token and cost breakdown across the fleet`,
|
|
5078
|
+
` ${color.dim("/fleet concurrency [n]")} Show or set the concurrent-subagent ceiling`,
|
|
4908
5079
|
` ${color.dim("/fleet journal")} Show recent journal entries from /goal journal`
|
|
4909
5080
|
].join("\n");
|
|
4910
5081
|
opts.renderer.write(msg2);
|
|
4911
5082
|
return { message: msg2 };
|
|
4912
5083
|
}
|
|
4913
|
-
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "journal"];
|
|
5084
|
+
const valid = ["status", "list", "dispatch", "usage", "spawn", "terminate", "kill", "retry", "concurrency", "journal"];
|
|
4914
5085
|
const msg = `Unknown subcommand "${cmd}". Valid subcommands: ${valid.join(", ")}. Run /fleet with no args to see status, or /fleet help for usage.`;
|
|
4915
5086
|
opts.renderer.writeWarning(msg);
|
|
4916
5087
|
return { message: msg };
|
|
@@ -5364,9 +5535,9 @@ function stateBadge(state) {
|
|
|
5364
5535
|
return color.dim(state);
|
|
5365
5536
|
}
|
|
5366
5537
|
}
|
|
5367
|
-
async function readConfig(
|
|
5538
|
+
async function readConfig(path26) {
|
|
5368
5539
|
try {
|
|
5369
|
-
return JSON.parse(await fsp4.readFile(
|
|
5540
|
+
return JSON.parse(await fsp4.readFile(path26, "utf8"));
|
|
5370
5541
|
} catch {
|
|
5371
5542
|
return {};
|
|
5372
5543
|
}
|
|
@@ -5374,11 +5545,11 @@ async function readConfig(path25) {
|
|
|
5374
5545
|
function isMcpServerRecord(value) {
|
|
5375
5546
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5376
5547
|
}
|
|
5377
|
-
async function writeConfig(
|
|
5548
|
+
async function writeConfig(path26, cfg) {
|
|
5378
5549
|
const raw = JSON.stringify(cfg, null, 2);
|
|
5379
|
-
const tmp =
|
|
5550
|
+
const tmp = path26 + ".tmp";
|
|
5380
5551
|
await fsp4.writeFile(tmp, raw, "utf8");
|
|
5381
|
-
await fsp4.rename(tmp,
|
|
5552
|
+
await fsp4.rename(tmp, path26);
|
|
5382
5553
|
}
|
|
5383
5554
|
|
|
5384
5555
|
// src/slash-commands/mcp.ts
|
|
@@ -5521,7 +5692,7 @@ function buildModeCommand(opts) {
|
|
|
5521
5692
|
" /mode brief Switch to brief mode",
|
|
5522
5693
|
" /mode teach Switch to teach mode"
|
|
5523
5694
|
].join("\n"),
|
|
5524
|
-
async run(args,
|
|
5695
|
+
async run(args, ctx) {
|
|
5525
5696
|
const modeStore = opts.modeStore;
|
|
5526
5697
|
if (!modeStore) {
|
|
5527
5698
|
return { message: "Mode store not available in this context." };
|
|
@@ -5535,6 +5706,7 @@ function buildModeCommand(opts) {
|
|
|
5535
5706
|
return { message: "Mode selection cancelled." };
|
|
5536
5707
|
}
|
|
5537
5708
|
await modeStore.setActiveMode(selected.id);
|
|
5709
|
+
ctx?.state?.setMeta?.("mode", selected.id);
|
|
5538
5710
|
return {
|
|
5539
5711
|
message: `Switched to "${selected.name}" mode.
|
|
5540
5712
|
${selected.description}`
|
|
@@ -5554,6 +5726,7 @@ ${selected.description}`
|
|
|
5554
5726
|
return { message: `Unknown mode "${target}". Available: ${available}` };
|
|
5555
5727
|
}
|
|
5556
5728
|
await modeStore.setActiveMode(targetMode.id);
|
|
5729
|
+
ctx?.state?.setMeta?.("mode", targetMode.id);
|
|
5557
5730
|
return {
|
|
5558
5731
|
message: `Switched to "${targetMode.name}" mode.
|
|
5559
5732
|
${targetMode.description}`
|
|
@@ -5561,7 +5734,7 @@ ${targetMode.description}`
|
|
|
5561
5734
|
}
|
|
5562
5735
|
};
|
|
5563
5736
|
}
|
|
5564
|
-
var
|
|
5737
|
+
var noOpVault2 = {
|
|
5565
5738
|
encrypt: (v) => v,
|
|
5566
5739
|
decrypt: (v) => v,
|
|
5567
5740
|
isEncrypted: () => false
|
|
@@ -5584,9 +5757,9 @@ async function patchGlobalConfig(globalConfigPath, mutate) {
|
|
|
5584
5757
|
}
|
|
5585
5758
|
parsed = {};
|
|
5586
5759
|
}
|
|
5587
|
-
const decrypted = decryptConfigSecrets$1(parsed,
|
|
5760
|
+
const decrypted = decryptConfigSecrets$1(parsed, noOpVault2);
|
|
5588
5761
|
mutate(decrypted);
|
|
5589
|
-
const encrypted = encryptConfigSecrets$1(decrypted,
|
|
5762
|
+
const encrypted = encryptConfigSecrets$1(decrypted, noOpVault2);
|
|
5590
5763
|
await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
5591
5764
|
return decrypted;
|
|
5592
5765
|
}
|
|
@@ -6036,7 +6209,7 @@ function summariseEvent(ev) {
|
|
|
6036
6209
|
return color.dim("\u2026");
|
|
6037
6210
|
}
|
|
6038
6211
|
}
|
|
6039
|
-
var
|
|
6212
|
+
var noOpVault3 = {
|
|
6040
6213
|
encrypt: (v) => v,
|
|
6041
6214
|
decrypt: (v) => v,
|
|
6042
6215
|
isEncrypted: () => false
|
|
@@ -6088,9 +6261,9 @@ async function patchGlobalConfig2(globalConfigPath, mutate) {
|
|
|
6088
6261
|
throw new Error(`Config at ${globalConfigPath} is not valid JSON: ${err.message}`);
|
|
6089
6262
|
parsed = {};
|
|
6090
6263
|
}
|
|
6091
|
-
const decrypted = decryptConfigSecrets$1(parsed,
|
|
6264
|
+
const decrypted = decryptConfigSecrets$1(parsed, noOpVault3);
|
|
6092
6265
|
mutate(decrypted);
|
|
6093
|
-
const encrypted = encryptConfigSecrets$1(decrypted,
|
|
6266
|
+
const encrypted = encryptConfigSecrets$1(decrypted, noOpVault3);
|
|
6094
6267
|
await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
6095
6268
|
return decrypted;
|
|
6096
6269
|
}
|
|
@@ -6250,38 +6423,7 @@ function buildSetModelCommand(opts) {
|
|
|
6250
6423
|
}
|
|
6251
6424
|
};
|
|
6252
6425
|
}
|
|
6253
|
-
|
|
6254
|
-
let raw;
|
|
6255
|
-
let fileExists = true;
|
|
6256
|
-
try {
|
|
6257
|
-
raw = await fsp4.readFile(deps.globalConfigPath, "utf8");
|
|
6258
|
-
} catch (err) {
|
|
6259
|
-
if (err.code !== "ENOENT") {
|
|
6260
|
-
throw new Error(`Could not read ${deps.globalConfigPath}: ${err.message}`);
|
|
6261
|
-
}
|
|
6262
|
-
fileExists = false;
|
|
6263
|
-
raw = "{}";
|
|
6264
|
-
}
|
|
6265
|
-
let parsed;
|
|
6266
|
-
try {
|
|
6267
|
-
parsed = JSON.parse(raw);
|
|
6268
|
-
} catch (err) {
|
|
6269
|
-
if (fileExists) {
|
|
6270
|
-
throw new Error(`Config at ${deps.globalConfigPath} is not valid JSON: ${err.message}`);
|
|
6271
|
-
}
|
|
6272
|
-
parsed = {};
|
|
6273
|
-
}
|
|
6274
|
-
const decrypted = decryptConfigSecrets$1(parsed, deps.vault);
|
|
6275
|
-
const autonomy = decrypted.autonomy ?? {};
|
|
6276
|
-
mutator(autonomy);
|
|
6277
|
-
decrypted.autonomy = autonomy;
|
|
6278
|
-
const encrypted = encryptConfigSecrets$1(decrypted, deps.vault);
|
|
6279
|
-
await atomicWrite(deps.globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
6280
|
-
deps.configStore.update({ autonomy: decrypted.autonomy });
|
|
6281
|
-
}
|
|
6282
|
-
|
|
6283
|
-
// src/slash-commands/settings.ts
|
|
6284
|
-
var noOpVault3 = {
|
|
6426
|
+
var noOpVault4 = {
|
|
6285
6427
|
encrypt: (v) => v,
|
|
6286
6428
|
decrypt: (v) => v,
|
|
6287
6429
|
isEncrypted: () => false
|
|
@@ -6346,7 +6488,7 @@ function buildSettingsCommand(opts) {
|
|
|
6346
6488
|
const persistDeps = {
|
|
6347
6489
|
configStore: opts.configStore,
|
|
6348
6490
|
globalConfigPath: opts.paths.globalConfig,
|
|
6349
|
-
vault:
|
|
6491
|
+
vault: noOpVault4
|
|
6350
6492
|
};
|
|
6351
6493
|
try {
|
|
6352
6494
|
if (sub === "delay") {
|
|
@@ -6390,6 +6532,157 @@ function buildSettingsCommand(opts) {
|
|
|
6390
6532
|
}
|
|
6391
6533
|
};
|
|
6392
6534
|
}
|
|
6535
|
+
var noOpVault5 = {
|
|
6536
|
+
encrypt: (v) => v,
|
|
6537
|
+
decrypt: (v) => v,
|
|
6538
|
+
isEncrypted: () => false
|
|
6539
|
+
};
|
|
6540
|
+
var HELP = [
|
|
6541
|
+
"Usage:",
|
|
6542
|
+
" /telegram-setup Show setup instructions",
|
|
6543
|
+
" /telegram-setup <botToken> Validate and save bot token",
|
|
6544
|
+
" /telegram-setup <botToken> <chatId> Save token and default chat ID",
|
|
6545
|
+
"",
|
|
6546
|
+
"Aliases: /tg-setup",
|
|
6547
|
+
"",
|
|
6548
|
+
"Quick start:",
|
|
6549
|
+
" 1. Message @BotFather on Telegram \u2192 /newbot \u2192 copy the token",
|
|
6550
|
+
" 2. Message your new bot, then visit:",
|
|
6551
|
+
" https://api.telegram.org/bot<TOKEN>/getUpdates",
|
|
6552
|
+
" Copy the chat.id from the JSON response.",
|
|
6553
|
+
" 3. Run: /telegram-setup <botToken> <chatId>",
|
|
6554
|
+
" 4. Restart WrongStack to activate the plugin."
|
|
6555
|
+
].join("\n");
|
|
6556
|
+
function buildTelegramSetupCommand(opts) {
|
|
6557
|
+
return {
|
|
6558
|
+
name: "telegram-setup",
|
|
6559
|
+
aliases: ["tg-setup"],
|
|
6560
|
+
description: "Configure Telegram bot token and default chat. /telegram-setup <token> [chatId]",
|
|
6561
|
+
argsHint: "[botToken] [chatId]",
|
|
6562
|
+
help: HELP,
|
|
6563
|
+
async run(args) {
|
|
6564
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
6565
|
+
const sub = (parts[0] ?? "").toLowerCase();
|
|
6566
|
+
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
6567
|
+
return { message: HELP };
|
|
6568
|
+
}
|
|
6569
|
+
if (!sub) {
|
|
6570
|
+
const config = opts.configStore.get();
|
|
6571
|
+
const hasTelegram = (config.plugins ?? []).some((p) => {
|
|
6572
|
+
const name = typeof p === "string" ? p : p.name;
|
|
6573
|
+
return name === "@wrongstack/telegram" || name === "telegram";
|
|
6574
|
+
});
|
|
6575
|
+
const lines = [
|
|
6576
|
+
`${color.bold("Telegram Setup")}`,
|
|
6577
|
+
""
|
|
6578
|
+
];
|
|
6579
|
+
if (!hasTelegram) {
|
|
6580
|
+
lines.push(
|
|
6581
|
+
`${color.amber("\u26A0")} Telegram plugin is not installed.`,
|
|
6582
|
+
` Run: ${color.cyan("/plugin install telegram")}`,
|
|
6583
|
+
` Then run ${color.cyan("/telegram-setup <botToken>")} to configure it.`,
|
|
6584
|
+
""
|
|
6585
|
+
);
|
|
6586
|
+
}
|
|
6587
|
+
lines.push(
|
|
6588
|
+
"1. Create a bot: message @BotFather \u2192 /newbot \u2192 copy the token",
|
|
6589
|
+
"2. Get your chat ID: message your bot, then open in browser:",
|
|
6590
|
+
` ${color.dim("https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates")}`,
|
|
6591
|
+
" Find chat.id in the JSON response.",
|
|
6592
|
+
"3. Configure: /telegram-setup <botToken> <chatId>",
|
|
6593
|
+
"4. Restart WrongStack."
|
|
6594
|
+
);
|
|
6595
|
+
return { message: lines.join("\n") };
|
|
6596
|
+
}
|
|
6597
|
+
const botToken = parts[0];
|
|
6598
|
+
const chatId = parts[1];
|
|
6599
|
+
if (!/^\d+:[A-Za-z0-9_-]+$/.test(botToken)) {
|
|
6600
|
+
return {
|
|
6601
|
+
message: [
|
|
6602
|
+
`${color.red("\u2717")} Invalid token format.`,
|
|
6603
|
+
`Expected: ${color.dim("123456789:ABCdefGHIjkl...")}`,
|
|
6604
|
+
`Got: ${botToken.slice(0, 20)}...`,
|
|
6605
|
+
"",
|
|
6606
|
+
"Get a valid token from @BotFather on Telegram."
|
|
6607
|
+
].join("\n")
|
|
6608
|
+
};
|
|
6609
|
+
}
|
|
6610
|
+
let botInfo;
|
|
6611
|
+
try {
|
|
6612
|
+
const res = await fetch(`https://api.telegram.org/bot${botToken}/getMe`, {
|
|
6613
|
+
signal: AbortSignal.timeout(1e4)
|
|
6614
|
+
});
|
|
6615
|
+
botInfo = await res.json();
|
|
6616
|
+
} catch (err) {
|
|
6617
|
+
return {
|
|
6618
|
+
message: [
|
|
6619
|
+
`${color.red("\u2717")} Could not reach Telegram API.`,
|
|
6620
|
+
`Error: ${err.message}`,
|
|
6621
|
+
"",
|
|
6622
|
+
"Check your network connection and try again."
|
|
6623
|
+
].join("\n")
|
|
6624
|
+
};
|
|
6625
|
+
}
|
|
6626
|
+
if (!botInfo.ok || !botInfo.result) {
|
|
6627
|
+
return {
|
|
6628
|
+
message: [
|
|
6629
|
+
`${color.red("\u2717")} Invalid bot token.`,
|
|
6630
|
+
`Telegram says: ${botInfo.description ?? "Unknown error"}`,
|
|
6631
|
+
"",
|
|
6632
|
+
"Get a valid token from @BotFather on Telegram."
|
|
6633
|
+
].join("\n")
|
|
6634
|
+
};
|
|
6635
|
+
}
|
|
6636
|
+
const bot = botInfo.result;
|
|
6637
|
+
const persistDeps = {
|
|
6638
|
+
configStore: opts.configStore,
|
|
6639
|
+
globalConfigPath: opts.paths?.globalConfig ?? "",
|
|
6640
|
+
vault: noOpVault5
|
|
6641
|
+
};
|
|
6642
|
+
if (!persistDeps.globalConfigPath) {
|
|
6643
|
+
return {
|
|
6644
|
+
message: `${color.red("\u2717")} Config path not available. Cannot persist settings.`
|
|
6645
|
+
};
|
|
6646
|
+
}
|
|
6647
|
+
try {
|
|
6648
|
+
await persistTelegramConfig(persistDeps, (telegram) => {
|
|
6649
|
+
telegram.botToken = botToken;
|
|
6650
|
+
if (chatId) {
|
|
6651
|
+
telegram.notifyChatId = /^\d+$/.test(chatId) ? Number(chatId) : chatId;
|
|
6652
|
+
}
|
|
6653
|
+
if (telegram.notifyOnSessionEnd === void 0) {
|
|
6654
|
+
telegram.notifyOnSessionEnd = true;
|
|
6655
|
+
}
|
|
6656
|
+
});
|
|
6657
|
+
const chatLine = chatId ? `
|
|
6658
|
+
Default chat: ${color.green(chatId)}` : `
|
|
6659
|
+
${color.dim("No default chat set. You can add it later: /telegram-setup <token> <chatId>")}`;
|
|
6660
|
+
return {
|
|
6661
|
+
message: [
|
|
6662
|
+
`${color.green("\u2713")} Telegram configured successfully!`,
|
|
6663
|
+
"",
|
|
6664
|
+
`Bot: ${color.bold(`@${bot.username ?? bot.first_name}`)} ${color.dim(`(id=${bot.id})`)}`,
|
|
6665
|
+
`Name: ${bot.first_name}`,
|
|
6666
|
+
chatLine,
|
|
6667
|
+
"",
|
|
6668
|
+
`${color.amber("\u26A0")} Restart WrongStack for the plugin to pick up the new config.`,
|
|
6669
|
+
"",
|
|
6670
|
+
"After restart, try:",
|
|
6671
|
+
` ${color.cyan("/telegram:status")} \u2014 check bot connection`,
|
|
6672
|
+
` ${color.cyan("/telegram:send")} \u2014 send a test message`
|
|
6673
|
+
].join("\n")
|
|
6674
|
+
};
|
|
6675
|
+
} catch (err) {
|
|
6676
|
+
return {
|
|
6677
|
+
message: [
|
|
6678
|
+
`${color.red("\u2717")} Failed to save config.`,
|
|
6679
|
+
`Error: ${err.message}`
|
|
6680
|
+
].join("\n")
|
|
6681
|
+
};
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
};
|
|
6685
|
+
}
|
|
6393
6686
|
|
|
6394
6687
|
// src/slash-commands/spawn-agents.ts
|
|
6395
6688
|
function buildSpawnCommand(opts) {
|
|
@@ -6573,10 +6866,24 @@ function buildStatuslineCommand(deps) {
|
|
|
6573
6866
|
}
|
|
6574
6867
|
};
|
|
6575
6868
|
}
|
|
6869
|
+
function findTodo(todos, query) {
|
|
6870
|
+
const asIndex = Number.parseInt(query, 10);
|
|
6871
|
+
if (!Number.isNaN(asIndex)) {
|
|
6872
|
+
const idx = asIndex - 1;
|
|
6873
|
+
const item = todos[idx];
|
|
6874
|
+
if (item) return { idx, item };
|
|
6875
|
+
}
|
|
6876
|
+
const byId = todos.findIndex((t) => t.id === query);
|
|
6877
|
+
if (byId >= 0) return { idx: byId, item: todos[byId] };
|
|
6878
|
+
const q = query.toLowerCase();
|
|
6879
|
+
const byContent = todos.findIndex((t) => t.content.toLowerCase().includes(q));
|
|
6880
|
+
if (byContent >= 0) return { idx: byContent, item: todos[byContent] };
|
|
6881
|
+
return null;
|
|
6882
|
+
}
|
|
6576
6883
|
function buildTodosCommand(opts) {
|
|
6577
6884
|
return {
|
|
6578
6885
|
name: "todos",
|
|
6579
|
-
description: "Inspect or edit the live todo list: /todos [show|clear|add
|
|
6886
|
+
description: "Inspect or edit the live todo list: /todos [show|clear|add|done|remove|rm <id|index>]",
|
|
6580
6887
|
async run(args) {
|
|
6581
6888
|
const ctx = opts.context;
|
|
6582
6889
|
if (!ctx) return { message: "No active context." };
|
|
@@ -6590,36 +6897,50 @@ function buildTodosCommand(opts) {
|
|
|
6590
6897
|
}
|
|
6591
6898
|
case "clear": {
|
|
6592
6899
|
const n = ctx.todos.length;
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
};
|
|
6900
|
+
if (n === 0) return { message: "Todos were already empty." };
|
|
6901
|
+
ctx.state.replaceTodos([]);
|
|
6902
|
+
return { message: `Cleared ${n} todo${n === 1 ? "" : "s"}.` };
|
|
6597
6903
|
}
|
|
6598
6904
|
case "add": {
|
|
6599
6905
|
if (!restJoined) return { message: "Usage: /todos add <text>" };
|
|
6600
|
-
|
|
6906
|
+
const item = {
|
|
6601
6907
|
id: `todo_${Date.now()}_${randomUUID().slice(0, 7)}`,
|
|
6602
6908
|
content: restJoined,
|
|
6603
6909
|
status: "pending"
|
|
6604
|
-
}
|
|
6910
|
+
};
|
|
6911
|
+
ctx.state.replaceTodos([...ctx.todos, item]);
|
|
6605
6912
|
return { message: `Added: ${restJoined}` };
|
|
6606
6913
|
}
|
|
6607
6914
|
case "done":
|
|
6608
6915
|
case "complete": {
|
|
6609
6916
|
if (!restJoined) return { message: "Usage: /todos done <id|index>" };
|
|
6610
|
-
const
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6917
|
+
const found = findTodo(ctx.todos, restJoined);
|
|
6918
|
+
if (!found) return { message: `No todo matched "${restJoined}".` };
|
|
6919
|
+
const doneItem = { ...found.item, status: "completed" };
|
|
6920
|
+
const nextTodos = [
|
|
6921
|
+
...ctx.todos.slice(0, found.idx),
|
|
6922
|
+
doneItem,
|
|
6923
|
+
...ctx.todos.slice(found.idx + 1)
|
|
6924
|
+
];
|
|
6925
|
+
ctx.state.replaceTodos(nextTodos);
|
|
6926
|
+
return { message: `Marked done: ${doneItem.content}` };
|
|
6927
|
+
}
|
|
6928
|
+
case "remove":
|
|
6929
|
+
case "rm":
|
|
6930
|
+
case "delete": {
|
|
6931
|
+
if (!restJoined) return { message: "Usage: /todos remove <id|index>" };
|
|
6932
|
+
const found = findTodo(ctx.todos, restJoined);
|
|
6933
|
+
if (!found) return { message: `No todo matched "${restJoined}".` };
|
|
6934
|
+
const nextTodos = [
|
|
6935
|
+
...ctx.todos.slice(0, found.idx),
|
|
6936
|
+
...ctx.todos.slice(found.idx + 1)
|
|
6937
|
+
];
|
|
6938
|
+
ctx.state.replaceTodos(nextTodos);
|
|
6939
|
+
return { message: `Removed: ${found.item.content}` };
|
|
6619
6940
|
}
|
|
6620
6941
|
default:
|
|
6621
6942
|
return {
|
|
6622
|
-
message: `Unknown subcommand "${verb}". Try: show | clear | add <text> | done <id|index>`
|
|
6943
|
+
message: `Unknown subcommand "${verb}". Try: show | clear | add <text> | done <id|index> | remove <id|index>`
|
|
6623
6944
|
};
|
|
6624
6945
|
}
|
|
6625
6946
|
}
|
|
@@ -6744,6 +7065,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6744
7065
|
buildClearCommand(opts),
|
|
6745
7066
|
buildCompactCommand(opts),
|
|
6746
7067
|
buildContextCommand(opts),
|
|
7068
|
+
buildCodebaseReindexCommand(opts),
|
|
6747
7069
|
buildToolsCommand(opts),
|
|
6748
7070
|
buildPluginCommand(opts),
|
|
6749
7071
|
buildMcpSlashCommand(opts),
|
|
@@ -6753,6 +7075,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6753
7075
|
buildAgentsCommand(opts),
|
|
6754
7076
|
buildDirectorCommand(opts),
|
|
6755
7077
|
buildFleetCommand(opts),
|
|
7078
|
+
buildEnhanceCommand(opts),
|
|
6756
7079
|
buildMemoryCommand(opts),
|
|
6757
7080
|
buildTodosCommand(opts),
|
|
6758
7081
|
buildSddCommand(opts),
|
|
@@ -6769,6 +7092,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
6769
7092
|
buildAutoPhaseCommand(opts),
|
|
6770
7093
|
buildWorktreeCommand(opts),
|
|
6771
7094
|
buildSettingsCommand(opts),
|
|
7095
|
+
buildTelegramSetupCommand(opts),
|
|
6772
7096
|
buildSetModelCommand(opts),
|
|
6773
7097
|
buildModelsCommand(opts),
|
|
6774
7098
|
buildCollabCommand(opts),
|
|
@@ -6822,7 +7146,7 @@ async function scaffoldAgentsMd(projectRoot) {
|
|
|
6822
7146
|
return file;
|
|
6823
7147
|
}
|
|
6824
7148
|
async function runProjectCheck(opts) {
|
|
6825
|
-
const { projectRoot, renderer, reader } = opts;
|
|
7149
|
+
const { projectRoot, cwd, renderer, reader } = opts;
|
|
6826
7150
|
const kind = await detectProjectKind(projectRoot);
|
|
6827
7151
|
if (kind === "initialized") {
|
|
6828
7152
|
renderer.write(
|
|
@@ -6881,10 +7205,10 @@ async function runProjectCheck(opts) {
|
|
|
6881
7205
|
if (answer2 === "y" || answer2 === "yes") {
|
|
6882
7206
|
try {
|
|
6883
7207
|
const { spawn: spawn3 } = await import('child_process');
|
|
6884
|
-
await new Promise((
|
|
6885
|
-
const child = spawn3("git", ["init"], { cwd
|
|
7208
|
+
await new Promise((resolve5, reject) => {
|
|
7209
|
+
const child = spawn3("git", ["init"], { cwd });
|
|
6886
7210
|
child.on("error", reject);
|
|
6887
|
-
child.on("close", (code) => code === 0 ?
|
|
7211
|
+
child.on("close", (code) => code === 0 ? resolve5() : reject(new Error(`git init failed with ${code}`)));
|
|
6888
7212
|
});
|
|
6889
7213
|
renderer.write(` ${color.green("\u2713")} Git repository initialized
|
|
6890
7214
|
`);
|
|
@@ -6915,7 +7239,43 @@ var LaunchAbortedError = class extends Error {
|
|
|
6915
7239
|
}
|
|
6916
7240
|
};
|
|
6917
7241
|
async function runLaunchPrompts(opts) {
|
|
6918
|
-
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned } = opts;
|
|
7242
|
+
const { renderer, reader, modePinned, yoloPinned, directorPinned, autonomyPinned, lastChoices } = opts;
|
|
7243
|
+
if (modePinned !== void 0 && yoloPinned !== void 0 && directorPinned !== void 0 && autonomyPinned !== void 0) {
|
|
7244
|
+
return { mode: modePinned, yolo: yoloPinned, director: directorPinned, autonomy: autonomyPinned };
|
|
7245
|
+
}
|
|
7246
|
+
if (lastChoices) {
|
|
7247
|
+
const effective = {
|
|
7248
|
+
mode: modePinned ?? lastChoices.mode,
|
|
7249
|
+
yolo: yoloPinned ?? lastChoices.yolo,
|
|
7250
|
+
director: directorPinned ?? lastChoices.director,
|
|
7251
|
+
autonomy: autonomyPinned ?? lastChoices.autonomy
|
|
7252
|
+
};
|
|
7253
|
+
const onOff = (v) => v ? color.green("on") : color.dim("off");
|
|
7254
|
+
const modeLabel = effective.mode.toUpperCase();
|
|
7255
|
+
renderer.write(
|
|
7256
|
+
`
|
|
7257
|
+
${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")}
|
|
7258
|
+
`
|
|
7259
|
+
);
|
|
7260
|
+
const answer = (await reader.readLine(
|
|
7261
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
7262
|
+
)).trim().toLowerCase();
|
|
7263
|
+
if (answer === "q") {
|
|
7264
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
7265
|
+
throw new LaunchAbortedError();
|
|
7266
|
+
}
|
|
7267
|
+
if (answer !== "n" && answer !== "no") {
|
|
7268
|
+
const badges2 = buildBadges(effective);
|
|
7269
|
+
const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
|
|
7270
|
+
renderer.write(
|
|
7271
|
+
`
|
|
7272
|
+
${color.green("\u25B6")} Launching in ${color.bold(modeLabel)} mode${badgeStr2}
|
|
7273
|
+
|
|
7274
|
+
`
|
|
7275
|
+
);
|
|
7276
|
+
return effective;
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
6919
7279
|
let mode;
|
|
6920
7280
|
if (modePinned) {
|
|
6921
7281
|
mode = modePinned;
|
|
@@ -6969,10 +7329,7 @@ async function runLaunchPrompts(opts) {
|
|
|
6969
7329
|
}
|
|
6970
7330
|
autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
|
|
6971
7331
|
}
|
|
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()}`));
|
|
7332
|
+
const badges = buildBadges({ yolo, director, autonomy });
|
|
6976
7333
|
const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
|
|
6977
7334
|
renderer.write(
|
|
6978
7335
|
`
|
|
@@ -6982,6 +7339,28 @@ async function runLaunchPrompts(opts) {
|
|
|
6982
7339
|
);
|
|
6983
7340
|
return { mode, yolo, director, autonomy };
|
|
6984
7341
|
}
|
|
7342
|
+
function buildBadges(chosen) {
|
|
7343
|
+
const badges = [];
|
|
7344
|
+
if (chosen.yolo) badges.push(color.yellow("YOLO"));
|
|
7345
|
+
if (chosen.director) badges.push(color.cyan("DIRECTOR"));
|
|
7346
|
+
if (chosen.autonomy !== "off") badges.push(color.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
|
|
7347
|
+
return badges;
|
|
7348
|
+
}
|
|
7349
|
+
async function persistLaunchChoices(configPath2, choices) {
|
|
7350
|
+
let existing = {};
|
|
7351
|
+
try {
|
|
7352
|
+
const raw = await fsp4.readFile(configPath2, "utf8");
|
|
7353
|
+
existing = JSON.parse(raw);
|
|
7354
|
+
} catch {
|
|
7355
|
+
}
|
|
7356
|
+
existing.yolo = choices.yolo;
|
|
7357
|
+
existing.launch = {
|
|
7358
|
+
mode: choices.mode,
|
|
7359
|
+
director: choices.director,
|
|
7360
|
+
autonomy: choices.autonomy
|
|
7361
|
+
};
|
|
7362
|
+
await atomicWrite(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7363
|
+
}
|
|
6985
7364
|
async function bootConfig(flags) {
|
|
6986
7365
|
const opts = { flags, appLabel: "wstack" };
|
|
6987
7366
|
const { cwd, projectRoot, userHome, wpaths, pathResolver, config, vault } = await bootConfig$1(opts);
|
|
@@ -7028,32 +7407,32 @@ var ReadlineInputReader = class {
|
|
|
7028
7407
|
async readLine(prompt) {
|
|
7029
7408
|
if (this.history.length === 0) await this.loadHistory();
|
|
7030
7409
|
while (this.pending) {
|
|
7031
|
-
await new Promise((
|
|
7410
|
+
await new Promise((resolve5) => setTimeout(resolve5, 50));
|
|
7032
7411
|
}
|
|
7033
7412
|
this.pending = true;
|
|
7034
7413
|
try {
|
|
7035
7414
|
if (this.rl) {
|
|
7036
7415
|
const old = this.rl;
|
|
7037
7416
|
this.rl = void 0;
|
|
7038
|
-
await new Promise((
|
|
7417
|
+
await new Promise((resolve5) => {
|
|
7039
7418
|
if (old.closed) {
|
|
7040
|
-
|
|
7419
|
+
resolve5();
|
|
7041
7420
|
} else {
|
|
7042
|
-
old.once("close",
|
|
7421
|
+
old.once("close", resolve5);
|
|
7043
7422
|
old.close();
|
|
7044
7423
|
}
|
|
7045
7424
|
});
|
|
7046
7425
|
}
|
|
7047
7426
|
const fresh = this.ensure();
|
|
7048
|
-
return new Promise((
|
|
7427
|
+
return new Promise((resolve5) => {
|
|
7049
7428
|
fresh.question(prompt ?? "> ", (line) => {
|
|
7050
7429
|
if (line.trim()) {
|
|
7051
7430
|
this.history.push(line);
|
|
7052
7431
|
void this.saveHistory();
|
|
7053
7432
|
}
|
|
7054
|
-
|
|
7433
|
+
resolve5(line);
|
|
7055
7434
|
});
|
|
7056
|
-
fresh.once("close", () =>
|
|
7435
|
+
fresh.once("close", () => resolve5(""));
|
|
7057
7436
|
}).then((result) => {
|
|
7058
7437
|
this.rl?.close();
|
|
7059
7438
|
return result;
|
|
@@ -7064,7 +7443,7 @@ var ReadlineInputReader = class {
|
|
|
7064
7443
|
}
|
|
7065
7444
|
async readKey(prompt, options) {
|
|
7066
7445
|
writeOut(prompt);
|
|
7067
|
-
return new Promise((
|
|
7446
|
+
return new Promise((resolve5) => {
|
|
7068
7447
|
const stdin = process.stdin;
|
|
7069
7448
|
const wasRaw = stdin.isRaw;
|
|
7070
7449
|
const wasPaused = stdin.isPaused();
|
|
@@ -7075,7 +7454,7 @@ var ReadlineInputReader = class {
|
|
|
7075
7454
|
if (key === "") {
|
|
7076
7455
|
cleanup();
|
|
7077
7456
|
writeOut("\n");
|
|
7078
|
-
|
|
7457
|
+
resolve5("");
|
|
7079
7458
|
return;
|
|
7080
7459
|
}
|
|
7081
7460
|
const opt = options.find(
|
|
@@ -7085,12 +7464,12 @@ var ReadlineInputReader = class {
|
|
|
7085
7464
|
cleanup();
|
|
7086
7465
|
writeOut(`${opt.key}
|
|
7087
7466
|
`);
|
|
7088
|
-
|
|
7467
|
+
resolve5(opt.value);
|
|
7089
7468
|
}
|
|
7090
7469
|
};
|
|
7091
7470
|
const onClose = () => {
|
|
7092
7471
|
cleanup();
|
|
7093
|
-
|
|
7472
|
+
resolve5("");
|
|
7094
7473
|
};
|
|
7095
7474
|
const cleanup = () => {
|
|
7096
7475
|
stdin.off("data", onData);
|
|
@@ -7118,7 +7497,7 @@ var ReadlineInputReader = class {
|
|
|
7118
7497
|
this.rl?.close();
|
|
7119
7498
|
this.rl = void 0;
|
|
7120
7499
|
writeOut(prompt);
|
|
7121
|
-
return new Promise((
|
|
7500
|
+
return new Promise((resolve5) => {
|
|
7122
7501
|
let buf = "";
|
|
7123
7502
|
const wasRaw = stdin.isRaw;
|
|
7124
7503
|
setRawMode(stdin, true);
|
|
@@ -7136,7 +7515,7 @@ var ReadlineInputReader = class {
|
|
|
7136
7515
|
cleanup();
|
|
7137
7516
|
writeOut(` ${dim(`[${buf.length} chars]`)}
|
|
7138
7517
|
`);
|
|
7139
|
-
|
|
7518
|
+
resolve5(buf);
|
|
7140
7519
|
return;
|
|
7141
7520
|
}
|
|
7142
7521
|
if (ch === "") {
|
|
@@ -7496,21 +7875,25 @@ async function restoreLast(homeFn = defaultHomeDir) {
|
|
|
7496
7875
|
|
|
7497
7876
|
// src/picker.ts
|
|
7498
7877
|
var theme = { primary: color.amber };
|
|
7499
|
-
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ??
|
|
7878
|
+
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os2__default.homedir()) {
|
|
7500
7879
|
try {
|
|
7501
|
-
const { atomicWrite:
|
|
7502
|
-
const
|
|
7880
|
+
const { atomicWrite: atomicWrite15 } = await import('@wrongstack/core');
|
|
7881
|
+
const fs27 = await import('fs/promises');
|
|
7503
7882
|
let existing = {};
|
|
7504
7883
|
try {
|
|
7505
|
-
const raw = await
|
|
7884
|
+
const raw = await fs27.readFile(configPath2, "utf8");
|
|
7506
7885
|
existing = JSON.parse(raw);
|
|
7507
7886
|
} catch {
|
|
7508
7887
|
}
|
|
7509
7888
|
const oldCfg = { ...existing };
|
|
7510
7889
|
existing.provider = provider;
|
|
7511
7890
|
existing.model = model;
|
|
7512
|
-
|
|
7513
|
-
|
|
7891
|
+
try {
|
|
7892
|
+
await backupCurrent(homeFn);
|
|
7893
|
+
} catch (err) {
|
|
7894
|
+
console.warn("[picker] backupCurrent failed:", err);
|
|
7895
|
+
}
|
|
7896
|
+
await atomicWrite15(configPath2, JSON.stringify(existing, null, 2), { mode: 384 });
|
|
7514
7897
|
try {
|
|
7515
7898
|
await appendHistory(
|
|
7516
7899
|
oldCfg,
|
|
@@ -7521,7 +7904,8 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7521
7904
|
} catch {
|
|
7522
7905
|
}
|
|
7523
7906
|
return true;
|
|
7524
|
-
} catch {
|
|
7907
|
+
} catch (err) {
|
|
7908
|
+
console.warn("[picker] saveToGlobalConfig failed:", err instanceof Error ? err.message : String(err));
|
|
7525
7909
|
return false;
|
|
7526
7910
|
}
|
|
7527
7911
|
}
|
|
@@ -8173,14 +8557,14 @@ function summarize(value, name) {
|
|
|
8173
8557
|
if (typeof v === "object" && v !== null) {
|
|
8174
8558
|
const o = v;
|
|
8175
8559
|
if (name === "edit") {
|
|
8176
|
-
const
|
|
8560
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8177
8561
|
const reps = typeof o["replacements"] === "number" ? o["replacements"] : 0;
|
|
8178
|
-
return `${
|
|
8562
|
+
return `${path26} ${reps} replacement${reps === 1 ? "" : "s"}`.trim();
|
|
8179
8563
|
}
|
|
8180
8564
|
if (name === "write") {
|
|
8181
|
-
const
|
|
8565
|
+
const path26 = typeof o["path"] === "string" ? o["path"] : "";
|
|
8182
8566
|
const bytes = typeof o["bytes"] === "number" ? o["bytes"] : void 0;
|
|
8183
|
-
return bytes !== void 0 ? `${
|
|
8567
|
+
return bytes !== void 0 ? `${path26} ${bytes}B` : path26;
|
|
8184
8568
|
}
|
|
8185
8569
|
if (typeof o["count"] === "number") {
|
|
8186
8570
|
return `${o["count"]} match${o["count"] === 1 ? "" : "es"}`;
|
|
@@ -9040,7 +9424,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9040
9424
|
deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
|
|
9041
9425
|
`);
|
|
9042
9426
|
try {
|
|
9043
|
-
const result = await new Promise((
|
|
9427
|
+
const result = await new Promise((resolve5, reject) => {
|
|
9044
9428
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
9045
9429
|
const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
|
|
9046
9430
|
cwd,
|
|
@@ -9051,7 +9435,7 @@ var updateCmd = async (args, deps) => {
|
|
|
9051
9435
|
_stderr += d;
|
|
9052
9436
|
});
|
|
9053
9437
|
child.on("error", reject);
|
|
9054
|
-
child.on("close", (code) =>
|
|
9438
|
+
child.on("close", (code) => resolve5({ code: code ?? 0 }));
|
|
9055
9439
|
});
|
|
9056
9440
|
if (result.code === 0) {
|
|
9057
9441
|
deps.renderer.write(`
|
|
@@ -9487,8 +9871,8 @@ async function serveMcpStdio(deps) {
|
|
|
9487
9871
|
log(
|
|
9488
9872
|
`wrongstack MCP server ready at ${handle2.url} \u2014 exposing ${allowed.length} tool(s) (${mode})${token ? " [token auth]" : ""}.`
|
|
9489
9873
|
);
|
|
9490
|
-
await new Promise((
|
|
9491
|
-
const stop = () =>
|
|
9874
|
+
await new Promise((resolve5) => {
|
|
9875
|
+
const stop = () => resolve5();
|
|
9492
9876
|
process.once("SIGINT", stop);
|
|
9493
9877
|
process.once("SIGTERM", stop);
|
|
9494
9878
|
});
|
|
@@ -10757,10 +11141,10 @@ var auditCmd = async (args, deps) => {
|
|
|
10757
11141
|
return verify.ok ? 0 : 1;
|
|
10758
11142
|
};
|
|
10759
11143
|
async function listAudits(log, dir, deps) {
|
|
10760
|
-
const
|
|
11144
|
+
const fs27 = await import('fs/promises');
|
|
10761
11145
|
let entries;
|
|
10762
11146
|
try {
|
|
10763
|
-
entries = await
|
|
11147
|
+
entries = await fs27.readdir(dir);
|
|
10764
11148
|
} catch {
|
|
10765
11149
|
deps.renderer.write(
|
|
10766
11150
|
color.dim(`No sessions dir found at ${dir}. Run a session first.`) + "\n"
|
|
@@ -10911,22 +11295,22 @@ function fmtDuration(ms) {
|
|
|
10911
11295
|
const remMin = m - h * 60;
|
|
10912
11296
|
return `${h}h${remMin}m`;
|
|
10913
11297
|
}
|
|
10914
|
-
function fmtTaskResultLine(r,
|
|
11298
|
+
function fmtTaskResultLine(r, color51) {
|
|
10915
11299
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
10916
11300
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
10917
11301
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
10918
11302
|
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}${
|
|
11303
|
+
const errKindChip = errKind ? color51.dim(` [${errKind}]`) : "";
|
|
11304
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color51.dim(errTail)}` : "";
|
|
10921
11305
|
switch (r.status) {
|
|
10922
11306
|
case "success":
|
|
10923
|
-
return { mark:
|
|
11307
|
+
return { mark: color51.green("\u2713"), stats, tail: "" };
|
|
10924
11308
|
case "timeout":
|
|
10925
|
-
return { mark:
|
|
11309
|
+
return { mark: color51.yellow("\u23F1"), stats: `${color51.yellow("timeout")} ${stats}`, tail: errSnip };
|
|
10926
11310
|
case "stopped":
|
|
10927
|
-
return { mark:
|
|
11311
|
+
return { mark: color51.dim("\u2298"), stats: `${color51.dim("stopped")} ${stats}`, tail: errSnip };
|
|
10928
11312
|
case "failed":
|
|
10929
|
-
return { mark:
|
|
11313
|
+
return { mark: color51.red("\u2717"), stats: `${color51.red("failed")} ${stats}`, tail: errSnip };
|
|
10930
11314
|
}
|
|
10931
11315
|
}
|
|
10932
11316
|
|
|
@@ -10970,7 +11354,15 @@ async function boot(argv) {
|
|
|
10970
11354
|
const { paths, config: _config, vault } = bootResult;
|
|
10971
11355
|
let config = _config;
|
|
10972
11356
|
const { cwd, projectRoot, userHome, wpaths, pathResolver } = paths;
|
|
10973
|
-
const logger = new DefaultLogger({
|
|
11357
|
+
const logger = new DefaultLogger({
|
|
11358
|
+
level: config.log.level,
|
|
11359
|
+
file: wpaths.logFile,
|
|
11360
|
+
// Suppress stderr output in TUI mode: plugin/library log messages
|
|
11361
|
+
// (e.g. Telegram "getUpdates failed") write directly to stderr and
|
|
11362
|
+
// bypass Ink, which breaks the Static/live boundary in non-altScreen
|
|
11363
|
+
// mode. Logs still go to the disk file for post-hoc debugging.
|
|
11364
|
+
stderr: !flags.tui
|
|
11365
|
+
});
|
|
10974
11366
|
const renderer = new TerminalRenderer();
|
|
10975
11367
|
const reader = new ReadlineInputReader({ historyFile: wpaths.historyFile });
|
|
10976
11368
|
const modelsRegistry = new DefaultModelsRegistry({
|
|
@@ -11040,7 +11432,7 @@ async function boot(argv) {
|
|
|
11040
11432
|
const isSingleShot = positional.length > 0 || typeof flags["prompt"] === "string";
|
|
11041
11433
|
const isInteractiveTTY = isStdinTTY() && !isSingleShot;
|
|
11042
11434
|
if (isInteractiveTTY) {
|
|
11043
|
-
const cont = await runProjectCheck({ projectRoot, renderer, reader });
|
|
11435
|
+
const cont = await runProjectCheck({ projectRoot, cwd, renderer, reader });
|
|
11044
11436
|
if (!cont) {
|
|
11045
11437
|
await reader.close();
|
|
11046
11438
|
return 0;
|
|
@@ -11050,20 +11442,51 @@ async function boot(argv) {
|
|
|
11050
11442
|
const modelFlag = typeof flags["model"] === "string" ? flags["model"] : void 0;
|
|
11051
11443
|
if (!(!!providerFlag && !!modelFlag)) {
|
|
11052
11444
|
if (isStdinTTY()) {
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11445
|
+
let picked;
|
|
11446
|
+
let skipPicker = false;
|
|
11447
|
+
const savedProvider = config.provider;
|
|
11448
|
+
const savedModel = config.model;
|
|
11449
|
+
if (savedProvider && savedModel) {
|
|
11450
|
+
renderer.write(
|
|
11451
|
+
`
|
|
11452
|
+
${color.dim("Last settings:")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11453
|
+
`
|
|
11454
|
+
);
|
|
11455
|
+
const answer = (await reader.readLine(
|
|
11456
|
+
` ${color.amber("?")} Continue with these? ${color.dim("[Y/n/q]")} `
|
|
11457
|
+
)).trim().toLowerCase();
|
|
11458
|
+
if (answer === "q") {
|
|
11459
|
+
renderer.write(color.dim(" Goodbye!\n"));
|
|
11460
|
+
await reader.close();
|
|
11461
|
+
return 0;
|
|
11462
|
+
}
|
|
11463
|
+
if (answer !== "n" && answer !== "no") {
|
|
11464
|
+
skipPicker = true;
|
|
11465
|
+
renderer.write(
|
|
11466
|
+
`
|
|
11467
|
+
${color.green("\u25B6")} ${color.bold(savedProvider)} / ${color.bold(savedModel)}
|
|
11468
|
+
|
|
11469
|
+
`
|
|
11470
|
+
);
|
|
11471
|
+
}
|
|
11472
|
+
}
|
|
11473
|
+
if (!skipPicker) {
|
|
11474
|
+
picked = await runPicker({
|
|
11475
|
+
modelsRegistry,
|
|
11476
|
+
renderer,
|
|
11477
|
+
reader,
|
|
11478
|
+
config,
|
|
11479
|
+
defaultProvider: providerFlag ?? config.provider,
|
|
11480
|
+
defaultModel: modelFlag ?? config.model
|
|
11481
|
+
});
|
|
11482
|
+
}
|
|
11483
|
+
if (!picked && !skipPicker) {
|
|
11062
11484
|
if (!config.provider || !config.model) {
|
|
11063
11485
|
await reader.close();
|
|
11064
11486
|
return 2;
|
|
11065
11487
|
}
|
|
11066
|
-
}
|
|
11488
|
+
}
|
|
11489
|
+
if (picked) {
|
|
11067
11490
|
const prevProvider = config.provider;
|
|
11068
11491
|
const prevModel = config.model;
|
|
11069
11492
|
config = patchConfig(config, { provider: picked.provider, model: picked.model });
|
|
@@ -11073,8 +11496,15 @@ async function boot(argv) {
|
|
|
11073
11496
|
picked.provider,
|
|
11074
11497
|
picked.model
|
|
11075
11498
|
);
|
|
11076
|
-
if (saved)
|
|
11499
|
+
if (saved) {
|
|
11500
|
+
renderer.writeInfo(`Saved ${picked.provider}/${picked.model} as default.
|
|
11077
11501
|
`);
|
|
11502
|
+
} else {
|
|
11503
|
+
renderer.writeWarning(
|
|
11504
|
+
`Could not save ${picked.provider}/${picked.model} to config. Check permissions or disk space.
|
|
11505
|
+
`
|
|
11506
|
+
);
|
|
11507
|
+
}
|
|
11078
11508
|
}
|
|
11079
11509
|
}
|
|
11080
11510
|
} else if (!config.provider || !config.model) {
|
|
@@ -11107,6 +11537,12 @@ async function boot(argv) {
|
|
|
11107
11537
|
} else if (flags["autonomy"] === true) {
|
|
11108
11538
|
autonomyPinned = "auto";
|
|
11109
11539
|
}
|
|
11540
|
+
const lastChoices = config.launch ? {
|
|
11541
|
+
mode: config.launch.mode ?? "tui",
|
|
11542
|
+
yolo: config.yolo ?? true,
|
|
11543
|
+
director: config.launch.director ?? true,
|
|
11544
|
+
autonomy: config.launch.autonomy ?? "auto"
|
|
11545
|
+
} : void 0;
|
|
11110
11546
|
let choices;
|
|
11111
11547
|
try {
|
|
11112
11548
|
choices = await runLaunchPrompts({
|
|
@@ -11115,7 +11551,8 @@ async function boot(argv) {
|
|
|
11115
11551
|
modePinned,
|
|
11116
11552
|
yoloPinned,
|
|
11117
11553
|
directorPinned,
|
|
11118
|
-
autonomyPinned
|
|
11554
|
+
autonomyPinned,
|
|
11555
|
+
lastChoices
|
|
11119
11556
|
});
|
|
11120
11557
|
} catch (err) {
|
|
11121
11558
|
if (err instanceof LaunchAbortedError) {
|
|
@@ -11134,6 +11571,10 @@ async function boot(argv) {
|
|
|
11134
11571
|
if (choices.yolo !== config.yolo) config = patchConfig(config, { yolo: choices.yolo });
|
|
11135
11572
|
if (choices.director) flags["director"] = true;
|
|
11136
11573
|
flags["autonomy"] = choices.autonomy;
|
|
11574
|
+
try {
|
|
11575
|
+
await persistLaunchChoices(wpaths.globalConfig, choices);
|
|
11576
|
+
} catch {
|
|
11577
|
+
}
|
|
11137
11578
|
printLaunchHints(renderer, flags, {
|
|
11138
11579
|
cursorFile: path8.join(wpaths.cacheDir, "hint-cursor")
|
|
11139
11580
|
});
|
|
@@ -11527,7 +11968,7 @@ async function runRepl(opts) {
|
|
|
11527
11968
|
`[eternal] ${err instanceof Error ? err.message : String(err)}`
|
|
11528
11969
|
);
|
|
11529
11970
|
}
|
|
11530
|
-
await new Promise((
|
|
11971
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11531
11972
|
continue;
|
|
11532
11973
|
}
|
|
11533
11974
|
} else if (opts.getAutonomy?.() === "eternal-parallel") {
|
|
@@ -11573,7 +12014,7 @@ async function runRepl(opts) {
|
|
|
11573
12014
|
`[parallel] ${err instanceof Error ? err.message : String(err)}`
|
|
11574
12015
|
);
|
|
11575
12016
|
}
|
|
11576
|
-
await new Promise((
|
|
12017
|
+
await new Promise((resolve5) => setTimeout(resolve5, 250));
|
|
11577
12018
|
continue;
|
|
11578
12019
|
}
|
|
11579
12020
|
}
|
|
@@ -12106,6 +12547,7 @@ async function execute(deps) {
|
|
|
12106
12547
|
director,
|
|
12107
12548
|
fleetRoster,
|
|
12108
12549
|
fleetStreamController,
|
|
12550
|
+
enhanceController,
|
|
12109
12551
|
statuslineHiddenItems,
|
|
12110
12552
|
setStatuslineHiddenItems,
|
|
12111
12553
|
agentsMonitorController,
|
|
@@ -12117,7 +12559,8 @@ async function execute(deps) {
|
|
|
12117
12559
|
getParallelEngine,
|
|
12118
12560
|
subscribeEternalIteration,
|
|
12119
12561
|
subscribeEternalStage,
|
|
12120
|
-
skillLoader
|
|
12562
|
+
skillLoader,
|
|
12563
|
+
modeId
|
|
12121
12564
|
} = deps;
|
|
12122
12565
|
let code = 0;
|
|
12123
12566
|
let fleetStatusLine = null;
|
|
@@ -12316,10 +12759,31 @@ async function execute(deps) {
|
|
|
12316
12759
|
return null;
|
|
12317
12760
|
},
|
|
12318
12761
|
getSettings: () => {
|
|
12319
|
-
const
|
|
12762
|
+
const cfg = configStore.get();
|
|
12763
|
+
const autonomy = cfg.autonomy;
|
|
12320
12764
|
const rawMode = autonomy?.defaultMode;
|
|
12321
12765
|
const mode = rawMode === "suggest" || rawMode === "auto" ? rawMode : "off";
|
|
12322
|
-
return {
|
|
12766
|
+
return {
|
|
12767
|
+
mode,
|
|
12768
|
+
delayMs: autonomy?.autoProceedDelayMs ?? 45e3,
|
|
12769
|
+
titleAnimation: autonomy?.terminalTitleAnimation !== false,
|
|
12770
|
+
yolo: autonomy?.yolo ?? false,
|
|
12771
|
+
streamFleet: autonomy?.streamFleet !== false,
|
|
12772
|
+
chime: autonomy?.chime ?? false,
|
|
12773
|
+
confirmExit: autonomy?.confirmExit !== false,
|
|
12774
|
+
nextPrediction: cfg.nextPrediction ?? false,
|
|
12775
|
+
featureMcp: cfg.features?.mcp !== false,
|
|
12776
|
+
featurePlugins: cfg.features?.plugins !== false,
|
|
12777
|
+
featureMemory: cfg.features?.memory !== false,
|
|
12778
|
+
featureSkills: cfg.features?.skills !== false,
|
|
12779
|
+
featureModelsRegistry: cfg.features?.modelsRegistry !== false,
|
|
12780
|
+
contextAutoCompact: cfg.context?.autoCompact !== false,
|
|
12781
|
+
contextStrategy: cfg.context?.strategy ?? "hybrid",
|
|
12782
|
+
logLevel: cfg.log?.level ?? "info",
|
|
12783
|
+
auditLevel: cfg.session?.auditLevel ?? "standard",
|
|
12784
|
+
indexOnStart: cfg.indexing?.onSessionStart !== false,
|
|
12785
|
+
maxIterations: cfg.tools?.maxIterations ?? 500
|
|
12786
|
+
};
|
|
12323
12787
|
},
|
|
12324
12788
|
async saveSettings(s) {
|
|
12325
12789
|
try {
|
|
@@ -12332,24 +12796,89 @@ async function execute(deps) {
|
|
|
12332
12796
|
(autonomy) => {
|
|
12333
12797
|
autonomy.defaultMode = s.mode;
|
|
12334
12798
|
autonomy.autoProceedDelayMs = s.delayMs;
|
|
12799
|
+
const a = autonomy;
|
|
12800
|
+
a["terminalTitleAnimation"] = s.titleAnimation ?? true;
|
|
12801
|
+
a["yolo"] = s.yolo ?? false;
|
|
12802
|
+
a["streamFleet"] = s.streamFleet ?? true;
|
|
12803
|
+
a["chime"] = s.chime ?? false;
|
|
12804
|
+
a["confirmExit"] = s.confirmExit ?? true;
|
|
12335
12805
|
}
|
|
12336
12806
|
);
|
|
12807
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.nextPrediction !== void 0) {
|
|
12808
|
+
const raw = await fsp4.readFile(wpaths.globalConfig, "utf8").catch(() => "{}");
|
|
12809
|
+
const parsed = JSON.parse(raw);
|
|
12810
|
+
const vault = { encrypt: (v) => v, decrypt: (v) => v, isEncrypted: () => false };
|
|
12811
|
+
const decrypted = decryptConfigSecrets$1(parsed, vault);
|
|
12812
|
+
if (s.nextPrediction !== void 0) {
|
|
12813
|
+
decrypted.nextPrediction = s.nextPrediction;
|
|
12814
|
+
}
|
|
12815
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0) {
|
|
12816
|
+
const feats = decrypted.features ?? {};
|
|
12817
|
+
if (s.featureMcp !== void 0) feats.mcp = s.featureMcp;
|
|
12818
|
+
if (s.featurePlugins !== void 0) feats.plugins = s.featurePlugins;
|
|
12819
|
+
if (s.featureMemory !== void 0) feats.memory = s.featureMemory;
|
|
12820
|
+
if (s.featureSkills !== void 0) feats.skills = s.featureSkills;
|
|
12821
|
+
if (s.featureModelsRegistry !== void 0) feats.modelsRegistry = s.featureModelsRegistry;
|
|
12822
|
+
decrypted.features = feats;
|
|
12823
|
+
}
|
|
12824
|
+
if (s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0) {
|
|
12825
|
+
const ctx = decrypted.context ?? {};
|
|
12826
|
+
if (s.contextAutoCompact !== void 0) ctx.autoCompact = s.contextAutoCompact;
|
|
12827
|
+
if (s.contextStrategy !== void 0) ctx.strategy = s.contextStrategy;
|
|
12828
|
+
decrypted.context = ctx;
|
|
12829
|
+
}
|
|
12830
|
+
if (s.logLevel !== void 0) {
|
|
12831
|
+
const log = decrypted.log ?? {};
|
|
12832
|
+
log.level = s.logLevel;
|
|
12833
|
+
decrypted.log = log;
|
|
12834
|
+
}
|
|
12835
|
+
if (s.auditLevel !== void 0) {
|
|
12836
|
+
const sess = decrypted.session ?? {};
|
|
12837
|
+
sess.auditLevel = s.auditLevel;
|
|
12838
|
+
decrypted.session = sess;
|
|
12839
|
+
}
|
|
12840
|
+
if (s.indexOnStart !== void 0) {
|
|
12841
|
+
const idx = decrypted.indexing ?? {};
|
|
12842
|
+
idx.onSessionStart = s.indexOnStart;
|
|
12843
|
+
decrypted.indexing = idx;
|
|
12844
|
+
}
|
|
12845
|
+
if (s.maxIterations !== void 0) {
|
|
12846
|
+
const tools = decrypted.tools ?? {};
|
|
12847
|
+
tools.maxIterations = s.maxIterations;
|
|
12848
|
+
decrypted.tools = tools;
|
|
12849
|
+
}
|
|
12850
|
+
const encrypted = encryptConfigSecrets$1(decrypted, vault);
|
|
12851
|
+
await atomicWrite(wpaths.globalConfig, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
12852
|
+
configStore.update({
|
|
12853
|
+
...s.nextPrediction !== void 0 ? { nextPrediction: s.nextPrediction } : {},
|
|
12854
|
+
...s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 ? { features: decrypted.features } : {},
|
|
12855
|
+
...s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 ? { context: decrypted.context } : {},
|
|
12856
|
+
...s.logLevel !== void 0 ? { log: decrypted.log } : {},
|
|
12857
|
+
...s.auditLevel !== void 0 ? { session: decrypted.session } : {},
|
|
12858
|
+
...s.indexOnStart !== void 0 ? { indexing: decrypted.indexing } : {},
|
|
12859
|
+
...s.maxIterations !== void 0 ? { tools: decrypted.tools } : {}
|
|
12860
|
+
});
|
|
12861
|
+
}
|
|
12862
|
+
if (s.streamFleet !== void 0) {
|
|
12863
|
+
fleetStreamController?.setEnabled(s.streamFleet);
|
|
12864
|
+
}
|
|
12337
12865
|
return null;
|
|
12338
12866
|
} catch (err) {
|
|
12339
12867
|
return err instanceof Error ? err.message : String(err);
|
|
12340
12868
|
}
|
|
12341
12869
|
},
|
|
12342
12870
|
effectiveMaxContext,
|
|
12871
|
+
// Terminal title animation: read from config (default on).
|
|
12872
|
+
titleAnimation: config.autonomy?.["terminalTitleAnimation"] ?? true,
|
|
12873
|
+
// Completion chime: terminal bell when agent finishes.
|
|
12874
|
+
chime: config.autonomy?.["chime"] ?? false,
|
|
12875
|
+
// Confirm before exit: show "confirm exit" prompt on Ctrl+C.
|
|
12876
|
+
confirmExit: config.autonomy?.["confirmExit"] ?? true,
|
|
12343
12877
|
// Default OFF so the terminal's native scrollback works for chat
|
|
12344
|
-
// history out of the box
|
|
12345
|
-
//
|
|
12346
|
-
// `--
|
|
12878
|
+
// history out of the box. Users who hit resize/overlay-leak
|
|
12879
|
+
// artifacts can opt back into alt-screen with `--alt-screen`.
|
|
12880
|
+
// `--no-alt-screen` still wins when both are passed.
|
|
12347
12881
|
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
12882
|
director,
|
|
12354
12883
|
fleetRoster,
|
|
12355
12884
|
onAfterExit: () => {
|
|
@@ -12362,6 +12891,7 @@ async function execute(deps) {
|
|
|
12362
12891
|
dispatch({ type: "resetContextChip" });
|
|
12363
12892
|
},
|
|
12364
12893
|
fleetStreamController,
|
|
12894
|
+
enhanceController,
|
|
12365
12895
|
statuslineHiddenItems,
|
|
12366
12896
|
setStatuslineHiddenItems,
|
|
12367
12897
|
agentsMonitorController,
|
|
@@ -12406,6 +12936,11 @@ async function execute(deps) {
|
|
|
12406
12936
|
}
|
|
12407
12937
|
}
|
|
12408
12938
|
return messages;
|
|
12939
|
+
},
|
|
12940
|
+
modeLabel: modeId,
|
|
12941
|
+
getModeLabel: () => {
|
|
12942
|
+
const metaMode = context.meta?.["mode"];
|
|
12943
|
+
return typeof metaMode === "string" ? metaMode : modeId ?? "default";
|
|
12409
12944
|
}
|
|
12410
12945
|
});
|
|
12411
12946
|
} finally {
|
|
@@ -12712,8 +13247,10 @@ var MultiAgentHost = class {
|
|
|
12712
13247
|
// meaningless to a single delegated subtask.
|
|
12713
13248
|
subagent: true
|
|
12714
13249
|
});
|
|
12715
|
-
|
|
12716
|
-
|
|
13250
|
+
baseSystem.unshift({ type: "text", text: DEFAULT_SUBAGENT_BASELINE });
|
|
13251
|
+
const rolePrompt = subCfg.systemPromptOverride ?? (subCfg.role ? FLEET_ROSTER[subCfg.role]?.prompt : void 0);
|
|
13252
|
+
if (rolePrompt) {
|
|
13253
|
+
baseSystem.push({ type: "text", text: rolePrompt });
|
|
12717
13254
|
}
|
|
12718
13255
|
let subSession;
|
|
12719
13256
|
if (this.sessionFactory) {
|
|
@@ -13243,11 +13780,11 @@ var SessionStats = class {
|
|
|
13243
13780
|
if (e.name === "bash") this.bashCommands++;
|
|
13244
13781
|
else if (e.name === "fetch") this.fetches++;
|
|
13245
13782
|
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(
|
|
13783
|
+
const path26 = typeof input?.path === "string" ? input.path : void 0;
|
|
13784
|
+
if (e.name === "read" && path26) this.readPaths.add(path26);
|
|
13785
|
+
else if (e.name === "edit" && path26) this.editedPaths.add(path26);
|
|
13786
|
+
else if (e.name === "write" && path26) {
|
|
13787
|
+
this.writtenPaths.add(path26);
|
|
13251
13788
|
const content = typeof input?.content === "string" ? input.content : "";
|
|
13252
13789
|
this.bytesWritten += Buffer.byteLength(content, "utf8");
|
|
13253
13790
|
}
|
|
@@ -13353,7 +13890,7 @@ function samplePaths(set) {
|
|
|
13353
13890
|
}
|
|
13354
13891
|
var WORKTREE_PHASE_CONCURRENCY = 4;
|
|
13355
13892
|
function gitText(args, cwd) {
|
|
13356
|
-
return new Promise((
|
|
13893
|
+
return new Promise((resolve5) => {
|
|
13357
13894
|
let out = "";
|
|
13358
13895
|
const child = spawn("git", args, {
|
|
13359
13896
|
cwd,
|
|
@@ -13366,8 +13903,8 @@ function gitText(args, cwd) {
|
|
|
13366
13903
|
child.stderr?.on("data", (c) => {
|
|
13367
13904
|
out += c.toString();
|
|
13368
13905
|
});
|
|
13369
|
-
child.on("error", () =>
|
|
13370
|
-
child.on("close", (code) =>
|
|
13906
|
+
child.on("error", () => resolve5({ code: 1, out }));
|
|
13907
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13371
13908
|
});
|
|
13372
13909
|
}
|
|
13373
13910
|
async function isGitRepo(cwd) {
|
|
@@ -13375,7 +13912,7 @@ async function isGitRepo(cwd) {
|
|
|
13375
13912
|
return code === 0 && out.trim() === "true";
|
|
13376
13913
|
}
|
|
13377
13914
|
function runCmd(cmd, args, cwd, shell = false) {
|
|
13378
|
-
return new Promise((
|
|
13915
|
+
return new Promise((resolve5) => {
|
|
13379
13916
|
let out = "";
|
|
13380
13917
|
const child = spawn(cmd, args, {
|
|
13381
13918
|
cwd,
|
|
@@ -13389,8 +13926,8 @@ function runCmd(cmd, args, cwd, shell = false) {
|
|
|
13389
13926
|
child.stderr?.on("data", (c) => {
|
|
13390
13927
|
out += c.toString();
|
|
13391
13928
|
});
|
|
13392
|
-
child.on("error", (e) =>
|
|
13393
|
-
child.on("close", (code) =>
|
|
13929
|
+
child.on("error", (e) => resolve5({ code: 1, out: `${out}${String(e)}` }));
|
|
13930
|
+
child.on("close", (code) => resolve5({ code: code ?? 1, out: out.trim() }));
|
|
13394
13931
|
});
|
|
13395
13932
|
}
|
|
13396
13933
|
function detectPackageManager2(root) {
|
|
@@ -14084,6 +14621,91 @@ function setupMetrics(params) {
|
|
|
14084
14621
|
}
|
|
14085
14622
|
return { metricsSink, healthRegistry, metricsServerHandle };
|
|
14086
14623
|
}
|
|
14624
|
+
var FILE_EDIT_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "multi-edit", "notebook-edit"]);
|
|
14625
|
+
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
14626
|
+
"node_modules",
|
|
14627
|
+
".git",
|
|
14628
|
+
"dist",
|
|
14629
|
+
"build",
|
|
14630
|
+
".next",
|
|
14631
|
+
"coverage",
|
|
14632
|
+
".turbo",
|
|
14633
|
+
"__snapshots__",
|
|
14634
|
+
".nyc_output"
|
|
14635
|
+
]);
|
|
14636
|
+
function isIgnored(rel) {
|
|
14637
|
+
return rel.split(/[/\\]/).some((seg) => IGNORE_DIRS.has(seg));
|
|
14638
|
+
}
|
|
14639
|
+
async function setupCodebaseIndexing(deps) {
|
|
14640
|
+
const { config, pipelines, projectRoot, logger } = deps;
|
|
14641
|
+
const idx = config.indexing;
|
|
14642
|
+
if (!idx) return () => {
|
|
14643
|
+
};
|
|
14644
|
+
const debounceMs = idx.debounceMs ?? 400;
|
|
14645
|
+
const onError = (err) => logger.debug(`codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
14646
|
+
if (idx.onSessionStart) {
|
|
14647
|
+
void runStartupIndex({ projectRoot }).then((r) => {
|
|
14648
|
+
const summary = `${color.green("\u2713")} codebase index ready ${color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`)}`;
|
|
14649
|
+
process.stderr.write(`
|
|
14650
|
+
${summary}
|
|
14651
|
+
`);
|
|
14652
|
+
}).catch((err) => {
|
|
14653
|
+
logger.warn(
|
|
14654
|
+
`codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
14655
|
+
);
|
|
14656
|
+
});
|
|
14657
|
+
}
|
|
14658
|
+
if (idx.onEdit) {
|
|
14659
|
+
pipelines.toolCall.use({
|
|
14660
|
+
name: "CodebaseAutoIndex",
|
|
14661
|
+
// Non-core owner → the pipeline error boundary swallows failures instead
|
|
14662
|
+
// of failing the turn (see wiring/pipeline.ts).
|
|
14663
|
+
owner: "codebase-index",
|
|
14664
|
+
handler: async (payload, next) => {
|
|
14665
|
+
try {
|
|
14666
|
+
const tool = payload.tool;
|
|
14667
|
+
if (tool?.mutating && FILE_EDIT_TOOLS.has(tool.name)) {
|
|
14668
|
+
const fp = payload.toolUse.input?.file_path;
|
|
14669
|
+
if (typeof fp === "string" && fp.length > 0) {
|
|
14670
|
+
const abs = path8.resolve(payload.ctx.cwd, fp);
|
|
14671
|
+
if (isIndexableFile(abs)) {
|
|
14672
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14673
|
+
}
|
|
14674
|
+
}
|
|
14675
|
+
}
|
|
14676
|
+
} catch {
|
|
14677
|
+
}
|
|
14678
|
+
return next(payload);
|
|
14679
|
+
}
|
|
14680
|
+
});
|
|
14681
|
+
}
|
|
14682
|
+
let watcher;
|
|
14683
|
+
if (idx.watchExternal) {
|
|
14684
|
+
try {
|
|
14685
|
+
watcher = fs12.watch(projectRoot, { recursive: true }, (_event, filename) => {
|
|
14686
|
+
if (!filename) return;
|
|
14687
|
+
const rel = filename.toString();
|
|
14688
|
+
if (isIgnored(rel)) return;
|
|
14689
|
+
const abs = path8.resolve(projectRoot, rel);
|
|
14690
|
+
if (!isIndexableFile(abs)) return;
|
|
14691
|
+
enqueueReindex({ projectRoot, files: [abs], debounceMs, onError });
|
|
14692
|
+
});
|
|
14693
|
+
watcher.on("error", (err) => logger.debug(`codebase index watcher error: ${err}`));
|
|
14694
|
+
watcher.unref?.();
|
|
14695
|
+
} catch (err) {
|
|
14696
|
+
logger.debug(
|
|
14697
|
+
`codebase index watcher unavailable: ${err instanceof Error ? err.message : String(err)}`
|
|
14698
|
+
);
|
|
14699
|
+
}
|
|
14700
|
+
}
|
|
14701
|
+
return () => {
|
|
14702
|
+
try {
|
|
14703
|
+
watcher?.close();
|
|
14704
|
+
} catch {
|
|
14705
|
+
}
|
|
14706
|
+
cancelPendingReindexes();
|
|
14707
|
+
};
|
|
14708
|
+
}
|
|
14087
14709
|
function createApi(ownerName, base) {
|
|
14088
14710
|
return new DefaultPluginAPI({ ownerName, ...base });
|
|
14089
14711
|
}
|
|
@@ -14117,7 +14739,22 @@ var BUILTIN_PLUGIN_FACTORIES = [
|
|
|
14117
14739
|
async () => {
|
|
14118
14740
|
const { createPlanPlugin } = await import('@wrongstack/core');
|
|
14119
14741
|
return createPlanPlugin();
|
|
14120
|
-
}
|
|
14742
|
+
},
|
|
14743
|
+
// ── Workspace plugins (@wrongstack/plugins subpath exports) ──────────
|
|
14744
|
+
async () => (await import('@wrongstack/plugins/cost-tracker')).default,
|
|
14745
|
+
async () => (await import('@wrongstack/plugins/json-path')).default,
|
|
14746
|
+
async () => (await import('@wrongstack/plugins/web-search')).default,
|
|
14747
|
+
async () => (await import('@wrongstack/plugins/file-watcher')).default,
|
|
14748
|
+
async () => (await import('@wrongstack/plugins/git-autocommit')).default,
|
|
14749
|
+
async () => (await import('@wrongstack/plugins/auto-doc')).default,
|
|
14750
|
+
async () => (await import('@wrongstack/plugins/shell-check')).default,
|
|
14751
|
+
async () => (await import('@wrongstack/plugins/cron')).default,
|
|
14752
|
+
async () => (await import('@wrongstack/plugins/template-engine')).default,
|
|
14753
|
+
async () => (await import('@wrongstack/plugins/semver-bump')).default,
|
|
14754
|
+
// ── LSP plugin ──────────────────────────────────────────────────────
|
|
14755
|
+
async () => (await import('@wrongstack/plug-lsp')).default,
|
|
14756
|
+
// ── Telegram plugin ─────────────────────────────────────────────────
|
|
14757
|
+
async () => (await import('@wrongstack/telegram')).default
|
|
14121
14758
|
];
|
|
14122
14759
|
async function setupPlugins(params) {
|
|
14123
14760
|
const {
|
|
@@ -14723,6 +15360,17 @@ async function main(argv) {
|
|
|
14723
15360
|
}).catch(() => {
|
|
14724
15361
|
});
|
|
14725
15362
|
});
|
|
15363
|
+
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
15364
|
+
if (!tuiOwnsScreen) {
|
|
15365
|
+
events.on("delegate.started", (e) => {
|
|
15366
|
+
const task = e.task.length > 100 ? `${e.task.slice(0, 99)}\u2026` : e.task;
|
|
15367
|
+
renderer.writeInfo(`\u{1F91D} Delegating \u2192 ${e.target}: ${task}`);
|
|
15368
|
+
});
|
|
15369
|
+
events.on("delegate.completed", (e) => {
|
|
15370
|
+
const cost = e.costUsd && e.costUsd > 0 ? ` \xB7 $${e.costUsd.toFixed(3)}` : "";
|
|
15371
|
+
renderer.writeInfo(`${e.ok ? "\u2705" : "\u274C"} ${e.summary}${cost}`);
|
|
15372
|
+
});
|
|
15373
|
+
}
|
|
14726
15374
|
events.on("tool.progress", (e) => {
|
|
14727
15375
|
sessionBridge.append({
|
|
14728
15376
|
type: "tool_progress",
|
|
@@ -14892,7 +15540,8 @@ async function main(argv) {
|
|
|
14892
15540
|
const directorMode = flags["director"] === true || typeof flags["resume"] === "string";
|
|
14893
15541
|
const maxConcurrentFromFlag = typeof flags["max-concurrent"] === "string" ? Number.parseInt(flags["max-concurrent"], 10) : void 0;
|
|
14894
15542
|
const maxConcurrentFromEnv = typeof process.env["WRONGSTACK_MAX_CONCURRENT"] === "string" ? Number.parseInt(process.env["WRONGSTACK_MAX_CONCURRENT"], 10) : void 0;
|
|
14895
|
-
const
|
|
15543
|
+
const maxConcurrentFromConfig = typeof config.maxConcurrent === "number" && config.maxConcurrent > 0 ? config.maxConcurrent : void 0;
|
|
15544
|
+
const maxConcurrent = Number.isFinite(maxConcurrentFromFlag) && maxConcurrentFromFlag > 0 ? maxConcurrentFromFlag : Number.isFinite(maxConcurrentFromEnv) && maxConcurrentFromEnv > 0 ? maxConcurrentFromEnv : Number.isFinite(maxConcurrentFromConfig) && maxConcurrentFromConfig > 0 ? maxConcurrentFromConfig : void 0;
|
|
14896
15545
|
let director = null;
|
|
14897
15546
|
let autonomyMode = (() => {
|
|
14898
15547
|
const v = flags["autonomy"];
|
|
@@ -14970,7 +15619,10 @@ async function main(argv) {
|
|
|
14970
15619
|
// this, a subagent that hit its iteration cap returns an empty
|
|
14971
15620
|
// result and the host LLM has no idea what work was done.
|
|
14972
15621
|
sessionsRoot: subagentSessionsRoot,
|
|
14973
|
-
directorRunId: session.id
|
|
15622
|
+
directorRunId: session.id,
|
|
15623
|
+
// Host bus so `delegate` can emit start/finish events that the TUI,
|
|
15624
|
+
// plain CLI, and Telegram bridge render as readable lines.
|
|
15625
|
+
events
|
|
14974
15626
|
})
|
|
14975
15627
|
);
|
|
14976
15628
|
toolRegistry.register(
|
|
@@ -15002,6 +15654,12 @@ async function main(argv) {
|
|
|
15002
15654
|
this.enabled = enabled;
|
|
15003
15655
|
}
|
|
15004
15656
|
};
|
|
15657
|
+
const enhanceController = {
|
|
15658
|
+
enabled: config.autonomy?.["enhance"] ?? true,
|
|
15659
|
+
setEnabled(enabled) {
|
|
15660
|
+
this.enabled = enabled;
|
|
15661
|
+
}
|
|
15662
|
+
};
|
|
15005
15663
|
const statuslineConfigDeps = {
|
|
15006
15664
|
get: () => loadStatuslineConfig(),
|
|
15007
15665
|
set: (cfg) => saveStatuslineConfig(cfg)
|
|
@@ -15052,6 +15710,7 @@ async function main(argv) {
|
|
|
15052
15710
|
planPath,
|
|
15053
15711
|
modeStore,
|
|
15054
15712
|
fleetStreamController,
|
|
15713
|
+
enhanceController,
|
|
15055
15714
|
llmProvider: provider,
|
|
15056
15715
|
llmModel: config.model,
|
|
15057
15716
|
statuslineConfig: statuslineConfigDeps,
|
|
@@ -15222,6 +15881,7 @@ async function main(argv) {
|
|
|
15222
15881
|
}
|
|
15223
15882
|
try {
|
|
15224
15883
|
multiAgentHost.setMaxConcurrent(n);
|
|
15884
|
+
events.emit("concurrency.changed", { n });
|
|
15225
15885
|
} catch (err) {
|
|
15226
15886
|
return err instanceof Error ? err.message : String(err);
|
|
15227
15887
|
}
|
|
@@ -15590,7 +16250,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15590
16250
|
const { spawn: spawn3 } = await import('child_process');
|
|
15591
16251
|
const cwd2 = projectRoot;
|
|
15592
16252
|
const statusResult = await new Promise(
|
|
15593
|
-
(
|
|
16253
|
+
(resolve5, reject) => {
|
|
15594
16254
|
const child = spawn3("git", ["status", "--porcelain"], {
|
|
15595
16255
|
cwd: cwd2,
|
|
15596
16256
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -15600,7 +16260,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15600
16260
|
stdout += d;
|
|
15601
16261
|
});
|
|
15602
16262
|
child.on("error", reject);
|
|
15603
|
-
child.on("close", (code) =>
|
|
16263
|
+
child.on("close", (code) => resolve5({ stdout, code: code ?? 0 }));
|
|
15604
16264
|
}
|
|
15605
16265
|
);
|
|
15606
16266
|
if (statusResult.stdout.trim().length > 0) {
|
|
@@ -15726,6 +16386,13 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15726
16386
|
if (eternalFlag.length > 0) {
|
|
15727
16387
|
autonomyMode = "eternal";
|
|
15728
16388
|
}
|
|
16389
|
+
const disposeIndexing = await setupCodebaseIndexing({
|
|
16390
|
+
config,
|
|
16391
|
+
pipelines,
|
|
16392
|
+
projectRoot,
|
|
16393
|
+
logger
|
|
16394
|
+
});
|
|
16395
|
+
process.once("exit", disposeIndexing);
|
|
15729
16396
|
const savedProviderCfg = config.providers?.[config.provider];
|
|
15730
16397
|
return execute({
|
|
15731
16398
|
agent,
|
|
@@ -15757,6 +16424,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15757
16424
|
director: director ?? null,
|
|
15758
16425
|
fleetRoster: FLEET_ROSTER,
|
|
15759
16426
|
fleetStreamController,
|
|
16427
|
+
enhanceController,
|
|
15760
16428
|
statuslineHiddenItems,
|
|
15761
16429
|
setStatuslineHiddenItems,
|
|
15762
16430
|
getYolo: () => {
|
|
@@ -15782,7 +16450,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
15782
16450
|
stageListeners.add(fn);
|
|
15783
16451
|
return () => stageListeners.delete(fn);
|
|
15784
16452
|
},
|
|
15785
|
-
skillLoader: config.features.skills ? skillLoader : void 0
|
|
16453
|
+
skillLoader: config.features.skills ? skillLoader : void 0,
|
|
16454
|
+
modeId
|
|
15786
16455
|
});
|
|
15787
16456
|
}
|
|
15788
16457
|
var isMain = import.meta.url === `file://${process.argv[1]?.replace(/\\/g, "/")}` || process.argv[1]?.endsWith("/cli/dist/index.js") || process.argv[1]?.endsWith("\\cli\\dist\\index.js");
|