@wrongstack/cli 1.0.9 → 1.0.11
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-CXLANMEZ.js → acp-IJ55NBMJ.js} +5 -3
- package/dist/acp-mcp-servers.d.ts +2 -0
- package/dist/arg-parser.d.ts +6 -0
- package/dist/{auth-3K6EN5JP.js → auth-YXK3EDUL.js} +9 -3
- package/dist/{chunk-EK2P53GL.js → chunk-C3Z4N6A6.js} +23 -3
- package/dist/{chunk-7K3IJGWC.js → chunk-OJR7K3OI.js} +8 -8
- package/dist/{chunk-SXJTVNWF.js → chunk-OWNC7LMD.js} +2 -2
- package/dist/{chunk-FSZ5QU3M.js → chunk-RDHFXOJM.js} +153 -69
- package/dist/{chunk-5VPDKQDH.js → chunk-TNZBQG45.js} +3 -3
- package/dist/{chunk-7FPN3QTH.js → chunk-YRC3I3LE.js} +172 -15
- package/dist/{cli-context-6GMXUOXD.js → cli-context-5IF7ZYEY.js} +7 -7
- package/dist/{cli-main-4E4YMCNS.js → cli-main-WC5JNIWY.js} +67 -48
- package/dist/{diag-doctor-PCER6KHH.js → diag-doctor-ANPRUYFM.js} +13 -3
- package/dist/{execution-4RXQLDAF.js → execution-EXDRBS4F.js} +2 -2
- package/dist/{hq-DQTUE7RC.js → hq-NO2NWGU4.js} +153 -5
- package/dist/hq-server/auth-state.d.ts +11 -0
- package/dist/hq-server/mailbox-gateway-health.d.ts +67 -0
- package/dist/hq-server/mailbox-gateway-manager.d.ts +38 -0
- package/dist/hq-server/routes/system-handlers.d.ts +27 -0
- package/dist/hq-server/routes.d.ts +11 -0
- package/dist/hq-server/snapshot.d.ts +14 -1
- package/dist/hq-server/upgrade-handler.d.ts +7 -0
- package/dist/{hq-server-JJFGFWI5.js → hq-server-KE5YDNGG.js} +2 -2
- package/dist/index.js +4 -4
- package/dist/{mcp-FX7TKPTV.js → mcp-DC5WSBOO.js} +28 -10
- package/dist/mcp-serve.d.ts +9 -0
- package/dist/services/mcp-management.d.ts +0 -6
- package/dist/{short-circuit-flags-LHUNLCZY.js → short-circuit-flags-72E77TJI.js} +3 -3
- package/dist/{subcommands-UXWY3OPC.js → subcommands-EJI7DBQS.js} +2 -2
- package/package.json +28 -28
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
removeSuggestions,
|
|
7
7
|
runGit,
|
|
8
8
|
setSuggestions
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-OWNC7LMD.js";
|
|
10
10
|
import {
|
|
11
11
|
setupPlugins
|
|
12
12
|
} from "./chunk-XJ7K67PP.js";
|
|
@@ -102,7 +102,7 @@ import {
|
|
|
102
102
|
runAuthLocal,
|
|
103
103
|
runProviderAuthLogin,
|
|
104
104
|
validateFamily
|
|
105
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-RDHFXOJM.js";
|
|
106
106
|
import "./chunk-2VMJ3E5Z.js";
|
|
107
107
|
import {
|
|
108
108
|
appendHistory
|
|
@@ -116,7 +116,7 @@ import {
|
|
|
116
116
|
} from "./chunk-YMXXOOFN.js";
|
|
117
117
|
import {
|
|
118
118
|
parseSpawnFlags
|
|
119
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-C3Z4N6A6.js";
|
|
120
120
|
import "./chunk-SIGUWXAA.js";
|
|
121
121
|
import "./chunk-DAKVBMD4.js";
|
|
122
122
|
import {
|
|
@@ -6231,7 +6231,7 @@ async function runCliExecution(params) {
|
|
|
6231
6231
|
governanceHandle,
|
|
6232
6232
|
setConfig
|
|
6233
6233
|
} = params;
|
|
6234
|
-
const { execute } = await import("./execution-
|
|
6234
|
+
const { execute } = await import("./execution-EXDRBS4F.js");
|
|
6235
6235
|
return execute(
|
|
6236
6236
|
toExecuteDeps({
|
|
6237
6237
|
core: {
|
|
@@ -8419,6 +8419,7 @@ ${diff}`;
|
|
|
8419
8419
|
}
|
|
8420
8420
|
|
|
8421
8421
|
// src/services/mcp-management.ts
|
|
8422
|
+
import { resolveMcpServerConfig } from "@wrongstack/core/infrastructure";
|
|
8422
8423
|
import {
|
|
8423
8424
|
color as color7,
|
|
8424
8425
|
expectDefined as expectDefined4,
|
|
@@ -8534,7 +8535,7 @@ async function runAdd(name, enable, configured, configPath, mcpRegistry, all) {
|
|
|
8534
8535
|
}
|
|
8535
8536
|
try {
|
|
8536
8537
|
if (mcpRegistry.list().some((server) => server.name === name)) {
|
|
8537
|
-
await mcpRegistry.restart(name);
|
|
8538
|
+
await mcpRegistry.restart(name, { ...nextCfg, name });
|
|
8538
8539
|
} else {
|
|
8539
8540
|
await mcpRegistry.start(nextCfg);
|
|
8540
8541
|
}
|
|
@@ -8572,24 +8573,21 @@ async function runRemove(name, configured, configPath, mcpRegistry) {
|
|
|
8572
8573
|
async function runEnable(name, configured, configPath, mcpRegistry) {
|
|
8573
8574
|
const cfg = configured[name];
|
|
8574
8575
|
if (!cfg) return `Server "${name}" is not in config. Run \`/mcp add ${name} --enable\` first.`;
|
|
8576
|
+
const resolved = resolveMcpServerConfig(name, cfg);
|
|
8577
|
+
if (!resolved) return `Server "${name}" has no transport and matches no preset.`;
|
|
8578
|
+
const startCfg = { ...resolved, enabled: true };
|
|
8579
|
+
const registered = mcpRegistry.list().some((server) => server.name === name);
|
|
8575
8580
|
if (cfg.enabled !== false) {
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
} catch {
|
|
8580
|
-
await mcpRegistry.start({ ...cfg, enabled: true });
|
|
8581
|
-
return `${color7.green("Enabled")} "${name}" and started.`;
|
|
8582
|
-
}
|
|
8581
|
+
if (registered) await mcpRegistry.restart(name, startCfg);
|
|
8582
|
+
else await mcpRegistry.start(startCfg);
|
|
8583
|
+
return `${color7.green("\u25CF")} "${name}" is already enabled and running.`;
|
|
8583
8584
|
}
|
|
8584
8585
|
await updateJsonObjectFile(configPath, (full) => {
|
|
8585
8586
|
const current = isMcpServerRecord(full.mcpServers) ? full.mcpServers : {};
|
|
8586
8587
|
setJsonPath(full, ["mcpServers", name], { ...cfg, ...current[name], enabled: true });
|
|
8587
8588
|
});
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
} catch {
|
|
8591
|
-
await mcpRegistry.start({ ...cfg, enabled: true });
|
|
8592
|
-
}
|
|
8589
|
+
if (registered) await mcpRegistry.restart(name, startCfg);
|
|
8590
|
+
else await mcpRegistry.start(startCfg);
|
|
8593
8591
|
return `${color7.green("Enabled")} "${name}" and started.`;
|
|
8594
8592
|
}
|
|
8595
8593
|
async function runDisable(name, configured, configPath, mcpRegistry) {
|
|
@@ -8642,6 +8640,8 @@ function stateBadge(state) {
|
|
|
8642
8640
|
return color7.dim("\u25CB disconnected");
|
|
8643
8641
|
case "failed":
|
|
8644
8642
|
return color7.red("\u2717 failed");
|
|
8643
|
+
case "dormant":
|
|
8644
|
+
return color7.dim("\u25CC dormant (spawns on first call)");
|
|
8645
8645
|
default:
|
|
8646
8646
|
return color7.dim(state);
|
|
8647
8647
|
}
|
|
@@ -8781,7 +8781,7 @@ async function checkUncommittedChanges(projectRoot) {
|
|
|
8781
8781
|
stdout += data;
|
|
8782
8782
|
});
|
|
8783
8783
|
child.on("error", reject);
|
|
8784
|
-
child.on("close", (code) => resolve9({ stdout, code: code ??
|
|
8784
|
+
child.on("close", (code) => resolve9({ stdout, code: code ?? 1 }));
|
|
8785
8785
|
});
|
|
8786
8786
|
if (!result.stdout.trim()) return void 0;
|
|
8787
8787
|
const count = result.stdout.split("\n").filter(Boolean).length;
|
|
@@ -17897,7 +17897,6 @@ function parseTaskEvidenceFlags(tokens) {
|
|
|
17897
17897
|
}
|
|
17898
17898
|
if (!inline && value.startsWith("-")) {
|
|
17899
17899
|
warnings.push(`${key} expects a URL but none was provided`);
|
|
17900
|
-
i++;
|
|
17901
17900
|
continue;
|
|
17902
17901
|
}
|
|
17903
17902
|
if (!inline) i++;
|
|
@@ -17913,7 +17912,6 @@ function parseTaskEvidenceFlags(tokens) {
|
|
|
17913
17912
|
}
|
|
17914
17913
|
if (!inline && raw.startsWith("-")) {
|
|
17915
17914
|
warnings.push(`${key} expects <checkId>=<status> but none was provided`);
|
|
17916
|
-
i++;
|
|
17917
17915
|
continue;
|
|
17918
17916
|
}
|
|
17919
17917
|
const sep2 = raw.lastIndexOf("=");
|
|
@@ -18148,10 +18146,16 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
|
|
|
18148
18146
|
}
|
|
18149
18147
|
if (board.lifecycle?.mode === "managed") {
|
|
18150
18148
|
const stageToColumn = board.lifecycle?.columns ?? {};
|
|
18151
|
-
const
|
|
18149
|
+
const currentTask = board.tasks.find((t) => t.id === taskId);
|
|
18150
|
+
if (!currentTask) {
|
|
18151
|
+
return { message: color36.red("Task not found") };
|
|
18152
|
+
}
|
|
18152
18153
|
const currentStage = Object.entries(stageToColumn).find(
|
|
18153
|
-
([, columnId]) => columnId ===
|
|
18154
|
+
([, columnId]) => columnId === currentTask.columnId
|
|
18154
18155
|
)?.[0];
|
|
18156
|
+
if (currentStage === "done") {
|
|
18157
|
+
return { message: color36.yellow("Task is already in Done \u2014 nothing to do.") };
|
|
18158
|
+
}
|
|
18155
18159
|
const path35 = currentStage === "backlog" ? ["todo", "running", "review", "done"] : currentStage === "todo" ? ["running", "review", "done"] : currentStage === "running" ? ["review", "done"] : currentStage === "review" ? ["done"] : null;
|
|
18156
18160
|
if (path35 === null) {
|
|
18157
18161
|
return {
|
|
@@ -18160,10 +18164,6 @@ async function handleTaskSubcommand(opts, projectRoot, args, showHelp) {
|
|
|
18160
18164
|
)
|
|
18161
18165
|
};
|
|
18162
18166
|
}
|
|
18163
|
-
const currentTask = board.tasks.find((t) => t.id === taskId);
|
|
18164
|
-
if (!currentTask) {
|
|
18165
|
-
return { message: color36.red("Task not found") };
|
|
18166
|
-
}
|
|
18167
18167
|
const preflightIssues = [];
|
|
18168
18168
|
if (!note?.trim()) {
|
|
18169
18169
|
return {
|
|
@@ -19920,7 +19920,7 @@ async function runAudienceMemory(store, rest) {
|
|
|
19920
19920
|
let imported = 0;
|
|
19921
19921
|
let skipped = 0;
|
|
19922
19922
|
for (const entry of entries) {
|
|
19923
|
-
if (typeof entry.text !== "string" || !entry.text.trim()) {
|
|
19923
|
+
if (!entry || typeof entry !== "object" || typeof entry.text !== "string" || !entry.text.trim()) {
|
|
19924
19924
|
skipped++;
|
|
19925
19925
|
continue;
|
|
19926
19926
|
}
|
|
@@ -20234,6 +20234,8 @@ var MEMORY_KINDS = [
|
|
|
20234
20234
|
"summary"
|
|
20235
20235
|
];
|
|
20236
20236
|
var MEMORY_SCOPES = ["project", "user", "session", "file", "symbol"];
|
|
20237
|
+
var DECIMAL_RE = /^(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
20238
|
+
var INTEGER_RE = /^\d+$/;
|
|
20237
20239
|
var MEMORY_STATUSES = [
|
|
20238
20240
|
"active",
|
|
20239
20241
|
"stale",
|
|
@@ -20258,7 +20260,7 @@ function parseMemoryFlags(tokens) {
|
|
|
20258
20260
|
errors.push(`${name} needs a value between 0 and 1.`);
|
|
20259
20261
|
return void 0;
|
|
20260
20262
|
}
|
|
20261
|
-
const parsed = Number.parseFloat(value);
|
|
20263
|
+
const parsed = DECIMAL_RE.test(value) ? Number.parseFloat(value) : Number.NaN;
|
|
20262
20264
|
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
|
|
20263
20265
|
errors.push(`${name} must be a number between 0 and 1 (got "${value}").`);
|
|
20264
20266
|
return void 0;
|
|
@@ -20368,7 +20370,7 @@ function parseForFileFlags(tokens) {
|
|
|
20368
20370
|
out.errors.push("--line needs a 1-indexed line number.");
|
|
20369
20371
|
continue;
|
|
20370
20372
|
}
|
|
20371
|
-
const parsed = Number.parseInt(next, 10);
|
|
20373
|
+
const parsed = INTEGER_RE.test(next) ? Number.parseInt(next, 10) : Number.NaN;
|
|
20372
20374
|
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
20373
20375
|
out.errors.push(`--line must be a positive integer (got "${next}").`);
|
|
20374
20376
|
continue;
|
|
@@ -20380,7 +20382,7 @@ function parseForFileFlags(tokens) {
|
|
|
20380
20382
|
out.errors.push("--limit needs a value between 1 and 200.");
|
|
20381
20383
|
continue;
|
|
20382
20384
|
}
|
|
20383
|
-
const parsed = Number.parseInt(next, 10);
|
|
20385
|
+
const parsed = INTEGER_RE.test(next) ? Number.parseInt(next, 10) : Number.NaN;
|
|
20384
20386
|
if (!Number.isFinite(parsed) || parsed < 1 || parsed > 200) {
|
|
20385
20387
|
out.errors.push(`--limit must be between 1 and 200 (got "${next}").`);
|
|
20386
20388
|
continue;
|
|
@@ -20880,7 +20882,8 @@ async function runStats(opts) {
|
|
|
20880
20882
|
"anti_pattern",
|
|
20881
20883
|
"untyped"
|
|
20882
20884
|
];
|
|
20883
|
-
|
|
20885
|
+
const extraTypes = [...byType.keys()].filter((t) => !typeOrder.includes(t)).sort();
|
|
20886
|
+
for (const t of [...typeOrder.slice(0, -1), ...extraTypes, "untyped"]) {
|
|
20884
20887
|
const count = byType.get(t);
|
|
20885
20888
|
if (count) {
|
|
20886
20889
|
const bar2 = "\u2588".repeat(Math.min(count, 20));
|
|
@@ -26831,6 +26834,11 @@ import { leaderTierPolicy, listTierIds, resolveTier } from "@wrongstack/core/coo
|
|
|
26831
26834
|
import { ConfigError as ConfigError6 } from "@wrongstack/core/types";
|
|
26832
26835
|
import { atomicWrite as atomicWrite10, color as color54, toErrorMessage as toErrorMessage25 } from "@wrongstack/core/utils";
|
|
26833
26836
|
var LEADER_MODES = ["off", "propose", "auto"];
|
|
26837
|
+
var DECIMAL_RE2 = /^(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
26838
|
+
var INTEGER_RE2 = /^\d+$/;
|
|
26839
|
+
function strictNumber(raw, pattern) {
|
|
26840
|
+
return pattern.test(raw) ? Number(raw) : Number.NaN;
|
|
26841
|
+
}
|
|
26834
26842
|
async function patchGlobalConfig3(globalConfigPath, mutate) {
|
|
26835
26843
|
let raw = "{}";
|
|
26836
26844
|
let fileExists2 = true;
|
|
@@ -27019,15 +27027,15 @@ function buildTierCommand(opts) {
|
|
|
27019
27027
|
message: `${color54.amber("Usage:")} /tier budget <tier> <maxCostUsd> [maxIterations] [maxToolCalls]`
|
|
27020
27028
|
};
|
|
27021
27029
|
}
|
|
27022
|
-
const usd =
|
|
27030
|
+
const usd = strictNumber(parts[2] ?? "", DECIMAL_RE2);
|
|
27023
27031
|
if (!Number.isFinite(usd) || usd < 0) {
|
|
27024
27032
|
return { message: `${color54.red("Invalid")} maxCostUsd: "${parts[2] ?? ""}"` };
|
|
27025
27033
|
}
|
|
27026
|
-
const iters = parts[3] !== void 0 ?
|
|
27034
|
+
const iters = parts[3] !== void 0 ? strictNumber(parts[3], INTEGER_RE2) : void 0;
|
|
27027
27035
|
if (iters !== void 0 && (!Number.isFinite(iters) || iters < 0)) {
|
|
27028
27036
|
return { message: `${color54.red("Invalid")} maxIterations: "${parts[3]}"` };
|
|
27029
27037
|
}
|
|
27030
|
-
const tools = parts[4] !== void 0 ?
|
|
27038
|
+
const tools = parts[4] !== void 0 ? strictNumber(parts[4], INTEGER_RE2) : void 0;
|
|
27031
27039
|
if (tools !== void 0 && (!Number.isFinite(tools) || tools < 0)) {
|
|
27032
27040
|
return { message: `${color54.red("Invalid")} maxToolCalls: "${parts[4]}"` };
|
|
27033
27041
|
}
|
|
@@ -27057,6 +27065,12 @@ function buildTierCommand(opts) {
|
|
|
27057
27065
|
for (const [key, value] of Object.entries(routing)) {
|
|
27058
27066
|
if (value === tier) delete routing[key];
|
|
27059
27067
|
}
|
|
27068
|
+
if (tiers["default"] === tier) delete tiers["default"];
|
|
27069
|
+
const leader = tiers["leader"];
|
|
27070
|
+
if (leader && typeof leader === "object") {
|
|
27071
|
+
const leaderRecord = leader;
|
|
27072
|
+
if (leaderRecord["maxTier"] === tier) delete leaderRecord["maxTier"];
|
|
27073
|
+
}
|
|
27060
27074
|
});
|
|
27061
27075
|
return { message: `${color54.green("\u2713")} tier ${color54.cyan(tier)} removed` };
|
|
27062
27076
|
}
|
|
@@ -27117,7 +27131,7 @@ function buildTierCommand(opts) {
|
|
|
27117
27131
|
};
|
|
27118
27132
|
}
|
|
27119
27133
|
if (action === "dwell") {
|
|
27120
|
-
const turns =
|
|
27134
|
+
const turns = strictNumber(parts[2] ?? "", INTEGER_RE2);
|
|
27121
27135
|
if (!Number.isFinite(turns) || turns < 0) {
|
|
27122
27136
|
return { message: `${color54.amber("Usage:")} /tier leader dwell <turns>` };
|
|
27123
27137
|
}
|
|
@@ -27180,7 +27194,7 @@ function buildAgentsCommand(opts) {
|
|
|
27180
27194
|
return {
|
|
27181
27195
|
name: "agents",
|
|
27182
27196
|
category: "Agent",
|
|
27183
|
-
description: "Monitor subagent activity: /agents [chat off|
|
|
27197
|
+
description: "Monitor subagent activity: /agents [chat off|full|status | stream on|off|status | list | show <id>]",
|
|
27184
27198
|
async run(args) {
|
|
27185
27199
|
if ((!args.trim() || args.trim() === "list") && opts.onPanelOpen?.current) {
|
|
27186
27200
|
const opened = opts.onPanelOpen.current("toggleAgentsMonitor");
|
|
@@ -28217,7 +28231,7 @@ async function runGit2(args, cwd) {
|
|
|
28217
28231
|
stdout += d;
|
|
28218
28232
|
});
|
|
28219
28233
|
child.on("error", () => resolve9({ stdout, code: 1 }));
|
|
28220
|
-
child.on("close", (code) => resolve9({ stdout, code: code ??
|
|
28234
|
+
child.on("close", (code) => resolve9({ stdout, code: code ?? 1 }));
|
|
28221
28235
|
});
|
|
28222
28236
|
}
|
|
28223
28237
|
async function getChangedFiles(cwd) {
|
|
@@ -31323,8 +31337,8 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
31323
31337
|
message: `${color65.green("\u2713")} long-tool \u2192 ${color65.dim("off")}`
|
|
31324
31338
|
};
|
|
31325
31339
|
}
|
|
31326
|
-
const ms = Number
|
|
31327
|
-
if (Number.
|
|
31340
|
+
const ms = /^\d+$/.test(raw) ? Number(raw) : Number.NaN;
|
|
31341
|
+
if (!Number.isSafeInteger(ms)) {
|
|
31328
31342
|
return {
|
|
31329
31343
|
message: `${color65.red("Invalid number")}: "${raw}". Enter milliseconds, e.g. /telegram-settings long-tool 15000`
|
|
31330
31344
|
};
|
|
@@ -31343,7 +31357,7 @@ function buildTelegramSettingsCommand(opts) {
|
|
|
31343
31357
|
message: `${color65.amber("Usage:")} /telegram-settings poll <seconds> ${color65.dim("(1\u201360)")}`
|
|
31344
31358
|
};
|
|
31345
31359
|
}
|
|
31346
|
-
const sec = Number
|
|
31360
|
+
const sec = /^\d+$/.test(raw) ? Number(raw) : Number.NaN;
|
|
31347
31361
|
if (Number.isNaN(sec) || sec < 1 || sec > 60) {
|
|
31348
31362
|
return {
|
|
31349
31363
|
message: `${color65.red("Invalid value")}: "${raw}". Enter seconds between 1 and 60.`
|
|
@@ -34697,7 +34711,7 @@ import * as path29 from "node:path";
|
|
|
34697
34711
|
import { getSharedProjectMailbox as getSharedProjectMailbox10 } from "@wrongstack/core/coordination";
|
|
34698
34712
|
import { CouncilOrchestrator, OneShotOrchestrator as OneShotOrchestrator3 } from "@wrongstack/core/execution";
|
|
34699
34713
|
import { countShellHooks, HookRegistry as HookRegistry2, HookRunner as HookRunner2, shellHooksEqual } from "@wrongstack/core/hooks";
|
|
34700
|
-
import {
|
|
34714
|
+
import { resolveMcpServerConfig as resolveMcpServerConfig2 } from "@wrongstack/core/infrastructure";
|
|
34701
34715
|
import { TOKENS as TOKENS11 } from "@wrongstack/core/kernel";
|
|
34702
34716
|
import { NotifierImpl } from "@wrongstack/core/notifications";
|
|
34703
34717
|
import {
|
|
@@ -35767,18 +35781,23 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
35767
35781
|
log: logger,
|
|
35768
35782
|
lazyMode: normalizeTokenSavingTier5(config.features.tokenSavingMode) !== "off",
|
|
35769
35783
|
cacheDir: wpaths.cacheDir,
|
|
35784
|
+
// Presets say `--project-root .`; resolve it against the project, not
|
|
35785
|
+
// wherever this process happens to be running.
|
|
35786
|
+
cwd: wpaths.projectRoot,
|
|
35770
35787
|
authorizationProviderFactory: createVaultBackedMcpAuthorizationProviderFactory({
|
|
35771
35788
|
store: mcpTokenStore
|
|
35772
35789
|
}),
|
|
35773
35790
|
authorizationManager: mcpAuthorizationManager
|
|
35774
35791
|
});
|
|
35775
35792
|
if (config.features.mcp) {
|
|
35776
|
-
const
|
|
35777
|
-
|
|
35778
|
-
|
|
35779
|
-
|
|
35780
|
-
|
|
35781
|
-
|
|
35793
|
+
for (const [name, entry] of Object.entries(config.mcpServers ?? {})) {
|
|
35794
|
+
const resolved = resolveMcpServerConfig2(name, entry);
|
|
35795
|
+
if (!resolved) {
|
|
35796
|
+
logger.warn(`MCP server "${name}" has no transport and matches no preset \u2014 skipped`);
|
|
35797
|
+
continue;
|
|
35798
|
+
}
|
|
35799
|
+
void mcpRegistry.start(resolved).catch((err) => {
|
|
35800
|
+
logger.warn(`MCP server "${name}" failed to start`, err);
|
|
35782
35801
|
});
|
|
35783
35802
|
}
|
|
35784
35803
|
}
|
|
@@ -38936,4 +38955,4 @@ export {
|
|
|
38936
38955
|
CLI_VERSION,
|
|
38937
38956
|
runInteractive
|
|
38938
38957
|
};
|
|
38939
|
-
//# sourceMappingURL=cli-main-
|
|
38958
|
+
//# sourceMappingURL=cli-main-WC5JNIWY.js.map
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import * as fs2 from "node:fs/promises";
|
|
14
14
|
import * as os from "node:os";
|
|
15
15
|
import * as path2 from "node:path";
|
|
16
|
+
import { resolveMcpServerConfig } from "@wrongstack/core/infrastructure";
|
|
16
17
|
import { color, toErrorMessage } from "@wrongstack/core/utils";
|
|
17
18
|
import {
|
|
18
19
|
applyProxyConfig,
|
|
@@ -328,8 +329,17 @@ var doctorCmd = async (args, deps) => {
|
|
|
328
329
|
});
|
|
329
330
|
}
|
|
330
331
|
const mcpEntries = Object.entries(cfg.mcpServers ?? {});
|
|
331
|
-
for (const [name,
|
|
332
|
-
if (
|
|
332
|
+
for (const [name, entry] of mcpEntries) {
|
|
333
|
+
if (entry.enabled === false) continue;
|
|
334
|
+
const srv = resolveMcpServerConfig(name, entry);
|
|
335
|
+
if (!srv) {
|
|
336
|
+
checks.push({
|
|
337
|
+
name: `mcp:${name}`,
|
|
338
|
+
status: "fail",
|
|
339
|
+
detail: "no transport and no built-in preset of this name"
|
|
340
|
+
});
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
333
343
|
if ((srv.transport === "sse" || srv.transport === "streamable-http") && !srv.url)
|
|
334
344
|
checks.push({ name: `mcp:${name}`, status: "fail", detail: "transport requires url" });
|
|
335
345
|
else if (srv.transport === "stdio" && !srv.command)
|
|
@@ -382,4 +392,4 @@ export {
|
|
|
382
392
|
doctorCmd,
|
|
383
393
|
proxyCmd
|
|
384
394
|
};
|
|
385
|
-
//# sourceMappingURL=diag-doctor-
|
|
395
|
+
//# sourceMappingURL=diag-doctor-ANPRUYFM.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
runGit,
|
|
5
5
|
setAutoSuggestions,
|
|
6
6
|
setSuggestions
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OWNC7LMD.js";
|
|
8
8
|
import {
|
|
9
9
|
deriveFsAccessPair,
|
|
10
10
|
filterSafeForProject,
|
|
@@ -6953,4 +6953,4 @@ export {
|
|
|
6953
6953
|
execute,
|
|
6954
6954
|
resolveReviewerFallbackModels
|
|
6955
6955
|
};
|
|
6956
|
-
//# sourceMappingURL=execution-
|
|
6956
|
+
//# sourceMappingURL=execution-EXDRBS4F.js.map
|
|
@@ -14,9 +14,11 @@ import {
|
|
|
14
14
|
|
|
15
15
|
// src/subcommands/handlers/hq.ts
|
|
16
16
|
import * as fs from "node:fs/promises";
|
|
17
|
+
import * as path from "node:path";
|
|
17
18
|
import {
|
|
18
19
|
HQ_AUTH_FILE_VERSION,
|
|
19
20
|
HQ_CLI_DEFAULT_HOST,
|
|
21
|
+
HqAlertEngine,
|
|
20
22
|
HqInsecureExposureError,
|
|
21
23
|
hqAuthAuditPath,
|
|
22
24
|
hqAuthContentHash,
|
|
@@ -25,6 +27,7 @@ import {
|
|
|
25
27
|
logHqAuthAudit,
|
|
26
28
|
mintHqToken,
|
|
27
29
|
mutateHqAuthFile,
|
|
30
|
+
readHqAlertsConfig,
|
|
28
31
|
readHqAuthFile,
|
|
29
32
|
resolveHqDataDir
|
|
30
33
|
} from "@wrongstack/core/hq";
|
|
@@ -48,6 +51,9 @@ var hqCmd = async (args, deps) => {
|
|
|
48
51
|
if (sub === "audit") {
|
|
49
52
|
return hqAuditCmd(args.slice(1), deps);
|
|
50
53
|
}
|
|
54
|
+
if (sub === "alerts") {
|
|
55
|
+
return hqAlertsCmd(args.slice(1), deps);
|
|
56
|
+
}
|
|
51
57
|
if (sub === "service") {
|
|
52
58
|
const { hqServiceCmd } = await import("./hq-service-L5INQFM4.js");
|
|
53
59
|
return hqServiceCmd(args.slice(1), deps);
|
|
@@ -62,7 +68,7 @@ var hqCmd = async (args, deps) => {
|
|
|
62
68
|
return 1;
|
|
63
69
|
};
|
|
64
70
|
async function startServer(deps) {
|
|
65
|
-
const { startHqServer } = await import("./hq-server-
|
|
71
|
+
const { startHqServer } = await import("./hq-server-KE5YDNGG.js");
|
|
66
72
|
const dataDir = resolveDataDir(deps);
|
|
67
73
|
const flags = deps.flags ?? {};
|
|
68
74
|
const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
|
|
@@ -188,7 +194,7 @@ async function startServer(deps) {
|
|
|
188
194
|
ipAllowlist === void 0 ? "Network allowlist: disabled (authentication remains required when configured).\n" : `Network allowlist: active (${ipAllowlist.length} configured rule${ipAllowlist.length === 1 ? "" : "s"} + loopback).
|
|
189
195
|
`
|
|
190
196
|
);
|
|
191
|
-
await new Promise((
|
|
197
|
+
await new Promise((resolve2) => {
|
|
192
198
|
const shutdown = async () => {
|
|
193
199
|
try {
|
|
194
200
|
await handle.close();
|
|
@@ -196,7 +202,7 @@ async function startServer(deps) {
|
|
|
196
202
|
deps.renderer.write(`HQ server close error: ${String(err)}
|
|
197
203
|
`);
|
|
198
204
|
}
|
|
199
|
-
|
|
205
|
+
resolve2();
|
|
200
206
|
};
|
|
201
207
|
process.on("SIGINT", shutdown);
|
|
202
208
|
process.on("SIGTERM", shutdown);
|
|
@@ -807,7 +813,7 @@ function printAuditHelp(deps) {
|
|
|
807
813
|
`
|
|
808
814
|
);
|
|
809
815
|
deps.renderer.write(
|
|
810
|
-
` auth.json and print it so an operator can compare
|
|
816
|
+
` on-disk auth.json and print it so an operator can compare
|
|
811
817
|
`
|
|
812
818
|
);
|
|
813
819
|
deps.renderer.write(
|
|
@@ -825,8 +831,150 @@ function printAuditHelp(deps) {
|
|
|
825
831
|
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
826
832
|
`);
|
|
827
833
|
}
|
|
834
|
+
async function hqAlertsCmd(args, deps) {
|
|
835
|
+
const action = args[0];
|
|
836
|
+
if (deps.flags?.["help"] === true || action === "help" || action === "--help") {
|
|
837
|
+
printAlertsHelp(deps);
|
|
838
|
+
return 0;
|
|
839
|
+
}
|
|
840
|
+
if (action === "eval" || action === void 0) {
|
|
841
|
+
return hqAlertsEval(args.slice(1), deps);
|
|
842
|
+
}
|
|
843
|
+
deps.renderer.writeError(`Unknown hq alerts subcommand: ${action ?? "(none)"}
|
|
844
|
+
`);
|
|
845
|
+
printAlertsHelp(deps);
|
|
846
|
+
return 1;
|
|
847
|
+
}
|
|
848
|
+
async function hqAlertsEval(_args, deps) {
|
|
849
|
+
const flags = deps.flags ?? {};
|
|
850
|
+
const snapshotArg = typeof flags["snapshot"] === "string" ? flags["snapshot"] : void 0;
|
|
851
|
+
let snapshotPath;
|
|
852
|
+
try {
|
|
853
|
+
if (snapshotArg !== void 0) {
|
|
854
|
+
snapshotPath = path.resolve(snapshotArg);
|
|
855
|
+
} else {
|
|
856
|
+
const dataDir2 = resolveDataDir(deps);
|
|
857
|
+
snapshotPath = path.join(dataDir2, "snapshot.json");
|
|
858
|
+
}
|
|
859
|
+
} catch (err) {
|
|
860
|
+
deps.renderer.writeError(`Failed to resolve snapshot path: ${err.message}
|
|
861
|
+
`);
|
|
862
|
+
return 2;
|
|
863
|
+
}
|
|
864
|
+
let raw;
|
|
865
|
+
try {
|
|
866
|
+
raw = await fs.readFile(snapshotPath, "utf8");
|
|
867
|
+
} catch (err) {
|
|
868
|
+
deps.renderer.writeError(
|
|
869
|
+
`Cannot read snapshot at ${snapshotPath}: ${err.message}
|
|
870
|
+
Pass --snapshot <path> to evaluate against a specific file.
|
|
871
|
+
`
|
|
872
|
+
);
|
|
873
|
+
return 2;
|
|
874
|
+
}
|
|
875
|
+
let snapshot;
|
|
876
|
+
try {
|
|
877
|
+
snapshot = JSON.parse(raw);
|
|
878
|
+
} catch (err) {
|
|
879
|
+
deps.renderer.writeError(
|
|
880
|
+
`Snapshot at ${snapshotPath} is not valid JSON: ${err.message}
|
|
881
|
+
`
|
|
882
|
+
);
|
|
883
|
+
return 2;
|
|
884
|
+
}
|
|
885
|
+
const dataDir = resolveDataDir(deps);
|
|
886
|
+
let thresholds;
|
|
887
|
+
try {
|
|
888
|
+
const config = await readHqAlertsConfig(dataDir);
|
|
889
|
+
thresholds = config.thresholds;
|
|
890
|
+
} catch {
|
|
891
|
+
}
|
|
892
|
+
const engine = new HqAlertEngine({
|
|
893
|
+
onAlert: () => {
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
let fired;
|
|
897
|
+
try {
|
|
898
|
+
fired = engine.evaluate(snapshot, thresholds);
|
|
899
|
+
} catch (err) {
|
|
900
|
+
deps.renderer.writeError(`Alert evaluation failed: ${err.message}
|
|
901
|
+
`);
|
|
902
|
+
return 2;
|
|
903
|
+
}
|
|
904
|
+
if (fired.length === 0) {
|
|
905
|
+
deps.renderer.write(`No alert rules fired against ${snapshotPath}.
|
|
906
|
+
`);
|
|
907
|
+
if (thresholds === void 0) {
|
|
908
|
+
deps.renderer.write(
|
|
909
|
+
"(No persisted thresholds; using built-in defaults. Run `wstack hq alerts` with a populated alerts-config.json to override.)\n"
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
return 0;
|
|
913
|
+
}
|
|
914
|
+
deps.renderer.write(`${fired.length} alert rule(s) fired against ${snapshotPath}:
|
|
915
|
+
`);
|
|
916
|
+
for (const alert of fired) {
|
|
917
|
+
deps.renderer.write(` [${alert.severity}] ${alert.ruleId}: ${alert.message}
|
|
918
|
+
`);
|
|
919
|
+
}
|
|
920
|
+
return 1;
|
|
921
|
+
}
|
|
922
|
+
function printAlertsHelp(deps) {
|
|
923
|
+
deps.renderer.write(`Usage: wstack hq alerts <eval>
|
|
924
|
+
`);
|
|
925
|
+
deps.renderer.write("\n");
|
|
926
|
+
deps.renderer.write(
|
|
927
|
+
` wstack hq alerts eval [--snapshot <path>] Run HqAlertEngine.evaluate() against a
|
|
928
|
+
`
|
|
929
|
+
);
|
|
930
|
+
deps.renderer.write(
|
|
931
|
+
` snapshot file (or the live <dataDir>/
|
|
932
|
+
`
|
|
933
|
+
);
|
|
934
|
+
deps.renderer.write(
|
|
935
|
+
` snapshot.json). Pure-function dry run;
|
|
936
|
+
`
|
|
937
|
+
);
|
|
938
|
+
deps.renderer.write(
|
|
939
|
+
` no server required. Exits 0 when no
|
|
940
|
+
`
|
|
941
|
+
);
|
|
942
|
+
deps.renderer.write(
|
|
943
|
+
` rules fire, 1 when rules fire, 2 on errors.
|
|
944
|
+
`
|
|
945
|
+
);
|
|
946
|
+
deps.renderer.write("\n");
|
|
947
|
+
deps.renderer.write(
|
|
948
|
+
`Persisted thresholds (<dataDir>/alerts-config.json) are loaded automatically when
|
|
949
|
+
`
|
|
950
|
+
);
|
|
951
|
+
deps.renderer.write(
|
|
952
|
+
`present; otherwise the engine's built-in defaults apply. Snoozes are NOT honored
|
|
953
|
+
`
|
|
954
|
+
);
|
|
955
|
+
deps.renderer.write(
|
|
956
|
+
`by this command \u2014 eval is a "what would fire RIGHT NOW if there were no snoozes"
|
|
957
|
+
`
|
|
958
|
+
);
|
|
959
|
+
deps.renderer.write(`probe.
|
|
960
|
+
`);
|
|
961
|
+
deps.renderer.write("\n");
|
|
962
|
+
deps.renderer.write(`Flags:
|
|
963
|
+
`);
|
|
964
|
+
deps.renderer.write(
|
|
965
|
+
` --snapshot <path> Evaluate against this snapshot file instead of the live one.
|
|
966
|
+
`
|
|
967
|
+
);
|
|
968
|
+
deps.renderer.write(
|
|
969
|
+
` --data-dir <path> Override HQ data directory (default ~/.wrongstack/hq).
|
|
970
|
+
`
|
|
971
|
+
);
|
|
972
|
+
deps.renderer.write("\n");
|
|
973
|
+
deps.renderer.write(`Run \`wstack hq --help\` for the full HQ command list.
|
|
974
|
+
`);
|
|
975
|
+
}
|
|
828
976
|
export {
|
|
829
977
|
hqCmd,
|
|
830
978
|
resolveAuditActor
|
|
831
979
|
};
|
|
832
|
-
//# sourceMappingURL=hq-
|
|
980
|
+
//# sourceMappingURL=hq-NO2NWGU4.js.map
|
|
@@ -26,6 +26,17 @@ interface HqAuthStateOptions {
|
|
|
26
26
|
* makes the latch unconditional.
|
|
27
27
|
*/
|
|
28
28
|
onApplied?: ((mutableAuth: HqRouterMutableAuth) => void) | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Invoked when browser tokens stopped being live — revoked by hand, or aged
|
|
31
|
+
* out — during an {@link HqAuthState.apply}. `keys` are the stored verifiers,
|
|
32
|
+
* `ids` the token ids of those that had one.
|
|
33
|
+
*
|
|
34
|
+
* W4 #15: an open WebSocket never re-presents its credential, so before this
|
|
35
|
+
* a revoked operator kept a working dashboard until the idle-eviction pass
|
|
36
|
+
* happened to catch them. Reporting the change at the single projection
|
|
37
|
+
* choke point is what lets the server close those sockets immediately.
|
|
38
|
+
*/
|
|
39
|
+
onTokensRevoked?: ((keys: readonly string[], ids: readonly string[]) => void) | undefined;
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Project an `auth.json` document onto the live `mutableAuth` used by every
|