@wrongstack/cli 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-GOQURNC2.js → acp-A5EQEXQO.js} +61 -6
- package/dist/{auth-WBXXIQUO.js → auth-3K6EN5JP.js} +3 -3
- package/dist/boot/container-wiring.d.ts +2 -0
- package/dist/{chunk-VUVOMXWP.js → chunk-3VXYY5JC.js} +8 -1
- package/dist/{chunk-NR7BD73C.js → chunk-4OLAZIIN.js} +2 -2
- package/dist/{chunk-5A5GCSJC.js → chunk-FSZ5QU3M.js} +2 -2
- package/dist/{chunk-KNMIBKLV.js → chunk-JY52HWL6.js} +47 -1
- package/dist/{chunk-QDQPF4PB.js → chunk-RLCKKLJA.js} +7 -7
- package/dist/{chunk-VPS2SJW4.js → chunk-RMQNCHGO.js} +5 -3
- package/dist/{chunk-PQZPHGGD.js → chunk-XIZZ2EXG.js} +34 -2
- package/dist/{cli-context-BYKJDAFF.js → cli-context-TIAP6YQK.js} +83 -12
- package/dist/cli-context.d.ts +2 -0
- package/dist/{cli-main-5WZBH3WA.js → cli-main-AKJHDSHX.js} +1006 -634
- package/dist/config-doctor.d.ts +1 -1
- package/dist/execute-deps.d.ts +3 -1
- package/dist/{execution-Z6A26EG6.js → execution-FJE27VQ6.js} +80 -3
- package/dist/{hq-V4PHEETW.js → hq-G5PCP325.js} +7 -5
- package/dist/hq-command-controller.d.ts +15 -0
- package/dist/{hq-server-MZ7DV6X7.js → hq-server-G3VVVMIG.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/input-reader.d.ts +2 -2
- package/dist/{modeldiag-46CMWUNM.js → modeldiag-CJSFHZ3J.js} +55 -31
- package/dist/permission-prompt-mirror.d.ts +70 -0
- package/dist/permission-prompt.d.ts +10 -1
- package/dist/{providers-models-6MOGAOVK.js → providers-models-LFNZ5WI7.js} +2 -2
- package/dist/{short-circuit-flags-KBTYSJTW.js → short-circuit-flags-RAT6UZVI.js} +2 -2
- package/dist/slash-commands/subagent-models.d.ts +4 -0
- package/dist/subagent-models/panel-service.d.ts +28 -0
- package/dist/subcommands/handlers/modeldiag-test.d.ts +7 -0
- package/dist/{subcommands-DEYSYHIM.js → subcommands-VFVUTYAV.js} +2 -2
- package/dist/webui-server/prefs-seeding.d.ts +8 -0
- package/dist/{webui-server-OBV5JYJV.js → webui-server-3NYXBZHX.js} +36 -12
- package/dist/wiring/hq-telemetry.d.ts +7 -0
- package/package.json +28 -28
|
@@ -31,11 +31,6 @@ import {
|
|
|
31
31
|
matchTaskNode,
|
|
32
32
|
sddState
|
|
33
33
|
} from "./chunk-JHUJUIOH.js";
|
|
34
|
-
import {
|
|
35
|
-
createHqCommandDispatcher,
|
|
36
|
-
createProjectKanbanAssignHandler,
|
|
37
|
-
createProjectKanbanTransitionHandler
|
|
38
|
-
} from "./chunk-KNMIBKLV.js";
|
|
39
34
|
import {
|
|
40
35
|
runProjectPicker
|
|
41
36
|
} from "./chunk-WQZW3RDP.js";
|
|
@@ -54,7 +49,7 @@ import {
|
|
|
54
49
|
detectProjectFacts,
|
|
55
50
|
makeConfirmAwaiter,
|
|
56
51
|
renderAgentsTemplate
|
|
57
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-RMQNCHGO.js";
|
|
58
53
|
import "./chunk-QD544J2B.js";
|
|
59
54
|
import {
|
|
60
55
|
fmtTaskResultLine,
|
|
@@ -88,6 +83,11 @@ import {
|
|
|
88
83
|
resolveProviderCfg,
|
|
89
84
|
setupProvider
|
|
90
85
|
} from "./chunk-KEPABQYT.js";
|
|
86
|
+
import {
|
|
87
|
+
createHqCommandDispatcher,
|
|
88
|
+
createProjectKanbanAssignHandler,
|
|
89
|
+
createProjectKanbanTransitionHandler
|
|
90
|
+
} from "./chunk-JY52HWL6.js";
|
|
91
91
|
import {
|
|
92
92
|
startCliHqConnection
|
|
93
93
|
} from "./chunk-TE3Q32JP.js";
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
runAuthLocal,
|
|
103
103
|
runProviderAuthLogin,
|
|
104
104
|
validateFamily
|
|
105
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-FSZ5QU3M.js";
|
|
106
106
|
import "./chunk-2VMJ3E5Z.js";
|
|
107
107
|
import {
|
|
108
108
|
appendHistory
|
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
import {
|
|
111
111
|
buildPickableProviders,
|
|
112
112
|
visibleModelIds
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-3VXYY5JC.js";
|
|
114
114
|
import {
|
|
115
115
|
activeProfileConfigPath
|
|
116
116
|
} from "./chunk-YMXXOOFN.js";
|
|
@@ -1960,10 +1960,14 @@ function registerDirectorStatsBridge(input) {
|
|
|
1960
1960
|
const perSubagent = usage?.perSubagent ?? {};
|
|
1961
1961
|
const subagentStatuses = payload.subagentStatuses.map((s) => {
|
|
1962
1962
|
const u = perSubagent[s.subagentId];
|
|
1963
|
-
|
|
1963
|
+
const resolved = director.resolvedModelFor?.(s.subagentId);
|
|
1964
|
+
const qualified = resolved?.provider && resolved.model ? `${resolved.provider}/${resolved.model}` : resolved?.model ?? void 0;
|
|
1965
|
+
if (u === void 0) {
|
|
1966
|
+
return qualified === void 0 ? s : { ...s, model: qualified };
|
|
1967
|
+
}
|
|
1964
1968
|
return {
|
|
1965
1969
|
...s,
|
|
1966
|
-
...u.model !== void 0 ? { model: u.model } : {},
|
|
1970
|
+
...qualified !== void 0 ? { model: qualified } : u.model !== void 0 ? { model: u.model } : {},
|
|
1967
1971
|
...u.cost !== void 0 ? { costUsd: u.cost } : {},
|
|
1968
1972
|
...u.startedAt !== void 0 ? { runtimeMs: Date.now() - u.startedAt } : {},
|
|
1969
1973
|
...u.lastEventAt !== void 0 ? { lastActivityAt: new Date(u.lastEventAt).toISOString() } : {},
|
|
@@ -2446,12 +2450,12 @@ function makeProviderClassifier(provider, model) {
|
|
|
2446
2450
|
}
|
|
2447
2451
|
|
|
2448
2452
|
// src/fleet/host-provider.ts
|
|
2449
|
-
import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
|
|
2450
2453
|
import {
|
|
2451
2454
|
getProxyConfig,
|
|
2452
2455
|
rewriteBaseUrl,
|
|
2453
2456
|
shouldRewriteFor
|
|
2454
2457
|
} from "@wrongstack/core/wiring/proxy-rewrite";
|
|
2458
|
+
import { makeProviderFromConfig, withCatalogCapabilities } from "@wrongstack/providers";
|
|
2455
2459
|
async function buildHostSubagentProvider(deps, config, overrideId, model) {
|
|
2456
2460
|
const requestedProviderId = overrideId ?? config.provider;
|
|
2457
2461
|
const providerId = requestedProviderId === config.provider || config.providers?.[requestedProviderId] !== void 0 || deps.providerRegistry.has(requestedProviderId) ? requestedProviderId : config.provider;
|
|
@@ -2469,7 +2473,7 @@ async function buildHostSubagentProvider(deps, config, overrideId, model) {
|
|
|
2469
2473
|
...baseUrl !== newCfg.baseUrl ? { baseUrl } : {},
|
|
2470
2474
|
...model ? { model } : {}
|
|
2471
2475
|
};
|
|
2472
|
-
let provider = deps.providerRegistry.has(
|
|
2476
|
+
let provider = deps.providerRegistry.has(factoryType) ? deps.providerRegistry.create(cfgWithType, factoryType) : makeProviderFromConfig(providerId, { ...cfgWithType, type: factoryType });
|
|
2473
2477
|
if (deps.modelsRegistry) {
|
|
2474
2478
|
const resolvedModel = model ?? config.model;
|
|
2475
2479
|
provider = await withCatalogCapabilities(deps.modelsRegistry, providerId, provider, {
|
|
@@ -4164,8 +4168,11 @@ var MultiAgentHost = class {
|
|
|
4164
4168
|
taskResultNotifier: (n) => this.reportTaskResultToLeader(n),
|
|
4165
4169
|
subagentIdleTimeoutMs,
|
|
4166
4170
|
...this.opts.statusTracker ? { statusTracker: this.opts.statusTracker } : {},
|
|
4167
|
-
|
|
4168
|
-
|
|
4171
|
+
// Live, like `modelMatrix` and `appConfig`: a `/model` switch has to
|
|
4172
|
+
// reach the NEXT spawn. Snapshotting here pinned every later worker to
|
|
4173
|
+
// the model the leader happened to run on when the fleet was built.
|
|
4174
|
+
sessionProvider: () => this.deps.configStore.get().provider,
|
|
4175
|
+
sessionModel: () => this.deps.configStore.get().model,
|
|
4169
4176
|
retireSubagentOnTaskComplete: this.opts.retireSubagentOnTaskComplete ?? fleetLifecycle?.retireOnTaskComplete ?? true
|
|
4170
4177
|
});
|
|
4171
4178
|
installDirectorTaskCompletedHandler({
|
|
@@ -5049,6 +5056,9 @@ function removeProviderFallbackReferences(config, providerId) {
|
|
|
5049
5056
|
if (Array.isArray(config["favoriteModels"])) {
|
|
5050
5057
|
config["favoriteModels"] = removeModelRefs(config["favoriteModels"]);
|
|
5051
5058
|
}
|
|
5059
|
+
if (Array.isArray(config["disabledModels"])) {
|
|
5060
|
+
config["disabledModels"] = removeModelRefs(config["disabledModels"]);
|
|
5061
|
+
}
|
|
5052
5062
|
if (isRecord(config["models"])) {
|
|
5053
5063
|
for (const [modelId, definition] of Object.entries(config["models"])) {
|
|
5054
5064
|
if (isRecord(definition) && definition["provider"] === providerId) {
|
|
@@ -6200,7 +6210,7 @@ async function runCliExecution(params) {
|
|
|
6200
6210
|
governanceHandle,
|
|
6201
6211
|
setConfig
|
|
6202
6212
|
} = params;
|
|
6203
|
-
const { execute } = await import("./execution-
|
|
6213
|
+
const { execute } = await import("./execution-FJE27VQ6.js");
|
|
6204
6214
|
return execute(
|
|
6205
6215
|
toExecuteDeps({
|
|
6206
6216
|
core: {
|
|
@@ -12902,6 +12912,7 @@ var KNOWN_TOP_LEVEL_KEYS = [
|
|
|
12902
12912
|
"modelMatrix",
|
|
12903
12913
|
"modelTiers",
|
|
12904
12914
|
"favoriteModels",
|
|
12915
|
+
"disabledModels",
|
|
12905
12916
|
"favoriteModelsOnly",
|
|
12906
12917
|
"modelAvailabilitySchedule",
|
|
12907
12918
|
"context",
|
|
@@ -22980,6 +22991,7 @@ async function switchProfile(wpaths, nameArg, renderer, configStore, syncConfig)
|
|
|
22980
22991
|
"fallbackProfiles",
|
|
22981
22992
|
"fallbackProfile",
|
|
22982
22993
|
"favoriteModels",
|
|
22994
|
+
"disabledModels",
|
|
22983
22995
|
"favoriteModelsOnly",
|
|
22984
22996
|
"modelAvailabilitySchedule",
|
|
22985
22997
|
"modelMatrix",
|
|
@@ -25894,11 +25906,331 @@ function buildSetModelCommand(opts) {
|
|
|
25894
25906
|
};
|
|
25895
25907
|
}
|
|
25896
25908
|
|
|
25909
|
+
// src/slash-commands/subagent-models.ts
|
|
25910
|
+
import {
|
|
25911
|
+
claimSubagentSlot,
|
|
25912
|
+
emptySubagentModelPlan,
|
|
25913
|
+
formatSubagentSlot,
|
|
25914
|
+
getSessionSubagentModelPlan,
|
|
25915
|
+
isSlotConfigured,
|
|
25916
|
+
MAX_SUBAGENT_SLOTS,
|
|
25917
|
+
normalizeSubagentModelPlan,
|
|
25918
|
+
planHasAssignments,
|
|
25919
|
+
resetSessionSubagentModelPlan,
|
|
25920
|
+
resolveModelMatrixResolution,
|
|
25921
|
+
setSessionSubagentModelPlan,
|
|
25922
|
+
subagentSlotOccupancy
|
|
25923
|
+
} from "@wrongstack/core/coordination";
|
|
25924
|
+
import { color as color51 } from "@wrongstack/core/utils";
|
|
25925
|
+
function providerHasKey2(entry) {
|
|
25926
|
+
if (!entry) return false;
|
|
25927
|
+
if (typeof entry.apiKey === "string" && entry.apiKey.length > 0) return true;
|
|
25928
|
+
if (Array.isArray(entry.apiKeys) && entry.apiKeys.some((k) => k?.apiKey)) return true;
|
|
25929
|
+
if (Array.isArray(entry.envVars) && entry.envVars.some((v) => !!process.env[v])) return true;
|
|
25930
|
+
return false;
|
|
25931
|
+
}
|
|
25932
|
+
function keyedProviderIds2(config) {
|
|
25933
|
+
const ids = /* @__PURE__ */ new Set();
|
|
25934
|
+
if (config.provider) ids.add(config.provider);
|
|
25935
|
+
for (const [id, entry] of Object.entries(config.providers ?? {})) {
|
|
25936
|
+
if (providerHasKey2(entry)) ids.add(id);
|
|
25937
|
+
}
|
|
25938
|
+
return [...ids].sort();
|
|
25939
|
+
}
|
|
25940
|
+
function parseTarget2(tokens, config) {
|
|
25941
|
+
const profiles = config.fallbackProfiles ?? {};
|
|
25942
|
+
if (tokens.length === 0) return { error: "missing <provider>/<model>" };
|
|
25943
|
+
if (tokens.length >= 2) {
|
|
25944
|
+
return { provider: tokens[0], model: tokens.slice(1).join(" ") };
|
|
25945
|
+
}
|
|
25946
|
+
const only = tokens[0];
|
|
25947
|
+
if (only.startsWith("tier:")) {
|
|
25948
|
+
const tier = only.slice(5).trim();
|
|
25949
|
+
return tier ? { tier } : { error: 'missing tier id after "tier:"' };
|
|
25950
|
+
}
|
|
25951
|
+
if (only.startsWith("profile:")) {
|
|
25952
|
+
const name = only.slice(8).trim();
|
|
25953
|
+
if (!name) return { error: 'missing profile name after "profile:"' };
|
|
25954
|
+
if (!profiles[name]) return { error: `unknown fallback profile "${name}"` };
|
|
25955
|
+
return { fallbackProfile: name };
|
|
25956
|
+
}
|
|
25957
|
+
if (profiles[only]) return { fallbackProfile: only };
|
|
25958
|
+
if (only.includes("/")) {
|
|
25959
|
+
const i = only.indexOf("/");
|
|
25960
|
+
return { provider: only.slice(0, i), model: only.slice(i + 1) };
|
|
25961
|
+
}
|
|
25962
|
+
return { model: only };
|
|
25963
|
+
}
|
|
25964
|
+
function formatSlot(slot, config) {
|
|
25965
|
+
if (!slot || !isSlotConfigured(slot)) return color51.dim("(inherit \u2014 matrix / tier / session)");
|
|
25966
|
+
const text = formatSubagentSlot(
|
|
25967
|
+
slot.model && !slot.provider ? { ...slot, provider: config.provider } : slot
|
|
25968
|
+
);
|
|
25969
|
+
return color51.cyan(text);
|
|
25970
|
+
}
|
|
25971
|
+
function parseLaneNumber(token, laneCount) {
|
|
25972
|
+
if (!token) return void 0;
|
|
25973
|
+
const n = Number.parseInt(token, 10);
|
|
25974
|
+
if (!Number.isFinite(n) || n < 1 || n > laneCount) return void 0;
|
|
25975
|
+
return n - 1;
|
|
25976
|
+
}
|
|
25977
|
+
function buildSubagentModelsCommand(opts) {
|
|
25978
|
+
const help = [
|
|
25979
|
+
"Usage:",
|
|
25980
|
+
" /subagent-models Show this session\u2019s lane plan",
|
|
25981
|
+
" /subagent-models set <n> <provider>/<model> Pin lane n (1-based)",
|
|
25982
|
+
" /subagent-models set <n> tier:<id> Pin lane n to a cost tier",
|
|
25983
|
+
" /subagent-models set <n> profile:<name> Pin lane n to a fallback profile",
|
|
25984
|
+
" /subagent-models clear <n|all> Unpin a lane (or every lane)",
|
|
25985
|
+
" /subagent-models role <role> <target> Session-scoped role override",
|
|
25986
|
+
" /subagent-models role <role> clear Drop that role override",
|
|
25987
|
+
` /subagent-models lanes <count> Resize the lane list (1\u2013${MAX_SUBAGENT_SLOTS})`,
|
|
25988
|
+
" /subagent-models lock on|off Whether lanes outrank the leader",
|
|
25989
|
+
" /subagent-models session on|off Run every plain subagent on YOUR model",
|
|
25990
|
+
" /subagent-models on|off Enable / disable the whole plan",
|
|
25991
|
+
" /subagent-models reset Drop the plan for this session",
|
|
25992
|
+
"",
|
|
25993
|
+
"Lanes are handed out by occupancy: each live subagent holds one lane and",
|
|
25994
|
+
"releases it when it retires, so N workers running at once run on N",
|
|
25995
|
+
"different models. A role override wins over the lanes and consumes none.",
|
|
25996
|
+
"",
|
|
25997
|
+
"`session on` is the coarse version of the same idea: every plain subagent",
|
|
25998
|
+
"runs on the model this session is using. It outranks the lanes.",
|
|
25999
|
+
"",
|
|
26000
|
+
"/setmodel routing is left intact \u2014 a role or phase you pinned there keeps",
|
|
26001
|
+
"its route, and only a session role override outranks it.",
|
|
26002
|
+
"",
|
|
26003
|
+
"With lock on (the default) a lane also overrides the provider/model the",
|
|
26004
|
+
"leader passes to spawn_subagent / delegate. Precedence at spawn:",
|
|
26005
|
+
"session plan \u2192 leader pin \u2192 /setmodel matrix \u2192 tier \u2192 session model.",
|
|
26006
|
+
"",
|
|
26007
|
+
"Scoped to THIS session and stored in the session journal, so /resume",
|
|
26008
|
+
"brings it back. It never touches config.json \u2014 use /setmodel for that."
|
|
26009
|
+
].join("\n");
|
|
26010
|
+
function planFor(sessionId) {
|
|
26011
|
+
return getSessionSubagentModelPlan(sessionId) ?? emptySubagentModelPlan();
|
|
26012
|
+
}
|
|
26013
|
+
function render(plan, sessionId) {
|
|
26014
|
+
const config = opts.configStore.get();
|
|
26015
|
+
const occupancy = subagentSlotOccupancy(sessionId);
|
|
26016
|
+
const lines = [
|
|
26017
|
+
`${color51.bold("WrongStack")} ${color51.dim("\u2014 Subagent models (this session)")}`,
|
|
26018
|
+
"",
|
|
26019
|
+
` ${color51.bold("status")} ${plan.enabled ? color51.green("on") : color51.red("off")} ${color51.bold("lock")} ${plan.lock ? color51.green("on") : color51.dim("off")} ${color51.bold("session model")} ${plan.followSessionModel ? color51.green("on") : color51.dim("off")} ` + color51.dim(plan.lock ? "lanes override the leader" : "leader pins win"),
|
|
26020
|
+
"",
|
|
26021
|
+
` ${color51.bold("lanes")} ${color51.dim("(first free lane wins; \u25CF = busy now)")}`
|
|
26022
|
+
];
|
|
26023
|
+
if (plan.followSessionModel) {
|
|
26024
|
+
lines.push(
|
|
26025
|
+
` ${color51.green("\u25B8")} every plain subagent runs on ${color51.cyan(`${config.provider}/${config.model}`)} ${color51.dim("(lanes below are inactive)")}`
|
|
26026
|
+
);
|
|
26027
|
+
}
|
|
26028
|
+
plan.slots.forEach((slot, i) => {
|
|
26029
|
+
const busy = occupancy[i]?.subagentIds.length ?? 0;
|
|
26030
|
+
const marker = busy > 0 ? color51.green(`\u25CF${busy > 1 ? busy : ""}`) : color51.dim("\u25CB");
|
|
26031
|
+
const label = slot.label ? color51.dim(` ${slot.label}`) : "";
|
|
26032
|
+
lines.push(
|
|
26033
|
+
` ${marker} ${color51.amber(String(i + 1).padStart(2))} ${formatSlot(slot, config)}${label}`
|
|
26034
|
+
);
|
|
26035
|
+
});
|
|
26036
|
+
const roles = Object.entries(plan.roles ?? {});
|
|
26037
|
+
if (roles.length > 0) {
|
|
26038
|
+
lines.push("", ` ${color51.bold("roles")} ${color51.dim("(beat the lanes, consume none)")}`);
|
|
26039
|
+
for (const [role, slot] of roles.sort(([a], [b]) => a.localeCompare(b))) {
|
|
26040
|
+
lines.push(` ${color51.amber(role.padEnd(22))} \u2192 ${formatSlot(slot, config)}`);
|
|
26041
|
+
}
|
|
26042
|
+
}
|
|
26043
|
+
if (!planHasAssignments(plan)) {
|
|
26044
|
+
lines.push(
|
|
26045
|
+
"",
|
|
26046
|
+
color51.dim(" no lane pinned \u2014 spawns resolve exactly as before"),
|
|
26047
|
+
color51.dim(" pin one: /subagent-models set 1 anthropic/claude-opus-5")
|
|
26048
|
+
);
|
|
26049
|
+
}
|
|
26050
|
+
lines.push(
|
|
26051
|
+
"",
|
|
26052
|
+
color51.dim(" /subagent-models set \xB7 clear \xB7 role \xB7 lanes \xB7 lock \xB7 reset \xB7 help")
|
|
26053
|
+
);
|
|
26054
|
+
return lines.join("\n");
|
|
26055
|
+
}
|
|
26056
|
+
return {
|
|
26057
|
+
name: "subagent-models",
|
|
26058
|
+
description: "Per-session provider/model lanes for spawned subagents",
|
|
26059
|
+
category: "Agent",
|
|
26060
|
+
argsHint: "[set <n> <provider>/<model> | clear <n|all> | role <role> <target> | lock on|off]",
|
|
26061
|
+
help,
|
|
26062
|
+
async run(args, ctx) {
|
|
26063
|
+
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
26064
|
+
const sub = (tokens[0] ?? "").toLowerCase();
|
|
26065
|
+
const sessionId = ctx?.session?.id;
|
|
26066
|
+
const config = opts.configStore.get();
|
|
26067
|
+
const plan = planFor(sessionId);
|
|
26068
|
+
if (!sub && opts.onPanelOpen?.current) {
|
|
26069
|
+
const opened = opts.onPanelOpen.current("subagentModelsOpen");
|
|
26070
|
+
if (opened) return { message: "" };
|
|
26071
|
+
}
|
|
26072
|
+
if (!sub || sub === "list" || sub === "show") {
|
|
26073
|
+
return { message: render(plan, sessionId), metadata: { subagentModelPlan: plan } };
|
|
26074
|
+
}
|
|
26075
|
+
if (!ctx?.session) {
|
|
26076
|
+
return { message: color51.red("No active session \u2014 cannot change the subagent model plan.") };
|
|
26077
|
+
}
|
|
26078
|
+
const next = normalizeSubagentModelPlan(plan);
|
|
26079
|
+
const save = async (message) => {
|
|
26080
|
+
await setSessionSubagentModelPlan(ctx, next);
|
|
26081
|
+
return { message, metadata: { subagentModelPlan: next } };
|
|
26082
|
+
};
|
|
26083
|
+
switch (sub) {
|
|
26084
|
+
case "set": {
|
|
26085
|
+
const index = parseLaneNumber(tokens[1], next.slots.length);
|
|
26086
|
+
if (index === void 0) {
|
|
26087
|
+
return {
|
|
26088
|
+
message: color51.red(`Lane must be a number between 1 and ${next.slots.length}.`)
|
|
26089
|
+
};
|
|
26090
|
+
}
|
|
26091
|
+
const target = parseTarget2(tokens.slice(2), config);
|
|
26092
|
+
if ("error" in target)
|
|
26093
|
+
return { message: color51.red(`/subagent-models set: ${target.error}`) };
|
|
26094
|
+
next.slots[index] = target;
|
|
26095
|
+
const provider = target.provider;
|
|
26096
|
+
const warning = provider && !keyedProviderIds2(config).includes(provider) ? `
|
|
26097
|
+
${color51.amber(`warning: provider "${provider}" has no configured key \u2014 spawns on lane ${index + 1} will fall back.`)}` : "";
|
|
26098
|
+
return save(
|
|
26099
|
+
`Lane ${index + 1} \u2192 ${formatSlot(target, config)}${warning}
|
|
26100
|
+
|
|
26101
|
+
${render(next, sessionId)}`
|
|
26102
|
+
);
|
|
26103
|
+
}
|
|
26104
|
+
case "clear": {
|
|
26105
|
+
if ((tokens[1] ?? "").toLowerCase() === "all") {
|
|
26106
|
+
next.slots = next.slots.map(() => ({}));
|
|
26107
|
+
return save(`Cleared every lane.
|
|
26108
|
+
|
|
26109
|
+
${render(next, sessionId)}`);
|
|
26110
|
+
}
|
|
26111
|
+
const index = parseLaneNumber(tokens[1], next.slots.length);
|
|
26112
|
+
if (index === void 0) {
|
|
26113
|
+
return {
|
|
26114
|
+
message: color51.red(
|
|
26115
|
+
`Lane must be a number between 1 and ${next.slots.length}, or "all".`
|
|
26116
|
+
)
|
|
26117
|
+
};
|
|
26118
|
+
}
|
|
26119
|
+
next.slots[index] = {};
|
|
26120
|
+
return save(`Cleared lane ${index + 1}.
|
|
26121
|
+
|
|
26122
|
+
${render(next, sessionId)}`);
|
|
26123
|
+
}
|
|
26124
|
+
case "role": {
|
|
26125
|
+
const role = tokens[1];
|
|
26126
|
+
if (!role) return { message: color51.red("/subagent-models role: missing <role>") };
|
|
26127
|
+
const rest = tokens.slice(2);
|
|
26128
|
+
const roles = { ...next.roles ?? {} };
|
|
26129
|
+
if (rest.length === 0 || ["clear", "none", "-"].includes((rest[0] ?? "").toLowerCase())) {
|
|
26130
|
+
delete roles[role];
|
|
26131
|
+
next.roles = roles;
|
|
26132
|
+
return save(`Dropped the override for role "${role}".
|
|
26133
|
+
|
|
26134
|
+
${render(next, sessionId)}`);
|
|
26135
|
+
}
|
|
26136
|
+
const target = parseTarget2(rest, config);
|
|
26137
|
+
if ("error" in target)
|
|
26138
|
+
return { message: color51.red(`/subagent-models role: ${target.error}`) };
|
|
26139
|
+
roles[role] = target;
|
|
26140
|
+
next.roles = roles;
|
|
26141
|
+
return save(
|
|
26142
|
+
`Role "${role}" \u2192 ${formatSlot(target, config)}
|
|
26143
|
+
|
|
26144
|
+
${render(next, sessionId)}`
|
|
26145
|
+
);
|
|
26146
|
+
}
|
|
26147
|
+
case "lanes": {
|
|
26148
|
+
const count = Number.parseInt(tokens[1] ?? "", 10);
|
|
26149
|
+
if (!Number.isFinite(count) || count < 1 || count > MAX_SUBAGENT_SLOTS) {
|
|
26150
|
+
return {
|
|
26151
|
+
message: color51.red(`Lane count must be between 1 and ${MAX_SUBAGENT_SLOTS}.`)
|
|
26152
|
+
};
|
|
26153
|
+
}
|
|
26154
|
+
const dropped = next.slots.slice(count).filter(isSlotConfigured).length;
|
|
26155
|
+
next.slots = count <= next.slots.length ? next.slots.slice(0, count) : [...next.slots, ...Array.from({ length: count - next.slots.length }, () => ({}))];
|
|
26156
|
+
const note = dropped > 0 ? color51.amber(` (${dropped} pinned lane(s) dropped)`) : "";
|
|
26157
|
+
return save(`Lane count \u2192 ${count}${note}
|
|
26158
|
+
|
|
26159
|
+
${render(next, sessionId)}`);
|
|
26160
|
+
}
|
|
26161
|
+
case "session": {
|
|
26162
|
+
const value = (tokens[1] ?? "").toLowerCase();
|
|
26163
|
+
if (value !== "on" && value !== "off") {
|
|
26164
|
+
return { message: color51.red('/subagent-models session: expected "on" or "off".') };
|
|
26165
|
+
}
|
|
26166
|
+
next.followSessionModel = value === "on";
|
|
26167
|
+
return save(
|
|
26168
|
+
`Follow session model ${value} \u2014 ${next.followSessionModel ? "every plain subagent runs on this session\u2019s model" : "lanes and routing decide again"}.
|
|
26169
|
+
|
|
26170
|
+
${render(next, sessionId)}`
|
|
26171
|
+
);
|
|
26172
|
+
}
|
|
26173
|
+
case "lock": {
|
|
26174
|
+
const value = (tokens[1] ?? "").toLowerCase();
|
|
26175
|
+
if (value !== "on" && value !== "off") {
|
|
26176
|
+
return { message: color51.red('/subagent-models lock: expected "on" or "off".') };
|
|
26177
|
+
}
|
|
26178
|
+
next.lock = value === "on";
|
|
26179
|
+
return save(
|
|
26180
|
+
`Lock ${value} \u2014 ${next.lock ? "lanes override leader-supplied models" : "leader pins win, lanes only fill gaps"}.
|
|
26181
|
+
|
|
26182
|
+
${render(next, sessionId)}`
|
|
26183
|
+
);
|
|
26184
|
+
}
|
|
26185
|
+
case "on":
|
|
26186
|
+
case "off": {
|
|
26187
|
+
next.enabled = sub === "on";
|
|
26188
|
+
return save(`Subagent model plan ${sub}.
|
|
26189
|
+
|
|
26190
|
+
${render(next, sessionId)}`);
|
|
26191
|
+
}
|
|
26192
|
+
case "reset": {
|
|
26193
|
+
const fresh = emptySubagentModelPlan();
|
|
26194
|
+
await setSessionSubagentModelPlan(ctx, fresh);
|
|
26195
|
+
resetSessionSubagentModelPlan(sessionId);
|
|
26196
|
+
return {
|
|
26197
|
+
message: `Reset the subagent model plan for this session.`,
|
|
26198
|
+
metadata: { subagentModelPlan: fresh }
|
|
26199
|
+
};
|
|
26200
|
+
}
|
|
26201
|
+
case "resolve": {
|
|
26202
|
+
const role = tokens[1];
|
|
26203
|
+
const routeSource = resolveModelMatrixResolution(config.modelMatrix, role)?.source;
|
|
26204
|
+
const routed = routeSource === "role" || routeSource === "phase";
|
|
26205
|
+
const claim = claimSubagentSlot(sessionId, { ...role ? { role } : {}, routed });
|
|
26206
|
+
claim?.abandon();
|
|
26207
|
+
if (!claim) {
|
|
26208
|
+
return {
|
|
26209
|
+
message: color51.dim(
|
|
26210
|
+
routed ? `Role "${role}" is routed by /setmodel (${routeSource}) \u2014 the session plan leaves it alone.` : "No lane would apply \u2014 resolution falls through to the matrix / tier / session model."
|
|
26211
|
+
)
|
|
26212
|
+
};
|
|
26213
|
+
}
|
|
26214
|
+
const where = claim.kind === "session-model" ? "use my model" : claim.slotIndex === void 0 ? `role "${role}"` : `lane ${claim.slotIndex + 1}`;
|
|
26215
|
+
const target = claim.kind === "session-model" ? { provider: config.provider, model: config.model } : claim.target;
|
|
26216
|
+
return {
|
|
26217
|
+
message: `Next spawn${role ? ` of role "${role}"` : ""} \u2192 ${formatSlot(target, config)} ${color51.dim(`(${where}, lock ${claim.lock ? "on" : "off"})`)}`
|
|
26218
|
+
};
|
|
26219
|
+
}
|
|
26220
|
+
default:
|
|
26221
|
+
return { message: color51.red(`Unknown subcommand "${sub}".
|
|
26222
|
+
|
|
26223
|
+
${help}`) };
|
|
26224
|
+
}
|
|
26225
|
+
}
|
|
26226
|
+
};
|
|
26227
|
+
}
|
|
26228
|
+
|
|
25897
26229
|
// src/slash-commands/suggest.ts
|
|
25898
26230
|
import { execFile } from "node:child_process";
|
|
25899
26231
|
import { access as access3 } from "node:fs/promises";
|
|
25900
26232
|
import * as path17 from "node:path";
|
|
25901
|
-
import { color as
|
|
26233
|
+
import { color as color52, toErrorMessage as toErrorMessage24 } from "@wrongstack/core/utils";
|
|
25902
26234
|
import { parseNextSteps } from "@wrongstack/tools/next-steps";
|
|
25903
26235
|
function readGitStatus(projectRoot, includeBranch) {
|
|
25904
26236
|
const args = ["status", "--short"];
|
|
@@ -25990,7 +26322,7 @@ function buildSuggestCommand(opts) {
|
|
|
25990
26322
|
const suggestions = await generateHeuristicSuggestions(opts);
|
|
25991
26323
|
setSuggestions(suggestions);
|
|
25992
26324
|
opts.onSuggestions?.(suggestions);
|
|
25993
|
-
const display = formatSuggestions(suggestions) + "\n" +
|
|
26325
|
+
const display = formatSuggestions(suggestions) + "\n" + color52.dim("(Heuristic fallback \u2014 multi-agent not enabled)");
|
|
25994
26326
|
return { message: display };
|
|
25995
26327
|
}
|
|
25996
26328
|
if (!fresh && suggestCache && Date.now() - suggestCache.at < SUGGEST_CACHE_TTL_MS) {
|
|
@@ -25998,7 +26330,7 @@ function buildSuggestCommand(opts) {
|
|
|
25998
26330
|
opts.onSuggestions?.(suggestCache.suggestions);
|
|
25999
26331
|
const ageSec = Math.round((Date.now() - suggestCache.at) / 1e3);
|
|
26000
26332
|
return {
|
|
26001
|
-
message: formatSuggestions(suggestCache.suggestions) + "\n" +
|
|
26333
|
+
message: formatSuggestions(suggestCache.suggestions) + "\n" + color52.dim(`(cached ${ageSec}s ago \u2014 /suggest --fresh to regenerate)`)
|
|
26002
26334
|
};
|
|
26003
26335
|
}
|
|
26004
26336
|
const contextText = await collectContext({
|
|
@@ -26006,7 +26338,7 @@ function buildSuggestCommand(opts) {
|
|
|
26006
26338
|
projectRoot: opts.projectRoot
|
|
26007
26339
|
});
|
|
26008
26340
|
const task = buildSuggestPrompt(contextText);
|
|
26009
|
-
opts.renderer.write(
|
|
26341
|
+
opts.renderer.write(color52.dim("Generating suggestions..."));
|
|
26010
26342
|
try {
|
|
26011
26343
|
const raw = await opts.onSpawnAndWait(task, {
|
|
26012
26344
|
name: "suggest"
|
|
@@ -26101,14 +26433,14 @@ async function generateHeuristicSuggestions(opts) {
|
|
|
26101
26433
|
}
|
|
26102
26434
|
function formatSuggestions(suggestions) {
|
|
26103
26435
|
if (suggestions.length === 0) {
|
|
26104
|
-
return
|
|
26436
|
+
return color52.dim("No suggestions available.");
|
|
26105
26437
|
}
|
|
26106
26438
|
const lines = [
|
|
26107
|
-
` ${
|
|
26439
|
+
` ${color52.cyan("\u{1F4A1} Next steps")} ${color52.dim("(use /next 1, /next 2, or /next 1 2 3)")}`,
|
|
26108
26440
|
""
|
|
26109
26441
|
];
|
|
26110
26442
|
for (let i = 0; i < suggestions.length; i++) {
|
|
26111
|
-
const num =
|
|
26443
|
+
const num = color52.bold(`${i + 1}.`);
|
|
26112
26444
|
const text = suggestions[i] ?? "";
|
|
26113
26445
|
lines.push(` ${num} ${text}`);
|
|
26114
26446
|
}
|
|
@@ -26175,7 +26507,7 @@ function buildWebuiCommand() {
|
|
|
26175
26507
|
|
|
26176
26508
|
// src/slash-commands/theme.ts
|
|
26177
26509
|
import { THEME_PRESET_IDS } from "@wrongstack/core/types";
|
|
26178
|
-
import { color as
|
|
26510
|
+
import { color as color53, writeOut as writeOut3 } from "@wrongstack/core/utils";
|
|
26179
26511
|
var THEME_META = {
|
|
26180
26512
|
catppuccin: { name: "Catppuccin Mocha", desc: "Soft pastel dark theme (Default)" },
|
|
26181
26513
|
"tokyo-night": { name: "Tokyo Night", desc: "Deep violet, neon orange & cyan" },
|
|
@@ -26368,19 +26700,19 @@ async function runThemePicker(reader, activeId) {
|
|
|
26368
26700
|
);
|
|
26369
26701
|
const lines = [];
|
|
26370
26702
|
lines.push("");
|
|
26371
|
-
lines.push(`${
|
|
26372
|
-
lines.push(
|
|
26703
|
+
lines.push(`${color53.bold(color53.amber("WrongStack") + color53.dim(" \u2014 TUI Theme Selection"))}`);
|
|
26704
|
+
lines.push(color53.dim(" \u2191\u2193 navigate Enter select q quit"));
|
|
26373
26705
|
lines.push("");
|
|
26374
|
-
if (hasAbove) lines.push(
|
|
26706
|
+
if (hasAbove) lines.push(color53.dim(` \u2026 ${start} more above`));
|
|
26375
26707
|
for (let i = start; i < end; i++) {
|
|
26376
26708
|
const p = THEME_OPTIONS[i];
|
|
26377
|
-
const mark = p.id === activeId ?
|
|
26378
|
-
const prefix = i === currentCursor ?
|
|
26379
|
-
const name = i === currentCursor ?
|
|
26709
|
+
const mark = p.id === activeId ? color53.green(" [active]") : "";
|
|
26710
|
+
const prefix = i === currentCursor ? color53.bold("\u276F ") : " ";
|
|
26711
|
+
const name = i === currentCursor ? color53.bold(p.name) : p.name;
|
|
26380
26712
|
const desc = truncateDesc(p.desc, columns, p.id === activeId);
|
|
26381
|
-
lines.push(` ${prefix}${name.padEnd(21)} ${
|
|
26713
|
+
lines.push(` ${prefix}${name.padEnd(21)} ${color53.dim(desc)}${mark}`);
|
|
26382
26714
|
}
|
|
26383
|
-
if (hasBelow) lines.push(
|
|
26715
|
+
if (hasBelow) lines.push(color53.dim(` \u2026 ${THEME_OPTIONS.length - end} more below`));
|
|
26384
26716
|
lines.push("");
|
|
26385
26717
|
return lines.join("\n");
|
|
26386
26718
|
};
|
|
@@ -26435,21 +26767,21 @@ function buildThemeCommand(opts) {
|
|
|
26435
26767
|
}
|
|
26436
26768
|
}
|
|
26437
26769
|
return {
|
|
26438
|
-
message:
|
|
26770
|
+
message: color53.green(`Switched TUI theme preset to "${selected}" (saved to config).`),
|
|
26439
26771
|
metadata: { themePreset: selected }
|
|
26440
26772
|
};
|
|
26441
26773
|
}
|
|
26442
26774
|
const lines = [
|
|
26443
|
-
|
|
26775
|
+
color53.bold(`Current TUI theme: ${activePreset}`),
|
|
26444
26776
|
"",
|
|
26445
|
-
|
|
26777
|
+
color53.bold("Available Theme Presets:")
|
|
26446
26778
|
];
|
|
26447
26779
|
for (const t of THEME_OPTIONS) {
|
|
26448
|
-
const mark = t.id === activePreset ?
|
|
26449
|
-
lines.push(` \u2022 ${
|
|
26780
|
+
const mark = t.id === activePreset ? color53.green(" [active]") : "";
|
|
26781
|
+
lines.push(` \u2022 ${color53.bold(t.id.padEnd(21))} ${t.desc}${mark}`);
|
|
26450
26782
|
}
|
|
26451
26783
|
lines.push("");
|
|
26452
|
-
lines.push(
|
|
26784
|
+
lines.push(color53.dim("Usage: /theme <preset>"));
|
|
26453
26785
|
return { message: lines.join("\n") };
|
|
26454
26786
|
}
|
|
26455
26787
|
const preset = args.trim().toLowerCase();
|
|
@@ -26465,7 +26797,7 @@ function buildThemeCommand(opts) {
|
|
|
26465
26797
|
}
|
|
26466
26798
|
}
|
|
26467
26799
|
return {
|
|
26468
|
-
message:
|
|
26800
|
+
message: color53.green(`Switched TUI theme preset to "${preset}" (saved to config).`),
|
|
26469
26801
|
metadata: { themePreset: preset }
|
|
26470
26802
|
};
|
|
26471
26803
|
}
|
|
@@ -26476,7 +26808,7 @@ function buildThemeCommand(opts) {
|
|
|
26476
26808
|
import * as fs17 from "node:fs/promises";
|
|
26477
26809
|
import { leaderTierPolicy, listTierIds, resolveTier } from "@wrongstack/core/coordination";
|
|
26478
26810
|
import { ConfigError as ConfigError6 } from "@wrongstack/core/types";
|
|
26479
|
-
import { atomicWrite as atomicWrite10, color as
|
|
26811
|
+
import { atomicWrite as atomicWrite10, color as color54, toErrorMessage as toErrorMessage25 } from "@wrongstack/core/utils";
|
|
26480
26812
|
var LEADER_MODES = ["off", "propose", "auto"];
|
|
26481
26813
|
async function patchGlobalConfig3(globalConfigPath, mutate) {
|
|
26482
26814
|
let raw = "{}";
|
|
@@ -26532,61 +26864,61 @@ function buildTierCommand(opts) {
|
|
|
26532
26864
|
const lines = [];
|
|
26533
26865
|
if (!tiers?.enabled) {
|
|
26534
26866
|
lines.push(
|
|
26535
|
-
`${
|
|
26536
|
-
|
|
26867
|
+
`${color54.amber("Model tiers are off.")} Turn them on with ${color54.dim("/tier on")}, then define levels:`,
|
|
26868
|
+
color54.dim(" /tier set budget cheap-profile \xB7 /tier budget budget 0.25"),
|
|
26537
26869
|
""
|
|
26538
26870
|
);
|
|
26539
26871
|
}
|
|
26540
26872
|
const ids = tiers?.enabled ? listTierIds(config) : Object.keys(tiers?.levels ?? {});
|
|
26541
26873
|
if (ids.length === 0) {
|
|
26542
|
-
lines.push(
|
|
26874
|
+
lines.push(color54.dim(" (no levels configured)"));
|
|
26543
26875
|
} else {
|
|
26544
|
-
lines.push(
|
|
26876
|
+
lines.push(color54.bold(" Levels"));
|
|
26545
26877
|
for (const id of ids) {
|
|
26546
26878
|
const level = tiers?.levels?.[id];
|
|
26547
26879
|
const resolved = tiers?.enabled ? resolveTier(config, { tier: id }) : void 0;
|
|
26548
|
-
const target = resolved?.model ? `${resolved.provider ?? config.provider}/${resolved.model}` :
|
|
26880
|
+
const target = resolved?.model ? `${resolved.provider ?? config.provider}/${resolved.model}` : color54.dim(level?.fallbackProfile ? `profile: ${level.fallbackProfile}` : "(empty)");
|
|
26549
26881
|
const budget = [
|
|
26550
26882
|
level?.maxCostUsd !== void 0 ? `$${level.maxCostUsd}` : "",
|
|
26551
26883
|
level?.maxIterations !== void 0 ? `${level.maxIterations} iters` : "",
|
|
26552
26884
|
level?.maxToolCalls !== void 0 ? `${level.maxToolCalls} tools` : ""
|
|
26553
26885
|
].filter(Boolean);
|
|
26554
26886
|
lines.push(
|
|
26555
|
-
` ${
|
|
26887
|
+
` ${color54.cyan(id)}: ${target}${budget.length ? color54.dim(` [${budget.join(" \xB7 ")}]`) : ""}`
|
|
26556
26888
|
);
|
|
26557
26889
|
}
|
|
26558
26890
|
}
|
|
26559
26891
|
const routing = tiers?.routing ?? {};
|
|
26560
|
-
lines.push("",
|
|
26892
|
+
lines.push("", color54.bold(" Routing"));
|
|
26561
26893
|
const routingKeys = Object.keys(routing);
|
|
26562
26894
|
if (routingKeys.length === 0) {
|
|
26563
26895
|
lines.push(
|
|
26564
|
-
|
|
26896
|
+
color54.dim(` (none \u2014 everything uses the default tier: ${tiers?.default ?? "standard"})`)
|
|
26565
26897
|
);
|
|
26566
26898
|
} else {
|
|
26567
|
-
for (const key of routingKeys) lines.push(` ${key} \u2192 ${
|
|
26899
|
+
for (const key of routingKeys) lines.push(` ${key} \u2192 ${color54.cyan(routing[key] ?? "")}`);
|
|
26568
26900
|
}
|
|
26569
26901
|
const policy = leaderTierPolicy(config);
|
|
26570
26902
|
lines.push(
|
|
26571
26903
|
"",
|
|
26572
|
-
|
|
26573
|
-
` mode: ${
|
|
26574
|
-
|
|
26904
|
+
color54.bold(" Leader self-switching"),
|
|
26905
|
+
` mode: ${color54.cyan(policy.mode)}${policy.mode === "propose" ? color54.dim(" (asks before switching)") : ""}`,
|
|
26906
|
+
color54.dim(
|
|
26575
26907
|
` dwell ${policy.dwellTurns} turn(s) \xB7 min saving $${policy.minSavingsUsd} \xB7 context cap ${Math.round(policy.maxContextFillForSwitch * 100)}%` + (policy.maxTier ? ` \xB7 ceiling ${policy.maxTier}` : "")
|
|
26576
26908
|
),
|
|
26577
26909
|
"",
|
|
26578
|
-
|
|
26910
|
+
color54.dim(" /tier help for the full command list")
|
|
26579
26911
|
);
|
|
26580
26912
|
return lines.join("\n");
|
|
26581
26913
|
}
|
|
26582
26914
|
const help = [
|
|
26583
|
-
|
|
26915
|
+
color54.bold("/tier \u2014 deterministic cost levels for models"),
|
|
26584
26916
|
"",
|
|
26585
26917
|
"A tier binds a fallback profile (which models), a budget (how much it may spend)",
|
|
26586
26918
|
"and a runtime setting (how hard it thinks) under one name, then routes work to it",
|
|
26587
26919
|
"by role or phase. Subagents, Kanban dispatch and the leader all read the same table.",
|
|
26588
26920
|
"",
|
|
26589
|
-
|
|
26921
|
+
color54.bold(" Levels"),
|
|
26590
26922
|
" /tier show everything",
|
|
26591
26923
|
" /tier on | off enable or disable the whole layer",
|
|
26592
26924
|
" /tier set <tier> <profile> point a level at a fallback profile",
|
|
@@ -26594,17 +26926,17 @@ function buildTierCommand(opts) {
|
|
|
26594
26926
|
" set the spend budget for a level",
|
|
26595
26927
|
" /tier remove <tier> delete a level",
|
|
26596
26928
|
"",
|
|
26597
|
-
|
|
26929
|
+
color54.bold(" Routing"),
|
|
26598
26930
|
" /tier route <role|phase|*> <tier> route work to a level",
|
|
26599
26931
|
" /tier unroute <role|phase|*> drop a routing rule",
|
|
26600
26932
|
" /tier default <tier> tier used when nothing matches",
|
|
26601
26933
|
"",
|
|
26602
|
-
|
|
26934
|
+
color54.bold(" Leader"),
|
|
26603
26935
|
` /tier leader <${LEADER_MODES.join("|")}> how much authority the leader has over its own tier`,
|
|
26604
26936
|
" /tier leader dwell <turns> minimum turns between switches",
|
|
26605
26937
|
" /tier leader ceiling <tier|none> highest tier the leader may pick alone",
|
|
26606
26938
|
"",
|
|
26607
|
-
|
|
26939
|
+
color54.dim(" Levels are ordered by declaration: the first is the cheapest rung.")
|
|
26608
26940
|
].join("\n");
|
|
26609
26941
|
return {
|
|
26610
26942
|
name: "tier",
|
|
@@ -26616,7 +26948,7 @@ function buildTierCommand(opts) {
|
|
|
26616
26948
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
26617
26949
|
const sub = (parts[0] ?? "").toLowerCase();
|
|
26618
26950
|
if (sub === "help" || sub === "--help") return { message: this.help ?? "" };
|
|
26619
|
-
if (!opts.paths) return { message: `${
|
|
26951
|
+
if (!opts.paths) return { message: `${color54.red("Error")} config paths not available.` };
|
|
26620
26952
|
if (!sub) return { message: currentView() };
|
|
26621
26953
|
const config = opts.configStore.get();
|
|
26622
26954
|
const globalConfigPath = activeProfileConfigPath(opts.paths, config);
|
|
@@ -26635,20 +26967,20 @@ function buildTierCommand(opts) {
|
|
|
26635
26967
|
tiers["enabled"] = enabled;
|
|
26636
26968
|
});
|
|
26637
26969
|
return {
|
|
26638
|
-
message: `${
|
|
26639
|
-
${
|
|
26970
|
+
message: `${color54.green("\u2713")} model tiers ${enabled ? color54.green("on") : color54.dim("off")}` + (enabled && Object.keys(config.modelTiers?.levels ?? {}).length === 0 ? `
|
|
26971
|
+
${color54.dim("No levels yet \u2014 try /tier set budget <profile>")}` : "")
|
|
26640
26972
|
};
|
|
26641
26973
|
}
|
|
26642
26974
|
if (sub === "set") {
|
|
26643
26975
|
const tier = parts[1];
|
|
26644
26976
|
const profile = parts[2];
|
|
26645
26977
|
if (!tier || !profile) {
|
|
26646
|
-
return { message: `${
|
|
26978
|
+
return { message: `${color54.amber("Usage:")} /tier set <tier> <fallback-profile>` };
|
|
26647
26979
|
}
|
|
26648
26980
|
if (!config.fallbackProfiles?.[profile]) {
|
|
26649
26981
|
const known = Object.keys(config.fallbackProfiles ?? {});
|
|
26650
26982
|
return {
|
|
26651
|
-
message: `${
|
|
26983
|
+
message: `${color54.red("Unknown fallback profile")} "${profile}"` + (known.length ? `. Known: ${known.join(", ")}` : `. Create one first: ${color54.dim("/fallback profile set <name> a,b")}`)
|
|
26652
26984
|
};
|
|
26653
26985
|
}
|
|
26654
26986
|
await persist((tiers) => {
|
|
@@ -26656,27 +26988,27 @@ function buildTierCommand(opts) {
|
|
|
26656
26988
|
levels[tier] = { ...levels[tier] ?? {}, fallbackProfile: profile };
|
|
26657
26989
|
});
|
|
26658
26990
|
return {
|
|
26659
|
-
message: `${
|
|
26991
|
+
message: `${color54.green("\u2713")} tier ${color54.cyan(tier)} \u2192 profile ${color54.cyan(profile)}`
|
|
26660
26992
|
};
|
|
26661
26993
|
}
|
|
26662
26994
|
if (sub === "budget") {
|
|
26663
26995
|
const tier = parts[1];
|
|
26664
26996
|
if (!tier) {
|
|
26665
26997
|
return {
|
|
26666
|
-
message: `${
|
|
26998
|
+
message: `${color54.amber("Usage:")} /tier budget <tier> <maxCostUsd> [maxIterations] [maxToolCalls]`
|
|
26667
26999
|
};
|
|
26668
27000
|
}
|
|
26669
27001
|
const usd = Number.parseFloat(parts[2] ?? "");
|
|
26670
27002
|
if (!Number.isFinite(usd) || usd < 0) {
|
|
26671
|
-
return { message: `${
|
|
27003
|
+
return { message: `${color54.red("Invalid")} maxCostUsd: "${parts[2] ?? ""}"` };
|
|
26672
27004
|
}
|
|
26673
27005
|
const iters = parts[3] !== void 0 ? Number.parseInt(parts[3], 10) : void 0;
|
|
26674
27006
|
if (iters !== void 0 && (!Number.isFinite(iters) || iters < 0)) {
|
|
26675
|
-
return { message: `${
|
|
27007
|
+
return { message: `${color54.red("Invalid")} maxIterations: "${parts[3]}"` };
|
|
26676
27008
|
}
|
|
26677
27009
|
const tools = parts[4] !== void 0 ? Number.parseInt(parts[4], 10) : void 0;
|
|
26678
27010
|
if (tools !== void 0 && (!Number.isFinite(tools) || tools < 0)) {
|
|
26679
|
-
return { message: `${
|
|
27011
|
+
return { message: `${color54.red("Invalid")} maxToolCalls: "${parts[4]}"` };
|
|
26680
27012
|
}
|
|
26681
27013
|
await persist((tiers) => {
|
|
26682
27014
|
const levels = levelsOf(tiers);
|
|
@@ -26688,14 +27020,14 @@ function buildTierCommand(opts) {
|
|
|
26688
27020
|
};
|
|
26689
27021
|
});
|
|
26690
27022
|
return {
|
|
26691
|
-
message: `${
|
|
27023
|
+
message: `${color54.green("\u2713")} tier ${color54.cyan(tier)} budget \u2192 $${usd}` + (iters !== void 0 && Number.isFinite(iters) ? ` \xB7 ${iters} iters` : "") + (tools !== void 0 && Number.isFinite(tools) ? ` \xB7 ${tools} tools` : "")
|
|
26692
27024
|
};
|
|
26693
27025
|
}
|
|
26694
27026
|
if (sub === "remove" || sub === "rm") {
|
|
26695
27027
|
const tier = parts[1];
|
|
26696
|
-
if (!tier) return { message: `${
|
|
27028
|
+
if (!tier) return { message: `${color54.amber("Usage:")} /tier remove <tier>` };
|
|
26697
27029
|
if (!config.modelTiers?.levels?.[tier]) {
|
|
26698
|
-
return { message: `${
|
|
27030
|
+
return { message: `${color54.red("No such tier")}: "${tier}"` };
|
|
26699
27031
|
}
|
|
26700
27032
|
await persist((tiers) => {
|
|
26701
27033
|
const levels = levelsOf(tiers);
|
|
@@ -26705,48 +27037,48 @@ function buildTierCommand(opts) {
|
|
|
26705
27037
|
if (value === tier) delete routing[key];
|
|
26706
27038
|
}
|
|
26707
27039
|
});
|
|
26708
|
-
return { message: `${
|
|
27040
|
+
return { message: `${color54.green("\u2713")} tier ${color54.cyan(tier)} removed` };
|
|
26709
27041
|
}
|
|
26710
27042
|
if (sub === "route") {
|
|
26711
27043
|
const key = parts[1];
|
|
26712
27044
|
const tier = parts[2];
|
|
26713
27045
|
if (!key || !tier) {
|
|
26714
|
-
return { message: `${
|
|
27046
|
+
return { message: `${color54.amber("Usage:")} /tier route <role|phase|*> <tier>` };
|
|
26715
27047
|
}
|
|
26716
27048
|
if (!config.modelTiers?.levels?.[tier]) {
|
|
26717
27049
|
const known = Object.keys(config.modelTiers?.levels ?? {});
|
|
26718
27050
|
return {
|
|
26719
|
-
message: `${
|
|
27051
|
+
message: `${color54.red("Unknown tier")} "${tier}"` + (known.length ? `. Known: ${known.join(", ")}` : ". Define one with /tier set.")
|
|
26720
27052
|
};
|
|
26721
27053
|
}
|
|
26722
27054
|
await persist((tiers) => {
|
|
26723
27055
|
routingOf(tiers)[key] = tier;
|
|
26724
27056
|
});
|
|
26725
27057
|
return {
|
|
26726
|
-
message: `${
|
|
27058
|
+
message: `${color54.green("\u2713")} ${color54.cyan(key)} \u2192 tier ${color54.cyan(tier)}`
|
|
26727
27059
|
};
|
|
26728
27060
|
}
|
|
26729
27061
|
if (sub === "unroute") {
|
|
26730
27062
|
const key = parts[1];
|
|
26731
|
-
if (!key) return { message: `${
|
|
27063
|
+
if (!key) return { message: `${color54.amber("Usage:")} /tier unroute <role|phase|*>` };
|
|
26732
27064
|
if (config.modelTiers?.routing?.[key] === void 0) {
|
|
26733
|
-
return { message: `${
|
|
27065
|
+
return { message: `${color54.red("No routing rule for")} "${key}"` };
|
|
26734
27066
|
}
|
|
26735
27067
|
await persist((tiers) => {
|
|
26736
27068
|
delete routingOf(tiers)[key];
|
|
26737
27069
|
});
|
|
26738
|
-
return { message: `${
|
|
27070
|
+
return { message: `${color54.green("\u2713")} routing rule for ${color54.cyan(key)} removed` };
|
|
26739
27071
|
}
|
|
26740
27072
|
if (sub === "default") {
|
|
26741
27073
|
const tier = parts[1];
|
|
26742
|
-
if (!tier) return { message: `${
|
|
27074
|
+
if (!tier) return { message: `${color54.amber("Usage:")} /tier default <tier>` };
|
|
26743
27075
|
if (!config.modelTiers?.levels?.[tier]) {
|
|
26744
|
-
return { message: `${
|
|
27076
|
+
return { message: `${color54.red("Unknown tier")} "${tier}".` };
|
|
26745
27077
|
}
|
|
26746
27078
|
await persist((tiers) => {
|
|
26747
27079
|
tiers["default"] = tier;
|
|
26748
27080
|
});
|
|
26749
|
-
return { message: `${
|
|
27081
|
+
return { message: `${color54.green("\u2713")} default tier \u2192 ${color54.cyan(tier)}` };
|
|
26750
27082
|
}
|
|
26751
27083
|
if (sub === "leader") {
|
|
26752
27084
|
const action = (parts[1] ?? "").toLowerCase();
|
|
@@ -26757,31 +27089,31 @@ function buildTierCommand(opts) {
|
|
|
26757
27089
|
tiers["leader"] = leader;
|
|
26758
27090
|
});
|
|
26759
27091
|
const note = action === "auto" ? `
|
|
26760
|
-
${
|
|
26761
|
-
${
|
|
27092
|
+
${color54.amber("The leader may now change its own model without asking.")} ` + color54.dim("Guard rails (dwell, context window, ceiling, break-even) still apply.") : action === "off" ? `
|
|
27093
|
+
${color54.dim("Tiers still route subagents and Kanban dispatch.")}` : "";
|
|
26762
27094
|
return {
|
|
26763
|
-
message: `${
|
|
27095
|
+
message: `${color54.green("\u2713")} leader tier mode \u2192 ${color54.cyan(action)}${note}`
|
|
26764
27096
|
};
|
|
26765
27097
|
}
|
|
26766
27098
|
if (action === "dwell") {
|
|
26767
27099
|
const turns = Number.parseInt(parts[2] ?? "", 10);
|
|
26768
27100
|
if (!Number.isFinite(turns) || turns < 0) {
|
|
26769
|
-
return { message: `${
|
|
27101
|
+
return { message: `${color54.amber("Usage:")} /tier leader dwell <turns>` };
|
|
26770
27102
|
}
|
|
26771
27103
|
await persist((tiers) => {
|
|
26772
27104
|
const leader = tiers["leader"] ?? {};
|
|
26773
27105
|
leader["dwellTurns"] = turns;
|
|
26774
27106
|
tiers["leader"] = leader;
|
|
26775
27107
|
});
|
|
26776
|
-
return { message: `${
|
|
27108
|
+
return { message: `${color54.green("\u2713")} leader dwell \u2192 ${turns} turn(s)` };
|
|
26777
27109
|
}
|
|
26778
27110
|
if (action === "ceiling") {
|
|
26779
27111
|
const tier = parts[2];
|
|
26780
27112
|
if (!tier) {
|
|
26781
|
-
return { message: `${
|
|
27113
|
+
return { message: `${color54.amber("Usage:")} /tier leader ceiling <tier|none>` };
|
|
26782
27114
|
}
|
|
26783
27115
|
if (tier !== "none" && !config.modelTiers?.levels?.[tier]) {
|
|
26784
|
-
return { message: `${
|
|
27116
|
+
return { message: `${color54.red("Unknown tier")} "${tier}".` };
|
|
26785
27117
|
}
|
|
26786
27118
|
await persist((tiers) => {
|
|
26787
27119
|
const leader = tiers["leader"] ?? {};
|
|
@@ -26790,18 +27122,18 @@ function buildTierCommand(opts) {
|
|
|
26790
27122
|
tiers["leader"] = leader;
|
|
26791
27123
|
});
|
|
26792
27124
|
return {
|
|
26793
|
-
message: `${
|
|
27125
|
+
message: `${color54.green("\u2713")} leader ceiling \u2192 ${tier === "none" ? color54.dim("none") : color54.cyan(tier)}`
|
|
26794
27126
|
};
|
|
26795
27127
|
}
|
|
26796
27128
|
return {
|
|
26797
|
-
message: `${
|
|
27129
|
+
message: `${color54.amber("Usage:")} /tier leader <${LEADER_MODES.join("|")}> | dwell <turns> | ceiling <tier|none>`
|
|
26798
27130
|
};
|
|
26799
27131
|
}
|
|
26800
27132
|
return {
|
|
26801
|
-
message: `${
|
|
27133
|
+
message: `${color54.red("Unknown subcommand")} "${sub}". Try ${color54.dim("/tier")} or ${color54.dim("/tier help")}.`
|
|
26802
27134
|
};
|
|
26803
27135
|
} catch (err) {
|
|
26804
|
-
return { message: `${
|
|
27136
|
+
return { message: `${color54.red("tier error")}: ${toErrorMessage25(err)}` };
|
|
26805
27137
|
}
|
|
26806
27138
|
}
|
|
26807
27139
|
};
|
|
@@ -27048,7 +27380,7 @@ ${lines.join("\n")}` };
|
|
|
27048
27380
|
// src/slash-commands/hq.ts
|
|
27049
27381
|
import { readHqRuntimeFileSync, resolveHqConfig, resolveHqDataDir } from "@wrongstack/core/hq";
|
|
27050
27382
|
import { noOpVault as noOpVault9 } from "@wrongstack/core/security";
|
|
27051
|
-
import { color as
|
|
27383
|
+
import { color as color55 } from "@wrongstack/core/utils";
|
|
27052
27384
|
function maskToken(t) {
|
|
27053
27385
|
if (t.length <= 10) return `${t.slice(0, 2)}\u2026(${t.length})`;
|
|
27054
27386
|
return `${t.slice(0, 6)}\u2026${t.slice(-4)} (${t.length} chars)`;
|
|
@@ -27059,12 +27391,12 @@ async function probeHq(url) {
|
|
|
27059
27391
|
const timer = setTimeout(() => ctrl.abort(), 2500);
|
|
27060
27392
|
const res = await fetch(url, { signal: ctrl.signal, redirect: "manual" }).catch(() => null);
|
|
27061
27393
|
clearTimeout(timer);
|
|
27062
|
-
if (!res) return
|
|
27063
|
-
if (res.ok) return
|
|
27064
|
-
if (res.status === 401) return
|
|
27065
|
-
return
|
|
27394
|
+
if (!res) return color55.red("unreachable");
|
|
27395
|
+
if (res.ok) return color55.green("reachable");
|
|
27396
|
+
if (res.status === 401) return color55.green("reachable") + color55.dim(" (token required)");
|
|
27397
|
+
return color55.amber(`reachable (HTTP ${res.status})`);
|
|
27066
27398
|
} catch {
|
|
27067
|
-
return
|
|
27399
|
+
return color55.red("unreachable");
|
|
27068
27400
|
}
|
|
27069
27401
|
}
|
|
27070
27402
|
function buildHqCommand(opts) {
|
|
@@ -27098,7 +27430,7 @@ function buildHqCommand(opts) {
|
|
|
27098
27430
|
const { cmd, rest } = parseSubcommand(args);
|
|
27099
27431
|
const sub = cmd;
|
|
27100
27432
|
if (!opts.configStore || !opts.paths) {
|
|
27101
|
-
return { message: `${
|
|
27433
|
+
return { message: `${color55.red("\u2717")} HQ config is unavailable in this surface.` };
|
|
27102
27434
|
}
|
|
27103
27435
|
const persistDeps = {
|
|
27104
27436
|
configStore: opts.configStore,
|
|
@@ -27112,14 +27444,14 @@ function buildHqCommand(opts) {
|
|
|
27112
27444
|
const url = (rest[0] ?? "").trim();
|
|
27113
27445
|
const token = rest.slice(1).join(" ").trim();
|
|
27114
27446
|
if (!url) {
|
|
27115
|
-
return { message: `${
|
|
27447
|
+
return { message: `${color55.amber("Usage:")} /hq set <http://host:3499> [client-token]` };
|
|
27116
27448
|
}
|
|
27117
27449
|
try {
|
|
27118
27450
|
const parsed = new URL(url);
|
|
27119
27451
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("proto");
|
|
27120
27452
|
} catch {
|
|
27121
27453
|
return {
|
|
27122
|
-
message: `${
|
|
27454
|
+
message: `${color55.red("Invalid URL:")} ${url} ${color55.dim("(expected http://host:3499)")}`
|
|
27123
27455
|
};
|
|
27124
27456
|
}
|
|
27125
27457
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -27131,16 +27463,16 @@ function buildHqCommand(opts) {
|
|
|
27131
27463
|
});
|
|
27132
27464
|
const reach = await probeHq(url);
|
|
27133
27465
|
const tokLine = token ? `
|
|
27134
|
-
token: ${
|
|
27466
|
+
token: ${color55.dim(maskToken(token))}` : "";
|
|
27135
27467
|
return {
|
|
27136
|
-
message: `${
|
|
27468
|
+
message: `${color55.green("\u2713")} HQ set \u2192 ${color55.cyan(url)}${tokLine}
|
|
27137
27469
|
status: ${reach}
|
|
27138
|
-
${
|
|
27470
|
+
${color55.dim("Connects on the next session start.")}`
|
|
27139
27471
|
};
|
|
27140
27472
|
}
|
|
27141
27473
|
if (sub === "token") {
|
|
27142
27474
|
const token = rest.join(" ").trim();
|
|
27143
|
-
if (!token) return { message: `${
|
|
27475
|
+
if (!token) return { message: `${color55.amber("Usage:")} /hq token <client-token>` };
|
|
27144
27476
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
27145
27477
|
const hq = cfg.hq ?? {};
|
|
27146
27478
|
hq.token = token;
|
|
@@ -27148,14 +27480,14 @@ function buildHqCommand(opts) {
|
|
|
27148
27480
|
cfg.hq = hq;
|
|
27149
27481
|
});
|
|
27150
27482
|
return {
|
|
27151
|
-
message: `${
|
|
27483
|
+
message: `${color55.green("\u2713")} HQ client token saved ${color55.dim(maskToken(token))}`
|
|
27152
27484
|
};
|
|
27153
27485
|
}
|
|
27154
27486
|
if (sub === "raw") {
|
|
27155
27487
|
const mode = (rest[0] ?? "").trim().toLowerCase();
|
|
27156
27488
|
if (mode !== "on" && mode !== "off") {
|
|
27157
27489
|
return {
|
|
27158
|
-
message: `${
|
|
27490
|
+
message: `${color55.amber("Usage:")} /hq raw on|off ${color55.dim("(publish raw chat/tool content to HQ)")}`
|
|
27159
27491
|
};
|
|
27160
27492
|
}
|
|
27161
27493
|
const on = mode === "on";
|
|
@@ -27165,8 +27497,8 @@ function buildHqCommand(opts) {
|
|
|
27165
27497
|
cfg.hq = hq;
|
|
27166
27498
|
});
|
|
27167
27499
|
return {
|
|
27168
|
-
message: `${
|
|
27169
|
-
${
|
|
27500
|
+
message: `${color55.green("\u2713")} HQ raw content \u2192 ${on ? color55.amber("on (unredacted)") : color55.dim("off (redacted)")}
|
|
27501
|
+
${color55.dim("Applies to sessions started after this change. Only enable for HQ servers you trust.")}`
|
|
27170
27502
|
};
|
|
27171
27503
|
}
|
|
27172
27504
|
if (sub === "on" || sub === "off") {
|
|
@@ -27177,29 +27509,29 @@ function buildHqCommand(opts) {
|
|
|
27177
27509
|
cfg.hq = hq;
|
|
27178
27510
|
});
|
|
27179
27511
|
return {
|
|
27180
|
-
message: `${
|
|
27512
|
+
message: `${color55.green("\u2713")} HQ publishing \u2192 ${on ? color55.cyan("on") : color55.dim("off")}`
|
|
27181
27513
|
};
|
|
27182
27514
|
}
|
|
27183
27515
|
if (sub === "clear") {
|
|
27184
27516
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
27185
27517
|
delete cfg.hq;
|
|
27186
27518
|
});
|
|
27187
|
-
return { message: `${
|
|
27519
|
+
return { message: `${color55.green("\u2713")} HQ configuration cleared.` };
|
|
27188
27520
|
}
|
|
27189
27521
|
if (sub === "" || sub === "status") {
|
|
27190
27522
|
const dataDir = resolveHqDataDir(currentHq?.dataDir);
|
|
27191
27523
|
const runtime = readHqRuntimeFileSync(dataDir);
|
|
27192
27524
|
const resolved = resolveHqConfig({ config: currentHq });
|
|
27193
|
-
const lines = [`${
|
|
27525
|
+
const lines = [`${color55.bold("\u{1F4CB} WrongStack HQ \u2014 connection")}`, ""];
|
|
27194
27526
|
if (!resolved) {
|
|
27195
27527
|
lines.push(
|
|
27196
|
-
` ${
|
|
27528
|
+
` ${color55.dim("Not configured.")} Use ${color55.cyan("/hq set <url> [token]")} to connect,`
|
|
27197
27529
|
);
|
|
27198
|
-
lines.push(` or run ${
|
|
27530
|
+
lines.push(` or run ${color55.cyan("wstack --hq")} locally (auto-discovered).`);
|
|
27199
27531
|
if (runtime) {
|
|
27200
27532
|
lines.push("");
|
|
27201
27533
|
lines.push(
|
|
27202
|
-
` ${
|
|
27534
|
+
` ${color55.green("A local HQ is running")} at ${color55.cyan(runtime.url)} ${color55.dim("(start a new session to attach)")}`
|
|
27203
27535
|
);
|
|
27204
27536
|
}
|
|
27205
27537
|
const message = lines.join("\n");
|
|
@@ -27207,35 +27539,35 @@ function buildHqCommand(opts) {
|
|
|
27207
27539
|
}
|
|
27208
27540
|
if (resolved.discover && !runtime) {
|
|
27209
27541
|
lines.push(
|
|
27210
|
-
` mode: ${
|
|
27542
|
+
` mode: ${color55.cyan("auto-discovery")} ${color55.dim("(no local HQ running yet)")}`
|
|
27211
27543
|
);
|
|
27212
27544
|
lines.push(
|
|
27213
|
-
` ${
|
|
27545
|
+
` ${color55.dim("This session will attach automatically when `wstack --hq` starts")}`
|
|
27214
27546
|
);
|
|
27215
|
-
lines.push(` ${
|
|
27216
|
-
lines.push(` ${
|
|
27547
|
+
lines.push(` ${color55.dim(`on this machine (watching ${dataDir}).`)}`);
|
|
27548
|
+
lines.push(` ${color55.dim("Disable with WRONGSTACK_HQ_ENABLED=0 or /hq off.")}`);
|
|
27217
27549
|
return { message: lines.join("\n") };
|
|
27218
27550
|
}
|
|
27219
27551
|
const source = process.env["WRONGSTACK_HQ_URL"] ? "WRONGSTACK_HQ_URL env" : currentHq?.url ? "config.json" : runtime ? `local HQ marker (pid ${runtime.pid ?? "?"})` : "default";
|
|
27220
|
-
lines.push(` url: ${
|
|
27552
|
+
lines.push(` url: ${color55.cyan(resolved.url)}`);
|
|
27221
27553
|
lines.push(
|
|
27222
|
-
` enabled: ${resolved.enabled === false ?
|
|
27554
|
+
` enabled: ${resolved.enabled === false ? color55.dim("false") : color55.green("true")}`
|
|
27223
27555
|
);
|
|
27224
|
-
if (resolved.discover) lines.push(` mode: ${
|
|
27225
|
-
lines.push(` source: ${
|
|
27556
|
+
if (resolved.discover) lines.push(` mode: ${color55.cyan("auto-discovery")}`);
|
|
27557
|
+
lines.push(` source: ${color55.dim(source)}`);
|
|
27226
27558
|
lines.push(
|
|
27227
|
-
` token: ${resolved.token ?
|
|
27559
|
+
` token: ${resolved.token ? color55.dim(maskToken(resolved.token)) : color55.dim("none (open mode)")}`
|
|
27228
27560
|
);
|
|
27229
27561
|
lines.push(
|
|
27230
|
-
` content: ${resolved.rawContent === true ?
|
|
27562
|
+
` content: ${resolved.rawContent === true ? color55.amber("raw (unredacted)") : color55.dim("redacted \u2014 explicitly disabled; enable with /hq raw on")}`
|
|
27231
27563
|
);
|
|
27232
|
-
if (resolved.projectAlias) lines.push(` alias: ${
|
|
27564
|
+
if (resolved.projectAlias) lines.push(` alias: ${color55.cyan(resolved.projectAlias)}`);
|
|
27233
27565
|
lines.push(` status: ${await probeHq(resolved.url)}`);
|
|
27234
27566
|
return { message: lines.join("\n") };
|
|
27235
27567
|
}
|
|
27236
27568
|
return {
|
|
27237
|
-
message: `${
|
|
27238
|
-
${
|
|
27569
|
+
message: `${color55.red("Unknown subcommand:")} ${sub}
|
|
27570
|
+
${color55.dim("Try /hq, /hq set <url> [token], /hq raw on|off, /hq on|off, /hq clear, or /help hq")}`
|
|
27239
27571
|
};
|
|
27240
27572
|
}
|
|
27241
27573
|
};
|
|
@@ -27290,7 +27622,7 @@ import * as fs18 from "node:fs/promises";
|
|
|
27290
27622
|
import { createRequire } from "node:module";
|
|
27291
27623
|
import * as path18 from "node:path";
|
|
27292
27624
|
import {
|
|
27293
|
-
color as
|
|
27625
|
+
color as color56,
|
|
27294
27626
|
ensureProjectGitignore,
|
|
27295
27627
|
ensureProjectIdentity as ensureProjectIdentity2,
|
|
27296
27628
|
projectIdentityPath,
|
|
@@ -27423,17 +27755,17 @@ async function projectIdentityCommand(opts, ctx, action, confirmed) {
|
|
|
27423
27755
|
if (action === "show") {
|
|
27424
27756
|
const identity = await readProjectIdentity(root);
|
|
27425
27757
|
return identity ? {
|
|
27426
|
-
message: `${
|
|
27427
|
-
${
|
|
27428
|
-
} : { message: `No committed project identity. Run ${
|
|
27758
|
+
message: `${color56.bold("Project ID:")} ${color56.cyan(identity.projectId)}
|
|
27759
|
+
${color56.dim(filePath)}`
|
|
27760
|
+
} : { message: `No committed project identity. Run ${color56.cyan("/project init")}.` };
|
|
27429
27761
|
}
|
|
27430
27762
|
if (action === "init") {
|
|
27431
27763
|
const result2 = await ensureProjectIdentity2(root);
|
|
27432
27764
|
await ensureProjectGitignore(root);
|
|
27433
27765
|
return {
|
|
27434
|
-
message: result2.created ? `${
|
|
27435
|
-
${
|
|
27436
|
-
${
|
|
27766
|
+
message: result2.created ? `${color56.green("Created")} ${filePath}
|
|
27767
|
+
${color56.cyan(result2.identity.projectId)}
|
|
27768
|
+
${color56.dim("Commit this file so every clone and machine shares the same HQ project.")}` : `${color56.dim("Project identity already exists:")} ${color56.cyan(result2.identity.projectId)}`
|
|
27437
27769
|
};
|
|
27438
27770
|
}
|
|
27439
27771
|
if (!confirmed && opts.confirm) {
|
|
@@ -27448,17 +27780,17 @@ ${color55.dim("Commit this file so every clone and machine shares the same HQ pr
|
|
|
27448
27780
|
}
|
|
27449
27781
|
if (!confirmed) {
|
|
27450
27782
|
return {
|
|
27451
|
-
message: `Rekey requires confirmation. Pass ${
|
|
27783
|
+
message: `Rekey requires confirmation. Pass ${color56.cyan("--yes")} or ${color56.cyan("-y")}.`
|
|
27452
27784
|
};
|
|
27453
27785
|
}
|
|
27454
27786
|
const result = await rekeyProjectIdentity(root);
|
|
27455
27787
|
await ensureProjectGitignore(root);
|
|
27456
27788
|
return {
|
|
27457
27789
|
message: [
|
|
27458
|
-
result.previous ?
|
|
27459
|
-
`${
|
|
27460
|
-
|
|
27461
|
-
|
|
27790
|
+
result.previous ? color56.dim(`Previous: ${result.previous.projectId}`) : color56.dim("Previous: none"),
|
|
27791
|
+
`${color56.green("New project ID:")} ${color56.cyan(result.identity.projectId)}`,
|
|
27792
|
+
color56.dim(`Commit ${filePath} to make this fork independent on every machine.`),
|
|
27793
|
+
color56.dim("Restart WrongStack before publishing HQ or Kanban updates under the new ID.")
|
|
27462
27794
|
].join("\n")
|
|
27463
27795
|
};
|
|
27464
27796
|
}
|
|
@@ -27467,7 +27799,7 @@ async function listProjectsCommand(opts, ctx) {
|
|
|
27467
27799
|
const currentRoot = ctx?.projectRoot;
|
|
27468
27800
|
if (manifest.projects.length === 0) {
|
|
27469
27801
|
return {
|
|
27470
|
-
message:
|
|
27802
|
+
message: color56.dim("No projects registered. Add one: /project add <path> [name]")
|
|
27471
27803
|
};
|
|
27472
27804
|
}
|
|
27473
27805
|
const sorted = [...manifest.projects].sort((a, b) => {
|
|
@@ -27479,19 +27811,19 @@ async function listProjectsCommand(opts, ctx) {
|
|
|
27479
27811
|
const lines = [`Projects (${sorted.length}) registered in projects.json:`, ""];
|
|
27480
27812
|
for (const p of sorted) {
|
|
27481
27813
|
const isCurrent = p.root === currentRoot;
|
|
27482
|
-
const marker = isCurrent ?
|
|
27483
|
-
const name = isCurrent ?
|
|
27484
|
-
const slug =
|
|
27485
|
-
const last =
|
|
27814
|
+
const marker = isCurrent ? color56.green("\u25CF") : color56.dim("\u25CB");
|
|
27815
|
+
const name = isCurrent ? color56.bold(p.name) : p.name;
|
|
27816
|
+
const slug = color56.dim(`[${p.slug}]`);
|
|
27817
|
+
const last = color56.dim(fmtLastSeen(p.lastSeen));
|
|
27486
27818
|
lines.push(` ${marker} ${name} ${slug} ${last}`);
|
|
27487
27819
|
lines.push(` ${p.root}`);
|
|
27488
27820
|
if (isCurrent) {
|
|
27489
|
-
lines.push(` ${
|
|
27821
|
+
lines.push(` ${color56.green("\u2190 active session")}`);
|
|
27490
27822
|
}
|
|
27491
27823
|
lines.push("");
|
|
27492
27824
|
}
|
|
27493
27825
|
lines.push(
|
|
27494
|
-
|
|
27826
|
+
color56.dim(
|
|
27495
27827
|
"Commands: add <path> [name] | rename <slug> <name> | remove <slug> | switch [dir] (no args = picker)"
|
|
27496
27828
|
)
|
|
27497
27829
|
);
|
|
@@ -27502,17 +27834,17 @@ async function addProjectCommand(opts, ctx, targetPath, displayName) {
|
|
|
27502
27834
|
try {
|
|
27503
27835
|
await fs18.access(resolved);
|
|
27504
27836
|
} catch {
|
|
27505
|
-
return { message:
|
|
27837
|
+
return { message: color56.red(`Directory not found: ${resolved}`) };
|
|
27506
27838
|
}
|
|
27507
27839
|
const stat6 = await fs18.stat(resolved);
|
|
27508
27840
|
if (!stat6.isDirectory()) {
|
|
27509
|
-
return { message:
|
|
27841
|
+
return { message: color56.red(`Not a directory: ${resolved}`) };
|
|
27510
27842
|
}
|
|
27511
27843
|
const manifest = await loadManifest(opts.paths?.globalConfig);
|
|
27512
27844
|
const existing = manifest.projects.find((p) => p.root === resolved);
|
|
27513
27845
|
if (existing) {
|
|
27514
27846
|
return {
|
|
27515
|
-
message:
|
|
27847
|
+
message: color56.yellow(`Project already registered: "${existing.name}" (${existing.slug})`)
|
|
27516
27848
|
};
|
|
27517
27849
|
}
|
|
27518
27850
|
const name = displayName?.trim() || path18.basename(resolved);
|
|
@@ -27524,9 +27856,9 @@ async function addProjectCommand(opts, ctx, targetPath, displayName) {
|
|
|
27524
27856
|
return {
|
|
27525
27857
|
message: [
|
|
27526
27858
|
"",
|
|
27527
|
-
|
|
27528
|
-
|
|
27529
|
-
|
|
27859
|
+
color56.green(` Added project: ${name}`),
|
|
27860
|
+
color56.dim(` Root: ${resolved}`),
|
|
27861
|
+
color56.dim(` Slug: ${slug}`),
|
|
27530
27862
|
""
|
|
27531
27863
|
].join("\n")
|
|
27532
27864
|
};
|
|
@@ -27536,7 +27868,7 @@ async function renameProjectCommand(opts, _ctx, slugOrName, newName) {
|
|
|
27536
27868
|
const project = findProject(manifest, slugOrName);
|
|
27537
27869
|
if (!project) {
|
|
27538
27870
|
return {
|
|
27539
|
-
message:
|
|
27871
|
+
message: color56.red(
|
|
27540
27872
|
`Project not found: "${slugOrName}". Use /project list to see available projects.`
|
|
27541
27873
|
)
|
|
27542
27874
|
};
|
|
@@ -27544,7 +27876,7 @@ async function renameProjectCommand(opts, _ctx, slugOrName, newName) {
|
|
|
27544
27876
|
const oldName = project.name;
|
|
27545
27877
|
project.name = newName;
|
|
27546
27878
|
await saveManifest(manifest, opts.paths?.globalConfig);
|
|
27547
|
-
return { message:
|
|
27879
|
+
return { message: color56.green(`Renamed: "${oldName}" \u2192 "${newName}" (${project.slug})`) };
|
|
27548
27880
|
}
|
|
27549
27881
|
async function removeProjectCommand(opts, _ctx, slugOrName) {
|
|
27550
27882
|
const manifest = await loadManifest(opts.paths?.globalConfig);
|
|
@@ -27553,7 +27885,7 @@ async function removeProjectCommand(opts, _ctx, slugOrName) {
|
|
|
27553
27885
|
);
|
|
27554
27886
|
if (idx === -1) {
|
|
27555
27887
|
return {
|
|
27556
|
-
message:
|
|
27888
|
+
message: color56.red(
|
|
27557
27889
|
`Project not found: "${slugOrName}". Use /project list to see available projects.`
|
|
27558
27890
|
)
|
|
27559
27891
|
};
|
|
@@ -27562,7 +27894,7 @@ async function removeProjectCommand(opts, _ctx, slugOrName) {
|
|
|
27562
27894
|
manifest.projects.splice(idx, 1);
|
|
27563
27895
|
await saveManifest(manifest, opts.paths?.globalConfig);
|
|
27564
27896
|
return {
|
|
27565
|
-
message:
|
|
27897
|
+
message: color56.dim(
|
|
27566
27898
|
`Removed: "${removed.name}" (${removed.root}) \u2014 data directory kept at ~/.wrongstack/projects/${removed.slug}/`
|
|
27567
27899
|
)
|
|
27568
27900
|
};
|
|
@@ -27572,11 +27904,11 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
|
|
|
27572
27904
|
try {
|
|
27573
27905
|
await fs18.access(resolved);
|
|
27574
27906
|
} catch {
|
|
27575
|
-
return { message:
|
|
27907
|
+
return { message: color56.red(`Directory not found: ${resolved}`) };
|
|
27576
27908
|
}
|
|
27577
27909
|
const stat6 = await fs18.stat(resolved);
|
|
27578
27910
|
if (!stat6.isDirectory()) {
|
|
27579
|
-
return { message:
|
|
27911
|
+
return { message: color56.red(`Not a directory: ${resolved}`) };
|
|
27580
27912
|
}
|
|
27581
27913
|
let cliPath;
|
|
27582
27914
|
try {
|
|
@@ -27589,7 +27921,7 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
|
|
|
27589
27921
|
cliPath = process.argv[1] ?? "";
|
|
27590
27922
|
if (!cliPath) {
|
|
27591
27923
|
return {
|
|
27592
|
-
message:
|
|
27924
|
+
message: color56.red(
|
|
27593
27925
|
"Could not locate the CLI entry point. Run `wstack` manually in the target directory."
|
|
27594
27926
|
)
|
|
27595
27927
|
};
|
|
@@ -27622,14 +27954,14 @@ async function switchProjectCommand(opts, ctx, target, displayName) {
|
|
|
27622
27954
|
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
27623
27955
|
});
|
|
27624
27956
|
child.on("error", (err) => {
|
|
27625
|
-
console.error(
|
|
27957
|
+
console.error(color56.red(`Failed to spawn wstack: ${err.message}`));
|
|
27626
27958
|
});
|
|
27627
27959
|
child.unref();
|
|
27628
27960
|
return {
|
|
27629
27961
|
message: [
|
|
27630
27962
|
"",
|
|
27631
|
-
|
|
27632
|
-
|
|
27963
|
+
color56.green(` Spawning wstack in ${resolved} ...`),
|
|
27964
|
+
color56.dim(" (current session stays open \u2014 Ctrl+C to return)"),
|
|
27633
27965
|
""
|
|
27634
27966
|
].join("\n")
|
|
27635
27967
|
};
|
|
@@ -27643,45 +27975,45 @@ async function confirmProjectSwitch(opts, targetName) {
|
|
|
27643
27975
|
const parallelActive = parallelEngine?.currentState === "running";
|
|
27644
27976
|
const hasActiveAgents = fleetRunning > 0 || eternalActive || parallelActive;
|
|
27645
27977
|
if (!hasActiveAgents) return true;
|
|
27646
|
-
const parts = [
|
|
27978
|
+
const parts = [color56.yellow(`\u26A0 Switching projects will stop all running agents.`), ""];
|
|
27647
27979
|
if (fleetRunning > 0) {
|
|
27648
|
-
parts.push(
|
|
27980
|
+
parts.push(color56.dim(` \u2022 ${fleetRunning} subagent(s) currently running`));
|
|
27649
27981
|
}
|
|
27650
27982
|
if (eternalActive) {
|
|
27651
|
-
parts.push(
|
|
27983
|
+
parts.push(color56.dim(" \u2022 Eternal engine is active"));
|
|
27652
27984
|
}
|
|
27653
27985
|
if (parallelActive) {
|
|
27654
|
-
parts.push(
|
|
27986
|
+
parts.push(color56.dim(" \u2022 Parallel engine is active"));
|
|
27655
27987
|
}
|
|
27656
27988
|
parts.push("");
|
|
27657
|
-
parts.push(
|
|
27989
|
+
parts.push(color56.dim(` Target: ${targetName}`));
|
|
27658
27990
|
opts.renderer.write(`
|
|
27659
27991
|
${parts.join("\n")}
|
|
27660
27992
|
`);
|
|
27661
27993
|
if (!opts.confirm) return true;
|
|
27662
27994
|
const confirmed = await opts.confirm(
|
|
27663
|
-
|
|
27995
|
+
color56.yellow(`Stop all agents and switch to "${targetName}"?`),
|
|
27664
27996
|
false
|
|
27665
27997
|
// default to No for safety
|
|
27666
27998
|
);
|
|
27667
27999
|
if (!confirmed) {
|
|
27668
|
-
opts.renderer.write(
|
|
28000
|
+
opts.renderer.write(color56.dim(" Switch cancelled.\n"));
|
|
27669
28001
|
return false;
|
|
27670
28002
|
}
|
|
27671
28003
|
if (fleetRunning > 0) {
|
|
27672
28004
|
const killed = opts.onFleetKill ? await opts.onFleetKill() : 0;
|
|
27673
28005
|
if (killed > 0) {
|
|
27674
|
-
opts.renderer.write(
|
|
28006
|
+
opts.renderer.write(color56.dim(` Stopped ${killed} subagent(s).
|
|
27675
28007
|
`));
|
|
27676
28008
|
}
|
|
27677
28009
|
}
|
|
27678
28010
|
if (eternalActive) {
|
|
27679
28011
|
eternalEngine?.stop();
|
|
27680
|
-
opts.renderer.write(
|
|
28012
|
+
opts.renderer.write(color56.dim(" Stopped eternal engine.\n"));
|
|
27681
28013
|
}
|
|
27682
28014
|
if (parallelActive) {
|
|
27683
28015
|
parallelEngine?.stop();
|
|
27684
|
-
opts.renderer.write(
|
|
28016
|
+
opts.renderer.write(color56.dim(" Stopped parallel engine.\n"));
|
|
27685
28017
|
}
|
|
27686
28018
|
return true;
|
|
27687
28019
|
}
|
|
@@ -27693,16 +28025,16 @@ async function switchInteractiveCommand(opts, ctx) {
|
|
|
27693
28025
|
currentProjectRoot: currentRoot
|
|
27694
28026
|
});
|
|
27695
28027
|
if (!result) {
|
|
27696
|
-
return { message:
|
|
28028
|
+
return { message: color56.dim("Cancelled.") };
|
|
27697
28029
|
}
|
|
27698
28030
|
switch (result.kind) {
|
|
27699
28031
|
case "project": {
|
|
27700
28032
|
const project = manifest.projects.find((p) => p.slug === result.key);
|
|
27701
28033
|
if (!project) {
|
|
27702
|
-
return { message:
|
|
28034
|
+
return { message: color56.red(`Project not found: ${result.key}`) };
|
|
27703
28035
|
}
|
|
27704
28036
|
if (project.root === currentRoot) {
|
|
27705
|
-
return { message:
|
|
28037
|
+
return { message: color56.dim(`Already in ${project.name} (${project.root})`) };
|
|
27706
28038
|
}
|
|
27707
28039
|
const canSwitch = await confirmProjectSwitch(opts, project.name);
|
|
27708
28040
|
if (!canSwitch) return { message: "" };
|
|
@@ -27715,11 +28047,11 @@ async function switchInteractiveCommand(opts, ctx) {
|
|
|
27715
28047
|
case "prev-sessions":
|
|
27716
28048
|
return handlePrevSessions(opts, ctx);
|
|
27717
28049
|
default:
|
|
27718
|
-
return { message:
|
|
28050
|
+
return { message: color56.dim("Cancelled.") };
|
|
27719
28051
|
}
|
|
27720
28052
|
}
|
|
27721
28053
|
default:
|
|
27722
|
-
return { message:
|
|
28054
|
+
return { message: color56.dim("Cancelled.") };
|
|
27723
28055
|
}
|
|
27724
28056
|
}
|
|
27725
28057
|
async function spawnInProject(opts, _ctx, root, projectName) {
|
|
@@ -27734,7 +28066,7 @@ async function spawnInProject(opts, _ctx, root, projectName) {
|
|
|
27734
28066
|
cliPath = process.argv[1] ?? "";
|
|
27735
28067
|
if (!cliPath) {
|
|
27736
28068
|
return {
|
|
27737
|
-
message:
|
|
28069
|
+
message: color56.red(
|
|
27738
28070
|
"Could not locate the CLI entry point. Run `wstack` manually in the target directory."
|
|
27739
28071
|
)
|
|
27740
28072
|
};
|
|
@@ -27764,15 +28096,15 @@ async function spawnInProject(opts, _ctx, root, projectName) {
|
|
|
27764
28096
|
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
27765
28097
|
});
|
|
27766
28098
|
child.on("error", (err) => {
|
|
27767
|
-
console.error(
|
|
28099
|
+
console.error(color56.red(`Failed to spawn wstack: ${err.message}`));
|
|
27768
28100
|
});
|
|
27769
28101
|
child.unref();
|
|
27770
28102
|
return {
|
|
27771
28103
|
message: [
|
|
27772
28104
|
"",
|
|
27773
|
-
|
|
27774
|
-
|
|
27775
|
-
|
|
28105
|
+
color56.green(` Switched to ${projectName}`),
|
|
28106
|
+
color56.dim(` Root: ${root}`),
|
|
28107
|
+
color56.dim(" (current session stays open \u2014 Ctrl+C to return)"),
|
|
27776
28108
|
""
|
|
27777
28109
|
].join("\n")
|
|
27778
28110
|
};
|
|
@@ -27789,7 +28121,7 @@ async function handleNewSession(_opts, _ctx) {
|
|
|
27789
28121
|
cliPath = process.argv[1] ?? "";
|
|
27790
28122
|
if (!cliPath) {
|
|
27791
28123
|
return {
|
|
27792
|
-
message:
|
|
28124
|
+
message: color56.red("Could not locate the CLI entry point. Run `wstack` manually.")
|
|
27793
28125
|
};
|
|
27794
28126
|
}
|
|
27795
28127
|
}
|
|
@@ -27806,14 +28138,14 @@ async function handleNewSession(_opts, _ctx) {
|
|
|
27806
28138
|
// and boot/tui-project-spawn.ts documents this exact bug being removed.
|
|
27807
28139
|
});
|
|
27808
28140
|
child.on("error", (err) => {
|
|
27809
|
-
console.error(
|
|
28141
|
+
console.error(color56.red(`Failed to spawn wstack: ${err.message}`));
|
|
27810
28142
|
});
|
|
27811
28143
|
child.unref();
|
|
27812
28144
|
return {
|
|
27813
28145
|
message: [
|
|
27814
28146
|
"",
|
|
27815
|
-
|
|
27816
|
-
|
|
28147
|
+
color56.green(" Starting new session ..."),
|
|
28148
|
+
color56.dim(" (current session stays open \u2014 Ctrl+C to return)"),
|
|
27817
28149
|
""
|
|
27818
28150
|
].join("\n")
|
|
27819
28151
|
};
|
|
@@ -27824,25 +28156,25 @@ async function handlePrevSessions(opts, _ctx) {
|
|
|
27824
28156
|
}
|
|
27825
28157
|
const list = await opts.sessionStore.list(15);
|
|
27826
28158
|
if (list.length === 0) {
|
|
27827
|
-
return { message:
|
|
28159
|
+
return { message: color56.dim("No saved sessions.") };
|
|
27828
28160
|
}
|
|
27829
28161
|
const currentId = opts.context?.session?.id;
|
|
27830
|
-
const lines = [
|
|
28162
|
+
const lines = [color56.bold(`Recent sessions (${list.length}):`), ""];
|
|
27831
28163
|
for (const s of list) {
|
|
27832
28164
|
const isCurrent = s.id === currentId;
|
|
27833
|
-
const marker = isCurrent ?
|
|
27834
|
-
const date =
|
|
28165
|
+
const marker = isCurrent ? color56.cyan("\u25CF") : " ";
|
|
28166
|
+
const date = color56.dim(s.startedAt.slice(0, 16).replace("T", " "));
|
|
27835
28167
|
const stats = [
|
|
27836
|
-
|
|
27837
|
-
s.toolCallCount ?
|
|
27838
|
-
s.iterationCount ?
|
|
28168
|
+
color56.dim(`${s.tokenTotal.toLocaleString()} tok`),
|
|
28169
|
+
s.toolCallCount ? color56.cyan(`${s.toolCallCount} calls`) : "",
|
|
28170
|
+
s.iterationCount ? color56.dim(`${s.iterationCount} iter`) : ""
|
|
27839
28171
|
].filter(Boolean).join(" ");
|
|
27840
|
-
const outcome = s.outcome === "completed" ?
|
|
27841
|
-
lines.push(` ${marker} ${
|
|
27842
|
-
lines.push(` ${stats} ${outcome} ${
|
|
28172
|
+
const outcome = s.outcome === "completed" ? color56.green("\u2713") : s.outcome === "aborted" ? color56.yellow("\u26A0") : s.outcome === "error" ? color56.red("\u2717") : color56.dim("?");
|
|
28173
|
+
lines.push(` ${marker} ${color56.bold(s.id)} ${date}`);
|
|
28174
|
+
lines.push(` ${stats} ${outcome} ${color56.dim(s.title)}`);
|
|
27843
28175
|
lines.push("");
|
|
27844
28176
|
}
|
|
27845
|
-
lines.push(
|
|
28177
|
+
lines.push(color56.dim("Resume: /sessions or wstack resume <id>"));
|
|
27846
28178
|
return { message: lines.join("\n") };
|
|
27847
28179
|
}
|
|
27848
28180
|
|
|
@@ -28050,7 +28382,7 @@ function buildSecurityCommand(opts) {
|
|
|
28050
28382
|
}
|
|
28051
28383
|
|
|
28052
28384
|
// src/slash-commands/settings.ts
|
|
28053
|
-
import { color as
|
|
28385
|
+
import { color as color59 } from "@wrongstack/core/utils";
|
|
28054
28386
|
|
|
28055
28387
|
// src/slash-commands/settings-mutations.ts
|
|
28056
28388
|
import { noOpVault as noOpVault10 } from "@wrongstack/core/security";
|
|
@@ -28059,7 +28391,7 @@ import {
|
|
|
28059
28391
|
isReasoningEffort as isReasoningEffort3,
|
|
28060
28392
|
REASONING_EFFORT_LEVELS as REASONING_EFFORT_LEVELS3
|
|
28061
28393
|
} from "@wrongstack/core/types";
|
|
28062
|
-
import { color as
|
|
28394
|
+
import { color as color57, toErrorMessage as toErrorMessage26 } from "@wrongstack/core/utils";
|
|
28063
28395
|
import { getProcessRegistry } from "@wrongstack/tools";
|
|
28064
28396
|
|
|
28065
28397
|
// src/utils/delay-format.ts
|
|
@@ -28128,7 +28460,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28128
28460
|
if (sub === "hq") {
|
|
28129
28461
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28130
28462
|
if (!["on", "off"].includes(raw)) {
|
|
28131
|
-
return { message: `${
|
|
28463
|
+
return { message: `${color57.amber("Usage:")} /settings hq on|off` };
|
|
28132
28464
|
}
|
|
28133
28465
|
const on = raw === "on";
|
|
28134
28466
|
await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
|
|
@@ -28137,17 +28469,17 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28137
28469
|
cfg.hq = hq;
|
|
28138
28470
|
});
|
|
28139
28471
|
return {
|
|
28140
|
-
message: `${
|
|
28472
|
+
message: `${color57.green("\u2713")} HQ publishing \u2192 ${on ? color57.cyan("on") : color57.dim("off")}`
|
|
28141
28473
|
};
|
|
28142
28474
|
}
|
|
28143
28475
|
if (sub === "hq-url") {
|
|
28144
28476
|
const raw = rest.join(" ").trim();
|
|
28145
|
-
if (!raw) return { message: `${
|
|
28477
|
+
if (!raw) return { message: `${color57.amber("Usage:")} /settings hq-url <http://host:3499>` };
|
|
28146
28478
|
try {
|
|
28147
28479
|
const url = new URL(raw);
|
|
28148
28480
|
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("bad protocol");
|
|
28149
28481
|
} catch {
|
|
28150
|
-
return { message: `${
|
|
28482
|
+
return { message: `${color57.red("Invalid URL")}: ${raw}` };
|
|
28151
28483
|
}
|
|
28152
28484
|
await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
|
|
28153
28485
|
const hq = cfg.hq ?? {};
|
|
@@ -28155,11 +28487,11 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28155
28487
|
hq.enabled = true;
|
|
28156
28488
|
cfg.hq = hq;
|
|
28157
28489
|
});
|
|
28158
|
-
return { message: `${
|
|
28490
|
+
return { message: `${color57.green("\u2713")} HQ URL \u2192 ${color57.cyan(raw)}` };
|
|
28159
28491
|
}
|
|
28160
28492
|
if (sub === "hq-token") {
|
|
28161
28493
|
const token = rest.join(" ").trim();
|
|
28162
|
-
if (!token) return { message: `${
|
|
28494
|
+
if (!token) return { message: `${color57.amber("Usage:")} /settings hq-token <client-token>` };
|
|
28163
28495
|
await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
|
|
28164
28496
|
const hq = cfg.hq ?? {};
|
|
28165
28497
|
hq.token = token;
|
|
@@ -28167,13 +28499,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28167
28499
|
cfg.hq = hq;
|
|
28168
28500
|
});
|
|
28169
28501
|
return {
|
|
28170
|
-
message: `${
|
|
28502
|
+
message: `${color57.green("\u2713")} HQ token saved ${color57.dim("(active profile config)")}`
|
|
28171
28503
|
};
|
|
28172
28504
|
}
|
|
28173
28505
|
if (sub === "hq-raw") {
|
|
28174
28506
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28175
28507
|
if (!["on", "off"].includes(raw)) {
|
|
28176
|
-
return { message: `${
|
|
28508
|
+
return { message: `${color57.amber("Usage:")} /settings hq-raw on|off` };
|
|
28177
28509
|
}
|
|
28178
28510
|
const on = raw === "on";
|
|
28179
28511
|
await persistConfigSetting({ ...persistDeps, forceGlobal: true }, (cfg) => {
|
|
@@ -28182,43 +28514,43 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28182
28514
|
cfg.hq = hq;
|
|
28183
28515
|
});
|
|
28184
28516
|
return {
|
|
28185
|
-
message: `${
|
|
28517
|
+
message: `${color57.green("\u2713")} HQ raw content \u2192 ${on ? color57.cyan("on") : color57.dim("off")}`
|
|
28186
28518
|
};
|
|
28187
28519
|
}
|
|
28188
28520
|
if (sub === "delay") {
|
|
28189
28521
|
const raw = rest[0];
|
|
28190
28522
|
if (raw === void 0) {
|
|
28191
28523
|
return {
|
|
28192
|
-
message: `${
|
|
28524
|
+
message: `${color57.amber("Usage:")} /settings delay <seconds> ${color57.dim("(0 disables)")}`
|
|
28193
28525
|
};
|
|
28194
28526
|
}
|
|
28195
28527
|
const seconds = Number.parseFloat(raw);
|
|
28196
28528
|
if (Number.isNaN(seconds) || seconds < 0) {
|
|
28197
28529
|
return {
|
|
28198
|
-
message: `${
|
|
28530
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings delay 30`
|
|
28199
28531
|
};
|
|
28200
28532
|
}
|
|
28201
28533
|
const ms = Math.round(seconds * 1e3);
|
|
28202
28534
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28203
28535
|
autonomy.autoProceedDelayMs = ms;
|
|
28204
28536
|
});
|
|
28205
|
-
return { message: `${
|
|
28537
|
+
return { message: `${color57.green("\u2713")} auto-proceed delay \u2192 ${formatDelay(ms)}` };
|
|
28206
28538
|
}
|
|
28207
28539
|
if (sub === "mode") {
|
|
28208
28540
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28209
28541
|
const modes = ["off", "suggest", "auto"];
|
|
28210
28542
|
if (!modes.includes(raw)) {
|
|
28211
|
-
return { message: `${
|
|
28543
|
+
return { message: `${color57.amber("Usage:")} /settings mode off|suggest|auto` };
|
|
28212
28544
|
}
|
|
28213
28545
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28214
28546
|
autonomy.defaultMode = raw;
|
|
28215
28547
|
});
|
|
28216
|
-
return { message: `${
|
|
28548
|
+
return { message: `${color57.green("\u2713")} default autonomy \u2192 ${color57.bold(raw)}` };
|
|
28217
28549
|
}
|
|
28218
28550
|
if (sub === "debug-stream") {
|
|
28219
28551
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28220
28552
|
if (!["on", "off"].includes(raw)) {
|
|
28221
|
-
return { message: `${
|
|
28553
|
+
return { message: `${color57.amber("Usage:")} /settings debug-stream on|off` };
|
|
28222
28554
|
}
|
|
28223
28555
|
const on = raw === "on";
|
|
28224
28556
|
const { setDebugStreamEnabled } = await import("@wrongstack/providers");
|
|
@@ -28227,24 +28559,24 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28227
28559
|
cfg.debugStream = on;
|
|
28228
28560
|
});
|
|
28229
28561
|
return {
|
|
28230
|
-
message: `${
|
|
28562
|
+
message: `${color57.green("\u2713")} debug stream \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("raw SSE hex-dump to stderr")}`
|
|
28231
28563
|
};
|
|
28232
28564
|
}
|
|
28233
28565
|
if (sub === "config-scope") {
|
|
28234
28566
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28235
28567
|
if (!["global", "project"].includes(raw)) {
|
|
28236
|
-
return { message: `${
|
|
28568
|
+
return { message: `${color57.amber("Usage:")} /settings config-scope global|project` };
|
|
28237
28569
|
}
|
|
28238
28570
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28239
28571
|
cfg.configScope = raw;
|
|
28240
28572
|
});
|
|
28241
|
-
const label = raw === "project" ? `${
|
|
28242
|
-
return { message: `${
|
|
28573
|
+
const label = raw === "project" ? `${color57.cyan("project")} \u2014 settings saved to <project>/.wrongstack/config.json` : `${color57.cyan("global")} \u2014 settings saved to ~/.wrongstack/profiles/${activeProfile}/config.json`;
|
|
28574
|
+
return { message: `${color57.green("\u2713")} config scope \u2192 ${label}` };
|
|
28243
28575
|
}
|
|
28244
28576
|
if (sub === "fs-access") {
|
|
28245
28577
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28246
28578
|
if (!["unrestricted", "project"].includes(raw)) {
|
|
28247
|
-
return { message: `${
|
|
28579
|
+
return { message: `${color57.amber("Usage:")} /settings fs-access unrestricted|project` };
|
|
28248
28580
|
}
|
|
28249
28581
|
const restrict = raw === "project";
|
|
28250
28582
|
const fsAccess = deriveFsAccessPair({ restrictFsToRoot: restrict });
|
|
@@ -28256,15 +28588,15 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28256
28588
|
features.allowOutsideProjectRoot = fsAccess.allowOutsideProjectRoot;
|
|
28257
28589
|
cfg.features = features;
|
|
28258
28590
|
});
|
|
28259
|
-
const label = restrict ? `${
|
|
28591
|
+
const label = restrict ? `${color57.cyan("project")} \u2014 file tools confined to the project root` : `${color57.cyan("unrestricted")} \u2014 file tools may access paths outside the project root`;
|
|
28260
28592
|
return {
|
|
28261
|
-
message: `${
|
|
28593
|
+
message: `${color57.green("\u2713")} filesystem access \u2192 ${label} ${color57.dim("(restart or re-open the session to apply)")}`
|
|
28262
28594
|
};
|
|
28263
28595
|
}
|
|
28264
28596
|
if (sub === "refine") {
|
|
28265
28597
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28266
28598
|
if (!["on", "off"].includes(raw)) {
|
|
28267
|
-
return { message: `${
|
|
28599
|
+
return { message: `${color57.amber("Usage:")} /settings refine on|off` };
|
|
28268
28600
|
}
|
|
28269
28601
|
const on = raw === "on";
|
|
28270
28602
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
@@ -28274,52 +28606,52 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28274
28606
|
opts.enhanceController.setEnabled(on);
|
|
28275
28607
|
}
|
|
28276
28608
|
return {
|
|
28277
|
-
message: `${
|
|
28609
|
+
message: `${color57.green("\u2713")} refine \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim(on ? "prompts will be refined before sending" : "prompts sent verbatim")}`
|
|
28278
28610
|
};
|
|
28279
28611
|
}
|
|
28280
28612
|
if (sub === "refine-delay") {
|
|
28281
28613
|
const raw = rest[0];
|
|
28282
28614
|
if (raw === void 0) {
|
|
28283
|
-
return { message: `${
|
|
28615
|
+
return { message: `${color57.amber("Usage:")} /settings refine-delay <seconds>` };
|
|
28284
28616
|
}
|
|
28285
28617
|
const seconds = Number.parseFloat(raw);
|
|
28286
28618
|
if (Number.isNaN(seconds) || seconds < 0) {
|
|
28287
28619
|
return {
|
|
28288
|
-
message: `${
|
|
28620
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings refine-delay 30`
|
|
28289
28621
|
};
|
|
28290
28622
|
}
|
|
28291
28623
|
const ms = Math.round(seconds * 1e3);
|
|
28292
28624
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28293
28625
|
autonomy.enhanceDelayMs = ms;
|
|
28294
28626
|
});
|
|
28295
|
-
return { message: `${
|
|
28627
|
+
return { message: `${color57.green("\u2713")} refine-delay \u2192 ${formatDelay(ms)}` };
|
|
28296
28628
|
}
|
|
28297
28629
|
if (sub === "refine-language") {
|
|
28298
28630
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28299
28631
|
if (!["original", "english"].includes(raw)) {
|
|
28300
28632
|
return {
|
|
28301
|
-
message: `${
|
|
28633
|
+
message: `${color57.amber("Usage:")} /settings refine-language original|english`
|
|
28302
28634
|
};
|
|
28303
28635
|
}
|
|
28304
28636
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28305
28637
|
autonomy.enhanceLanguage = raw;
|
|
28306
28638
|
});
|
|
28307
|
-
const label = raw === "original" ? `${
|
|
28308
|
-
return { message: `${
|
|
28639
|
+
const label = raw === "original" ? `${color57.cyan("original")} \u2014 use the language you wrote in` : `${color57.cyan("english")} \u2014 translate to English`;
|
|
28640
|
+
return { message: `${color57.green("\u2713")} refine-language \u2192 ${label}` };
|
|
28309
28641
|
}
|
|
28310
28642
|
if (sub === "refiner-provider") {
|
|
28311
28643
|
const raw = rest.join(" ").trim();
|
|
28312
28644
|
const currentProvider = opts.configStore.get().autonomy?.refinerProvider;
|
|
28313
28645
|
if (!raw) {
|
|
28314
28646
|
return {
|
|
28315
|
-
message: `${
|
|
28647
|
+
message: `${color57.amber("Usage:")} /settings refiner-provider <providerId> ${color57.dim('(e.g. "openai", "anthropic")' + (currentProvider ? ` Current: ${currentProvider}` : ""))}`
|
|
28316
28648
|
};
|
|
28317
28649
|
}
|
|
28318
28650
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28319
28651
|
autonomy.refinerProvider = raw;
|
|
28320
28652
|
});
|
|
28321
28653
|
return {
|
|
28322
|
-
message: `${
|
|
28654
|
+
message: `${color57.green("\u2713")} refiner-provider \u2192 ${color57.cyan(raw)} ${color57.dim("goal refinement will use this provider when refiner-model is also set")}`
|
|
28323
28655
|
};
|
|
28324
28656
|
}
|
|
28325
28657
|
if (sub === "refiner-model") {
|
|
@@ -28327,14 +28659,14 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28327
28659
|
const currentModel = opts.configStore.get().autonomy?.refinerModel;
|
|
28328
28660
|
if (!raw) {
|
|
28329
28661
|
return {
|
|
28330
|
-
message: `${
|
|
28662
|
+
message: `${color57.amber("Usage:")} /settings refiner-model <modelId> ${color57.dim('(must be a favorite or the active model; e.g. "gpt-4o-mini")' + (currentModel ? ` Current: ${currentModel}` : ""))}`
|
|
28331
28663
|
};
|
|
28332
28664
|
}
|
|
28333
28665
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28334
28666
|
autonomy.refinerModel = raw;
|
|
28335
28667
|
});
|
|
28336
28668
|
return {
|
|
28337
|
-
message: `${
|
|
28669
|
+
message: `${color57.green("\u2713")} refiner-model \u2192 ${color57.cyan(raw)} ${color57.dim("goal refinement will use this model when it passes favorites/active validation")}`
|
|
28338
28670
|
};
|
|
28339
28671
|
}
|
|
28340
28672
|
if (sub === "refiner-fallback-profile") {
|
|
@@ -28342,14 +28674,14 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28342
28674
|
const currentProfile = opts.configStore.get().autonomy?.refinerFallbackProfile;
|
|
28343
28675
|
if (!raw) {
|
|
28344
28676
|
return {
|
|
28345
|
-
message: `${
|
|
28677
|
+
message: `${color57.amber("Usage:")} /settings refiner-fallback-profile <name> ${color57.dim('(e.g. "default")' + (currentProfile ? ` Current: ${currentProfile}` : ""))}`
|
|
28346
28678
|
};
|
|
28347
28679
|
}
|
|
28348
28680
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28349
28681
|
autonomy.refinerFallbackProfile = raw;
|
|
28350
28682
|
});
|
|
28351
28683
|
return {
|
|
28352
|
-
message: `${
|
|
28684
|
+
message: `${color57.green("\u2713")} refiner-fallback-profile \u2192 ${color57.cyan(raw)} ${color57.dim("goal refinement will use the first valid entry from this profile chain")}`
|
|
28353
28685
|
};
|
|
28354
28686
|
}
|
|
28355
28687
|
if (sub === "refiner-clear") {
|
|
@@ -28359,7 +28691,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28359
28691
|
autonomy.refinerFallbackProfile = void 0;
|
|
28360
28692
|
});
|
|
28361
28693
|
return {
|
|
28362
|
-
message: `${
|
|
28694
|
+
message: `${color57.green("\u2713")} Refiner config cleared ${color57.dim("goal refinement will use the session provider+model")}`
|
|
28363
28695
|
};
|
|
28364
28696
|
}
|
|
28365
28697
|
if (sub === "semver-part") {
|
|
@@ -28367,7 +28699,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28367
28699
|
const parts = ["patch", "minor", "major", "auto"];
|
|
28368
28700
|
if (!parts.includes(raw)) {
|
|
28369
28701
|
return {
|
|
28370
|
-
message: `${
|
|
28702
|
+
message: `${color57.amber("Usage:")} /settings semver-part patch|minor|major|auto`
|
|
28371
28703
|
};
|
|
28372
28704
|
}
|
|
28373
28705
|
await persistConfigSetting({ ...persistDeps, inProjectConfigPath: void 0 }, (cfg) => {
|
|
@@ -28376,13 +28708,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28376
28708
|
cfg.extensions = ext;
|
|
28377
28709
|
});
|
|
28378
28710
|
return {
|
|
28379
|
-
message: `${
|
|
28711
|
+
message: `${color57.green("\u2713")} semver default part \u2192 ${color57.bold(raw)} ${color57.dim("saved to active profile config; used when /semver or semver_bump gets no explicit part")}`
|
|
28380
28712
|
};
|
|
28381
28713
|
}
|
|
28382
28714
|
if (sub === "breaker") {
|
|
28383
28715
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28384
28716
|
if (!["on", "off"].includes(raw)) {
|
|
28385
|
-
return { message: `${
|
|
28717
|
+
return { message: `${color57.amber("Usage:")} /settings breaker on|off` };
|
|
28386
28718
|
}
|
|
28387
28719
|
const on = raw === "on";
|
|
28388
28720
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28391,20 +28723,20 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28391
28723
|
});
|
|
28392
28724
|
getProcessRegistry().setBreakerConfig({ enabled: on });
|
|
28393
28725
|
return {
|
|
28394
|
-
message: `${
|
|
28726
|
+
message: `${color57.green("\u2713")} circuit breaker \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim(on ? "bash/exec gated on repeated failures; trips arm the kill/reset countdown" : "bash/exec always proceed")}`
|
|
28395
28727
|
};
|
|
28396
28728
|
}
|
|
28397
28729
|
if (sub === "breaker-timeout") {
|
|
28398
28730
|
const raw = rest[0];
|
|
28399
28731
|
if (raw === void 0) {
|
|
28400
28732
|
return {
|
|
28401
|
-
message: `${
|
|
28733
|
+
message: `${color57.amber("Usage:")} /settings breaker-timeout <seconds> ${color57.dim("(0 = manual recovery only)")}`
|
|
28402
28734
|
};
|
|
28403
28735
|
}
|
|
28404
28736
|
const seconds = Number.parseFloat(raw);
|
|
28405
28737
|
if (Number.isNaN(seconds) || seconds < 0) {
|
|
28406
28738
|
return {
|
|
28407
|
-
message: `${
|
|
28739
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter seconds, e.g. /settings breaker-timeout 60`
|
|
28408
28740
|
};
|
|
28409
28741
|
}
|
|
28410
28742
|
const ms = Math.round(seconds * 1e3);
|
|
@@ -28417,7 +28749,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28417
28749
|
});
|
|
28418
28750
|
getProcessRegistry().setBreakerConfig({ autoKillResetMs: ms });
|
|
28419
28751
|
return {
|
|
28420
|
-
message: `${
|
|
28752
|
+
message: `${color57.green("\u2713")} breaker kill/reset timeout \u2192 ${ms > 0 ? formatDelay(ms) : color57.dim("manual")} ${color57.dim(ms > 0 ? "statusline shows a countdown when the breaker trips" : "breaker trips require /kill reset")}`
|
|
28421
28753
|
};
|
|
28422
28754
|
}
|
|
28423
28755
|
if (sub === "context-mode") {
|
|
@@ -28425,7 +28757,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28425
28757
|
const modes = ["balanced", "frugal", "deep"];
|
|
28426
28758
|
if (!modes.includes(raw)) {
|
|
28427
28759
|
return {
|
|
28428
|
-
message: `${
|
|
28760
|
+
message: `${color57.amber("Usage:")} /settings context-mode balanced|frugal|deep`
|
|
28429
28761
|
};
|
|
28430
28762
|
}
|
|
28431
28763
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28434,7 +28766,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28434
28766
|
cfg.context = ctx;
|
|
28435
28767
|
});
|
|
28436
28768
|
return {
|
|
28437
|
-
message: `${
|
|
28769
|
+
message: `${color57.green("\u2713")} context mode \u2192 ${color57.cyan(raw)} ${color57.dim("context window policy")}`
|
|
28438
28770
|
};
|
|
28439
28771
|
}
|
|
28440
28772
|
if (sub === "context-strategy") {
|
|
@@ -28442,7 +28774,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28442
28774
|
const strategies = ["hybrid", "intelligent", "selective"];
|
|
28443
28775
|
if (!strategies.includes(raw)) {
|
|
28444
28776
|
return {
|
|
28445
|
-
message: `${
|
|
28777
|
+
message: `${color57.amber("Usage:")} /settings context-strategy hybrid|intelligent|selective`
|
|
28446
28778
|
};
|
|
28447
28779
|
}
|
|
28448
28780
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28451,13 +28783,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28451
28783
|
cfg.context = ctx;
|
|
28452
28784
|
});
|
|
28453
28785
|
return {
|
|
28454
|
-
message: `${
|
|
28786
|
+
message: `${color57.green("\u2713")} context strategy \u2192 ${color57.cyan(raw)} ${color57.dim("compactor strategy")}`
|
|
28455
28787
|
};
|
|
28456
28788
|
}
|
|
28457
28789
|
if (sub === "context-auto-compact") {
|
|
28458
28790
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28459
28791
|
if (!["on", "off"].includes(raw)) {
|
|
28460
|
-
return { message: `${
|
|
28792
|
+
return { message: `${color57.amber("Usage:")} /settings context-auto-compact on|off` };
|
|
28461
28793
|
}
|
|
28462
28794
|
const on = raw === "on";
|
|
28463
28795
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28466,13 +28798,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28466
28798
|
cfg.context = ctx;
|
|
28467
28799
|
});
|
|
28468
28800
|
return {
|
|
28469
|
-
message: `${
|
|
28801
|
+
message: `${color57.green("\u2713")} context auto-compact \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("auto-compact context when thresholds crossed")}`
|
|
28470
28802
|
};
|
|
28471
28803
|
}
|
|
28472
28804
|
if (sub === "nextsteps-tool") {
|
|
28473
28805
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28474
28806
|
if (!["on", "off"].includes(raw)) {
|
|
28475
|
-
return { message: `${
|
|
28807
|
+
return { message: `${color57.amber("Usage:")} /settings nextsteps-tool on|off` };
|
|
28476
28808
|
}
|
|
28477
28809
|
const on = raw === "on";
|
|
28478
28810
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28481,13 +28813,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28481
28813
|
cfg.tools = tools;
|
|
28482
28814
|
});
|
|
28483
28815
|
return {
|
|
28484
|
-
message: `${
|
|
28816
|
+
message: `${color57.green("\u2713")} nextsteps tool \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("takes effect in the next session")}`
|
|
28485
28817
|
};
|
|
28486
28818
|
}
|
|
28487
28819
|
if (sub === "autothin" || sub === "auto-thin") {
|
|
28488
28820
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28489
28821
|
if (!["on", "off", "status"].includes(raw)) {
|
|
28490
|
-
return { message: `${
|
|
28822
|
+
return { message: `${color57.amber("Usage:")} /settings autothin on|off|status` };
|
|
28491
28823
|
}
|
|
28492
28824
|
if (raw === "status") {
|
|
28493
28825
|
return { message: "Use `/tool autothin status` for the live read-out." };
|
|
@@ -28500,13 +28832,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28500
28832
|
cfg.tools = tools;
|
|
28501
28833
|
});
|
|
28502
28834
|
return {
|
|
28503
|
-
message: `${
|
|
28835
|
+
message: `${color57.green("\u2713")} tools.autoThin.enabled \u2192 ${on ? color57.cyan("true") : color57.dim("false")} ${color57.dim("use /tool autothin candidates|apply|undo")}`
|
|
28504
28836
|
};
|
|
28505
28837
|
}
|
|
28506
28838
|
if (sub === "autothin-idle") {
|
|
28507
28839
|
const n = Number(rest[0]);
|
|
28508
28840
|
if (!Number.isFinite(n) || n < 0) {
|
|
28509
|
-
return { message: `${
|
|
28841
|
+
return { message: `${color57.amber("Usage:")} /settings autothin-idle <days>` };
|
|
28510
28842
|
}
|
|
28511
28843
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28512
28844
|
const tools = cfg.tools ?? {};
|
|
@@ -28514,12 +28846,12 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28514
28846
|
tools.autoThin = { ...existing, idleDays: n };
|
|
28515
28847
|
cfg.tools = tools;
|
|
28516
28848
|
});
|
|
28517
|
-
return { message: `${
|
|
28849
|
+
return { message: `${color57.green("\u2713")} tools.autoThin.idleDays \u2192 ${color57.cyan(String(n))}` };
|
|
28518
28850
|
}
|
|
28519
28851
|
if (sub === "autothin-min") {
|
|
28520
28852
|
const n = Number(rest[0]);
|
|
28521
28853
|
if (!Number.isFinite(n) || n < 0) {
|
|
28522
|
-
return { message: `${
|
|
28854
|
+
return { message: `${color57.amber("Usage:")} /settings autothin-min <count>` };
|
|
28523
28855
|
}
|
|
28524
28856
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28525
28857
|
const tools = cfg.tools ?? {};
|
|
@@ -28528,13 +28860,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28528
28860
|
cfg.tools = tools;
|
|
28529
28861
|
});
|
|
28530
28862
|
return {
|
|
28531
|
-
message: `${
|
|
28863
|
+
message: `${color57.green("\u2713")} tools.autoThin.minInvocations \u2192 ${color57.cyan(String(n))}`
|
|
28532
28864
|
};
|
|
28533
28865
|
}
|
|
28534
28866
|
if (sub === "autothin-boot") {
|
|
28535
28867
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28536
28868
|
if (!["on", "off"].includes(raw)) {
|
|
28537
|
-
return { message: `${
|
|
28869
|
+
return { message: `${color57.amber("Usage:")} /settings autothin-boot on|off` };
|
|
28538
28870
|
}
|
|
28539
28871
|
const on = raw === "on";
|
|
28540
28872
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28544,7 +28876,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28544
28876
|
cfg.tools = tools;
|
|
28545
28877
|
});
|
|
28546
28878
|
return {
|
|
28547
|
-
message: `${
|
|
28879
|
+
message: `${color57.green("\u2713")} tools.autoThin.applyOnBoot \u2192 ${on ? color57.cyan("true") : color57.dim("false")}`
|
|
28548
28880
|
};
|
|
28549
28881
|
}
|
|
28550
28882
|
if (sub === "token-saving") {
|
|
@@ -28552,7 +28884,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28552
28884
|
const tiers = ["auto", "off", "minimal", "light", "medium", "aggressive"];
|
|
28553
28885
|
if (!tiers.includes(raw)) {
|
|
28554
28886
|
return {
|
|
28555
|
-
message: `${
|
|
28887
|
+
message: `${color57.amber("Usage:")} /settings token-saving auto|off|minimal|light|medium|aggressive`
|
|
28556
28888
|
};
|
|
28557
28889
|
}
|
|
28558
28890
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28561,48 +28893,48 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28561
28893
|
cfg.features = feat;
|
|
28562
28894
|
});
|
|
28563
28895
|
return {
|
|
28564
|
-
message: `${
|
|
28565
|
-
` +
|
|
28896
|
+
message: `${color57.green("\u2713")} token-saving \u2192 ${color57.cyan(raw)} ${color57.dim("token-saving mode")}
|
|
28897
|
+
` + color57.dim(" Applies to the next session - the tool registry is tiered at startup.")
|
|
28566
28898
|
};
|
|
28567
28899
|
}
|
|
28568
28900
|
if (sub === "max-concurrent") {
|
|
28569
28901
|
const raw = rest[0];
|
|
28570
28902
|
if (raw === void 0) {
|
|
28571
28903
|
return {
|
|
28572
|
-
message: `${
|
|
28904
|
+
message: `${color57.amber("Usage:")} /settings max-concurrent <n> ${color57.dim("(0 = default)")}`
|
|
28573
28905
|
};
|
|
28574
28906
|
}
|
|
28575
28907
|
const n = Number.parseInt(raw, 10);
|
|
28576
28908
|
if (Number.isNaN(n) || n < 0) {
|
|
28577
28909
|
return {
|
|
28578
|
-
message: `${
|
|
28910
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter a non-negative integer (0 = default)`
|
|
28579
28911
|
};
|
|
28580
28912
|
}
|
|
28581
28913
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28582
28914
|
cfg.maxConcurrent = n;
|
|
28583
28915
|
});
|
|
28584
28916
|
return {
|
|
28585
|
-
message: `${
|
|
28917
|
+
message: `${color57.green("\u2713")} max-concurrent \u2192 ${color57.cyan(n === 0 ? "default" : String(n))} ${color57.dim("max concurrent subagents")}`
|
|
28586
28918
|
};
|
|
28587
28919
|
}
|
|
28588
28920
|
if (sub === "title-animation") {
|
|
28589
28921
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28590
28922
|
if (!["on", "off"].includes(raw)) {
|
|
28591
|
-
return { message: `${
|
|
28923
|
+
return { message: `${color57.amber("Usage:")} /settings title-animation on|off` };
|
|
28592
28924
|
}
|
|
28593
28925
|
const on = raw === "on";
|
|
28594
28926
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28595
28927
|
autonomy.terminalTitleAnimation = on;
|
|
28596
28928
|
});
|
|
28597
28929
|
return {
|
|
28598
|
-
message: `${
|
|
28930
|
+
message: `${color57.green("\u2713")} title animation \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("terminal title animation")}`
|
|
28599
28931
|
};
|
|
28600
28932
|
}
|
|
28601
28933
|
if (sub === "reasoning") {
|
|
28602
28934
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28603
28935
|
const modes = ["auto", "on", "off"];
|
|
28604
28936
|
if (!modes.includes(raw)) {
|
|
28605
|
-
return { message: `${
|
|
28937
|
+
return { message: `${color57.amber("Usage:")} /settings reasoning auto|on|off` };
|
|
28606
28938
|
}
|
|
28607
28939
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28608
28940
|
const mr = cfg.modelRuntime;
|
|
@@ -28610,13 +28942,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28610
28942
|
reasoning.mode = raw;
|
|
28611
28943
|
cfg.modelRuntime = { ...mr, reasoning };
|
|
28612
28944
|
});
|
|
28613
|
-
return { message: `${
|
|
28945
|
+
return { message: `${color57.green("\u2713")} reasoning mode \u2192 ${color57.bold(raw)}` };
|
|
28614
28946
|
}
|
|
28615
28947
|
if (sub === "reasoning-effort") {
|
|
28616
28948
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28617
28949
|
if (!isReasoningEffort3(raw)) {
|
|
28618
28950
|
return {
|
|
28619
|
-
message: `${
|
|
28951
|
+
message: `${color57.amber("Usage:")} /settings reasoning-effort ${REASONING_EFFORT_LEVELS3.join("|")}`
|
|
28620
28952
|
};
|
|
28621
28953
|
}
|
|
28622
28954
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28625,12 +28957,12 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28625
28957
|
reasoning.effort = raw;
|
|
28626
28958
|
cfg.modelRuntime = { ...mr, reasoning };
|
|
28627
28959
|
});
|
|
28628
|
-
return { message: `${
|
|
28960
|
+
return { message: `${color57.green("\u2713")} reasoning effort \u2192 ${color57.bold(raw)}` };
|
|
28629
28961
|
}
|
|
28630
28962
|
if (sub === "reasoning-preserve") {
|
|
28631
28963
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28632
28964
|
if (!["on", "off"].includes(raw)) {
|
|
28633
|
-
return { message: `${
|
|
28965
|
+
return { message: `${color57.amber("Usage:")} /settings reasoning-preserve on|off` };
|
|
28634
28966
|
}
|
|
28635
28967
|
const on = raw === "on";
|
|
28636
28968
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
@@ -28640,24 +28972,24 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28640
28972
|
cfg.modelRuntime = { ...mr, reasoning };
|
|
28641
28973
|
});
|
|
28642
28974
|
return {
|
|
28643
|
-
message: `${
|
|
28975
|
+
message: `${color57.green("\u2713")} reasoning preserve \u2192 ${on ? color57.cyan("on") : color57.dim("off")}`
|
|
28644
28976
|
};
|
|
28645
28977
|
}
|
|
28646
28978
|
if (sub === "cache-ttl") {
|
|
28647
28979
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28648
28980
|
if (!["5m", "1h"].includes(raw)) {
|
|
28649
|
-
return { message: `${
|
|
28981
|
+
return { message: `${color57.amber("Usage:")} /settings cache-ttl 5m|1h` };
|
|
28650
28982
|
}
|
|
28651
28983
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28652
28984
|
const mr = cfg.modelRuntime;
|
|
28653
28985
|
cfg.modelRuntime = { ...mr, cache: { ttl: raw } };
|
|
28654
28986
|
});
|
|
28655
|
-
return { message: `${
|
|
28987
|
+
return { message: `${color57.green("\u2713")} cache TTL \u2192 ${color57.bold(raw)}` };
|
|
28656
28988
|
}
|
|
28657
28989
|
if (sub === "mcp") {
|
|
28658
28990
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28659
28991
|
if (!["on", "off"].includes(raw))
|
|
28660
|
-
return { message: `${
|
|
28992
|
+
return { message: `${color57.amber("Usage:")} /settings mcp on|off` };
|
|
28661
28993
|
const on = raw === "on";
|
|
28662
28994
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28663
28995
|
const feats = cfg.features ?? {};
|
|
@@ -28665,13 +28997,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28665
28997
|
cfg.features = feats;
|
|
28666
28998
|
});
|
|
28667
28999
|
return {
|
|
28668
|
-
message: `${
|
|
29000
|
+
message: `${color57.green("\u2713")} MCP features \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("restart to apply")}`
|
|
28669
29001
|
};
|
|
28670
29002
|
}
|
|
28671
29003
|
if (sub === "plugins") {
|
|
28672
29004
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28673
29005
|
if (!["on", "off"].includes(raw))
|
|
28674
|
-
return { message: `${
|
|
29006
|
+
return { message: `${color57.amber("Usage:")} /settings plugins on|off` };
|
|
28675
29007
|
const on = raw === "on";
|
|
28676
29008
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28677
29009
|
const feats = cfg.features ?? {};
|
|
@@ -28679,13 +29011,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28679
29011
|
cfg.features = feats;
|
|
28680
29012
|
});
|
|
28681
29013
|
return {
|
|
28682
|
-
message: `${
|
|
29014
|
+
message: `${color57.green("\u2713")} Plugin features \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("restart to apply")}`
|
|
28683
29015
|
};
|
|
28684
29016
|
}
|
|
28685
29017
|
if (sub === "memory") {
|
|
28686
29018
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28687
29019
|
if (!["on", "off"].includes(raw))
|
|
28688
|
-
return { message: `${
|
|
29020
|
+
return { message: `${color57.amber("Usage:")} /settings memory on|off` };
|
|
28689
29021
|
const on = raw === "on";
|
|
28690
29022
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28691
29023
|
const feats = cfg.features ?? {};
|
|
@@ -28693,13 +29025,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28693
29025
|
cfg.features = feats;
|
|
28694
29026
|
});
|
|
28695
29027
|
return {
|
|
28696
|
-
message: `${
|
|
29028
|
+
message: `${color57.green("\u2713")} Memory features \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("restart to apply")}`
|
|
28697
29029
|
};
|
|
28698
29030
|
}
|
|
28699
29031
|
if (sub === "skills") {
|
|
28700
29032
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28701
29033
|
if (!["on", "off"].includes(raw))
|
|
28702
|
-
return { message: `${
|
|
29034
|
+
return { message: `${color57.amber("Usage:")} /settings skills on|off` };
|
|
28703
29035
|
const on = raw === "on";
|
|
28704
29036
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28705
29037
|
const feats = cfg.features ?? {};
|
|
@@ -28707,13 +29039,13 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28707
29039
|
cfg.features = feats;
|
|
28708
29040
|
});
|
|
28709
29041
|
return {
|
|
28710
|
-
message: `${
|
|
29042
|
+
message: `${color57.green("\u2713")} Skills features \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("restart to apply")}`
|
|
28711
29043
|
};
|
|
28712
29044
|
}
|
|
28713
29045
|
if (sub === "models-registry") {
|
|
28714
29046
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28715
29047
|
if (!["on", "off"].includes(raw))
|
|
28716
|
-
return { message: `${
|
|
29048
|
+
return { message: `${color57.amber("Usage:")} /settings models-registry on|off` };
|
|
28717
29049
|
const on = raw === "on";
|
|
28718
29050
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28719
29051
|
const feats = cfg.features ?? {};
|
|
@@ -28721,7 +29053,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28721
29053
|
cfg.features = feats;
|
|
28722
29054
|
});
|
|
28723
29055
|
return {
|
|
28724
|
-
message: `${
|
|
29056
|
+
message: `${color57.green("\u2713")} Models registry \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("restart to apply")}`
|
|
28725
29057
|
};
|
|
28726
29058
|
}
|
|
28727
29059
|
if (sub === "stream-fleet") {
|
|
@@ -28729,7 +29061,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28729
29061
|
const mode = raw === "on" ? "full" : raw === "off" || raw === "full" ? raw : void 0;
|
|
28730
29062
|
if (!mode)
|
|
28731
29063
|
return {
|
|
28732
|
-
message: `${
|
|
29064
|
+
message: `${color57.amber("Usage:")} /settings stream-fleet off|full (on = full)`
|
|
28733
29065
|
};
|
|
28734
29066
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28735
29067
|
autonomy.fleetChatVerbosity = mode;
|
|
@@ -28737,43 +29069,43 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28737
29069
|
opts.fleetStreamController?.setMode(mode);
|
|
28738
29070
|
const desc = mode === "full" ? "every subagent tool call and message in chat" : "subagent chat lines hidden (F2/F3 stay live)";
|
|
28739
29071
|
return {
|
|
28740
|
-
message: `${
|
|
29072
|
+
message: `${color57.green("\u2713")} fleet chat \u2192 ${color57.cyan(mode)} ${color57.dim(desc)}`
|
|
28741
29073
|
};
|
|
28742
29074
|
}
|
|
28743
29075
|
if (sub === "chime") {
|
|
28744
29076
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28745
29077
|
if (!["on", "off"].includes(raw))
|
|
28746
|
-
return { message: `${
|
|
29078
|
+
return { message: `${color57.amber("Usage:")} /settings chime on|off` };
|
|
28747
29079
|
const on = raw === "on";
|
|
28748
29080
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28749
29081
|
autonomy.chime = on;
|
|
28750
29082
|
});
|
|
28751
29083
|
return {
|
|
28752
|
-
message: `${
|
|
29084
|
+
message: `${color57.green("\u2713")} completion chime \u2192 ${on ? color57.cyan("on") : color57.dim("off")}`
|
|
28753
29085
|
};
|
|
28754
29086
|
}
|
|
28755
29087
|
if (sub === "confirm-exit") {
|
|
28756
29088
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28757
29089
|
if (!["on", "off"].includes(raw))
|
|
28758
|
-
return { message: `${
|
|
29090
|
+
return { message: `${color57.amber("Usage:")} /settings confirm-exit on|off` };
|
|
28759
29091
|
const on = raw === "on";
|
|
28760
29092
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28761
29093
|
autonomy.confirmExit = on;
|
|
28762
29094
|
});
|
|
28763
29095
|
return {
|
|
28764
|
-
message: `${
|
|
29096
|
+
message: `${color57.green("\u2713")} confirm before exit \u2192 ${on ? color57.cyan("on") : color57.dim("off")}`
|
|
28765
29097
|
};
|
|
28766
29098
|
}
|
|
28767
29099
|
if (sub === "max-iterations") {
|
|
28768
29100
|
const raw = rest[0];
|
|
28769
29101
|
if (raw === void 0)
|
|
28770
29102
|
return {
|
|
28771
|
-
message: `${
|
|
29103
|
+
message: `${color57.amber("Usage:")} /settings max-iterations <n> ${color57.dim("(0 = default)")}`
|
|
28772
29104
|
};
|
|
28773
29105
|
const n = Number.parseInt(raw, 10);
|
|
28774
29106
|
if (Number.isNaN(n) || n < 0)
|
|
28775
29107
|
return {
|
|
28776
|
-
message: `${
|
|
29108
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
|
|
28777
29109
|
};
|
|
28778
29110
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28779
29111
|
const tools = cfg.tools ?? {};
|
|
@@ -28781,31 +29113,31 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28781
29113
|
cfg.tools = tools;
|
|
28782
29114
|
});
|
|
28783
29115
|
return {
|
|
28784
|
-
message: `${
|
|
29116
|
+
message: `${color57.green("\u2713")} max iterations \u2192 ${color57.cyan(n === 0 ? "default" : String(n))} ${color57.dim("agent pauses after this many iterations")}`
|
|
28785
29117
|
};
|
|
28786
29118
|
}
|
|
28787
29119
|
if (sub === "auto-proceed-max-iterations") {
|
|
28788
29120
|
const raw = rest[0];
|
|
28789
29121
|
if (raw === void 0)
|
|
28790
29122
|
return {
|
|
28791
|
-
message: `${
|
|
29123
|
+
message: `${color57.amber("Usage:")} /settings auto-proceed-max-iterations <n> ${color57.dim("(0 = unlimited)")}`
|
|
28792
29124
|
};
|
|
28793
29125
|
const n = Number.parseInt(raw, 10);
|
|
28794
29126
|
if (Number.isNaN(n) || n < 0)
|
|
28795
29127
|
return {
|
|
28796
|
-
message: `${
|
|
29128
|
+
message: `${color57.red("Invalid number")}: "${raw}". Enter a non-negative integer.`
|
|
28797
29129
|
};
|
|
28798
29130
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28799
29131
|
autonomy.autoProceedMaxIterations = n;
|
|
28800
29132
|
});
|
|
28801
29133
|
return {
|
|
28802
|
-
message: `${
|
|
29134
|
+
message: `${color57.green("\u2713")} auto-proceed max iterations \u2192 ${color57.cyan(n === 0 ? "unlimited" : String(n))}`
|
|
28803
29135
|
};
|
|
28804
29136
|
}
|
|
28805
29137
|
if (sub === "index-on-start") {
|
|
28806
29138
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28807
29139
|
if (!["on", "off"].includes(raw))
|
|
28808
|
-
return { message: `${
|
|
29140
|
+
return { message: `${color57.amber("Usage:")} /settings index-on-start on|off` };
|
|
28809
29141
|
const on = raw === "on";
|
|
28810
29142
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28811
29143
|
const idx = cfg.indexing ?? {};
|
|
@@ -28813,7 +29145,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28813
29145
|
cfg.indexing = idx;
|
|
28814
29146
|
});
|
|
28815
29147
|
return {
|
|
28816
|
-
message: `${
|
|
29148
|
+
message: `${color57.green("\u2713")} index on session start \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim("effective next session")}`
|
|
28817
29149
|
};
|
|
28818
29150
|
}
|
|
28819
29151
|
if (sub === "log-level") {
|
|
@@ -28821,21 +29153,21 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28821
29153
|
const levels = ["error", "warn", "info", "debug", "trace"];
|
|
28822
29154
|
if (!levels.includes(raw))
|
|
28823
29155
|
return {
|
|
28824
|
-
message: `${
|
|
29156
|
+
message: `${color57.amber("Usage:")} /settings log-level error|warn|info|debug|trace`
|
|
28825
29157
|
};
|
|
28826
29158
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28827
29159
|
const log = cfg.log ?? {};
|
|
28828
29160
|
log.level = raw;
|
|
28829
29161
|
cfg.log = log;
|
|
28830
29162
|
});
|
|
28831
|
-
return { message: `${
|
|
29163
|
+
return { message: `${color57.green("\u2713")} log level \u2192 ${color57.cyan(raw)}` };
|
|
28832
29164
|
}
|
|
28833
29165
|
if (sub === "audit-level") {
|
|
28834
29166
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28835
29167
|
const levels = ["minimal", "standard", "full"];
|
|
28836
29168
|
if (!levels.includes(raw))
|
|
28837
29169
|
return {
|
|
28838
|
-
message: `${
|
|
29170
|
+
message: `${color57.amber("Usage:")} /settings audit-level minimal|standard|full`
|
|
28839
29171
|
};
|
|
28840
29172
|
await persistConfigSetting(persistDeps, (cfg) => {
|
|
28841
29173
|
const sess = cfg.session ?? {};
|
|
@@ -28843,37 +29175,37 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28843
29175
|
cfg.session = sess;
|
|
28844
29176
|
});
|
|
28845
29177
|
return {
|
|
28846
|
-
message: `${
|
|
29178
|
+
message: `${color57.green("\u2713")} audit level \u2192 ${color57.cyan(raw)} ${color57.dim("restart to apply")}`
|
|
28847
29179
|
};
|
|
28848
29180
|
}
|
|
28849
29181
|
if (sub === "thinking-word") {
|
|
28850
29182
|
const raw = rest.join(" ").trim();
|
|
28851
29183
|
if (!raw)
|
|
28852
29184
|
return {
|
|
28853
|
-
message: `${
|
|
29185
|
+
message: `${color57.amber("Usage:")} /settings thinking-word <word> ${color57.dim('single short word, e.g. "thinking", "vibing", "cooking"')}`
|
|
28854
29186
|
};
|
|
28855
|
-
if (raw.length > 16) return { message: `${
|
|
29187
|
+
if (raw.length > 16) return { message: `${color57.red("Word too long")}: max 16 characters.` };
|
|
28856
29188
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28857
29189
|
autonomy.thinkingWord = raw;
|
|
28858
29190
|
});
|
|
28859
|
-
return { message: `${
|
|
29191
|
+
return { message: `${color57.green("\u2713")} thinking word \u2192 ${color57.cyan(raw)}` };
|
|
28860
29192
|
}
|
|
28861
29193
|
if (sub === "statusline") {
|
|
28862
29194
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28863
29195
|
const modes = ["minimum", "detailed", "no-color"];
|
|
28864
29196
|
if (!modes.includes(raw))
|
|
28865
29197
|
return {
|
|
28866
|
-
message: `${
|
|
29198
|
+
message: `${color57.amber("Usage:")} /settings statusline minimum|detailed|no-color`
|
|
28867
29199
|
};
|
|
28868
29200
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28869
29201
|
autonomy.statuslineMode = raw;
|
|
28870
29202
|
});
|
|
28871
|
-
return { message: `${
|
|
29203
|
+
return { message: `${color57.green("\u2713")} statusline mode \u2192 ${color57.cyan(raw)}` };
|
|
28872
29204
|
}
|
|
28873
29205
|
if (sub === "read-symbols") {
|
|
28874
29206
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
28875
29207
|
if (!["on", "off"].includes(raw)) {
|
|
28876
|
-
return { message: `${
|
|
29208
|
+
return { message: `${color57.amber("Usage:")} /settings read-symbols on|off` };
|
|
28877
29209
|
}
|
|
28878
29210
|
const on = raw === "on";
|
|
28879
29211
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
@@ -28883,7 +29215,7 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28883
29215
|
opts.context.meta["tools.read.advancedMode"] = on;
|
|
28884
29216
|
}
|
|
28885
29217
|
return {
|
|
28886
|
-
message: `${
|
|
29218
|
+
message: `${color57.green("\u2713")} read symbols \u2192 ${on ? color57.cyan("on") : color57.dim("off")} ${color57.dim(on ? "codebase-index symbols will be included in read tool results" : "read tool returns file content only")}`
|
|
28887
29219
|
};
|
|
28888
29220
|
}
|
|
28889
29221
|
if (sub === "animation") {
|
|
@@ -28891,22 +29223,22 @@ async function executeSettingsSubcommand(sub, rest, opts) {
|
|
|
28891
29223
|
const styles = ["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"];
|
|
28892
29224
|
if (!styles.includes(raw))
|
|
28893
29225
|
return {
|
|
28894
|
-
message: `${
|
|
29226
|
+
message: `${color57.amber("Usage:")} /settings animation rainbow|wave|pulse|dots|breathe|static|cycle`
|
|
28895
29227
|
};
|
|
28896
29228
|
await persistAutonomySetting(persistDeps, (autonomy) => {
|
|
28897
29229
|
autonomy.animationStyle = raw;
|
|
28898
29230
|
});
|
|
28899
|
-
return { message: `${
|
|
29231
|
+
return { message: `${color57.green("\u2713")} animation style \u2192 ${color57.cyan(raw)}` };
|
|
28900
29232
|
}
|
|
28901
29233
|
if (sub === "reset") {
|
|
28902
29234
|
return executeSettingsReset(rest, persistDeps, opts, activeProfile);
|
|
28903
29235
|
}
|
|
28904
29236
|
return {
|
|
28905
|
-
message: `${
|
|
29237
|
+
message: `${color57.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ALL_SETTINGS_KEYS, "settings")}`
|
|
28906
29238
|
};
|
|
28907
29239
|
} catch (err) {
|
|
28908
29240
|
return {
|
|
28909
|
-
message: `${
|
|
29241
|
+
message: `${color57.red("Settings error")}: ${toErrorMessage26(err)}`
|
|
28910
29242
|
};
|
|
28911
29243
|
}
|
|
28912
29244
|
}
|
|
@@ -28916,9 +29248,9 @@ async function executeSettingsReset(rest, persistDeps, opts, profileName) {
|
|
|
28916
29248
|
if (args.length === 0) {
|
|
28917
29249
|
return {
|
|
28918
29250
|
message: [
|
|
28919
|
-
`${
|
|
29251
|
+
`${color57.amber("Usage:")} /settings reset all ${color57.dim("or pick sections:")}`,
|
|
28920
29252
|
` ${RESET_SECTIONS.join(", ")}`,
|
|
28921
|
-
|
|
29253
|
+
color57.dim(
|
|
28922
29254
|
`Identity is kept (providers, models, API keys, MCP servers, extensions, plugins, fallbacks). Profile: ${profileName}`
|
|
28923
29255
|
)
|
|
28924
29256
|
].join("\n")
|
|
@@ -28928,13 +29260,13 @@ async function executeSettingsReset(rest, persistDeps, opts, profileName) {
|
|
|
28928
29260
|
const invalid = args.filter((a) => a !== "all" && !RESET_SECTIONS.includes(a));
|
|
28929
29261
|
if (invalid.length > 0) {
|
|
28930
29262
|
return {
|
|
28931
|
-
message: `${
|
|
29263
|
+
message: `${color57.red("Unknown section")}: ${invalid.join(", ")}. Valid: ${color57.cyan(RESET_SECTIONS.join(", "))}, all`
|
|
28932
29264
|
};
|
|
28933
29265
|
}
|
|
28934
29266
|
const sections = wantsAll ? [...RESET_SECTIONS] : [...new Set(args)];
|
|
28935
29267
|
if (!opts.confirm) {
|
|
28936
29268
|
return {
|
|
28937
|
-
message: `${
|
|
29269
|
+
message: `${color57.red("Reset unavailable")}: no confirmation surface in this context. Run /settings reset from the interactive REPL or TUI.`
|
|
28938
29270
|
};
|
|
28939
29271
|
}
|
|
28940
29272
|
const confirmed = await opts.confirm(
|
|
@@ -28942,7 +29274,7 @@ async function executeSettingsReset(rest, persistDeps, opts, profileName) {
|
|
|
28942
29274
|
false
|
|
28943
29275
|
);
|
|
28944
29276
|
if (confirmed !== true) {
|
|
28945
|
-
return { message: `${
|
|
29277
|
+
return { message: `${color57.dim("Reset cancelled \u2014 nothing changed.")}` };
|
|
28946
29278
|
}
|
|
28947
29279
|
const defaults = structuredClone(CONFIG_BEHAVIOR_DEFAULTS);
|
|
28948
29280
|
const patch = {};
|
|
@@ -28963,13 +29295,13 @@ async function executeSettingsReset(rest, persistDeps, opts, profileName) {
|
|
|
28963
29295
|
});
|
|
28964
29296
|
opts.configStore.update(patch);
|
|
28965
29297
|
return {
|
|
28966
|
-
message: `${
|
|
29298
|
+
message: `${color57.green("\u2713")} Reset ${sections.length} section(s) \u2192 ${color57.cyan(sections.join(", "))} ${color57.dim(`profile: ${profileName}; some halves apply on next session start`)}`
|
|
28967
29299
|
};
|
|
28968
29300
|
}
|
|
28969
29301
|
|
|
28970
29302
|
// src/slash-commands/settings-view.ts
|
|
28971
29303
|
import { resolveFleetChatVerbosity } from "@wrongstack/core/types";
|
|
28972
|
-
import { color as
|
|
29304
|
+
import { color as color58 } from "@wrongstack/core/utils";
|
|
28973
29305
|
var SETTINGS_HELP = [
|
|
28974
29306
|
"Usage:",
|
|
28975
29307
|
" /settings Show current settings",
|
|
@@ -29031,15 +29363,15 @@ var SETTINGS_HELP = [
|
|
|
29031
29363
|
].join("\n");
|
|
29032
29364
|
function formatSettingsDefaults() {
|
|
29033
29365
|
return [
|
|
29034
|
-
`${
|
|
29366
|
+
`${color58.bold("Default Values")}`,
|
|
29035
29367
|
"",
|
|
29036
|
-
` auto-proceed delay: ${
|
|
29037
|
-
` default autonomy mode: ${
|
|
29038
|
-
` iteration timeout: ${
|
|
29039
|
-
` session timeout: ${
|
|
29040
|
-
` max iterations: ${
|
|
29041
|
-
` max concurrent: ${
|
|
29042
|
-
` semver default part: ${
|
|
29368
|
+
` auto-proceed delay: ${color58.cyan("45s")} ${color58.dim("(WRONGSTACK_AUTO_PROCEED_DELAY_MS env)")}`,
|
|
29369
|
+
` default autonomy mode: ${color58.cyan("off")}`,
|
|
29370
|
+
` iteration timeout: ${color58.cyan("5 min")}`,
|
|
29371
|
+
` session timeout: ${color58.cyan("30 min")}`,
|
|
29372
|
+
` max iterations: ${color58.cyan("100")}`,
|
|
29373
|
+
` max concurrent: ${color58.cyan("4")}`,
|
|
29374
|
+
` semver default part: ${color58.cyan("patch")}`
|
|
29043
29375
|
].join("\n");
|
|
29044
29376
|
}
|
|
29045
29377
|
function formatCurrentSettingsView(opts) {
|
|
@@ -29087,59 +29419,59 @@ function formatCurrentSettingsView(opts) {
|
|
|
29087
29419
|
const idx = opts.configStore.get().indexing;
|
|
29088
29420
|
const sess = opts.configStore.get().session;
|
|
29089
29421
|
return [
|
|
29090
|
-
`${
|
|
29422
|
+
`${color58.bold("WrongStack")} ${color58.dim("\u2014 Settings")}`,
|
|
29091
29423
|
"",
|
|
29092
|
-
` auto-proceed delay: ${
|
|
29093
|
-
` default autonomy mode: ${
|
|
29094
|
-
` fleet chat: ${
|
|
29095
|
-
` completion chime: ${au?.chime === true ?
|
|
29096
|
-
` confirm before exit: ${au?.confirmExit !== false ?
|
|
29097
|
-
` debug stream: ${debugStream ?
|
|
29098
|
-
` config scope: ${
|
|
29099
|
-
` filesystem access: ${
|
|
29100
|
-
` refine: ${enhanceEnabled ?
|
|
29101
|
-
` refine-delay: ${
|
|
29102
|
-
` refine-language: ${
|
|
29103
|
-
` refiner-provider: ${
|
|
29104
|
-
` refiner-model: ${
|
|
29105
|
-
` refiner-fallback-profile: ${
|
|
29106
|
-
` semver default part: ${
|
|
29107
|
-
` circuit breaker: ${breakerEnabled ?
|
|
29108
|
-
` context mode: ${
|
|
29109
|
-
` context strategy: ${
|
|
29110
|
-
` context auto-compact: ${contextAutoCompact ?
|
|
29111
|
-
` token-saving: ${
|
|
29112
|
-
` nextsteps tool: ${nextStepsToolEnabled ?
|
|
29113
|
-
` auto-thinning: ${autoThinEnabled ?
|
|
29114
|
-
` auto-thinning boot-apply: ${autoThinApplyOnBoot ?
|
|
29115
|
-
` auto-thinning idle window: ${
|
|
29116
|
-
` auto-thinning min invocations: ${
|
|
29117
|
-
` MCP features: ${feats?.mcp !== false ?
|
|
29118
|
-
` plugin features: ${feats?.plugins !== false ?
|
|
29119
|
-
` memory features: ${feats?.memory !== false ?
|
|
29120
|
-
` skills features: ${feats?.skills !== false ?
|
|
29121
|
-
` models registry: ${feats?.modelsRegistry !== false ?
|
|
29122
|
-
` max concurrent: ${
|
|
29123
|
-
` max iterations: ${
|
|
29124
|
-
` auto-proceed max iters: ${
|
|
29125
|
-
` title animation: ${titleAnimation ?
|
|
29126
|
-
` thinking word: ${
|
|
29127
|
-
` statusline mode: ${
|
|
29128
|
-
` animation style: ${
|
|
29129
|
-
` read symbols: ${au?.readAdvancedMode === true ?
|
|
29130
|
-
` reasoning mode: ${
|
|
29131
|
-
` reasoning effort: ${
|
|
29132
|
-
` reasoning preserve: ${reasoningPreserve ?
|
|
29133
|
-
` cache TTL: ${
|
|
29134
|
-
` index on start: ${idx?.onSessionStart !== false ?
|
|
29135
|
-
` log level: ${
|
|
29136
|
-
` audit level: ${
|
|
29137
|
-
` HQ publishing: ${hqEnabled ?
|
|
29138
|
-
` HQ URL: ${
|
|
29139
|
-
` HQ token: ${
|
|
29140
|
-
` HQ raw content: ${hq?.rawContent === true ?
|
|
29424
|
+
` auto-proceed delay: ${color58.cyan(formatDelay(delay))} ${color58.dim("change: /settings delay <seconds>")}`,
|
|
29425
|
+
` default autonomy mode: ${color58.cyan(mode)} ${color58.dim("change: /settings mode off|suggest|auto")}`,
|
|
29426
|
+
` fleet chat: ${color58.cyan(resolveFleetChatVerbosity(au))} ${color58.dim("change: /settings stream-fleet off|full")}`,
|
|
29427
|
+
` completion chime: ${au?.chime === true ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings chime on|off")}`,
|
|
29428
|
+
` confirm before exit: ${au?.confirmExit !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings confirm-exit on|off")}`,
|
|
29429
|
+
` debug stream: ${debugStream ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings debug-stream on|off")}`,
|
|
29430
|
+
` config scope: ${color58.cyan(configScope)} ${color58.dim("change: /settings config-scope global|project")}`,
|
|
29431
|
+
` filesystem access: ${color58.cyan(fsAccess)} ${color58.dim("change: /settings fs-access unrestricted|project")}`,
|
|
29432
|
+
` refine: ${enhanceEnabled ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings refine on|off")}`,
|
|
29433
|
+
` refine-delay: ${color58.cyan(formatDelay(enhanceDelay))} ${color58.dim("change: /settings refine-delay <seconds>")}`,
|
|
29434
|
+
` refine-language: ${color58.cyan(enhanceLanguage)} ${color58.dim("change: /settings refine-language original|english")}`,
|
|
29435
|
+
` refiner-provider: ${color58.cyan(au?.refinerProvider ?? color58.dim("(unset)"))} ${color58.dim("change: /settings refiner-provider <id>")}`,
|
|
29436
|
+
` refiner-model: ${color58.cyan(au?.refinerModel ?? color58.dim("(unset)"))} ${color58.dim("change: /settings refiner-model <model>")}`,
|
|
29437
|
+
` refiner-fallback-profile: ${color58.cyan(au?.refinerFallbackProfile ?? color58.dim("(unset)"))} ${color58.dim("change: /settings refiner-fallback-profile <name>")}`,
|
|
29438
|
+
` semver default part: ${color58.cyan(semverPart)} ${color58.dim("change: /settings semver-part patch|minor|major|auto")}`,
|
|
29439
|
+
` circuit breaker: ${breakerEnabled ? color58.cyan("on") : color58.dim("off")} (${breakerTimeout > 0 ? formatDelay(breakerTimeout) : color58.dim("manual")}) ${color58.dim("change: /settings breaker on|off")}`,
|
|
29440
|
+
` context mode: ${color58.cyan(contextMode)} ${color58.dim("change: /settings context-mode balanced|frugal|deep")}`,
|
|
29441
|
+
` context strategy: ${color58.cyan(contextStrategy)} ${color58.dim("change: /settings context-strategy hybrid|intelligent|selective")}`,
|
|
29442
|
+
` context auto-compact: ${contextAutoCompact ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings context-auto-compact on|off")}`,
|
|
29443
|
+
` token-saving: ${color58.cyan(tokenSavingTier)} ${color58.dim("change: /settings token-saving off|minimal|light|medium|aggressive")}`,
|
|
29444
|
+
` nextsteps tool: ${nextStepsToolEnabled ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings nextsteps-tool on|off")}`,
|
|
29445
|
+
` auto-thinning: ${autoThinEnabled ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings autothin on|off|status")}`,
|
|
29446
|
+
` auto-thinning boot-apply: ${autoThinApplyOnBoot ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings autothin-boot on|off")}`,
|
|
29447
|
+
` auto-thinning idle window: ${color58.cyan(`${autoThinIdleDays}d`)} ${color58.dim("change: /settings autothin-idle <days>")}`,
|
|
29448
|
+
` auto-thinning min invocations: ${color58.cyan(String(autoThinMinInvocations))} ${color58.dim("change: /settings autothin-min <count>")}`,
|
|
29449
|
+
` MCP features: ${feats?.mcp !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings mcp on|off")}`,
|
|
29450
|
+
` plugin features: ${feats?.plugins !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings plugins on|off")}`,
|
|
29451
|
+
` memory features: ${feats?.memory !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings memory on|off")}`,
|
|
29452
|
+
` skills features: ${feats?.skills !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings skills on|off")}`,
|
|
29453
|
+
` models registry: ${feats?.modelsRegistry !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings models-registry on|off")}`,
|
|
29454
|
+
` max concurrent: ${color58.cyan(maxConcurrent === 0 ? "default" : String(maxConcurrent))} ${color58.dim("change: /settings max-concurrent <n>")}`,
|
|
29455
|
+
` max iterations: ${color58.cyan(String(tools?.maxIterations ?? "default"))} ${color58.dim("change: /settings max-iterations <n>")}`,
|
|
29456
|
+
` auto-proceed max iters: ${color58.cyan(String(au?.autoProceedMaxIterations ?? "unlimited"))} ${color58.dim("change: /settings auto-proceed-max-iterations <n>")}`,
|
|
29457
|
+
` title animation: ${titleAnimation ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings title-animation on|off")}`,
|
|
29458
|
+
` thinking word: ${color58.cyan(au?.thinkingWord ?? "thinking")} ${color58.dim("change: /settings thinking-word <word>")}`,
|
|
29459
|
+
` statusline mode: ${color58.cyan(au?.statuslineMode ?? "minimum")} ${color58.dim("change: /settings statusline minimum|detailed|no-color")}`,
|
|
29460
|
+
` animation style: ${color58.cyan(au?.animationStyle ?? "rainbow")} ${color58.dim("change: /settings animation rainbow|wave|pulse|dots|breathe|static|cycle")}`,
|
|
29461
|
+
` read symbols: ${au?.readAdvancedMode === true ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings read-symbols on|off")}`,
|
|
29462
|
+
` reasoning mode: ${color58.cyan(reasoningMode)} ${color58.dim("change: /settings reasoning auto|on|off")}`,
|
|
29463
|
+
` reasoning effort: ${color58.cyan(reasoningEffort)} ${color58.dim("change: /settings reasoning-effort <level>")}`,
|
|
29464
|
+
` reasoning preserve: ${reasoningPreserve ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings reasoning-preserve on|off")}`,
|
|
29465
|
+
` cache TTL: ${color58.cyan(cacheTtl)} ${color58.dim("change: /settings cache-ttl 5m|1h")}`,
|
|
29466
|
+
` index on start: ${idx?.onSessionStart !== false ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings index-on-start on|off")}`,
|
|
29467
|
+
` log level: ${color58.cyan(log?.level ?? "info")} ${color58.dim("change: /settings log-level error|warn|info|debug|trace")}`,
|
|
29468
|
+
` audit level: ${color58.cyan(sess?.auditLevel ?? "standard")} ${color58.dim("change: /settings audit-level minimal|standard|full")}`,
|
|
29469
|
+
` HQ publishing: ${hqEnabled ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings hq on|off")}`,
|
|
29470
|
+
` HQ URL: ${color58.cyan(hqUrl)} ${color58.dim("change: /settings hq-url <url>")}`,
|
|
29471
|
+
` HQ token: ${color58.cyan(hqToken)} ${color58.dim("change: /settings hq-token <token>")}`,
|
|
29472
|
+
` HQ raw content: ${hq?.rawContent === true ? color58.cyan("on") : color58.dim("off")} ${color58.dim("change: /settings hq-raw on|off")}`,
|
|
29141
29473
|
"",
|
|
29142
|
-
|
|
29474
|
+
color58.dim(` Persisted to ${persistedTo} \xB7 /settings help for more`)
|
|
29143
29475
|
].join("\n");
|
|
29144
29476
|
}
|
|
29145
29477
|
|
|
@@ -29157,7 +29489,7 @@ function buildSettingsCommand(opts) {
|
|
|
29157
29489
|
return { message: this.help ?? "" };
|
|
29158
29490
|
}
|
|
29159
29491
|
if (!opts.configStore || !opts.paths) {
|
|
29160
|
-
return { message: `${
|
|
29492
|
+
return { message: `${color59.red("Error")} config store not available.` };
|
|
29161
29493
|
}
|
|
29162
29494
|
if (!sub) {
|
|
29163
29495
|
return { message: formatCurrentSettingsView(opts) };
|
|
@@ -29174,7 +29506,7 @@ function buildSettingsCommand(opts) {
|
|
|
29174
29506
|
|
|
29175
29507
|
// src/slash-commands/shadow.ts
|
|
29176
29508
|
import { ToolValidationError as ToolValidationError4 } from "@wrongstack/core/types";
|
|
29177
|
-
import { color as
|
|
29509
|
+
import { color as color60 } from "@wrongstack/core/utils";
|
|
29178
29510
|
var DEFAULT_SHADOW_INTERVAL_MS = 3e4;
|
|
29179
29511
|
var MIN_SHADOW_INTERVAL_MS = 5e3;
|
|
29180
29512
|
function buildShadowCommand(opts) {
|
|
@@ -29244,7 +29576,7 @@ function buildShadowCommand(opts) {
|
|
|
29244
29576
|
if (opts.shadowController?.activeId != null) {
|
|
29245
29577
|
return {
|
|
29246
29578
|
message: [
|
|
29247
|
-
`${
|
|
29579
|
+
`${color60.yellow("\u26A0")} A Shadow Agent is already running (${opts.shadowController.activeId.slice(0, 8)}).`,
|
|
29248
29580
|
"",
|
|
29249
29581
|
"Only one Shadow Agent instance is allowed per session.",
|
|
29250
29582
|
"Use /shadow status to view the current instance."
|
|
@@ -29283,16 +29615,16 @@ function buildShadowCommand(opts) {
|
|
|
29283
29615
|
shadowIntervalMs: intervalMs
|
|
29284
29616
|
});
|
|
29285
29617
|
return {
|
|
29286
|
-
message: `${
|
|
29287
|
-
${
|
|
29288
|
-
${
|
|
29618
|
+
message: `${color60.green("\u2713")} Shadow Agent queued: ${spawnId}
|
|
29619
|
+
${color60.dim("Mode:")} one-shot quiet check
|
|
29620
|
+
${color60.dim("Model:")} ${modelRef.label}`
|
|
29289
29621
|
};
|
|
29290
29622
|
}
|
|
29291
29623
|
case "stop": {
|
|
29292
29624
|
const activeId = opts.shadowController?.activeId;
|
|
29293
29625
|
if (!activeId) {
|
|
29294
29626
|
return {
|
|
29295
|
-
message: `${
|
|
29627
|
+
message: `${color60.yellow("\u26A0")} No active Shadow Agent is registered for this session.`
|
|
29296
29628
|
};
|
|
29297
29629
|
}
|
|
29298
29630
|
if (!opts.onFleetTerminate) {
|
|
@@ -29301,12 +29633,12 @@ ${color59.dim("Model:")} ${modelRef.label}`
|
|
|
29301
29633
|
const ok = await opts.onFleetTerminate(activeId);
|
|
29302
29634
|
if (ok) {
|
|
29303
29635
|
opts.shadowController?.clear();
|
|
29304
|
-
return { message: `${
|
|
29636
|
+
return { message: `${color60.green("\u2713")} Shadow Agent stopped: ${activeId}` };
|
|
29305
29637
|
}
|
|
29306
29638
|
return {
|
|
29307
29639
|
message: [
|
|
29308
|
-
`${
|
|
29309
|
-
`It may already be stopped. Use ${
|
|
29640
|
+
`${color60.red("\u2717")} Failed to stop Shadow Agent ${color60.bold(activeId)}.`,
|
|
29641
|
+
`It may already be stopped. Use ${color60.bold("/shadow status")} to inspect active agents.`
|
|
29310
29642
|
].join("\n")
|
|
29311
29643
|
};
|
|
29312
29644
|
}
|
|
@@ -29334,10 +29666,10 @@ ${color59.dim("Model:")} ${modelRef.label}`
|
|
|
29334
29666
|
opts.shadowController?.clear();
|
|
29335
29667
|
return {
|
|
29336
29668
|
message: [
|
|
29337
|
-
`${
|
|
29669
|
+
`${color60.red("\u26A0")} HOOP: Stopped ${killed} running agent(s)`,
|
|
29338
29670
|
"",
|
|
29339
|
-
`Target: ${
|
|
29340
|
-
`Reason: ${
|
|
29671
|
+
`Target: ${color60.bold("all")}`,
|
|
29672
|
+
`Reason: ${color60.yellow(reason)}`
|
|
29341
29673
|
].join("\n")
|
|
29342
29674
|
};
|
|
29343
29675
|
}
|
|
@@ -29351,10 +29683,10 @@ ${color59.dim("Model:")} ${modelRef.label}`
|
|
|
29351
29683
|
}
|
|
29352
29684
|
return {
|
|
29353
29685
|
message: [
|
|
29354
|
-
ok ? `${
|
|
29686
|
+
ok ? `${color60.red("\u26A0")} HOOP: Stopped agent` : `${color60.red("\u2717")} HOOP: Failed to stop agent`,
|
|
29355
29687
|
"",
|
|
29356
|
-
`Target: ${
|
|
29357
|
-
`Reason: ${
|
|
29688
|
+
`Target: ${color60.bold(targetId)}`,
|
|
29689
|
+
`Reason: ${color60.yellow(reason)}`,
|
|
29358
29690
|
agentInfo ? `
|
|
29359
29691
|
Agent info:
|
|
29360
29692
|
${agentInfo}` : ""
|
|
@@ -29379,7 +29711,7 @@ Current default: ${defaultModelRef.label}`
|
|
|
29379
29711
|
opts.shadowController?.setDefaults?.({ provider: parsed.provider, model: parsed.model });
|
|
29380
29712
|
return {
|
|
29381
29713
|
message: `/shadow model ${parsed.label}
|
|
29382
|
-
${
|
|
29714
|
+
${color60.dim("Model will be applied on next /shadow start")}`
|
|
29383
29715
|
};
|
|
29384
29716
|
}
|
|
29385
29717
|
case "interval": {
|
|
@@ -29399,7 +29731,7 @@ Current default: ${DEFAULT_SHADOW_INTERVAL_MS}ms (30 seconds)`
|
|
|
29399
29731
|
opts.shadowController?.setDefaults?.({ intervalMs: ms });
|
|
29400
29732
|
return {
|
|
29401
29733
|
message: `/shadow interval ${ms}ms
|
|
29402
|
-
${
|
|
29734
|
+
${color60.dim("Interval will be applied on next /shadow start")}`
|
|
29403
29735
|
};
|
|
29404
29736
|
}
|
|
29405
29737
|
default: {
|
|
@@ -29466,7 +29798,7 @@ function parseFlags2(args) {
|
|
|
29466
29798
|
}
|
|
29467
29799
|
|
|
29468
29800
|
// src/slash-commands/sidebar.ts
|
|
29469
|
-
import { color as
|
|
29801
|
+
import { color as color61 } from "@wrongstack/core/utils";
|
|
29470
29802
|
function buildSidebarCommand(opts) {
|
|
29471
29803
|
return {
|
|
29472
29804
|
name: "sidebar",
|
|
@@ -29486,7 +29818,7 @@ function buildSidebarCommand(opts) {
|
|
|
29486
29818
|
return { message: this.help ?? "" };
|
|
29487
29819
|
}
|
|
29488
29820
|
if (!opts.configStore) {
|
|
29489
|
-
return { message: `${
|
|
29821
|
+
return { message: `${color61.red("Error")} config store not available.` };
|
|
29490
29822
|
}
|
|
29491
29823
|
const current = opts.configStore.get().autonomy?.showSidebar ?? true;
|
|
29492
29824
|
let next;
|
|
@@ -29498,7 +29830,7 @@ function buildSidebarCommand(opts) {
|
|
|
29498
29830
|
next = false;
|
|
29499
29831
|
} else if (sub === "status") {
|
|
29500
29832
|
return {
|
|
29501
|
-
message: `Right sidebar is currently ${current ?
|
|
29833
|
+
message: `Right sidebar is currently ${current ? color61.green("on") : color61.yellow("off")}.`
|
|
29502
29834
|
};
|
|
29503
29835
|
} else {
|
|
29504
29836
|
return {
|
|
@@ -29512,7 +29844,7 @@ function buildSidebarCommand(opts) {
|
|
|
29512
29844
|
}
|
|
29513
29845
|
});
|
|
29514
29846
|
return {
|
|
29515
|
-
message: `Right sidebar is now ${next ?
|
|
29847
|
+
message: `Right sidebar is now ${next ? color61.green("on") : color61.yellow("off")}.`
|
|
29516
29848
|
};
|
|
29517
29849
|
}
|
|
29518
29850
|
};
|
|
@@ -29757,7 +30089,7 @@ function buildStatuslineCommand(deps) {
|
|
|
29757
30089
|
}
|
|
29758
30090
|
|
|
29759
30091
|
// src/slash-commands/supervisor.ts
|
|
29760
|
-
import { color as
|
|
30092
|
+
import { color as color62 } from "@wrongstack/core/utils";
|
|
29761
30093
|
function fmtAge4(at) {
|
|
29762
30094
|
const s = Math.max(0, Math.round((Date.now() - at) / 1e3));
|
|
29763
30095
|
if (s < 60) return `${s}s ago`;
|
|
@@ -29793,13 +30125,13 @@ function buildSupervisorCommand(opts) {
|
|
|
29793
30125
|
}
|
|
29794
30126
|
if (sub === "on") {
|
|
29795
30127
|
supervisor.start();
|
|
29796
|
-
const msg2 = `Fleet supervisor ${
|
|
30128
|
+
const msg2 = `Fleet supervisor ${color62.green("armed")} \u2014 evaluating every ${Math.round(supervisor.configSnapshot().intervalMs / 1e3)}s.`;
|
|
29797
30129
|
opts.renderer.write(msg2);
|
|
29798
30130
|
return { message: msg2 };
|
|
29799
30131
|
}
|
|
29800
30132
|
if (sub === "off") {
|
|
29801
30133
|
supervisor.stop();
|
|
29802
|
-
const msg2 = `Fleet supervisor ${
|
|
30134
|
+
const msg2 = `Fleet supervisor ${color62.yellow("disarmed")} \u2014 no further automatic interventions this session.`;
|
|
29803
30135
|
opts.renderer.write(msg2);
|
|
29804
30136
|
return { message: msg2 };
|
|
29805
30137
|
}
|
|
@@ -29812,10 +30144,10 @@ function buildSupervisorCommand(opts) {
|
|
|
29812
30144
|
return { message: msg3 };
|
|
29813
30145
|
}
|
|
29814
30146
|
const lines2 = entries.map((e) => {
|
|
29815
|
-
const who = e.subagentId ? ` ${
|
|
30147
|
+
const who = e.subagentId ? ` ${color62.cyan(e.subagentId)}` : "";
|
|
29816
30148
|
const task = e.taskId ? ` task=${e.taskId.slice(0, 8)}` : "";
|
|
29817
|
-
const outcome = e.outcome === "approved" ?
|
|
29818
|
-
return `${
|
|
30149
|
+
const outcome = e.outcome === "approved" ? color62.green(e.outcome) : e.outcome === "denied" || e.outcome === "error" ? color62.red(e.outcome) : color62.yellow(e.outcome);
|
|
30150
|
+
return `${color62.dim(fmtAge4(e.at))} ${e.kind}${who}${task} \u2192 ${e.proposedAction} [${outcome}] ${color62.dim(e.detail)}`;
|
|
29819
30151
|
});
|
|
29820
30152
|
const msg2 = lines2.join("\n");
|
|
29821
30153
|
opts.renderer.write(msg2);
|
|
@@ -29825,12 +30157,12 @@ function buildSupervisorCommand(opts) {
|
|
|
29825
30157
|
const history = supervisor.history();
|
|
29826
30158
|
const last = history[history.length - 1];
|
|
29827
30159
|
const lines = [
|
|
29828
|
-
`Fleet supervisor: ${supervisor.isRunning() ?
|
|
30160
|
+
`Fleet supervisor: ${supervisor.isRunning() ? color62.green("armed") : color62.yellow("disarmed")}`,
|
|
29829
30161
|
` interval ${Math.round(cfg.intervalMs / 1e3)}s \xB7 cooldown ${Math.round(cfg.cooldownMs / 1e3)}s \xB7 max ${cfg.maxInterventionsPerSubagent} interventions/agent`,
|
|
29830
30162
|
` signals: starvation>${Math.round(cfg.pinnedWaitMs / 1e3)}s \xB7 overload\u2265${cfg.overloadPinnedThreshold} pinned \xB7 backlog>${cfg.backlogFactor}\xD7workers \xB7 stuck>${Math.round(cfg.stuckMs / 1e3)}s \xB7 failstreak\u2265${cfg.failureStreak}`,
|
|
29831
30163
|
` actions: retarget \u2713 \xB7 spawn ${cfg.allowSpawn ? "\u2713" : "\u2717"} \xB7 steer \u2713 \xB7 terminate ${cfg.allowTerminate ? "\u2713" : "\u2717 (config fleet.supervisor.allowTerminate)"}`,
|
|
29832
30164
|
` activity: ${history.length} engagement(s)${last ? ` \u2014 last: ${last.kind} \u2192 ${last.proposedAction} [${last.outcome}] ${fmtAge4(last.at)}` : ""}`,
|
|
29833
|
-
|
|
30165
|
+
color62.dim(" decisions are gated by the Brain \u2014 see /brain (risk ceiling applies)")
|
|
29834
30166
|
];
|
|
29835
30167
|
const msg = lines.join("\n");
|
|
29836
30168
|
opts.renderer.write(msg);
|
|
@@ -30259,7 +30591,7 @@ ${formatTaskProgress(file.tasks)}`;
|
|
|
30259
30591
|
// src/slash-commands/techstack.ts
|
|
30260
30592
|
import * as fs19 from "node:fs/promises";
|
|
30261
30593
|
import * as path20 from "node:path";
|
|
30262
|
-
import { color as
|
|
30594
|
+
import { color as color63, toErrorMessage as toErrorMessage28 } from "@wrongstack/core/utils";
|
|
30263
30595
|
async function discoverPackageFiles(projectRoot) {
|
|
30264
30596
|
const files = [];
|
|
30265
30597
|
const rootPkg = path20.join(projectRoot, "package.json");
|
|
@@ -30409,10 +30741,10 @@ function buildTechStackCommand(opts) {
|
|
|
30409
30741
|
" 1. Reads every package.json in the project",
|
|
30410
30742
|
" 2. Looks up latest versions on the npm registry",
|
|
30411
30743
|
" 3. Flags outdated, dead, or obsolete packages",
|
|
30412
|
-
` 4. Writes a ${
|
|
30744
|
+
` 4. Writes a ${color63.cyan("techstack.md")} (or .json) report to the project root`,
|
|
30413
30745
|
"",
|
|
30414
30746
|
"Uses the `tech-stack` skill for version verification rules.",
|
|
30415
|
-
`Hooked into ${
|
|
30747
|
+
`Hooked into ${color63.cyan("/init")} \u2014 runs automatically on first project setup.`
|
|
30416
30748
|
].join("\n"),
|
|
30417
30749
|
async run(args, _ctx) {
|
|
30418
30750
|
const trimmed = args.trim().toLowerCase();
|
|
@@ -30496,12 +30828,12 @@ function buildTechStackCommand(opts) {
|
|
|
30496
30828
|
try {
|
|
30497
30829
|
packageFiles = await discoverPackageFiles(opts.projectRoot);
|
|
30498
30830
|
if (packageFiles.length === 0) {
|
|
30499
|
-
discoveryNote =
|
|
30831
|
+
discoveryNote = color63.amber(
|
|
30500
30832
|
"\u26A0 No package.json files found. This does not look like a Node.js project."
|
|
30501
30833
|
);
|
|
30502
30834
|
}
|
|
30503
30835
|
} catch (err) {
|
|
30504
|
-
discoveryNote =
|
|
30836
|
+
discoveryNote = color63.red(`Could not scan for package files: ${toErrorMessage28(err)}`);
|
|
30505
30837
|
}
|
|
30506
30838
|
const task = buildTechStackTask({
|
|
30507
30839
|
projectRoot: opts.projectRoot,
|
|
@@ -30524,11 +30856,11 @@ function buildTechStackCommand(opts) {
|
|
|
30524
30856
|
};
|
|
30525
30857
|
}
|
|
30526
30858
|
const header = isInit ? "Tech Stack Init Audit" : "Tech Stack Audit";
|
|
30527
|
-
const label = `${
|
|
30859
|
+
const label = `${color63.cyan("\u{1F50D}")} ${color63.bold(header)} ${color63.dim(`(${packageFiles.length} package files)`)}`;
|
|
30528
30860
|
opts.renderer.write(label);
|
|
30529
30861
|
if (discoveryNote) opts.renderer.write(discoveryNote);
|
|
30530
30862
|
opts.renderer.write(
|
|
30531
|
-
|
|
30863
|
+
color63.dim(
|
|
30532
30864
|
`Spawning tech-stack subagent \u2192 writes ${outputFormat === "json" ? "techstack.json" : "techstack.md"} when done.`
|
|
30533
30865
|
)
|
|
30534
30866
|
);
|
|
@@ -30550,10 +30882,10 @@ function buildTechStackCommand(opts) {
|
|
|
30550
30882
|
}
|
|
30551
30883
|
|
|
30552
30884
|
// src/slash-commands/telegram-settings.ts
|
|
30553
|
-
import { color as
|
|
30885
|
+
import { color as color65, toErrorMessage as toErrorMessage29 } from "@wrongstack/core/utils";
|
|
30554
30886
|
|
|
30555
30887
|
// src/slash-commands/telegram-setup.ts
|
|
30556
|
-
import { color as
|
|
30888
|
+
import { color as color64 } from "@wrongstack/core/utils";
|
|
30557
30889
|
|
|
30558
30890
|
// src/slash-commands/telegram-pairing.ts
|
|
30559
30891
|
var DISCOVERY_LIMIT = 25;
|
|
@@ -30669,31 +31001,31 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30669
31001
|
if (BOT_TOKEN_RE.test(first)) {
|
|
30670
31002
|
return {
|
|
30671
31003
|
message: [
|
|
30672
|
-
`${
|
|
30673
|
-
`Run ${
|
|
31004
|
+
`${color64.red("\u2717")} Bot tokens are no longer accepted as slash-command arguments.`,
|
|
31005
|
+
`Run ${color64.cyan("/telegram-setup [chatId]")} and enter it at the masked prompt.`
|
|
30674
31006
|
].join("\n")
|
|
30675
31007
|
};
|
|
30676
31008
|
}
|
|
30677
31009
|
if (parts.length > 1) {
|
|
30678
|
-
return { message: `${
|
|
31010
|
+
return { message: `${color64.amber("Usage:")} /telegram-setup [chatId]` };
|
|
30679
31011
|
}
|
|
30680
31012
|
if (!opts.readSecret || !opts.vault || !opts.paths?.globalConfig) {
|
|
30681
31013
|
return {
|
|
30682
|
-
message: `${
|
|
31014
|
+
message: `${color64.red("\u2717")} Secure Telegram setup is unavailable in this session.`
|
|
30683
31015
|
};
|
|
30684
31016
|
}
|
|
30685
31017
|
let botToken;
|
|
30686
31018
|
try {
|
|
30687
|
-
botToken = (await opts.readSecret(`Telegram bot token ${
|
|
31019
|
+
botToken = (await opts.readSecret(`Telegram bot token ${color64.dim("(hidden, paste OK)")}: `)).trim();
|
|
30688
31020
|
} catch {
|
|
30689
|
-
return { message:
|
|
31021
|
+
return { message: color64.dim("Telegram setup cancelled.") };
|
|
30690
31022
|
}
|
|
30691
|
-
if (!botToken) return { message:
|
|
31023
|
+
if (!botToken) return { message: color64.dim("Telegram setup cancelled.") };
|
|
30692
31024
|
if (!BOT_TOKEN_RE.test(botToken)) {
|
|
30693
31025
|
return {
|
|
30694
31026
|
message: [
|
|
30695
|
-
`${
|
|
30696
|
-
`Expected: ${
|
|
31027
|
+
`${color64.red("\u2717")} Invalid token format.`,
|
|
31028
|
+
`Expected: ${color64.dim("123456789:ABCdefGHIjkl...")}`,
|
|
30697
31029
|
"",
|
|
30698
31030
|
"Get a valid token from @BotFather on Telegram."
|
|
30699
31031
|
].join("\n")
|
|
@@ -30708,7 +31040,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30708
31040
|
} catch {
|
|
30709
31041
|
return {
|
|
30710
31042
|
message: [
|
|
30711
|
-
`${
|
|
31043
|
+
`${color64.red("\u2717")} Could not reach Telegram API.`,
|
|
30712
31044
|
"",
|
|
30713
31045
|
"Check your network connection and try again."
|
|
30714
31046
|
].join("\n")
|
|
@@ -30717,7 +31049,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30717
31049
|
if (!botInfo.ok || !botInfo.result) {
|
|
30718
31050
|
return {
|
|
30719
31051
|
message: [
|
|
30720
|
-
`${
|
|
31052
|
+
`${color64.red("\u2717")} Invalid bot token.`,
|
|
30721
31053
|
"",
|
|
30722
31054
|
"Get a valid token from @BotFather on Telegram."
|
|
30723
31055
|
].join("\n")
|
|
@@ -30727,13 +31059,13 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30727
31059
|
const classifiedChatId = chatId ? classifyTelegramChatId(chatId) : void 0;
|
|
30728
31060
|
if (classifiedChatId?.kind === "invalid") {
|
|
30729
31061
|
return {
|
|
30730
|
-
message: `${
|
|
31062
|
+
message: `${color64.red("\u2717")} Invalid Telegram chat ID. Expected a positive private chat ID.`
|
|
30731
31063
|
};
|
|
30732
31064
|
}
|
|
30733
31065
|
if (classifiedChatId?.kind === "group") {
|
|
30734
31066
|
return {
|
|
30735
31067
|
message: [
|
|
30736
|
-
`${
|
|
31068
|
+
`${color64.amber("\u26A0")} Shared group, supergroup, and channel IDs cannot be paired by manual ID.`,
|
|
30737
31069
|
"Run /telegram-setup without a chat ID and select a discovered private identity.",
|
|
30738
31070
|
"No configuration was changed."
|
|
30739
31071
|
].join("\n")
|
|
@@ -30747,7 +31079,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30747
31079
|
} catch {
|
|
30748
31080
|
return {
|
|
30749
31081
|
message: [
|
|
30750
|
-
`${
|
|
31082
|
+
`${color64.red("\u2717")} Could not discover recent Telegram chats.`,
|
|
30751
31083
|
"Message the bot once, then run /telegram-setup again.",
|
|
30752
31084
|
"No configuration was changed."
|
|
30753
31085
|
].join("\n")
|
|
@@ -30756,7 +31088,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30756
31088
|
if (candidates.length === 0) {
|
|
30757
31089
|
return {
|
|
30758
31090
|
message: [
|
|
30759
|
-
`${
|
|
31091
|
+
`${color64.amber("No recent chats found.")}`,
|
|
30760
31092
|
"Message the bot from the private account you want to pair, then run setup again.",
|
|
30761
31093
|
"No configuration was changed."
|
|
30762
31094
|
].join("\n")
|
|
@@ -30764,31 +31096,31 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30764
31096
|
}
|
|
30765
31097
|
opts.renderer.write(
|
|
30766
31098
|
[
|
|
30767
|
-
|
|
31099
|
+
color64.bold("Recent Telegram identities"),
|
|
30768
31100
|
formatTelegramPairingCandidates(candidates),
|
|
30769
31101
|
"",
|
|
30770
|
-
|
|
31102
|
+
color64.dim("Choose a private candidate number, or press Enter to cancel.")
|
|
30771
31103
|
].join("\n")
|
|
30772
31104
|
);
|
|
30773
31105
|
let choiceInput;
|
|
30774
31106
|
try {
|
|
30775
31107
|
choiceInput = opts.readText ? await opts.readText("Pair candidate \u203A ") : await opts.reader.readLine("Pair candidate \u203A ");
|
|
30776
31108
|
} catch {
|
|
30777
|
-
return { message:
|
|
31109
|
+
return { message: color64.dim("Telegram setup cancelled. No configuration was changed.") };
|
|
30778
31110
|
}
|
|
30779
31111
|
const choice = parseTelegramPairingChoice(choiceInput, candidates);
|
|
30780
31112
|
if (choice.kind === "cancel") {
|
|
30781
|
-
return { message:
|
|
31113
|
+
return { message: color64.dim("Telegram setup cancelled. No configuration was changed.") };
|
|
30782
31114
|
}
|
|
30783
31115
|
if (choice.kind === "invalid") {
|
|
30784
31116
|
return {
|
|
30785
|
-
message: `${
|
|
31117
|
+
message: `${color64.red("\u2717")} Invalid pairing choice. No configuration was changed.`
|
|
30786
31118
|
};
|
|
30787
31119
|
}
|
|
30788
31120
|
if (!choice.candidate.eligible) {
|
|
30789
31121
|
return {
|
|
30790
31122
|
message: [
|
|
30791
|
-
`${
|
|
31123
|
+
`${color64.amber("\u26A0")} Shared, group, or ambiguous identities are not paired automatically.`,
|
|
30792
31124
|
"Use a private chat where chat_id and user_id identify the same account.",
|
|
30793
31125
|
"No configuration was changed."
|
|
30794
31126
|
].join("\n")
|
|
@@ -30830,7 +31162,7 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30830
31162
|
} catch {
|
|
30831
31163
|
return {
|
|
30832
31164
|
message: [
|
|
30833
|
-
`${
|
|
31165
|
+
`${color64.red("\u2717")} Failed to save Telegram configuration.`,
|
|
30834
31166
|
"The token was not printed. Check the config path and vault, then try again."
|
|
30835
31167
|
].join("\n")
|
|
30836
31168
|
};
|
|
@@ -30838,15 +31170,15 @@ function buildTelegramSetupCommand(opts) {
|
|
|
30838
31170
|
const bot = botInfo.result;
|
|
30839
31171
|
return {
|
|
30840
31172
|
message: [
|
|
30841
|
-
`${
|
|
31173
|
+
`${color64.green("\u2713")} Telegram configured successfully.`,
|
|
30842
31174
|
"",
|
|
30843
|
-
`Bot: ${
|
|
31175
|
+
`Bot: ${color64.bold(`@${bot.username ?? bot.first_name}`)}`,
|
|
30844
31176
|
...pairedCandidate ? [
|
|
30845
|
-
`Paired private chat: ${
|
|
30846
|
-
`Paired user: ${
|
|
30847
|
-
] : chatId ? [`Default chat: ${
|
|
31177
|
+
`Paired private chat: ${color64.green(String(pairedCandidate.chatId))}`,
|
|
31178
|
+
`Paired user: ${color64.green(String(pairedCandidate.userId))}`
|
|
31179
|
+
] : chatId ? [`Default chat: ${color64.green(chatId)}`] : [],
|
|
30848
31180
|
"",
|
|
30849
|
-
`${
|
|
31181
|
+
`${color64.amber("\u26A0")} Restart WrongStack for the plugin to load the new token.`
|
|
30850
31182
|
].join("\n")
|
|
30851
31183
|
};
|
|
30852
31184
|
}
|
|
@@ -30880,15 +31212,15 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
30880
31212
|
const chat = tg.notifyChatId !== void 0 && tg.notifyChatId !== null ? String(tg.notifyChatId) : "not set";
|
|
30881
31213
|
const hasToken = typeof tg.botToken === "string" && tg.botToken.length > 0;
|
|
30882
31214
|
return [
|
|
30883
|
-
`${
|
|
31215
|
+
`${color65.bold("Telegram")} ${color65.dim("\u2014 Notification Settings")}`,
|
|
30884
31216
|
"",
|
|
30885
|
-
` session end: ${sessionEnd ?
|
|
30886
|
-
` delegate done: ${delegate ?
|
|
30887
|
-
` long tool: ${
|
|
30888
|
-
` poll interval: ${
|
|
30889
|
-
` notify chat: ${
|
|
31217
|
+
` session end: ${sessionEnd ? color65.cyan("on") : color65.dim("off")} ${color65.dim("change: /telegram-settings session-end on|off")}`,
|
|
31218
|
+
` delegate done: ${delegate ? color65.cyan("on") : color65.dim("off")} ${color65.dim("change: /telegram-settings delegate on|off")}`,
|
|
31219
|
+
` long tool: ${color65.cyan(longTool)} ${color65.dim("change: /telegram-settings long-tool <ms|off>")}`,
|
|
31220
|
+
` poll interval: ${color65.cyan(poll)} ${color65.dim("change: /telegram-settings poll <seconds>")}`,
|
|
31221
|
+
` notify chat: ${color65.cyan(chat)} ${color65.dim("change: /telegram-settings chat <chatId>")}`,
|
|
30890
31222
|
"",
|
|
30891
|
-
hasToken ?
|
|
31223
|
+
hasToken ? color65.dim(" Bot token configured. Changes apply immediately.") : `${color65.amber("\u26A0")} No bot token configured. Run: /telegram-setup <botToken> [chatId]`
|
|
30892
31224
|
].join("\n");
|
|
30893
31225
|
}
|
|
30894
31226
|
return {
|
|
@@ -30904,7 +31236,7 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
30904
31236
|
return { message: HELP2 };
|
|
30905
31237
|
}
|
|
30906
31238
|
if (!opts.configStore || !opts.paths?.globalConfig || !opts.vault) {
|
|
30907
|
-
return { message: `${
|
|
31239
|
+
return { message: `${color65.red("Error")} secure config persistence not available.` };
|
|
30908
31240
|
}
|
|
30909
31241
|
if (!sub) {
|
|
30910
31242
|
return { message: currentView() };
|
|
@@ -30918,7 +31250,7 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
30918
31250
|
if (sub === "all") {
|
|
30919
31251
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
30920
31252
|
if (!["on", "off"].includes(raw)) {
|
|
30921
|
-
return { message: `${
|
|
31253
|
+
return { message: `${color65.amber("Usage:")} /telegram-settings all on|off` };
|
|
30922
31254
|
}
|
|
30923
31255
|
const on = raw === "on";
|
|
30924
31256
|
await persistTelegramConfig(persistDeps, (tg) => {
|
|
@@ -30926,40 +31258,40 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
30926
31258
|
tg.notifyOnDelegate = on;
|
|
30927
31259
|
});
|
|
30928
31260
|
return {
|
|
30929
|
-
message: `${
|
|
31261
|
+
message: `${color65.green("\u2713")} all event notifications \u2192 ${on ? color65.cyan("on") : color65.dim("off")} ${color65.dim("(session-end, delegate)")}`
|
|
30930
31262
|
};
|
|
30931
31263
|
}
|
|
30932
31264
|
if (sub === "session-end") {
|
|
30933
31265
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
30934
31266
|
if (!["on", "off"].includes(raw)) {
|
|
30935
|
-
return { message: `${
|
|
31267
|
+
return { message: `${color65.amber("Usage:")} /telegram-settings session-end on|off` };
|
|
30936
31268
|
}
|
|
30937
31269
|
const on = raw === "on";
|
|
30938
31270
|
await persistTelegramConfig(persistDeps, (tg) => {
|
|
30939
31271
|
tg.notifyOnSessionEnd = on;
|
|
30940
31272
|
});
|
|
30941
31273
|
return {
|
|
30942
|
-
message: `${
|
|
31274
|
+
message: `${color65.green("\u2713")} session-end \u2192 ${on ? color65.cyan("on") : color65.dim("off")}`
|
|
30943
31275
|
};
|
|
30944
31276
|
}
|
|
30945
31277
|
if (sub === "delegate") {
|
|
30946
31278
|
const raw = (rest[0] ?? "").toLowerCase();
|
|
30947
31279
|
if (!["on", "off"].includes(raw)) {
|
|
30948
|
-
return { message: `${
|
|
31280
|
+
return { message: `${color65.amber("Usage:")} /telegram-settings delegate on|off` };
|
|
30949
31281
|
}
|
|
30950
31282
|
const on = raw === "on";
|
|
30951
31283
|
await persistTelegramConfig(persistDeps, (tg) => {
|
|
30952
31284
|
tg.notifyOnDelegate = on;
|
|
30953
31285
|
});
|
|
30954
31286
|
return {
|
|
30955
|
-
message: `${
|
|
31287
|
+
message: `${color65.green("\u2713")} delegate \u2192 ${on ? color65.cyan("on") : color65.dim("off")}`
|
|
30956
31288
|
};
|
|
30957
31289
|
}
|
|
30958
31290
|
if (sub === "long-tool") {
|
|
30959
31291
|
const raw = rest[0];
|
|
30960
31292
|
if (raw === void 0) {
|
|
30961
31293
|
return {
|
|
30962
|
-
message: `${
|
|
31294
|
+
message: `${color65.amber("Usage:")} /telegram-settings long-tool <ms|off> ${color65.dim("(0 or off disables)")}`
|
|
30963
31295
|
};
|
|
30964
31296
|
}
|
|
30965
31297
|
if (raw === "off") {
|
|
@@ -30967,57 +31299,57 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
30967
31299
|
tg.longToolThresholdMs = 0;
|
|
30968
31300
|
});
|
|
30969
31301
|
return {
|
|
30970
|
-
message: `${
|
|
31302
|
+
message: `${color65.green("\u2713")} long-tool \u2192 ${color65.dim("off")}`
|
|
30971
31303
|
};
|
|
30972
31304
|
}
|
|
30973
31305
|
const ms = Number.parseInt(raw, 10);
|
|
30974
31306
|
if (Number.isNaN(ms) || ms < 0) {
|
|
30975
31307
|
return {
|
|
30976
|
-
message: `${
|
|
31308
|
+
message: `${color65.red("Invalid number")}: "${raw}". Enter milliseconds, e.g. /telegram-settings long-tool 15000`
|
|
30977
31309
|
};
|
|
30978
31310
|
}
|
|
30979
31311
|
await persistTelegramConfig(persistDeps, (tg) => {
|
|
30980
31312
|
tg.longToolThresholdMs = ms;
|
|
30981
31313
|
});
|
|
30982
31314
|
return {
|
|
30983
|
-
message: `${
|
|
31315
|
+
message: `${color65.green("\u2713")} long-tool \u2192 ${color65.cyan(`${ms}ms`)}`
|
|
30984
31316
|
};
|
|
30985
31317
|
}
|
|
30986
31318
|
if (sub === "poll") {
|
|
30987
31319
|
const raw = rest[0];
|
|
30988
31320
|
if (raw === void 0) {
|
|
30989
31321
|
return {
|
|
30990
|
-
message: `${
|
|
31322
|
+
message: `${color65.amber("Usage:")} /telegram-settings poll <seconds> ${color65.dim("(1\u201360)")}`
|
|
30991
31323
|
};
|
|
30992
31324
|
}
|
|
30993
31325
|
const sec = Number.parseInt(raw, 10);
|
|
30994
31326
|
if (Number.isNaN(sec) || sec < 1 || sec > 60) {
|
|
30995
31327
|
return {
|
|
30996
|
-
message: `${
|
|
31328
|
+
message: `${color65.red("Invalid value")}: "${raw}". Enter seconds between 1 and 60.`
|
|
30997
31329
|
};
|
|
30998
31330
|
}
|
|
30999
31331
|
await persistTelegramConfig(persistDeps, (tg) => {
|
|
31000
31332
|
tg.pollIntervalSec = sec;
|
|
31001
31333
|
});
|
|
31002
31334
|
return {
|
|
31003
|
-
message: `${
|
|
31335
|
+
message: `${color65.green("\u2713")} poll \u2192 ${color65.cyan(`${sec}s`)}`
|
|
31004
31336
|
};
|
|
31005
31337
|
}
|
|
31006
31338
|
if (sub === "chat") {
|
|
31007
31339
|
const raw = rest[0];
|
|
31008
31340
|
if (!raw) {
|
|
31009
|
-
return { message: `${
|
|
31341
|
+
return { message: `${color65.amber("Usage:")} /telegram-settings chat <chatId>` };
|
|
31010
31342
|
}
|
|
31011
31343
|
const classification = classifyTelegramChatId(raw);
|
|
31012
31344
|
if (classification.kind === "invalid") {
|
|
31013
|
-
return { message: `${
|
|
31345
|
+
return { message: `${color65.red("Invalid chat ID")}: expected a non-zero integer.` };
|
|
31014
31346
|
}
|
|
31015
31347
|
const current = opts.configStore.get();
|
|
31016
31348
|
const allowGroupChats = current.extensions?.telegram?.allowGroupChats === true;
|
|
31017
31349
|
if (classification.kind === "group" && !allowGroupChats) {
|
|
31018
31350
|
return {
|
|
31019
31351
|
message: [
|
|
31020
|
-
`${
|
|
31352
|
+
`${color65.amber("\u26A0")} Group, supergroup, and channel targets require explicit allowGroupChats=true.`,
|
|
31021
31353
|
"No configuration was changed."
|
|
31022
31354
|
].join("\n")
|
|
31023
31355
|
};
|
|
@@ -31040,15 +31372,15 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
31040
31372
|
}
|
|
31041
31373
|
});
|
|
31042
31374
|
return {
|
|
31043
|
-
message: `${
|
|
31375
|
+
message: `${color65.green("\u2713")} notify chat \u2192 ${color65.cyan(raw)}`
|
|
31044
31376
|
};
|
|
31045
31377
|
}
|
|
31046
31378
|
return {
|
|
31047
|
-
message: `${
|
|
31379
|
+
message: `${color65.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["session-end", "delegate", "long-tool", "poll", "chat", "all"], "telegram-settings")}`
|
|
31048
31380
|
};
|
|
31049
31381
|
} catch (err) {
|
|
31050
31382
|
return {
|
|
31051
|
-
message: `${
|
|
31383
|
+
message: `${color65.red("Settings error")}: ${toErrorMessage29(err)}`
|
|
31052
31384
|
};
|
|
31053
31385
|
}
|
|
31054
31386
|
}
|
|
@@ -31196,7 +31528,7 @@ function buildTodosCommand(opts) {
|
|
|
31196
31528
|
// src/slash-commands/tool.ts
|
|
31197
31529
|
import { noOpVault as noOpVault11 } from "@wrongstack/core/security";
|
|
31198
31530
|
import {
|
|
31199
|
-
color as
|
|
31531
|
+
color as color66,
|
|
31200
31532
|
getToolDescriptionMode,
|
|
31201
31533
|
getToolResultRenderMode,
|
|
31202
31534
|
normalizeToolDescriptionMode,
|
|
@@ -31210,16 +31542,16 @@ function fit(text, width) {
|
|
|
31210
31542
|
}
|
|
31211
31543
|
function formatDescriptionMode(mode) {
|
|
31212
31544
|
const raw = `desc:${mode}`;
|
|
31213
|
-
return mode === "simple" ?
|
|
31545
|
+
return mode === "simple" ? color66.amber(raw) : color66.cyan(raw);
|
|
31214
31546
|
}
|
|
31215
31547
|
function formatResultRenderMode(mode) {
|
|
31216
31548
|
const raw = `result:${mode}`;
|
|
31217
|
-
return mode === "simple" ?
|
|
31549
|
+
return mode === "simple" ? color66.amber(raw) : color66.cyan(raw);
|
|
31218
31550
|
}
|
|
31219
31551
|
function toolStatus(reg, name) {
|
|
31220
|
-
if (reg.isDisabled(name)) return
|
|
31221
|
-
if (reg.isExposedToProvider?.(name) === false) return
|
|
31222
|
-
return
|
|
31552
|
+
if (reg.isDisabled(name)) return color66.red("disabled");
|
|
31553
|
+
if (reg.isExposedToProvider?.(name) === false) return color66.cyan("lazy");
|
|
31554
|
+
return color66.green("direct");
|
|
31223
31555
|
}
|
|
31224
31556
|
function buildToolCommand(opts) {
|
|
31225
31557
|
const help = [
|
|
@@ -31333,52 +31665,52 @@ function buildToolCommand(opts) {
|
|
|
31333
31665
|
const resultSimple = Object.entries(configured.resultRenderMode ?? {}).filter(([, mode]) => normalizeToolResultRenderMode(mode) === "simple").map(([name]) => name).sort();
|
|
31334
31666
|
const disabled = opts.toolRegistry.listDisabled();
|
|
31335
31667
|
const lines = [
|
|
31336
|
-
`${
|
|
31668
|
+
`${color66.bold("Tool modes")} ${color66.dim("(default: extend on both axes)")}`,
|
|
31337
31669
|
"",
|
|
31338
|
-
`${formatDescriptionMode("simple")}: ${descSimple.length > 0 ? descSimple.map((n) =>
|
|
31339
|
-
`${formatResultRenderMode("simple")}: ${resultSimple.length > 0 ? resultSimple.map((n) =>
|
|
31670
|
+
`${formatDescriptionMode("simple")}: ${descSimple.length > 0 ? descSimple.map((n) => color66.cyan(n)).join(", ") : color66.dim("none")}`,
|
|
31671
|
+
`${formatResultRenderMode("simple")}: ${resultSimple.length > 0 ? resultSimple.map((n) => color66.cyan(n)).join(", ") : color66.dim("none")}`,
|
|
31340
31672
|
""
|
|
31341
31673
|
];
|
|
31342
31674
|
if (disabled.length > 0) {
|
|
31343
31675
|
lines.push(
|
|
31344
|
-
`${
|
|
31676
|
+
`${color66.bold("Disabled tools")}`,
|
|
31345
31677
|
"",
|
|
31346
|
-
` ${
|
|
31678
|
+
` ${color66.red("disabled")}: ${disabled.map(({ tool }) => color66.dim(tool.name)).join(", ")}`,
|
|
31347
31679
|
""
|
|
31348
31680
|
);
|
|
31349
31681
|
}
|
|
31350
31682
|
const lazy = opts.toolRegistry.listWithOwner().filter(({ tool }) => opts.toolRegistry.isExposedToProvider?.(tool.name) === false).map(({ tool }) => tool.name);
|
|
31351
31683
|
if (lazy.length > 0) {
|
|
31352
31684
|
lines.push(
|
|
31353
|
-
`${
|
|
31685
|
+
`${color66.bold("Held back by the token-saving tier")} ${color66.dim(`(${lazy.length})`)}`,
|
|
31354
31686
|
"",
|
|
31355
|
-
` ${
|
|
31687
|
+
` ${color66.cyan("lazy")}: ${lazy.map((n) => color66.dim(n)).join(", ")}`,
|
|
31356
31688
|
"",
|
|
31357
|
-
|
|
31689
|
+
color66.dim(
|
|
31358
31690
|
" Still callable via tool_search/tool_use; their schemas are not sent each turn."
|
|
31359
31691
|
),
|
|
31360
|
-
|
|
31692
|
+
color66.dim(" Change the tier with /settings token-saving <tier>."),
|
|
31361
31693
|
""
|
|
31362
31694
|
);
|
|
31363
31695
|
}
|
|
31364
31696
|
lines.push(
|
|
31365
|
-
|
|
31697
|
+
color66.dim(
|
|
31366
31698
|
" /tool <name> desc simple \xB7 /tool <name> result simple \xB7 /tool list \xB7 /tool disable|enable <name>"
|
|
31367
31699
|
)
|
|
31368
31700
|
);
|
|
31369
31701
|
return lines.join("\n");
|
|
31370
31702
|
}
|
|
31371
31703
|
function formatList() {
|
|
31372
|
-
const header = ` ${
|
|
31704
|
+
const header = ` ${color66.dim(fit("tool", 28))} ${color66.dim(fit("owner", 28))} ${color66.dim(fit("status", 10))} ${color66.dim(fit("desc", 14))} ` + color66.dim("result");
|
|
31373
31705
|
const rows = opts.toolRegistry.listWithOwner().map(({ tool }) => {
|
|
31374
31706
|
const descMode = getToolDescriptionMode(opts.toolRegistry, tool.name);
|
|
31375
31707
|
const resultMode = getToolResultRenderMode(opts.toolRegistry, tool.name);
|
|
31376
31708
|
const owner = opts.toolRegistry.ownerOf(tool.name) ?? "core";
|
|
31377
31709
|
const status = toolStatus(opts.toolRegistry, tool.name);
|
|
31378
|
-
return ` ${fit(tool.name, 28)} ${
|
|
31710
|
+
return ` ${fit(tool.name, 28)} ${color66.dim(fit(`[${owner}]`, 28))} ${fit(status, 10)} ${fit(formatDescriptionMode(descMode), 14)} ` + formatResultRenderMode(resultMode);
|
|
31379
31711
|
});
|
|
31380
31712
|
return [
|
|
31381
|
-
`${
|
|
31713
|
+
`${color66.bold("Tool modes")} ${color66.dim("(default: extend on both axes)")}`,
|
|
31382
31714
|
"",
|
|
31383
31715
|
header,
|
|
31384
31716
|
...rows
|
|
@@ -31389,57 +31721,57 @@ function buildToolCommand(opts) {
|
|
|
31389
31721
|
const tool = reg.get(name);
|
|
31390
31722
|
if (!tool) {
|
|
31391
31723
|
if (reg.isDisabled(name)) {
|
|
31392
|
-
return `${
|
|
31724
|
+
return `${color66.amber(name)} is disabled. Use ${color66.dim(`/tool enable ${name}`)} to restore.`;
|
|
31393
31725
|
}
|
|
31394
|
-
return `${
|
|
31726
|
+
return `${color66.red("Unknown tool")}: ${name}. Use ${color66.dim("/tools")} to list registered tools.`;
|
|
31395
31727
|
}
|
|
31396
31728
|
const descMode = getToolDescriptionMode(reg, name);
|
|
31397
31729
|
const resultMode = getToolResultRenderMode(reg, name);
|
|
31398
|
-
const status = reg.isDisabled(name) ?
|
|
31730
|
+
const status = reg.isDisabled(name) ? color66.red("disabled") : color66.green("active");
|
|
31399
31731
|
return [
|
|
31400
|
-
`${
|
|
31732
|
+
`${color66.bold(name)} ${status}`,
|
|
31401
31733
|
`description mode: ${formatDescriptionMode(descMode)}`,
|
|
31402
31734
|
`result mode: ${formatResultRenderMode(resultMode)}`,
|
|
31403
31735
|
"",
|
|
31404
|
-
|
|
31736
|
+
color66.dim(tool.description)
|
|
31405
31737
|
].join("\n");
|
|
31406
31738
|
}
|
|
31407
31739
|
async function cmdEnable(name) {
|
|
31408
31740
|
const reg = opts.toolRegistry;
|
|
31409
31741
|
if (!reg.isDisabled(name)) {
|
|
31410
|
-
return `${
|
|
31742
|
+
return `${color66.amber(name)} is not disabled.`;
|
|
31411
31743
|
}
|
|
31412
31744
|
const ok = reg.enable(name);
|
|
31413
|
-
if (!ok) return `${
|
|
31745
|
+
if (!ok) return `${color66.red("Could not enable")}: ${name}.`;
|
|
31414
31746
|
const disabled = currentDisabledSet();
|
|
31415
31747
|
disabled.delete(name);
|
|
31416
31748
|
await persistDisabled(Array.from(disabled));
|
|
31417
|
-
return `${
|
|
31749
|
+
return `${color66.green("\u2713")} ${color66.cyan(name)} re-enabled \u2014 will appear in next provider request.`;
|
|
31418
31750
|
}
|
|
31419
31751
|
async function cmdEnableAll() {
|
|
31420
31752
|
const reg = opts.toolRegistry;
|
|
31421
31753
|
const count = reg.enableAll();
|
|
31422
|
-
if (count === 0) return `${
|
|
31754
|
+
if (count === 0) return `${color66.amber("No disabled tools to re-enable.")}`;
|
|
31423
31755
|
await persistDisabled([]);
|
|
31424
|
-
return `${
|
|
31756
|
+
return `${color66.green("\u2713")} All ${count} disabled tool(s) re-enabled.`;
|
|
31425
31757
|
}
|
|
31426
31758
|
async function cmdDisable(name) {
|
|
31427
31759
|
const reg = opts.toolRegistry;
|
|
31428
31760
|
const tool = reg.get(name);
|
|
31429
31761
|
if (!tool) {
|
|
31430
31762
|
if (reg.isDisabled(name)) {
|
|
31431
|
-
return `${
|
|
31763
|
+
return `${color66.amber(name)} is already disabled.`;
|
|
31432
31764
|
}
|
|
31433
|
-
return `${
|
|
31765
|
+
return `${color66.red("Unknown tool")}: ${name}. Use ${color66.dim("/tools")} to list registered tools.`;
|
|
31434
31766
|
}
|
|
31435
31767
|
const ok = reg.disable(name);
|
|
31436
|
-
if (!ok) return `${
|
|
31768
|
+
if (!ok) return `${color66.red("Could not disable")}: ${name}.`;
|
|
31437
31769
|
const disabled = currentDisabledSet();
|
|
31438
31770
|
disabled.add(name);
|
|
31439
31771
|
await persistDisabledWithMeta(Array.from(disabled), {
|
|
31440
31772
|
[name]: { reason: "user", at: Date.now() }
|
|
31441
31773
|
});
|
|
31442
|
-
return `${
|
|
31774
|
+
return `${color66.green("\u2713")} ${color66.cyan(name)} disabled \u2014 removed from system prompt and tool registry.`;
|
|
31443
31775
|
}
|
|
31444
31776
|
function getAutoThin() {
|
|
31445
31777
|
const raw = getCurrentTools().autoThin;
|
|
@@ -31521,43 +31853,43 @@ function buildToolCommand(opts) {
|
|
|
31521
31853
|
const userCount = allDisabled.filter((d) => d.meta.reason === "user").length;
|
|
31522
31854
|
const autoCount = allDisabled.filter((d) => d.meta.reason === "auto-thinned").length;
|
|
31523
31855
|
const lines = [
|
|
31524
|
-
`${
|
|
31856
|
+
`${color66.bold("Auto-thinning")} ${color66.dim("(`tools.autoThin`)")}`,
|
|
31525
31857
|
"",
|
|
31526
|
-
` enabled: ${cfg.enabled ?
|
|
31527
|
-
` applyOnBoot: ${cfg.applyOnBoot ?
|
|
31528
|
-
` idleDays: ${
|
|
31529
|
-
` minInvocations: ${
|
|
31530
|
-
` neverAutoThin: ${cfg.neverAutoThin && cfg.neverAutoThin.length > 0 ? cfg.neverAutoThin.map((n) =>
|
|
31858
|
+
` enabled: ${cfg.enabled ? color66.green("on") : color66.amber("off")}`,
|
|
31859
|
+
` applyOnBoot: ${cfg.applyOnBoot ? color66.green("on") : color66.amber("off")}`,
|
|
31860
|
+
` idleDays: ${color66.cyan(String(cfg.idleDays))}`,
|
|
31861
|
+
` minInvocations: ${color66.cyan(String(cfg.minInvocations))}`,
|
|
31862
|
+
` neverAutoThin: ${cfg.neverAutoThin && cfg.neverAutoThin.length > 0 ? cfg.neverAutoThin.map((n) => color66.cyan(n)).join(", ") : color66.dim("none")}`,
|
|
31531
31863
|
"",
|
|
31532
|
-
`${
|
|
31864
|
+
`${color66.bold("Disabled tools")}: ${color66.cyan(String(allDisabled.length))} (${color66.cyan(String(userCount))} ${color66.dim("user")}, ${color66.cyan(String(autoCount))} ${color66.dim("auto-thinned")})`
|
|
31533
31865
|
];
|
|
31534
31866
|
return lines.join("\n");
|
|
31535
31867
|
}
|
|
31536
31868
|
async function cmdAutoThinCandidates() {
|
|
31537
31869
|
const cfg = getAutoThin();
|
|
31538
31870
|
if (!cfg.enabled) {
|
|
31539
|
-
return `${
|
|
31871
|
+
return `${color66.amber("Auto-thinning is off")}. Run ${color66.cyan("/settings autothin on")} first.`;
|
|
31540
31872
|
}
|
|
31541
31873
|
const { candidates, source } = await runAutoThinDryRun();
|
|
31542
31874
|
if (candidates.length === 0) {
|
|
31543
|
-
return `${
|
|
31875
|
+
return `${color66.green("No candidates")} (source: ${color66.cyan(source)}, idle ${cfg.idleDays}d, min ${cfg.minInvocations}).`;
|
|
31544
31876
|
}
|
|
31545
31877
|
const rows = candidates.map((c) => {
|
|
31546
31878
|
const idle = c.daysSinceLastUse === null ? "never" : `${c.daysSinceLastUse}d`;
|
|
31547
|
-
return ` ${
|
|
31879
|
+
return ` ${color66.cyan(c.name.padEnd(28))} ${color66.dim("invocations=")} ${color66.cyan(String(c.invocations).padStart(3))} ${color66.dim("idle=")} ${color66.cyan(idle)}`;
|
|
31548
31880
|
});
|
|
31549
31881
|
return [
|
|
31550
|
-
`${
|
|
31882
|
+
`${color66.bold("Auto-thin candidates")} ${color66.dim(`(source: ${source})`)}`,
|
|
31551
31883
|
"",
|
|
31552
31884
|
...rows,
|
|
31553
31885
|
"",
|
|
31554
|
-
`${
|
|
31886
|
+
`${color66.dim(`Run ${color66.cyan("/tool autothin apply")} to disable, or ${color66.cyan("/tool autothin undo")} to re-enable auto-thinned tools.`)}`
|
|
31555
31887
|
].join("\n");
|
|
31556
31888
|
}
|
|
31557
31889
|
async function cmdAutoThinApply() {
|
|
31558
31890
|
const cfg = getAutoThin();
|
|
31559
31891
|
if (!cfg.enabled) {
|
|
31560
|
-
return `${
|
|
31892
|
+
return `${color66.amber("Auto-thinning is off")}. Run ${color66.cyan("/settings autothin on")} first.`;
|
|
31561
31893
|
}
|
|
31562
31894
|
const { runBootAutoThin } = await import("./boot-auto-thin-MANHOYHE.js");
|
|
31563
31895
|
const result = await runBootAutoThin({
|
|
@@ -31570,20 +31902,20 @@ function buildToolCommand(opts) {
|
|
|
31570
31902
|
dryRun: false
|
|
31571
31903
|
});
|
|
31572
31904
|
if (result.applied.length === 0) {
|
|
31573
|
-
return `${
|
|
31905
|
+
return `${color66.green("No tools to thin")} (source: ${color66.cyan(result.source)}).`;
|
|
31574
31906
|
}
|
|
31575
31907
|
return [
|
|
31576
|
-
`${
|
|
31908
|
+
`${color66.green("\u2713")} Thinned ${color66.cyan(String(result.applied.length))} tool(s) (source: ${color66.cyan(result.source)}):`,
|
|
31577
31909
|
"",
|
|
31578
|
-
...result.applied.map((n) => ` ${
|
|
31910
|
+
...result.applied.map((n) => ` ${color66.cyan(n)}`),
|
|
31579
31911
|
"",
|
|
31580
|
-
`${
|
|
31912
|
+
`${color66.dim(`Re-enable with ${color66.cyan("/tool autothin undo")}.`)}`
|
|
31581
31913
|
].join("\n");
|
|
31582
31914
|
}
|
|
31583
31915
|
async function cmdAutoThinUndo() {
|
|
31584
31916
|
const restored = opts.toolRegistry.enableAutoThinned();
|
|
31585
31917
|
if (restored.length === 0) {
|
|
31586
|
-
return `${
|
|
31918
|
+
return `${color66.amber("No auto-thinned tools to restore")}.`;
|
|
31587
31919
|
}
|
|
31588
31920
|
const current = getCurrentTools();
|
|
31589
31921
|
const disabled = (current.disabledTools ?? []).filter((n) => !restored.includes(n));
|
|
@@ -31611,9 +31943,9 @@ function buildToolCommand(opts) {
|
|
|
31611
31943
|
);
|
|
31612
31944
|
}
|
|
31613
31945
|
return [
|
|
31614
|
-
`${
|
|
31946
|
+
`${color66.green("\u2713")} Re-enabled ${color66.cyan(String(restored.length))} auto-thinned tool(s):`,
|
|
31615
31947
|
"",
|
|
31616
|
-
...restored.map((n) => ` ${
|
|
31948
|
+
...restored.map((n) => ` ${color66.cyan(n)}`)
|
|
31617
31949
|
].join("\n");
|
|
31618
31950
|
}
|
|
31619
31951
|
async function cmdAutoThinConfig(rest) {
|
|
@@ -31621,21 +31953,21 @@ function buildToolCommand(opts) {
|
|
|
31621
31953
|
if (parts.length === 0) {
|
|
31622
31954
|
const cfg2 = getAutoThin();
|
|
31623
31955
|
return [
|
|
31624
|
-
`${
|
|
31956
|
+
`${color66.bold("Auto-thin config")}`,
|
|
31625
31957
|
"",
|
|
31626
|
-
` ${
|
|
31627
|
-
` ${
|
|
31628
|
-
` ${
|
|
31629
|
-
` ${
|
|
31630
|
-
` ${
|
|
31958
|
+
` ${color66.dim("enabled")} ${cfg2.enabled ? color66.green("true") : color66.amber("false")}`,
|
|
31959
|
+
` ${color66.dim("applyOnBoot")} ${cfg2.applyOnBoot ? color66.green("true") : color66.amber("false")}`,
|
|
31960
|
+
` ${color66.dim("idleDays")} ${color66.cyan(String(cfg2.idleDays))}`,
|
|
31961
|
+
` ${color66.dim("minInvocations")} ${color66.cyan(String(cfg2.minInvocations))}`,
|
|
31962
|
+
` ${color66.dim("neverAutoThin")} ${cfg2.neverAutoThin && cfg2.neverAutoThin.length > 0 ? cfg2.neverAutoThin.join(", ") : color66.dim("none")}`,
|
|
31631
31963
|
"",
|
|
31632
|
-
`${
|
|
31633
|
-
` ${
|
|
31964
|
+
`${color66.dim("Usage: /tool autothin config <key> <value>")}`,
|
|
31965
|
+
` ${color66.dim("keys: enabled | applyOnBoot | idleDays | minInvocations | neverAutoThin")}`
|
|
31634
31966
|
].join("\n");
|
|
31635
31967
|
}
|
|
31636
31968
|
const [key, valueRaw, ...restTokens] = parts;
|
|
31637
31969
|
if (restTokens.length > 0) {
|
|
31638
|
-
return `${
|
|
31970
|
+
return `${color66.amber("Usage:")} /tool autothin config <key> <value>`;
|
|
31639
31971
|
}
|
|
31640
31972
|
const value = valueRaw ?? "";
|
|
31641
31973
|
const cfg = getAutoThin();
|
|
@@ -31643,36 +31975,36 @@ function buildToolCommand(opts) {
|
|
|
31643
31975
|
case "enabled": {
|
|
31644
31976
|
const on = ["on", "true", "1", "yes"].includes(value.toLowerCase());
|
|
31645
31977
|
await persistAutoThin({ ...cfg, enabled: on });
|
|
31646
|
-
return `${
|
|
31978
|
+
return `${color66.green("\u2713")} autoThin.enabled = ${color66.cyan(String(on))}`;
|
|
31647
31979
|
}
|
|
31648
31980
|
case "applyOnBoot": {
|
|
31649
31981
|
const on = ["on", "true", "1", "yes"].includes(value.toLowerCase());
|
|
31650
31982
|
await persistAutoThin({ ...cfg, applyOnBoot: on });
|
|
31651
|
-
return `${
|
|
31983
|
+
return `${color66.green("\u2713")} autoThin.applyOnBoot = ${color66.cyan(String(on))}`;
|
|
31652
31984
|
}
|
|
31653
31985
|
case "idleDays": {
|
|
31654
31986
|
const n = Number(value);
|
|
31655
31987
|
if (!Number.isFinite(n) || n < 0) {
|
|
31656
|
-
return `${
|
|
31988
|
+
return `${color66.amber("idleDays must be a non-negative number")}`;
|
|
31657
31989
|
}
|
|
31658
31990
|
await persistAutoThin({ ...cfg, idleDays: n });
|
|
31659
|
-
return `${
|
|
31991
|
+
return `${color66.green("\u2713")} autoThin.idleDays = ${color66.cyan(String(n))}`;
|
|
31660
31992
|
}
|
|
31661
31993
|
case "minInvocations": {
|
|
31662
31994
|
const n = Number(value);
|
|
31663
31995
|
if (!Number.isFinite(n) || n < 0) {
|
|
31664
|
-
return `${
|
|
31996
|
+
return `${color66.amber("minInvocations must be a non-negative number")}`;
|
|
31665
31997
|
}
|
|
31666
31998
|
await persistAutoThin({ ...cfg, minInvocations: n });
|
|
31667
|
-
return `${
|
|
31999
|
+
return `${color66.green("\u2713")} autoThin.minInvocations = ${color66.cyan(String(n))}`;
|
|
31668
32000
|
}
|
|
31669
32001
|
case "neverAutoThin": {
|
|
31670
32002
|
const list = value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
31671
32003
|
await persistAutoThin({ ...cfg, neverAutoThin: list });
|
|
31672
|
-
return `${
|
|
32004
|
+
return `${color66.green("\u2713")} autoThin.neverAutoThin = ${color66.cyan(list.join(", ") || "none")}`;
|
|
31673
32005
|
}
|
|
31674
32006
|
default:
|
|
31675
|
-
return `${
|
|
32007
|
+
return `${color66.amber("Unknown key")}: ${key}. Use: enabled | applyOnBoot | idleDays | minInvocations | neverAutoThin`;
|
|
31676
32008
|
}
|
|
31677
32009
|
}
|
|
31678
32010
|
function applyDescMode(name, mode) {
|
|
@@ -31689,7 +32021,7 @@ function buildToolCommand(opts) {
|
|
|
31689
32021
|
help,
|
|
31690
32022
|
async run(args) {
|
|
31691
32023
|
if (!opts.configStore) {
|
|
31692
|
-
return { message: `${
|
|
32024
|
+
return { message: `${color66.red("Error")} config store not available.` };
|
|
31693
32025
|
}
|
|
31694
32026
|
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
31695
32027
|
const sub = (parts[0] ?? "").toLowerCase();
|
|
@@ -31700,7 +32032,7 @@ function buildToolCommand(opts) {
|
|
|
31700
32032
|
try {
|
|
31701
32033
|
return { message: await cmdEnableAll() };
|
|
31702
32034
|
} catch (err) {
|
|
31703
|
-
return { message: `${
|
|
32035
|
+
return { message: `${color66.red("Error")}: ${toErrorMessage30(err)}` };
|
|
31704
32036
|
}
|
|
31705
32037
|
}
|
|
31706
32038
|
if (sub === "autothin" || sub === "auto-thin") {
|
|
@@ -31724,11 +32056,11 @@ function buildToolCommand(opts) {
|
|
|
31724
32056
|
return { message: await cmdAutoThinConfig(parts.slice(2).join(" ")) };
|
|
31725
32057
|
default:
|
|
31726
32058
|
return {
|
|
31727
|
-
message: `${
|
|
32059
|
+
message: `${color66.amber("Usage:")} /tool autothin <status|candidates|apply|undo|config>`
|
|
31728
32060
|
};
|
|
31729
32061
|
}
|
|
31730
32062
|
} catch (err) {
|
|
31731
|
-
return { message: `${
|
|
32063
|
+
return { message: `${color66.red("Error")}: ${toErrorMessage30(err)}` };
|
|
31732
32064
|
}
|
|
31733
32065
|
}
|
|
31734
32066
|
const name = parts[0] ?? "";
|
|
@@ -31736,43 +32068,43 @@ function buildToolCommand(opts) {
|
|
|
31736
32068
|
if (sub === "disable") {
|
|
31737
32069
|
const targets = parts.slice(1);
|
|
31738
32070
|
if (targets.length === 0)
|
|
31739
|
-
return { message: `${
|
|
32071
|
+
return { message: `${color66.amber("Usage:")} /tool disable <name> [name...]` };
|
|
31740
32072
|
try {
|
|
31741
32073
|
const results = [];
|
|
31742
32074
|
for (const t of targets) results.push(await cmdDisable(t));
|
|
31743
32075
|
return { message: results.join("\n") };
|
|
31744
32076
|
} catch (err) {
|
|
31745
|
-
return { message: `${
|
|
32077
|
+
return { message: `${color66.red("Error")}: ${toErrorMessage30(err)}` };
|
|
31746
32078
|
}
|
|
31747
32079
|
}
|
|
31748
32080
|
if (sub === "enable") {
|
|
31749
32081
|
const targets = parts.slice(1);
|
|
31750
32082
|
if (targets.length === 0)
|
|
31751
|
-
return { message: `${
|
|
32083
|
+
return { message: `${color66.amber("Usage:")} /tool enable <name> [name...]` };
|
|
31752
32084
|
try {
|
|
31753
32085
|
const results = [];
|
|
31754
32086
|
for (const t of targets) results.push(await cmdEnable(t));
|
|
31755
32087
|
return { message: results.join("\n") };
|
|
31756
32088
|
} catch (err) {
|
|
31757
|
-
return { message: `${
|
|
32089
|
+
return { message: `${color66.red("Error")}: ${toErrorMessage30(err)}` };
|
|
31758
32090
|
}
|
|
31759
32091
|
}
|
|
31760
32092
|
const action = parts[1]?.toLowerCase();
|
|
31761
32093
|
if (action === "disable" || action === "enable") {
|
|
31762
32094
|
if (parts.length > 2) {
|
|
31763
32095
|
return {
|
|
31764
|
-
message: `${
|
|
32096
|
+
message: `${color66.amber("Usage:")} /tool ${name} ${action}`
|
|
31765
32097
|
};
|
|
31766
32098
|
}
|
|
31767
32099
|
try {
|
|
31768
32100
|
return { message: action === "disable" ? await cmdDisable(name) : await cmdEnable(name) };
|
|
31769
32101
|
} catch (err) {
|
|
31770
|
-
return { message: `${
|
|
32102
|
+
return { message: `${color66.red("Error")}: ${toErrorMessage30(err)}` };
|
|
31771
32103
|
}
|
|
31772
32104
|
}
|
|
31773
32105
|
if (!opts.toolRegistry.get(name) && !opts.toolRegistry.isDisabled(name)) {
|
|
31774
32106
|
return {
|
|
31775
|
-
message: `${
|
|
32107
|
+
message: `${color66.red("Unknown tool")}: ${name}. Use ${color66.dim("/tools")} to list registered tools.`
|
|
31776
32108
|
};
|
|
31777
32109
|
}
|
|
31778
32110
|
if (parts.length === 1) return { message: formatOne(name) };
|
|
@@ -31781,53 +32113,53 @@ function buildToolCommand(opts) {
|
|
|
31781
32113
|
const rawMode = parts[2];
|
|
31782
32114
|
if (!rawMode) {
|
|
31783
32115
|
return {
|
|
31784
|
-
message: `${
|
|
32116
|
+
message: `${color66.amber("Usage:")} /tool ${name} ${axis} simple|extend`
|
|
31785
32117
|
};
|
|
31786
32118
|
}
|
|
31787
32119
|
const mode2 = normalizeToolDescriptionMode(rawMode);
|
|
31788
32120
|
if (!mode2) {
|
|
31789
32121
|
return {
|
|
31790
|
-
message: `${
|
|
32122
|
+
message: `${color66.amber("Usage:")} /tool ${name} ${axis} simple|extend`
|
|
31791
32123
|
};
|
|
31792
32124
|
}
|
|
31793
32125
|
try {
|
|
31794
32126
|
if (axis === "desc") {
|
|
31795
32127
|
const persisted2 = await persistModeForAxis(name, "desc", mode2);
|
|
31796
32128
|
applyDescMode(name, mode2);
|
|
31797
|
-
const persistence2 = persisted2 ?
|
|
32129
|
+
const persistence2 = persisted2 ? color66.dim("saved") : color66.dim("runtime only; config paths unavailable");
|
|
31798
32130
|
return {
|
|
31799
|
-
message: `${
|
|
32131
|
+
message: `${color66.green("\u2713")} ${color66.cyan(name)} ${formatDescriptionMode(mode2)} ${persistence2}`
|
|
31800
32132
|
};
|
|
31801
32133
|
}
|
|
31802
32134
|
const persisted = await persistModeForAxis(name, "result", mode2);
|
|
31803
32135
|
applyResultMode(name, mode2);
|
|
31804
|
-
const persistence = persisted ?
|
|
32136
|
+
const persistence = persisted ? color66.dim("saved") : color66.dim("runtime only; config paths unavailable");
|
|
31805
32137
|
return {
|
|
31806
|
-
message: `${
|
|
32138
|
+
message: `${color66.green("\u2713")} ${color66.cyan(name)} ${formatResultRenderMode(mode2)} ${persistence}`
|
|
31807
32139
|
};
|
|
31808
32140
|
} catch (err) {
|
|
31809
32141
|
return {
|
|
31810
|
-
message: `${
|
|
32142
|
+
message: `${color66.red("Could not save tool setting")}: ${toErrorMessage30(err)}`
|
|
31811
32143
|
};
|
|
31812
32144
|
}
|
|
31813
32145
|
}
|
|
31814
32146
|
const mode = normalizeToolDescriptionMode(axis);
|
|
31815
32147
|
if (!mode) {
|
|
31816
32148
|
return {
|
|
31817
|
-
message: `${
|
|
32149
|
+
message: `${color66.amber("Usage:")} /tool ${name} [desc|result] simple|extend`
|
|
31818
32150
|
};
|
|
31819
32151
|
}
|
|
31820
32152
|
try {
|
|
31821
32153
|
const persisted = await persistModeBoth(name, mode);
|
|
31822
32154
|
applyDescMode(name, mode);
|
|
31823
32155
|
applyResultMode(name, mode);
|
|
31824
|
-
const persistence = persisted ?
|
|
32156
|
+
const persistence = persisted ? color66.dim("saved (both axes)") : color66.dim("runtime only; config paths unavailable");
|
|
31825
32157
|
return {
|
|
31826
|
-
message: `${
|
|
32158
|
+
message: `${color66.green("\u2713")} ${color66.cyan(name)} ${formatDescriptionMode(mode)} + ${formatResultRenderMode(mode)} ${persistence}`
|
|
31827
32159
|
};
|
|
31828
32160
|
} catch (err) {
|
|
31829
32161
|
return {
|
|
31830
|
-
message: `${
|
|
32162
|
+
message: `${color66.red("Could not save tool setting")}: ${toErrorMessage30(err)}`
|
|
31831
32163
|
};
|
|
31832
32164
|
}
|
|
31833
32165
|
}
|
|
@@ -31835,19 +32167,19 @@ function buildToolCommand(opts) {
|
|
|
31835
32167
|
}
|
|
31836
32168
|
|
|
31837
32169
|
// src/slash-commands/tools.ts
|
|
31838
|
-
import { color as
|
|
32170
|
+
import { color as color67, getToolDescriptionMode as getToolDescriptionMode2 } from "@wrongstack/core/utils";
|
|
31839
32171
|
function fit2(text, width) {
|
|
31840
32172
|
if (text.length <= width) return text.padEnd(width);
|
|
31841
32173
|
return `${text.slice(0, Math.max(0, width - 3))}...`;
|
|
31842
32174
|
}
|
|
31843
32175
|
function formatDescriptionMode2(mode) {
|
|
31844
32176
|
const raw = `desc:${mode}`;
|
|
31845
|
-
return mode === "simple" ?
|
|
32177
|
+
return mode === "simple" ? color67.amber(raw) : color67.dim(raw);
|
|
31846
32178
|
}
|
|
31847
32179
|
function toolStatus2(reg, name) {
|
|
31848
|
-
if (reg.isDisabled(name)) return
|
|
31849
|
-
if (reg.isExposedToProvider?.(name) === false) return
|
|
31850
|
-
return
|
|
32180
|
+
if (reg.isDisabled(name)) return color67.red("disabled");
|
|
32181
|
+
if (reg.isExposedToProvider?.(name) === false) return color67.cyan("lazy");
|
|
32182
|
+
return color67.green("direct");
|
|
31851
32183
|
}
|
|
31852
32184
|
function buildToolsCommand(opts) {
|
|
31853
32185
|
return {
|
|
@@ -31868,16 +32200,16 @@ function buildToolsCommand(opts) {
|
|
|
31868
32200
|
if (opened) return { message: "" };
|
|
31869
32201
|
}
|
|
31870
32202
|
if (filter && all.length === 0) {
|
|
31871
|
-
const msg2 = `${
|
|
32203
|
+
const msg2 = `${color67.bold("Tools")} \u2014 no tool name or owner matched "${filter}".`;
|
|
31872
32204
|
opts.renderer.write(msg2);
|
|
31873
32205
|
return { message: msg2 };
|
|
31874
32206
|
}
|
|
31875
|
-
const header = ` ${
|
|
32207
|
+
const header = ` ${color67.dim(fit2("tool", 28))} ${color67.dim(fit2("owner", 28))} ${color67.dim(fit2("rw", 4))} ${color67.dim(fit2("perm", 8))} ${color67.dim(fit2("status", 10))} ` + color67.dim("description");
|
|
31876
32208
|
const lines = all.map(({ tool, owner }) => {
|
|
31877
32209
|
const mode = getToolDescriptionMode2(reg, tool.name);
|
|
31878
|
-
const rw = tool.mutating ?
|
|
32210
|
+
const rw = tool.mutating ? color67.yellow(fit2("mut", 4)) : color67.cyan(fit2("ro", 4));
|
|
31879
32211
|
const status = toolStatus2(reg, tool.name);
|
|
31880
|
-
return ` ${fit2(tool.name, 28)} ${
|
|
32212
|
+
return ` ${fit2(tool.name, 28)} ${color67.dim(fit2(`[${owner}]`, 28))} ${rw} ${color67.dim(fit2(tool.permission, 8))} ${fit2(status, 10)} ` + formatDescriptionMode2(mode);
|
|
31881
32213
|
});
|
|
31882
32214
|
const lazy = allTools.filter(
|
|
31883
32215
|
({ tool }) => !reg.isDisabled(tool.name) && reg.isExposedToProvider?.(tool.name) === false
|
|
@@ -31894,12 +32226,12 @@ function buildToolsCommand(opts) {
|
|
|
31894
32226
|
);
|
|
31895
32227
|
}
|
|
31896
32228
|
const extra = notes.length > 0 ? `
|
|
31897
|
-
${
|
|
31898
|
-
const filterNote = filter ?
|
|
32229
|
+
${color67.dim(notes.join("\n"))}` : "";
|
|
32230
|
+
const filterNote = filter ? color67.dim(` matching "${filter}" (${all.length} of ${allTools.length})`) : "";
|
|
31899
32231
|
const directCount = allTools.filter(
|
|
31900
32232
|
({ tool }) => !reg.isDisabled(tool.name) && reg.isExposedToProvider?.(tool.name) !== false
|
|
31901
32233
|
).length;
|
|
31902
|
-
const msg = `${
|
|
32234
|
+
const msg = `${color67.bold("Tools")}${filterNote} (${all.length} shown, ${directCount} direct, ${lazy.length} lazy, ${disabled.length} disabled) ${color67.dim("description detail via /tool <name> simple|extend")}:
|
|
31903
32235
|
${header}
|
|
31904
32236
|
${lines.join("\n")}${extra}
|
|
31905
32237
|
`;
|
|
@@ -31913,7 +32245,7 @@ ${lines.join("\n")}${extra}
|
|
|
31913
32245
|
import * as fs20 from "node:fs/promises";
|
|
31914
32246
|
import * as os3 from "node:os";
|
|
31915
32247
|
import * as path21 from "node:path";
|
|
31916
|
-
import { atomicWrite as atomicWrite11, color as
|
|
32248
|
+
import { atomicWrite as atomicWrite11, color as color68 } from "@wrongstack/core/utils";
|
|
31917
32249
|
|
|
31918
32250
|
// src/tuneup.ts
|
|
31919
32251
|
var DEFAULT_EAGER_MAX_CHARS = 24e3;
|
|
@@ -32391,17 +32723,17 @@ function buildTuneupCommand(opts) {
|
|
|
32391
32723
|
const parsed = parseArgs(args);
|
|
32392
32724
|
if (parsed.mode === "help") return { message: help };
|
|
32393
32725
|
if (parsed.mode === "usage") {
|
|
32394
|
-
return { message: `${
|
|
32726
|
+
return { message: `${color68.amber("Usage:")} /tuneup [fix [--power] [--pick] | deep]` };
|
|
32395
32727
|
}
|
|
32396
32728
|
if (!opts.paths) {
|
|
32397
|
-
return { message: `${
|
|
32729
|
+
return { message: `${color68.red("Error")} config paths not available.` };
|
|
32398
32730
|
}
|
|
32399
32731
|
const input = await gatherInput(opts, parsed.power);
|
|
32400
32732
|
const report = runTuneup(input);
|
|
32401
|
-
const lines = [`${
|
|
32733
|
+
const lines = [`${color68.bold("WrongStack")} ${color68.dim("\u2014 Tune-up")}`];
|
|
32402
32734
|
renderFindings(lines, report.findings);
|
|
32403
32735
|
if (parsed.mode === "deep") {
|
|
32404
|
-
lines.push("",
|
|
32736
|
+
lines.push("", color68.dim(" \u2192 asking the agent for a project-specific optimization plan\u2026"));
|
|
32405
32737
|
return { message: lines.join("\n"), runText: buildDeepPrompt(report) };
|
|
32406
32738
|
}
|
|
32407
32739
|
if (parsed.mode === "report") {
|
|
@@ -32423,18 +32755,18 @@ function buildTuneupCommand(opts) {
|
|
|
32423
32755
|
const applied = await applyActions(actions, opts);
|
|
32424
32756
|
lines.push("");
|
|
32425
32757
|
if (applied.messages.length === 0) {
|
|
32426
|
-
lines.push(
|
|
32758
|
+
lines.push(color68.dim(" no deterministic fixes to apply"));
|
|
32427
32759
|
} else {
|
|
32428
|
-
for (const m of applied.messages) lines.push(` ${
|
|
32760
|
+
for (const m of applied.messages) lines.push(` ${color68.green("\u2713")} ${m}`);
|
|
32429
32761
|
if (applied.changed) {
|
|
32430
32762
|
lines.push(
|
|
32431
|
-
` ${
|
|
32763
|
+
` ${color68.green("\u2713")} written ${color68.dim("(backup: config.json.last + timestamped .bak)")}`
|
|
32432
32764
|
);
|
|
32433
32765
|
}
|
|
32434
32766
|
}
|
|
32435
32767
|
const runText = report.agentHandoff || void 0;
|
|
32436
32768
|
if (runText) {
|
|
32437
|
-
lines.push("",
|
|
32769
|
+
lines.push("", color68.dim(" \u2192 handing instruction-file cleanups to the agent\u2026"));
|
|
32438
32770
|
}
|
|
32439
32771
|
return { message: lines.join("\n"), ...runText ? { runText } : {} };
|
|
32440
32772
|
}
|
|
@@ -32595,7 +32927,7 @@ async function applyActions(actions, opts) {
|
|
|
32595
32927
|
parsed = JSON.parse(raw);
|
|
32596
32928
|
} catch {
|
|
32597
32929
|
return {
|
|
32598
|
-
messages: [`${
|
|
32930
|
+
messages: [`${color68.red("\u2717")} global config is not valid JSON \u2014 run /doctor fix first`],
|
|
32599
32931
|
changed: false
|
|
32600
32932
|
};
|
|
32601
32933
|
}
|
|
@@ -32704,26 +33036,26 @@ var CATEGORY_ORDER = [
|
|
|
32704
33036
|
function severityIcon(severity) {
|
|
32705
33037
|
switch (severity) {
|
|
32706
33038
|
case "error":
|
|
32707
|
-
return
|
|
33039
|
+
return color68.red("\u2717");
|
|
32708
33040
|
case "warning":
|
|
32709
|
-
return
|
|
33041
|
+
return color68.amber("!");
|
|
32710
33042
|
case "ok":
|
|
32711
|
-
return
|
|
33043
|
+
return color68.green("\u2713");
|
|
32712
33044
|
default:
|
|
32713
|
-
return
|
|
33045
|
+
return color68.cyan("\xB7");
|
|
32714
33046
|
}
|
|
32715
33047
|
}
|
|
32716
33048
|
function renderFindings(lines, findings) {
|
|
32717
33049
|
for (const category of CATEGORY_ORDER) {
|
|
32718
33050
|
const group = findings.filter((f) => f.category === category);
|
|
32719
33051
|
if (group.length === 0) continue;
|
|
32720
|
-
lines.push("",
|
|
33052
|
+
lines.push("", color68.bold(CATEGORY_LABELS[category]));
|
|
32721
33053
|
for (const f of group) {
|
|
32722
33054
|
lines.push(` ${severityIcon(f.severity)} ${f.problem}`);
|
|
32723
33055
|
if (f.suggestion) {
|
|
32724
|
-
for (const s of f.suggestion.split("\n")) lines.push(
|
|
33056
|
+
for (const s of f.suggestion.split("\n")) lines.push(color68.dim(` ${s}`));
|
|
32725
33057
|
}
|
|
32726
|
-
if (f.fix) lines.push(
|
|
33058
|
+
if (f.fix) lines.push(color68.dim(` \u2192 fixable: ${f.fix}`));
|
|
32727
33059
|
}
|
|
32728
33060
|
}
|
|
32729
33061
|
}
|
|
@@ -32732,20 +33064,20 @@ function summaryLine(findings, fixable, handoffs, power) {
|
|
|
32732
33064
|
(f) => f.severity === "warning" || f.severity === "error"
|
|
32733
33065
|
).length;
|
|
32734
33066
|
if (warnings === 0 && fixable === 0 && handoffs === 0) {
|
|
32735
|
-
return `${
|
|
33067
|
+
return `${color68.green("\u2713")} everything looks healthy`;
|
|
32736
33068
|
}
|
|
32737
33069
|
const parts = [];
|
|
32738
33070
|
if (warnings > 0) parts.push(`${warnings} warning(s)`);
|
|
32739
33071
|
if (fixable > 0) parts.push(`${fixable} auto-fixable`);
|
|
32740
33072
|
if (handoffs > 0) parts.push(`${handoffs} for the agent`);
|
|
32741
33073
|
const cmd = power ? "/tuneup fix --power" : "/tuneup fix";
|
|
32742
|
-
return `${parts.join(", ")} ${
|
|
33074
|
+
return `${parts.join(", ")} ${color68.dim(`\u2014 run ${cmd}`)}`;
|
|
32743
33075
|
}
|
|
32744
33076
|
|
|
32745
33077
|
// src/slash-commands/working-dir.ts
|
|
32746
33078
|
import * as fs21 from "node:fs/promises";
|
|
32747
33079
|
import * as path22 from "node:path";
|
|
32748
|
-
import { color as
|
|
33080
|
+
import { color as color69, toErrorMessage as toErrorMessage31 } from "@wrongstack/core/utils";
|
|
32749
33081
|
function buildWorkingDirCommand(_opts) {
|
|
32750
33082
|
return {
|
|
32751
33083
|
name: "working_dir",
|
|
@@ -32764,16 +33096,16 @@ function buildWorkingDirCommand(_opts) {
|
|
|
32764
33096
|
].join("\n"),
|
|
32765
33097
|
async run(args, ctx) {
|
|
32766
33098
|
if (!ctx) {
|
|
32767
|
-
return { message:
|
|
33099
|
+
return { message: color69.yellow("No active context. Start a session first.") };
|
|
32768
33100
|
}
|
|
32769
33101
|
const trimmed = args.trim();
|
|
32770
33102
|
if (!trimmed) {
|
|
32771
33103
|
const rel2 = path22.relative(ctx.projectRoot, ctx.workingDir) || ".";
|
|
32772
33104
|
return {
|
|
32773
33105
|
message: [
|
|
32774
|
-
`Working directory: ${
|
|
32775
|
-
|
|
32776
|
-
|
|
33106
|
+
`Working directory: ${color69.bold(ctx.workingDir)}`,
|
|
33107
|
+
color69.dim(` (relative to root: ${rel2})`),
|
|
33108
|
+
color69.dim(` Project root: ${ctx.projectRoot}`)
|
|
32777
33109
|
].join("\n")
|
|
32778
33110
|
};
|
|
32779
33111
|
}
|
|
@@ -32782,7 +33114,7 @@ function buildWorkingDirCommand(_opts) {
|
|
|
32782
33114
|
const rel = path22.relative(root, resolved);
|
|
32783
33115
|
if (rel.startsWith("..") || path22.isAbsolute(rel)) {
|
|
32784
33116
|
return {
|
|
32785
|
-
message:
|
|
33117
|
+
message: color69.red(
|
|
32786
33118
|
`Directory "${trimmed}" is outside the project root.
|
|
32787
33119
|
Resolved: ${resolved}
|
|
32788
33120
|
Root: ${root}`
|
|
@@ -32792,25 +33124,25 @@ function buildWorkingDirCommand(_opts) {
|
|
|
32792
33124
|
try {
|
|
32793
33125
|
const stat6 = await fs21.stat(resolved);
|
|
32794
33126
|
if (!stat6.isDirectory()) {
|
|
32795
|
-
return { message:
|
|
33127
|
+
return { message: color69.red(`Not a directory: ${resolved}`) };
|
|
32796
33128
|
}
|
|
32797
33129
|
} catch {
|
|
32798
|
-
return { message:
|
|
33130
|
+
return { message: color69.red(`Directory does not exist: ${resolved}`) };
|
|
32799
33131
|
}
|
|
32800
33132
|
const previous = ctx.workingDir;
|
|
32801
33133
|
try {
|
|
32802
33134
|
ctx.setWorkingDir(resolved);
|
|
32803
33135
|
} catch (err) {
|
|
32804
33136
|
return {
|
|
32805
|
-
message:
|
|
33137
|
+
message: color69.red(toErrorMessage31(err))
|
|
32806
33138
|
};
|
|
32807
33139
|
}
|
|
32808
33140
|
const prevRel = path22.relative(ctx.projectRoot, previous) || ".";
|
|
32809
33141
|
const newRel = path22.relative(ctx.projectRoot, resolved) || ".";
|
|
32810
33142
|
return {
|
|
32811
33143
|
message: [
|
|
32812
|
-
|
|
32813
|
-
|
|
33144
|
+
color69.green(` \u2713 ${prevRel} \u2192 ${color69.bold(newRel)}`),
|
|
33145
|
+
color69.dim(` ${resolved}`)
|
|
32814
33146
|
].join("\n")
|
|
32815
33147
|
};
|
|
32816
33148
|
}
|
|
@@ -32884,7 +33216,7 @@ import {
|
|
|
32884
33216
|
isDestructiveKind,
|
|
32885
33217
|
LOCKED_DESTRUCTIVE_KINDS
|
|
32886
33218
|
} from "@wrongstack/core/security";
|
|
32887
|
-
import { color as
|
|
33219
|
+
import { color as color70 } from "@wrongstack/core/utils";
|
|
32888
33220
|
var KIND_BLURBS = {
|
|
32889
33221
|
"disk-wipe": "mkfs, dd to a raw device, format C:, fork bomb",
|
|
32890
33222
|
"system-halt": "shutdown, reboot",
|
|
@@ -32900,12 +33232,12 @@ function renderConfirmList(opts, map) {
|
|
|
32900
33232
|
const lines = ["Kinds that still prompt while YOLO is on:", ""];
|
|
32901
33233
|
for (const kind of ALL_DESTRUCTIVE_KINDS) {
|
|
32902
33234
|
const locked = LOCKED_DESTRUCTIVE_KINDS.has(kind);
|
|
32903
|
-
const state = map[kind] ? locked ?
|
|
32904
|
-
lines.push(` ${kind.padEnd(17)} ${state.padEnd(20)} ${
|
|
33235
|
+
const state = map[kind] ? locked ? color70.dim("ALWAYS ASKS") : color70.yellow("ASKS") : color70.green("runs");
|
|
33236
|
+
lines.push(` ${kind.padEnd(17)} ${state.padEnd(20)} ${color70.dim(KIND_BLURBS[kind])}`);
|
|
32905
33237
|
}
|
|
32906
|
-
lines.push("",
|
|
33238
|
+
lines.push("", color70.dim(" /yolo confirm <kind> off lets YOLO run that kind unattended"));
|
|
32907
33239
|
lines.push(
|
|
32908
|
-
|
|
33240
|
+
color70.dim(" ALWAYS ASKS cannot be turned off \u2014 those writes can disable approval itself")
|
|
32909
33241
|
);
|
|
32910
33242
|
const msg = lines.join("\n");
|
|
32911
33243
|
opts.renderer.write(msg);
|
|
@@ -32937,11 +33269,11 @@ function runConfirm(opts, rest) {
|
|
|
32937
33269
|
}
|
|
32938
33270
|
const after = opts.onYoloConfirm({ kind: rawKind, confirm });
|
|
32939
33271
|
if (!confirm && after[rawKind]) {
|
|
32940
|
-
const msg2 = `${
|
|
33272
|
+
const msg2 = `${color70.amber(rawKind)} always asks \u2014 ${KIND_BLURBS[rawKind]} can switch the approval system itself off.`;
|
|
32941
33273
|
opts.renderer.writeWarning(msg2);
|
|
32942
33274
|
return { message: msg2 };
|
|
32943
33275
|
}
|
|
32944
|
-
const msg = confirm ? `${
|
|
33276
|
+
const msg = confirm ? `${color70.yellow(rawKind)} will keep asking under YOLO.` : `${color70.green(rawKind)} will now run unattended under YOLO.`;
|
|
32945
33277
|
opts.renderer.write(msg);
|
|
32946
33278
|
return { message: msg };
|
|
32947
33279
|
}
|
|
@@ -32973,7 +33305,7 @@ function buildYoloCommand(opts) {
|
|
|
32973
33305
|
}
|
|
32974
33306
|
if (!arg) {
|
|
32975
33307
|
const current = opts.onYolo();
|
|
32976
|
-
const status = current ? `${
|
|
33308
|
+
const status = current ? `${color70.yellow("ON")} ${color70.dim("(auto-approving tool calls)")}` : `${color70.green("OFF")} ${color70.dim("(permission prompts active)")}`;
|
|
32977
33309
|
const msg2 = `YOLO mode: ${status}`;
|
|
32978
33310
|
opts.renderer.write(msg2);
|
|
32979
33311
|
return { message: msg2 };
|
|
@@ -32993,7 +33325,7 @@ function buildYoloCommand(opts) {
|
|
|
32993
33325
|
return { message: msg2 };
|
|
32994
33326
|
}
|
|
32995
33327
|
opts.onYolo(newState);
|
|
32996
|
-
const label = newState ? `${
|
|
33328
|
+
const label = newState ? `${color70.yellow("ENABLED")} \u2014 tool calls will be auto-approved unless explicitly denied` : `${color70.green("DISABLED")} \u2014 permission prompts are active`;
|
|
32997
33329
|
const msg = `YOLO mode: ${label}`;
|
|
32998
33330
|
opts.renderer.write(msg);
|
|
32999
33331
|
return { message: msg };
|
|
@@ -33073,6 +33405,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
33073
33405
|
buildTelegramSetupCommand(opts),
|
|
33074
33406
|
buildTelegramSettingsCommand(opts),
|
|
33075
33407
|
buildSetModelCommand(opts),
|
|
33408
|
+
buildSubagentModelsCommand(opts),
|
|
33076
33409
|
buildEffortCommand(opts),
|
|
33077
33410
|
buildRefinerCommand(opts),
|
|
33078
33411
|
buildFallbackCommand(opts),
|
|
@@ -34030,6 +34363,8 @@ function setupCliHeapWatchdog({
|
|
|
34030
34363
|
// src/wiring/hq-telemetry.ts
|
|
34031
34364
|
import * as path26 from "node:path";
|
|
34032
34365
|
import {
|
|
34366
|
+
createApprovalRegistry,
|
|
34367
|
+
startApprovalTelemetryBridge,
|
|
34033
34368
|
startBrainTelemetryBridge,
|
|
34034
34369
|
startCostTelemetryBridge,
|
|
34035
34370
|
startFleetTelemetryBridge,
|
|
@@ -34147,6 +34482,18 @@ function setupHqTelemetry(deps) {
|
|
|
34147
34482
|
} = deps;
|
|
34148
34483
|
let stopHqSessionBridge;
|
|
34149
34484
|
const stopHqAuxBridges = [];
|
|
34485
|
+
const approvalRegistry = createApprovalRegistry(events);
|
|
34486
|
+
teardownHandlers.push(() => approvalRegistry.dispose());
|
|
34487
|
+
if (deps.approvalMirror) {
|
|
34488
|
+
deps.approvalMirror.current = approvalRegistry;
|
|
34489
|
+
deps.approvalMirror.sessionId = () => session.id;
|
|
34490
|
+
teardownHandlers.push(() => {
|
|
34491
|
+
if (deps.approvalMirror?.current === approvalRegistry) {
|
|
34492
|
+
deps.approvalMirror.current = void 0;
|
|
34493
|
+
deps.approvalMirror.sessionId = void 0;
|
|
34494
|
+
}
|
|
34495
|
+
});
|
|
34496
|
+
}
|
|
34150
34497
|
const hqCommandController = {
|
|
34151
34498
|
steerMailbox: brainMailbox,
|
|
34152
34499
|
interruptLeader: () => false,
|
|
@@ -34156,6 +34503,8 @@ function setupHqTelemetry(deps) {
|
|
|
34156
34503
|
// `ctx.session` for a new writer object and this captured one goes stale.
|
|
34157
34504
|
sessionId: () => session.id,
|
|
34158
34505
|
allowRunCommand: () => flags["hq-allow-exec"] === true,
|
|
34506
|
+
resolveApproval: (toolUseId, decision, commandSessionId) => approvalRegistry.resolve(toolUseId, decision, commandSessionId),
|
|
34507
|
+
resolveUserInput: (requestId, response, commandSessionId) => approvalRegistry.resolveUserInput?.(requestId, response, commandSessionId) ?? false,
|
|
34159
34508
|
kanbanTransition: createProjectKanbanTransitionHandler(projectRoot),
|
|
34160
34509
|
kanbanAssign: createProjectKanbanAssignHandler(projectRoot)
|
|
34161
34510
|
};
|
|
@@ -34172,6 +34521,7 @@ function setupHqTelemetry(deps) {
|
|
|
34172
34521
|
"fleet.summary",
|
|
34173
34522
|
"session.summary",
|
|
34174
34523
|
"control.receive",
|
|
34524
|
+
"control.approve",
|
|
34175
34525
|
"kanban.dispatch"
|
|
34176
34526
|
],
|
|
34177
34527
|
onConnect: (publisher) => {
|
|
@@ -34264,6 +34614,17 @@ function setupHqTelemetry(deps) {
|
|
|
34264
34614
|
);
|
|
34265
34615
|
} catch {
|
|
34266
34616
|
}
|
|
34617
|
+
try {
|
|
34618
|
+
stopHqAuxBridges.push(
|
|
34619
|
+
startApprovalTelemetryBridge({
|
|
34620
|
+
registry: approvalRegistry,
|
|
34621
|
+
publisher,
|
|
34622
|
+
projectRoot,
|
|
34623
|
+
sessionId: session.id
|
|
34624
|
+
})
|
|
34625
|
+
);
|
|
34626
|
+
} catch {
|
|
34627
|
+
}
|
|
34267
34628
|
}
|
|
34268
34629
|
});
|
|
34269
34630
|
hqPublisherRef.getKanbanSyncStats = () => hqConnection.getKanbanSyncStats();
|
|
@@ -34610,7 +34971,8 @@ function setupMetrics(params) {
|
|
|
34610
34971
|
// src/wiring/pipeline.ts
|
|
34611
34972
|
import {
|
|
34612
34973
|
Agent as Agent2,
|
|
34613
|
-
createDefaultPipelines as createDefaultPipelines2
|
|
34974
|
+
createDefaultPipelines as createDefaultPipelines2,
|
|
34975
|
+
createEventUserInputAwaiter
|
|
34614
34976
|
} from "@wrongstack/core/agent";
|
|
34615
34977
|
import {
|
|
34616
34978
|
AutoCompactionMiddleware,
|
|
@@ -34877,6 +35239,9 @@ async function setupCompaction(params) {
|
|
|
34877
35239
|
return { effectiveMaxContext, autoCompactor, sessionBridge: resolvedBridge };
|
|
34878
35240
|
}
|
|
34879
35241
|
function createAgent(params) {
|
|
35242
|
+
if (!params.context.userInputAwaiter) {
|
|
35243
|
+
params.context.userInputAwaiter = createEventUserInputAwaiter(params.events);
|
|
35244
|
+
}
|
|
34880
35245
|
const secretScrubber = params.container.resolve(TOKENS10.SecretScrubber);
|
|
34881
35246
|
const renderer = params.container.has(TOKENS10.Renderer) ? params.container.resolve(TOKENS10.Renderer) : void 0;
|
|
34882
35247
|
const logger = params.container.resolve(TOKENS10.Logger);
|
|
@@ -35858,6 +36223,7 @@ function setupProviderRuntime(deps) {
|
|
|
35858
36223
|
"fallbackProfiles",
|
|
35859
36224
|
"fallbackProfile",
|
|
35860
36225
|
"favoriteModels",
|
|
36226
|
+
"disabledModels",
|
|
35861
36227
|
"favoriteModelsOnly",
|
|
35862
36228
|
"modelAvailabilitySchedule",
|
|
35863
36229
|
"modelMatrix",
|
|
@@ -36441,6 +36807,7 @@ import { randomBytes as randomBytes2 } from "node:crypto";
|
|
|
36441
36807
|
import * as path31 from "node:path";
|
|
36442
36808
|
import { Context as Context2 } from "@wrongstack/core/agent";
|
|
36443
36809
|
import {
|
|
36810
|
+
restoreSessionSubagentModelPlan,
|
|
36444
36811
|
restoreSessionSubagentPolicy,
|
|
36445
36812
|
seedSessionSubagentPolicy
|
|
36446
36813
|
} from "@wrongstack/core/coordination";
|
|
@@ -36466,7 +36833,8 @@ import {
|
|
|
36466
36833
|
import {
|
|
36467
36834
|
attachSessionKanbanMirror,
|
|
36468
36835
|
hydrateSessionKanban,
|
|
36469
|
-
sessionKanbanDegradation
|
|
36836
|
+
sessionKanbanDegradation,
|
|
36837
|
+
settleSessionKanbanBackgroundWork
|
|
36470
36838
|
} from "@wrongstack/tools/session-kanban";
|
|
36471
36839
|
|
|
36472
36840
|
// src/wiring/resume-candidate.ts
|
|
@@ -36665,6 +37033,7 @@ async function setupSession(params) {
|
|
|
36665
37033
|
}
|
|
36666
37034
|
if (restoredEvents.length > 0 || restoredSubagentsAllowed !== void 0) {
|
|
36667
37035
|
restoreSessionSubagentPolicy(context, restoredEvents, restoredSubagentsAllowed);
|
|
37036
|
+
restoreSessionSubagentModelPlan(context, restoredEvents);
|
|
36668
37037
|
} else seedSessionSubagentPolicy(context);
|
|
36669
37038
|
const queueStore = new QueueStore({
|
|
36670
37039
|
dir: sessionDir,
|
|
@@ -36740,6 +37109,7 @@ async function setupSession(params) {
|
|
|
36740
37109
|
cacheLedger?.dispose();
|
|
36741
37110
|
await checkpointRebindTail;
|
|
36742
37111
|
await detachCurrentCheckpoint();
|
|
37112
|
+
await settleSessionKanbanBackgroundWork();
|
|
36743
37113
|
};
|
|
36744
37114
|
let dirState;
|
|
36745
37115
|
if (resumeId) {
|
|
@@ -37435,7 +37805,7 @@ function wireSessionEvents(deps) {
|
|
|
37435
37805
|
}
|
|
37436
37806
|
|
|
37437
37807
|
// src/session-stats.ts
|
|
37438
|
-
import { color as
|
|
37808
|
+
import { color as color71 } from "@wrongstack/core/utils";
|
|
37439
37809
|
var SESSION_STATS_MAX_PATHS = 1e4;
|
|
37440
37810
|
function addBoundedPath(set, path35) {
|
|
37441
37811
|
if (set.has(path35)) return;
|
|
@@ -37526,13 +37896,13 @@ var SessionStats = class {
|
|
|
37526
37896
|
const elapsedSec = ((Date.now() - this.startedAt) / 1e3).toFixed(1);
|
|
37527
37897
|
const lines = [];
|
|
37528
37898
|
lines.push("");
|
|
37529
|
-
lines.push(
|
|
37530
|
-
lines.push(
|
|
37899
|
+
lines.push(color71.bold("Session report"));
|
|
37900
|
+
lines.push(color71.dim("\u2500".repeat(40)));
|
|
37531
37901
|
lines.push(` Elapsed: ${elapsedSec}s`);
|
|
37532
37902
|
lines.push(` Iterations: ${this.iterations}`);
|
|
37533
37903
|
lines.push(` API requests: ${this.apiRequests}`);
|
|
37534
37904
|
if (this.errors > 0) {
|
|
37535
|
-
lines.push(` Errors: ${
|
|
37905
|
+
lines.push(` Errors: ${color71.yellow(String(this.errors))}`);
|
|
37536
37906
|
}
|
|
37537
37907
|
lines.push("");
|
|
37538
37908
|
lines.push(
|
|
@@ -37542,48 +37912,48 @@ var SessionStats = class {
|
|
|
37542
37912
|
if (cache.readTokens > 0 || cache.writeTokens > 0) {
|
|
37543
37913
|
const pct2 = (cache.hitRatio * 100).toFixed(1);
|
|
37544
37914
|
lines.push(
|
|
37545
|
-
` Prompt cache: ${pct2}% hit ${
|
|
37915
|
+
` Prompt cache: ${pct2}% hit ${color71.dim(`(${fmtTok(cache.readTokens)} read / ${fmtTok(cache.writeTokens)} write)`)}`
|
|
37546
37916
|
);
|
|
37547
37917
|
}
|
|
37548
37918
|
if (cost.total > 0) {
|
|
37549
37919
|
lines.push(
|
|
37550
|
-
` Cost: $${cost.total.toFixed(4)}${
|
|
37920
|
+
` Cost: $${cost.total.toFixed(4)}${color71.dim(` (in $${cost.input.toFixed(4)} / out $${cost.output.toFixed(4)})`)}`
|
|
37551
37921
|
);
|
|
37552
37922
|
} else {
|
|
37553
|
-
lines.push(` Cost: ${
|
|
37923
|
+
lines.push(` Cost: ${color71.dim("$0 (no pricing on this plan)")}`);
|
|
37554
37924
|
}
|
|
37555
37925
|
if (this.toolStats.size > 0) {
|
|
37556
37926
|
lines.push("");
|
|
37557
|
-
lines.push(` ${
|
|
37927
|
+
lines.push(` ${color71.bold("Tool calls")}`);
|
|
37558
37928
|
const sorted = [...this.toolStats.entries()].sort(
|
|
37559
37929
|
(a, b) => b[1].ok + b[1].fail - (a[1].ok + a[1].fail)
|
|
37560
37930
|
);
|
|
37561
37931
|
for (const [name, s] of sorted) {
|
|
37562
37932
|
const total = s.ok + s.fail;
|
|
37563
|
-
const failPart = s.fail > 0 ?
|
|
37933
|
+
const failPart = s.fail > 0 ? color71.yellow(` (${s.fail} failed)`) : "";
|
|
37564
37934
|
const avgMs = total > 0 ? Math.round(s.totalMs / total) : 0;
|
|
37565
37935
|
lines.push(
|
|
37566
|
-
` ${name.padEnd(12)} ${String(total).padStart(3)}\xD7 ${
|
|
37936
|
+
` ${name.padEnd(12)} ${String(total).padStart(3)}\xD7 ${color71.dim(`avg ${avgMs}ms`)}${failPart}`
|
|
37567
37937
|
);
|
|
37568
37938
|
}
|
|
37569
37939
|
}
|
|
37570
37940
|
const fileActivity = this.readPaths.size > 0 || this.editedPaths.size > 0 || this.writtenPaths.size > 0 || this.bytesWritten > 0;
|
|
37571
37941
|
if (fileActivity) {
|
|
37572
37942
|
lines.push("");
|
|
37573
|
-
lines.push(` ${
|
|
37943
|
+
lines.push(` ${color71.bold("Files")}`);
|
|
37574
37944
|
if (this.readPaths.size > 0)
|
|
37575
37945
|
lines.push(
|
|
37576
|
-
` read: ${this.readPaths.size} ${
|
|
37946
|
+
` read: ${this.readPaths.size} ${color71.dim(samplePaths(this.readPaths))}`
|
|
37577
37947
|
);
|
|
37578
37948
|
if (this.editedPaths.size > 0)
|
|
37579
37949
|
lines.push(
|
|
37580
|
-
` edited: ${this.editedPaths.size} ${
|
|
37950
|
+
` edited: ${this.editedPaths.size} ${color71.dim(samplePaths(this.editedPaths))}`
|
|
37581
37951
|
);
|
|
37582
37952
|
if (this.writtenPaths.size > 0) {
|
|
37583
37953
|
const bytes = this.bytesWritten;
|
|
37584
37954
|
const byteStr = bytes > 1024 ? `${(bytes / 1024).toFixed(1)}KB` : `${bytes}B`;
|
|
37585
37955
|
lines.push(
|
|
37586
|
-
` written: ${this.writtenPaths.size} (${byteStr}) ${
|
|
37956
|
+
` written: ${this.writtenPaths.size} (${byteStr}) ${color71.dim(samplePaths(this.writtenPaths))}`
|
|
37587
37957
|
);
|
|
37588
37958
|
}
|
|
37589
37959
|
}
|
|
@@ -37798,6 +38168,7 @@ async function runInteractive(cliCtx) {
|
|
|
37798
38168
|
needsSetup,
|
|
37799
38169
|
events,
|
|
37800
38170
|
container,
|
|
38171
|
+
approvalMirror,
|
|
37801
38172
|
configStore,
|
|
37802
38173
|
updateInfo,
|
|
37803
38174
|
webuiSessionChild
|
|
@@ -38191,6 +38562,7 @@ async function runInteractive(cliCtx) {
|
|
|
38191
38562
|
teardownHandlers,
|
|
38192
38563
|
mailboxSessionTag: mailboxSessionTag7,
|
|
38193
38564
|
hqPublisherRef,
|
|
38565
|
+
approvalMirror,
|
|
38194
38566
|
mcpRegistry
|
|
38195
38567
|
});
|
|
38196
38568
|
setupDepWatcherConsumers({
|
|
@@ -38524,4 +38896,4 @@ export {
|
|
|
38524
38896
|
CLI_VERSION,
|
|
38525
38897
|
runInteractive
|
|
38526
38898
|
};
|
|
38527
|
-
//# sourceMappingURL=cli-main-
|
|
38899
|
+
//# sourceMappingURL=cli-main-AKJHDSHX.js.map
|