@wrongstack/cli 1.1.2 → 1.1.5

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.
Files changed (117) hide show
  1. package/dist/{acp-HCGUTFNE.js → acp-NKUEYJDZ.js} +14 -5
  2. package/dist/acp-leader/acp-leader-confirm.d.ts +20 -0
  3. package/dist/acp-leader/acp-leader-context.d.ts +29 -0
  4. package/dist/acp-leader/acp-leader-fleet.d.ts +26 -0
  5. package/dist/acp-leader/acp-leader-host-binding.d.ts +17 -0
  6. package/dist/acp-leader/acp-leader-host.d.ts +82 -0
  7. package/dist/acp-leader/acp-leader-picker.d.ts +24 -0
  8. package/dist/acp-leader/acp-leader-provider.d.ts +85 -0
  9. package/dist/acp-leader/acp-leader-resume.d.ts +10 -0
  10. package/dist/acp-leader/acp-leader-stream.d.ts +83 -0
  11. package/dist/{auth-ANOVZVHE.js → auth-2ZG5DBHS.js} +62 -66
  12. package/dist/auth-menu/index.d.ts +1 -2
  13. package/dist/boot/dispatch-webui.d.ts +16 -0
  14. package/dist/boot/launch-menu-arrow.d.ts +20 -0
  15. package/dist/boot/launch-menu-types.d.ts +36 -0
  16. package/dist/boot/launch-menu.d.ts +1 -57
  17. package/dist/boot/tui-session-resume-rollback.d.ts +31 -0
  18. package/dist/{boot-auto-thin-7D4OVEWA.js → boot-auto-thin-N2CIGTXE.js} +3 -3
  19. package/dist/{chunk-TZPKOS5G.js → chunk-2XQ6SRKG.js} +2 -2
  20. package/dist/chunk-3LEIFO5D.js +65 -0
  21. package/dist/chunk-5SGMUDP5.js +752 -0
  22. package/dist/{chunk-3EXRPTAU.js → chunk-5TQ65PXQ.js} +17 -17
  23. package/dist/{chunk-GRAGMA4B.js → chunk-7BM4LGKQ.js} +18 -18
  24. package/dist/{chunk-VAQXOZKP.js → chunk-AJM4EFCM.js} +139 -136
  25. package/dist/{chunk-C2BBH4S4.js → chunk-E3MJFAFR.js} +2 -2
  26. package/dist/{chunk-5TRZZHMN.js → chunk-JCZ2D3VV.js} +4 -65
  27. package/dist/{chunk-AWRZWPJ3.js → chunk-JFYQGMMM.js} +99 -75
  28. package/dist/{chunk-BIGSVBPI.js → chunk-KNYIEQAY.js} +64 -61
  29. package/dist/chunk-LUEO5HLZ.js +50 -0
  30. package/dist/chunk-LYWOV4OX.js +252 -0
  31. package/dist/chunk-M7FNHCE3.js +2070 -0
  32. package/dist/{chunk-75OLD563.js → chunk-M7PSENGF.js} +3 -1
  33. package/dist/{chunk-NMXQFQ26.js → chunk-MEBXWI7U.js} +5 -5
  34. package/dist/{chunk-RAWHRRUJ.js → chunk-MKMM5RIW.js} +209 -201
  35. package/dist/{chunk-3R3OADC5.js → chunk-P7MEEUGT.js} +281 -252
  36. package/dist/chunk-QLYPIJ7X.js +258 -0
  37. package/dist/chunk-RN5CFAVQ.js +292 -0
  38. package/dist/{chunk-WDXNBYGD.js → chunk-TDP7CZGE.js} +6 -1
  39. package/dist/{chunk-6VPWQ4TG.js → chunk-UROB7MK5.js} +2 -1
  40. package/dist/chunk-VEESMPTX.js +254 -0
  41. package/dist/{chunk-IJLIAPCW.js → chunk-VPSAKGLK.js} +47 -47
  42. package/dist/{cli-context-YIT4FEDM.js → cli-context-CQYGIWOU.js} +254 -237
  43. package/dist/{cli-main-JIADJ5OL.js → cli-main-VRUJNUBX.js} +2081 -1594
  44. package/dist/cli-main-boot.d.ts +1 -1
  45. package/dist/config-doctor-known-keys.d.ts +33 -0
  46. package/dist/config-doctor.d.ts +2 -47
  47. package/dist/config-history-support.d.ts +36 -0
  48. package/dist/config-history.d.ts +1 -1
  49. package/dist/{config-transfer-Y7XJMJRN.js → config-transfer-B4GOZTFC.js} +2 -2
  50. package/dist/{execution-BAP566QC.js → execution-IV72RUSM.js} +5354 -5258
  51. package/dist/execution-tui.d.ts +30 -0
  52. package/dist/fleet/acp-live-steer.d.ts +28 -0
  53. package/dist/fleet/acp-permission-bridge.d.ts +49 -0
  54. package/dist/fleet/acp-quota-hold.d.ts +3 -0
  55. package/dist/fleet/acp-quota-reading.d.ts +3 -0
  56. package/dist/fleet/acp-turn-reminders.d.ts +15 -0
  57. package/dist/fleet/acp-wrongstack-bridge.d.ts +50 -0
  58. package/dist/fleet/host-acp.d.ts +23 -2
  59. package/dist/fleet/wrongforge-client.d.ts +116 -0
  60. package/dist/fleet/wrongforge-gateway.d.ts +20 -0
  61. package/dist/fleet/wrongforge-info.d.ts +32 -0
  62. package/dist/fleet/wrongforge-quota.d.ts +10 -0
  63. package/dist/fleet/wrongforge-runner.d.ts +37 -0
  64. package/dist/fleet/wrongforge-runtime.d.ts +10 -0
  65. package/dist/{hq-JD5AZVMG.js → hq-54PQYR5O.js} +311 -307
  66. package/dist/hq-server/sweeps.d.ts +28 -0
  67. package/dist/{hq-server-BI23EPM7.js → hq-server-YK7FBLL6.js} +3 -3
  68. package/dist/index.js +8 -5
  69. package/dist/mcp-22CFBX4H.js +236 -0
  70. package/dist/mcp-serve-project.d.ts +18 -0
  71. package/dist/mcp-serve.d.ts +0 -63
  72. package/dist/{modeldiag-HDIKG37X.js → modeldiag-5PBB777J.js} +4 -4
  73. package/dist/{per-subcommand-help-D6J4ZXW2.js → per-subcommand-help-MQGERD4E.js} +2 -2
  74. package/dist/plugin-llm-command.d.ts +9 -0
  75. package/dist/{plugin-usage-TYF5HY4K.js → plugin-usage-UWKYMNQU.js} +3 -3
  76. package/dist/{plugins-XGAXDLPT.js → plugins-VP7JQH47.js} +4 -4
  77. package/dist/{sdd-runtime-6MFUXWJK.js → sdd-runtime-HIJ4Z5TF.js} +2 -2
  78. package/dist/services/sdd/state.d.ts +2 -0
  79. package/dist/session-event-wiring-types.d.ts +62 -0
  80. package/dist/session-event-wiring.d.ts +2 -52
  81. package/dist/{sessions-config-SJVQXCIE.js → sessions-config-7MK742OW.js} +2 -2
  82. package/dist/short-circuit-flags-AGHURHMQ.js +11 -0
  83. package/dist/slash-commands/command-context-fleet.d.ts +187 -0
  84. package/dist/slash-commands/command-context-sdd-goal.d.ts +102 -0
  85. package/dist/slash-commands/command-context.d.ts +3 -282
  86. package/dist/slash-commands/project-switch-interactive.d.ts +11 -0
  87. package/dist/slash-commands/setmodel-helpers.d.ts +36 -0
  88. package/dist/subcommands/handlers/hq-token.d.ts +3 -0
  89. package/dist/subcommands/handlers/hq.d.ts +0 -21
  90. package/dist/subcommands/handlers/per-subcommand-help-operations.d.ts +8 -0
  91. package/dist/subcommands/handlers/tools-cli-args.d.ts +57 -0
  92. package/dist/subcommands/handlers/tools-cli.d.ts +5 -0
  93. package/dist/subcommands/handlers/tools-serve.d.ts +4 -0
  94. package/dist/{subcommands-VTMIZQBP.js → subcommands-OCJNO57E.js} +2 -2
  95. package/dist/tool-gateway-http.d.ts +30 -0
  96. package/dist/tool-gateway.d.ts +185 -0
  97. package/dist/tools-cli-44MLIUQO.js +509 -0
  98. package/dist/tools-serve-TRCET2M7.js +102 -0
  99. package/dist/{tools-skills-55QVTMSK.js → tools-skills-WDTMCE46.js} +7 -2
  100. package/dist/tuneup-runtime-checks.d.ts +7 -0
  101. package/dist/tuneup-types.d.ts +118 -0
  102. package/dist/tuneup.d.ts +3 -122
  103. package/dist/{typesafe-YBEADNAH.js → typesafe-QLSMFU7J.js} +1 -1
  104. package/dist/{version-help-RBZC5GZZ.js → version-help-X6CC4CFY.js} +2 -2
  105. package/dist/{webui-server-HIUY3RHD.js → webui-server-V2R5WQUK.js} +79 -3
  106. package/dist/wiring/provider-runtime-setup.d.ts +3 -1
  107. package/dist/wiring/session-runtime.d.ts +1 -1
  108. package/dist/wrongforge-gateway-UOFBK56J.js +92 -0
  109. package/dist/wrongforge-leader/wrongforge-leader-gateway.d.ts +9 -0
  110. package/dist/wrongforge-leader/wrongforge-leader-picker.d.ts +12 -0
  111. package/dist/wrongforge-leader/wrongforge-leader-provider.d.ts +49 -0
  112. package/package.json +34 -30
  113. package/dist/auth-menu/anthropic-oauth.d.ts +0 -43
  114. package/dist/chunk-XT3NAHRX.js +0 -337
  115. package/dist/chunk-ZNNFEKDZ.js +0 -319
  116. package/dist/mcp-2XWBJEQN.js +0 -464
  117. package/dist/short-circuit-flags-CPCT5MWB.js +0 -11
@@ -1,19 +1,7 @@
1
1
 
2
- // src/hq-server/audit-actor.ts
3
- import * as os from "node:os";
4
- function resolveAuditActor() {
5
- const user = (process.env.USERNAME ?? process.env.USER ?? "").toString();
6
- try {
7
- const host = os.hostname();
8
- return user ? `${user}@${host}` : `cli@${host}`;
9
- } catch {
10
- return user ? `${user}@unknown` : "cli";
11
- }
12
- }
13
-
14
2
  // src/hq-server/utils.ts
15
3
  import * as fs from "node:fs/promises";
16
- import * as os2 from "node:os";
4
+ import * as os from "node:os";
17
5
  import * as path from "node:path";
18
6
  import { resolveHqDataDir } from "@wrongstack/core/hq";
19
7
  import { isSafeSessionId as coreIsSafeSessionId } from "@wrongstack/core/utils";
@@ -166,7 +154,7 @@ function hqRuntimeMarkerPath(dataDir) {
166
154
  function lanIPv4Addresses() {
167
155
  const out = [];
168
156
  try {
169
- const ifaces = os2.networkInterfaces();
157
+ const ifaces = os.networkInterfaces();
170
158
  for (const name of Object.keys(ifaces)) {
171
159
  for (const ni of ifaces[name] ?? []) {
172
160
  if (ni.family === "IPv4" && !ni.internal) out.push(ni.address);
@@ -212,8 +200,19 @@ function recordTimeseriesSignal(persistence, event) {
212
200
  }
213
201
  }
214
202
 
203
+ // src/hq-server/audit-actor.ts
204
+ import * as os2 from "node:os";
205
+ function resolveAuditActor() {
206
+ const user = (process.env.USERNAME ?? process.env.USER ?? "").toString();
207
+ try {
208
+ const host = os2.hostname();
209
+ return user ? `${user}@${host}` : `cli@${host}`;
210
+ } catch {
211
+ return user ? `${user}@unknown` : "cli";
212
+ }
213
+ }
214
+
215
215
  export {
216
- resolveAuditActor,
217
216
  TRANSCRIPT_RING_MAX,
218
217
  MAX_TRANSCRIPT_SESSIONS,
219
218
  MAX_AGENT_RINGS,
@@ -234,6 +233,7 @@ export {
234
233
  truncateHqSummary,
235
234
  hqMachineKey,
236
235
  recordTimeseriesSignal,
237
- sanitizeApiError
236
+ sanitizeApiError,
237
+ resolveAuditActor
238
238
  };
239
- //# sourceMappingURL=chunk-3EXRPTAU.js.map
239
+ //# sourceMappingURL=chunk-5TQ65PXQ.js.map
@@ -3,40 +3,40 @@
3
3
  var loaders = {
4
4
  automation: async () => (await import("./automation-O7ZRZSFS.js")).automationCmd,
5
5
  sandbox: async () => (await import("./sandbox-EZQ76MNY.js")).sandboxCmd,
6
- acp: async () => (await import("./acp-HCGUTFNE.js")).acpCmd,
6
+ acp: async () => (await import("./acp-NKUEYJDZ.js")).acpCmd,
7
7
  init: async () => (await import("./init-5PLABNLR.js")).initCmd,
8
- auth: async () => (await import("./auth-ANOVZVHE.js")).authCmd,
8
+ auth: async () => (await import("./auth-2ZG5DBHS.js")).authCmd,
9
9
  update: async () => (await import("./update-54W7GUS5.js")).updateCmd,
10
10
  remote: async () => (await import("./remote-AKKRJEHK.js")).remoteCmd,
11
- sessions: async () => (await import("./sessions-config-SJVQXCIE.js")).sessionsCmd,
12
- config: async () => (await import("./sessions-config-SJVQXCIE.js")).configCmd,
13
- "config-export": async () => (await import("./config-transfer-Y7XJMJRN.js")).configExportCmd,
14
- "config-import": async () => (await import("./config-transfer-Y7XJMJRN.js")).configImportCmd,
11
+ sessions: async () => (await import("./sessions-config-7MK742OW.js")).sessionsCmd,
12
+ config: async () => (await import("./sessions-config-7MK742OW.js")).configCmd,
13
+ "config-export": async () => (await import("./config-transfer-B4GOZTFC.js")).configExportCmd,
14
+ "config-import": async () => (await import("./config-transfer-B4GOZTFC.js")).configImportCmd,
15
15
  rewind: async () => (await import("./rewind-GAUXWSTU.js")).rewindCmd,
16
16
  replay: async () => (await import("./replay-URJFMQCU.js")).replayCmd,
17
17
  audit: async () => (await import("./audit-NH7NUKBV.js")).auditCmd,
18
- tools: async () => (await import("./tools-skills-55QVTMSK.js")).toolsCmd,
19
- skills: async () => (await import("./tools-skills-55QVTMSK.js")).skillsCmd,
18
+ tools: async () => (await import("./tools-skills-WDTMCE46.js")).toolsCmd,
19
+ skills: async () => (await import("./tools-skills-WDTMCE46.js")).skillsCmd,
20
20
  "skill-suggest": async () => (await import("./skill-suggest-LZV2TIPQ.js")).skillSuggestCmd,
21
- typesafe: async () => (await import("./typesafe-YBEADNAH.js")).typesafeCmd,
21
+ typesafe: async () => (await import("./typesafe-QLSMFU7J.js")).typesafeCmd,
22
22
  providers: async () => (await import("./providers-models-CDI5GVBX.js")).providersCmd,
23
23
  models: async () => (await import("./providers-models-CDI5GVBX.js")).modelsCmd,
24
- mcp: async () => (await import("./mcp-2XWBJEQN.js")).mcpCmd,
25
- plugin: async () => (await import("./plugin-usage-TYF5HY4K.js")).pluginCmd,
26
- plugins: async () => (await import("./plugin-usage-TYF5HY4K.js")).pluginCmd,
24
+ mcp: async () => (await import("./mcp-22CFBX4H.js")).mcpCmd,
25
+ plugin: async () => (await import("./plugin-usage-UWKYMNQU.js")).pluginCmd,
26
+ plugins: async () => (await import("./plugin-usage-UWKYMNQU.js")).pluginCmd,
27
27
  diag: async () => (await import("./diag-doctor-5SVYK2DR.js")).diagCmd,
28
28
  doctor: async () => (await import("./diag-doctor-5SVYK2DR.js")).doctorCmd,
29
29
  "proxy-status": async () => (await import("./diag-doctor-5SVYK2DR.js")).proxyCmd,
30
30
  export: async () => (await import("./export-W27PTU6Y.js")).exportCmd,
31
- usage: async () => (await import("./plugin-usage-TYF5HY4K.js")).usageCmd,
32
- version: async () => (await import("./version-help-RBZC5GZZ.js")).versionCmd,
33
- help: async () => (await import("./version-help-RBZC5GZZ.js")).helpCmd,
31
+ usage: async () => (await import("./plugin-usage-UWKYMNQU.js")).usageCmd,
32
+ version: async () => (await import("./version-help-X6CC4CFY.js")).versionCmd,
33
+ help: async () => (await import("./version-help-X6CC4CFY.js")).helpCmd,
34
34
  projects: async () => (await import("./projects-FWRJHW3S.js")).projectsCmd,
35
- modeldiag: async () => (await import("./modeldiag-HDIKG37X.js")).modeldiagCmd,
35
+ modeldiag: async () => (await import("./modeldiag-5PBB777J.js")).modeldiagCmd,
36
36
  quick: async () => (await import("./quick-NPC3N3ZX.js")).quickCmd,
37
37
  bench: async () => (await import("./bench-NDYES33Y.js")).benchCmd,
38
38
  chronicle: async () => (await import("./chronicle-WBK3TJRB.js")).chronicleCmd,
39
- hq: async () => (await import("./hq-JD5AZVMG.js")).hqCmd,
39
+ hq: async () => (await import("./hq-54PQYR5O.js")).hqCmd,
40
40
  mailbox: async () => (await import("./mailbox-serve-MMQCHOHI.js")).mailboxServeCmd,
41
41
  permissions: async () => (await import("./permissions-6YJ64W65.js")).permissionsCmd,
42
42
  project: async () => (await import("./project-V5KNTLV4.js")).projectCmd,
@@ -58,4 +58,4 @@ export {
58
58
  subcommands,
59
59
  subcommandNames
60
60
  };
61
- //# sourceMappingURL=chunk-GRAGMA4B.js.map
61
+ //# sourceMappingURL=chunk-7BM4LGKQ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  backupCurrent
3
- } from "./chunk-BIGSVBPI.js";
3
+ } from "./chunk-KNYIEQAY.js";
4
4
 
5
5
  // src/wiring/external-plugins.ts
6
6
  import { isAbsolute, join, resolve } from "node:path";
@@ -345,7 +345,7 @@ import {
345
345
  resolvePluginTarget as resolvePluginTarget2,
346
346
  unpinPluginTrust
347
347
  } from "@wrongstack/core/plugin";
348
- import { atomicWrite } from "@wrongstack/core/utils";
348
+ import { atomicWrite as atomicWrite2 } from "@wrongstack/core/utils";
349
349
  import {
350
350
  PLUGIN_AUDIT_ENTRIES
351
351
  } from "@wrongstack/plugins/plugin-audit-catalog";
@@ -420,6 +420,139 @@ function isRecord(value) {
420
420
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
421
421
  }
422
422
 
423
+ // src/plugin-llm-command.ts
424
+ import { atomicWrite } from "@wrongstack/core/utils";
425
+ var PLUGIN_LLM_USAGE = [
426
+ "Usage:",
427
+ " wstack plugin llm List every per-plugin LLM override.",
428
+ " wstack plugin llm <plugin> Show one plugin's LLM override.",
429
+ " wstack plugin llm <plugin> <provider> [model] Route this plugin through a provider (and model).",
430
+ " wstack plugin llm <plugin> - <model> Keep the session provider, override only the model.",
431
+ " wstack plugin llm <plugin> --clear Remove the override (back to the session default).",
432
+ "",
433
+ "The override is stored as config.extensions.<plugin>.llm and is used by",
434
+ "every api.llm call the plugin makes. Without an override, plugins follow",
435
+ "the active session provider/model (the chat leader)."
436
+ ].join("\n");
437
+ function renderPluginLlmOverviews(config, sessionDefault) {
438
+ const rows = [];
439
+ for (const [pluginName2, ext] of Object.entries(config.extensions ?? {})) {
440
+ const llm = ext?.["llm"];
441
+ if (llm && typeof llm === "object") {
442
+ const o = llm;
443
+ rows.push({
444
+ name: pluginName2,
445
+ provider: o.provider ?? "(session)",
446
+ model: o.model ?? "(session)"
447
+ });
448
+ }
449
+ }
450
+ const lines = [`Per-plugin LLM routing (session default: ${sessionDefault}):`];
451
+ if (rows.length === 0) {
452
+ lines.push(
453
+ " No plugin overrides \u2014 every plugin follows the session default.",
454
+ " Set one with: wstack plugin llm <plugin> <provider> [model]"
455
+ );
456
+ } else {
457
+ rows.sort((a, b) => a.name.localeCompare(b.name));
458
+ for (const r of rows) {
459
+ lines.push(` ${r.name.padEnd(24)} provider=${r.provider.padEnd(16)} model=${r.model}`);
460
+ }
461
+ lines.push("", "Clear one with: wstack plugin llm <plugin> --clear");
462
+ }
463
+ return lines.join("\n");
464
+ }
465
+ async function runPluginLlmCommand(args, deps) {
466
+ const sessionDefault = `${deps.config.provider ?? "?"} / ${deps.config.model ?? "?"}`;
467
+ if (args.length === 0 || args[0] === "list") {
468
+ return {
469
+ code: 0,
470
+ level: "output",
471
+ message: renderPluginLlmOverviews(deps.config, sessionDefault)
472
+ };
473
+ }
474
+ const name = args[0];
475
+ if (!name || name.startsWith("-")) return errorResult(PLUGIN_LLM_USAGE);
476
+ const currentOverride = deps.config.extensions?.[name]?.["llm"];
477
+ if (args.length === 1) {
478
+ const lines = [`LLM routing for plugin "${name}":`];
479
+ if (currentOverride && typeof currentOverride === "object") {
480
+ const o = currentOverride;
481
+ lines.push(
482
+ ` override: provider=${o.provider ?? "(session)"} model=${o.model ?? "(session)"}`,
483
+ ` session default: ${sessionDefault}`
484
+ );
485
+ } else {
486
+ lines.push(
487
+ ` no override \u2014 follows the session default (${sessionDefault}).`,
488
+ ` Set one with: wstack plugin llm ${name} <provider> [model]`
489
+ );
490
+ }
491
+ return { code: 0, level: "output", message: lines.join("\n") };
492
+ }
493
+ const existing = await readConfig(deps.configPath);
494
+ const fileExtensions = isRecord(existing.extensions) ? existing.extensions : {};
495
+ const pluginExt = isRecord(fileExtensions[name]) ? { ...fileExtensions[name] } : {};
496
+ if (args[1] === "--clear" || args[1] === "clear") {
497
+ if (!("llm" in pluginExt) && !currentOverride) {
498
+ return { code: 0, level: "info", message: `Plugin "${name}" has no LLM override.` };
499
+ }
500
+ delete pluginExt["llm"];
501
+ if (Object.keys(pluginExt).length === 0) delete fileExtensions[name];
502
+ else fileExtensions[name] = pluginExt;
503
+ existing.extensions = fileExtensions;
504
+ await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
505
+ const merged2 = mergeExtensionsForPatch(deps.config, fileExtensions);
506
+ const mergedEntry = merged2[name];
507
+ if (mergedEntry) {
508
+ delete mergedEntry["llm"];
509
+ if (Object.keys(mergedEntry).length === 0) delete merged2[name];
510
+ }
511
+ return {
512
+ code: 0,
513
+ level: "info",
514
+ message: `Cleared LLM override for "${name}" \u2014 it now follows the session default (${sessionDefault}). Takes effect immediately for api.llm calls.`,
515
+ patch: { extensions: merged2 }
516
+ };
517
+ }
518
+ const providerArg = args[1];
519
+ const modelArg = args[2];
520
+ if (!providerArg || providerArg.startsWith("--")) return errorResult(PLUGIN_LLM_USAGE);
521
+ const provider = providerArg === "-" ? void 0 : providerArg;
522
+ const model = modelArg && modelArg !== "-" ? modelArg : void 0;
523
+ if (!provider && !model) return errorResult(PLUGIN_LLM_USAGE);
524
+ const llm = {};
525
+ if (provider) llm["provider"] = provider;
526
+ if (model) llm["model"] = model;
527
+ pluginExt["llm"] = llm;
528
+ fileExtensions[name] = pluginExt;
529
+ existing.extensions = fileExtensions;
530
+ await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
531
+ const configured = Object.keys(deps.config.providers ?? {});
532
+ const note = provider && configured.length > 0 && !configured.includes(provider) ? `
533
+ Note: "${provider}" is not in config.providers (configured: ${configured.join(", ")}). Catalog providers (anthropic, openai, \u2026) still resolve if credentials are available.` : "";
534
+ const merged = mergeExtensionsForPatch(deps.config, fileExtensions);
535
+ return {
536
+ code: 0,
537
+ level: "info",
538
+ message: `Plugin "${name}" now routes api.llm calls via provider=${provider ?? "(session)"} model=${model ?? "(session)"}. Session default stays ${sessionDefault}. Takes effect immediately for api.llm calls.${note}`,
539
+ patch: { extensions: merged }
540
+ };
541
+ }
542
+ function mergeExtensionsForPatch(config, fileExtensions) {
543
+ const merged = {};
544
+ for (const [k, v] of Object.entries(config.extensions ?? {})) {
545
+ merged[k] = { ...v };
546
+ }
547
+ for (const [k, v] of Object.entries(fileExtensions)) {
548
+ if (isRecord(v)) merged[k] = { ...merged[k] ?? {}, ...v };
549
+ }
550
+ for (const k of Object.keys(merged)) {
551
+ if (!(k in fileExtensions) && !(k in (config.extensions ?? {}))) delete merged[k];
552
+ }
553
+ return merged;
554
+ }
555
+
423
556
  // src/plugin-package-install.ts
424
557
  import { execFile } from "node:child_process";
425
558
  import * as fs2 from "node:fs/promises";
@@ -710,7 +843,7 @@ ${locked.map((name2) => ` ${name2}`).join("\n")}`
710
843
  const next = action === "lock" ? current.some((entry) => canonicalPolicyName(entry) === canonical) ? current : [...current, name] : current.filter((entry) => canonicalPolicyName(entry) !== canonical);
711
844
  const pluginManager = { locked: next };
712
845
  existing.pluginManager = { ...filePolicy ?? {}, ...pluginManager };
713
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
846
+ await atomicWrite2(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
714
847
  return {
715
848
  code: 0,
716
849
  level: "info",
@@ -722,136 +855,6 @@ function canonicalPolicyName(name) {
722
855
  if (name === "*") return name;
723
856
  return resolvePluginToggleSpecifier(name).trim().toLowerCase();
724
857
  }
725
- var PLUGIN_LLM_USAGE = [
726
- "Usage:",
727
- " wstack plugin llm List every per-plugin LLM override.",
728
- " wstack plugin llm <plugin> Show one plugin's LLM override.",
729
- " wstack plugin llm <plugin> <provider> [model] Route this plugin through a provider (and model).",
730
- " wstack plugin llm <plugin> - <model> Keep the session provider, override only the model.",
731
- " wstack plugin llm <plugin> --clear Remove the override (back to the session default).",
732
- "",
733
- "The override is stored as config.extensions.<plugin>.llm and is used by",
734
- "every api.llm call the plugin makes. Without an override, plugins follow",
735
- "the active session provider/model (the chat leader)."
736
- ].join("\n");
737
- function renderPluginLlmOverviews(config, sessionDefault) {
738
- const rows = [];
739
- for (const [pluginName2, ext] of Object.entries(config.extensions ?? {})) {
740
- const llm = ext?.["llm"];
741
- if (llm && typeof llm === "object") {
742
- const o = llm;
743
- rows.push({
744
- name: pluginName2,
745
- provider: o.provider ?? "(session)",
746
- model: o.model ?? "(session)"
747
- });
748
- }
749
- }
750
- const lines = [`Per-plugin LLM routing (session default: ${sessionDefault}):`];
751
- if (rows.length === 0) {
752
- lines.push(
753
- " No plugin overrides \u2014 every plugin follows the session default.",
754
- " Set one with: wstack plugin llm <plugin> <provider> [model]"
755
- );
756
- } else {
757
- rows.sort((a, b) => a.name.localeCompare(b.name));
758
- for (const r of rows) {
759
- lines.push(` ${r.name.padEnd(24)} provider=${r.provider.padEnd(16)} model=${r.model}`);
760
- }
761
- lines.push("", "Clear one with: wstack plugin llm <plugin> --clear");
762
- }
763
- return lines.join("\n");
764
- }
765
- async function runPluginLlmCommand(args, deps) {
766
- const sessionDefault = `${deps.config.provider ?? "?"} / ${deps.config.model ?? "?"}`;
767
- if (args.length === 0 || args[0] === "list") {
768
- return {
769
- code: 0,
770
- level: "output",
771
- message: renderPluginLlmOverviews(deps.config, sessionDefault)
772
- };
773
- }
774
- const name = args[0];
775
- if (!name || name.startsWith("-")) return errorResult(PLUGIN_LLM_USAGE);
776
- const currentOverride = deps.config.extensions?.[name]?.["llm"];
777
- if (args.length === 1) {
778
- const lines = [`LLM routing for plugin "${name}":`];
779
- if (currentOverride && typeof currentOverride === "object") {
780
- const o = currentOverride;
781
- lines.push(
782
- ` override: provider=${o.provider ?? "(session)"} model=${o.model ?? "(session)"}`,
783
- ` session default: ${sessionDefault}`
784
- );
785
- } else {
786
- lines.push(
787
- ` no override \u2014 follows the session default (${sessionDefault}).`,
788
- ` Set one with: wstack plugin llm ${name} <provider> [model]`
789
- );
790
- }
791
- return { code: 0, level: "output", message: lines.join("\n") };
792
- }
793
- const existing = await readConfig(deps.configPath);
794
- const fileExtensions = isRecord(existing.extensions) ? existing.extensions : {};
795
- const pluginExt = isRecord(fileExtensions[name]) ? { ...fileExtensions[name] } : {};
796
- if (args[1] === "--clear" || args[1] === "clear") {
797
- if (!("llm" in pluginExt) && !currentOverride) {
798
- return { code: 0, level: "info", message: `Plugin "${name}" has no LLM override.` };
799
- }
800
- delete pluginExt["llm"];
801
- if (Object.keys(pluginExt).length === 0) delete fileExtensions[name];
802
- else fileExtensions[name] = pluginExt;
803
- existing.extensions = fileExtensions;
804
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
805
- const merged2 = mergeExtensionsForPatch(deps.config, fileExtensions);
806
- const mergedEntry = merged2[name];
807
- if (mergedEntry) {
808
- delete mergedEntry["llm"];
809
- if (Object.keys(mergedEntry).length === 0) delete merged2[name];
810
- }
811
- return {
812
- code: 0,
813
- level: "info",
814
- message: `Cleared LLM override for "${name}" \u2014 it now follows the session default (${sessionDefault}). Takes effect immediately for api.llm calls.`,
815
- patch: { extensions: merged2 }
816
- };
817
- }
818
- const providerArg = args[1];
819
- const modelArg = args[2];
820
- if (!providerArg || providerArg.startsWith("--")) return errorResult(PLUGIN_LLM_USAGE);
821
- const provider = providerArg === "-" ? void 0 : providerArg;
822
- const model = modelArg && modelArg !== "-" ? modelArg : void 0;
823
- if (!provider && !model) return errorResult(PLUGIN_LLM_USAGE);
824
- const llm = {};
825
- if (provider) llm["provider"] = provider;
826
- if (model) llm["model"] = model;
827
- pluginExt["llm"] = llm;
828
- fileExtensions[name] = pluginExt;
829
- existing.extensions = fileExtensions;
830
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
831
- const configured = Object.keys(deps.config.providers ?? {});
832
- const note = provider && configured.length > 0 && !configured.includes(provider) ? `
833
- Note: "${provider}" is not in config.providers (configured: ${configured.join(", ")}). Catalog providers (anthropic, openai, \u2026) still resolve if credentials are available.` : "";
834
- const merged = mergeExtensionsForPatch(deps.config, fileExtensions);
835
- return {
836
- code: 0,
837
- level: "info",
838
- message: `Plugin "${name}" now routes api.llm calls via provider=${provider ?? "(session)"} model=${model ?? "(session)"}. Session default stays ${sessionDefault}. Takes effect immediately for api.llm calls.${note}`,
839
- patch: { extensions: merged }
840
- };
841
- }
842
- function mergeExtensionsForPatch(config, fileExtensions) {
843
- const merged = {};
844
- for (const [k, v] of Object.entries(config.extensions ?? {})) {
845
- merged[k] = { ...v };
846
- }
847
- for (const [k, v] of Object.entries(fileExtensions)) {
848
- if (isRecord(v)) merged[k] = { ...merged[k] ?? {}, ...v };
849
- }
850
- for (const k of Object.keys(merged)) {
851
- if (!(k in fileExtensions) && !(k in (config.extensions ?? {}))) delete merged[k];
852
- }
853
- return merged;
854
- }
855
858
  function resolvePluginSpecifier(input) {
856
859
  return OFFICIAL_ALIASES.get(input.toLowerCase()) ?? input;
857
860
  }
@@ -1014,7 +1017,7 @@ async function togglePlugin(spec, deps) {
1014
1017
  };
1015
1018
  existing.plugins = nextPlugins;
1016
1019
  existing.features = features;
1017
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1020
+ await atomicWrite2(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1018
1021
  const restartRequired = spec === "branch-guard" && !nextEnabled ? void 0 : true;
1019
1022
  return {
1020
1023
  code: 0,
@@ -1032,7 +1035,7 @@ async function removePlugin(spec, deps) {
1032
1035
  return errorResult(`Plugin "${spec}" not in config.`);
1033
1036
  }
1034
1037
  existing.plugins = next;
1035
- await atomicWrite(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1038
+ await atomicWrite2(deps.configPath, JSON.stringify(existing, null, 2), { mode: 384 });
1036
1039
  return {
1037
1040
  code: 0,
1038
1041
  level: "info",
@@ -1136,4 +1139,4 @@ export {
1136
1139
  PLUGIN_AUDIT_ENTRIES,
1137
1140
  runPluginManagementCommand
1138
1141
  };
1139
- //# sourceMappingURL=chunk-VAQXOZKP.js.map
1142
+ //# sourceMappingURL=chunk-AJM4EFCM.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  appendHistory,
3
3
  backupCurrent
4
- } from "./chunk-BIGSVBPI.js";
4
+ } from "./chunk-KNYIEQAY.js";
5
5
 
6
6
  // src/settings-menu.ts
7
7
  import * as fs from "node:fs/promises";
@@ -246,4 +246,4 @@ export {
246
246
  persistTelegramConfig,
247
247
  deriveFsAccessPair
248
248
  };
249
- //# sourceMappingURL=chunk-C2BBH4S4.js.map
249
+ //# sourceMappingURL=chunk-E3MJFAFR.js.map
@@ -147,64 +147,6 @@ function renderPayloadPreview(input) {
147
147
  return typeof diff === "string" && diff ? clipPreview(diff, diffLineStyle) : "";
148
148
  }
149
149
 
150
- // src/boot/restricted-mode.ts
151
- import { lockToProjectRoot, lockYoloOff, ToolCapabilities } from "@wrongstack/core/security";
152
- var RESTRICTED_ENV = "WRONGSTACK_RESTRICTED";
153
- var RESTRICTED_DENY_CAPABILITIES = [
154
- ToolCapabilities.SHELL_ARBITRARY,
155
- ToolCapabilities.SHELL_RESTRICTED,
156
- ToolCapabilities.SHELL_EXEC,
157
- ToolCapabilities.NET_OUTBOUND,
158
- ToolCapabilities.PACKAGE_INSTALL,
159
- ToolCapabilities.CONFIG_MUTATE,
160
- ToolCapabilities.FS_WRITE_OUTSIDE_PROJECT,
161
- ToolCapabilities.TOOL_MUTATE_ANY,
162
- ToolCapabilities.MCP_PROXY
163
- ];
164
- var CONFLICTING_FLAGS = [
165
- "yolo",
166
- "yolo-plus",
167
- "yolo-destructive",
168
- "full-auto",
169
- "mcp-config",
170
- // Pre-approving a tool would let writes skip the prompt this mode promises.
171
- "allowed-tools"
172
- ];
173
- function isRestrictedMode(flags) {
174
- return flags["restricted"] === true || process.env[RESTRICTED_ENV] === "1";
175
- }
176
- function validateRestrictedMode(flags) {
177
- if (!isRestrictedMode(flags)) return false;
178
- const conflict = CONFLICTING_FLAGS.find(
179
- (name) => flags[name] !== void 0 && flags[name] !== false
180
- );
181
- if (conflict) throw new Error(`--${conflict} cannot be combined with --restricted`);
182
- return true;
183
- }
184
- function withRestrictedTools(restriction, restricted) {
185
- if (!restricted) return restriction;
186
- return {
187
- ...restriction?.only ? { only: restriction.only } : {},
188
- deny: [...restriction?.deny ?? [], "mcp__*"],
189
- denyCapabilities: RESTRICTED_DENY_CAPABILITIES,
190
- requireDeclaredCapabilities: true
191
- };
192
- }
193
- var RESTRICTED_NOTICE = "Restricted mode: no shell, network, installs or MCP tools; files stay inside the project; YOLO is off.";
194
- var announced = false;
195
- function activateRestrictedMode(flags, write) {
196
- if (!validateRestrictedMode(flags)) return false;
197
- lockToProjectRoot();
198
- lockYoloOff();
199
- process.env[RESTRICTED_ENV] = "1";
200
- if (!announced) {
201
- announced = true;
202
- write(`${RESTRICTED_NOTICE}
203
- `);
204
- }
205
- return true;
206
- }
207
-
208
150
  // src/boot/safe-mode.ts
209
151
  var SAFE_MODE_ENV = "WRONGSTACK_SAFE_MODE";
210
152
  function isSafeMode(flags) {
@@ -216,11 +158,11 @@ function propagateSafeMode(flags) {
216
158
  return on;
217
159
  }
218
160
  var SAFE_MODE_NOTICE = "Safe mode: third-party plugins, hooks, configured MCP servers, skills and instruction overrides are off.";
219
- var announced2 = false;
161
+ var announced = false;
220
162
  function announceSafeMode(flags, write) {
221
163
  const on = propagateSafeMode(flags);
222
- if (on && !announced2) {
223
- announced2 = true;
164
+ if (on && !announced) {
165
+ announced = true;
224
166
  write(`${SAFE_MODE_NOTICE}
225
167
  `);
226
168
  }
@@ -597,9 +539,6 @@ export {
597
539
  resolveLaunchAllowedTools,
598
540
  resolveToolRestriction,
599
541
  unknownRestrictedToolNames,
600
- isRestrictedMode,
601
- withRestrictedTools,
602
- activateRestrictedMode,
603
542
  isSafeMode,
604
543
  announceSafeMode,
605
544
  isSimpleUiFullAuto,
@@ -608,4 +547,4 @@ export {
608
547
  detectProjectFacts,
609
548
  renderAgentsTemplate
610
549
  };
611
- //# sourceMappingURL=chunk-5TRZZHMN.js.map
550
+ //# sourceMappingURL=chunk-JCZ2D3VV.js.map