@wrongstack/cli 0.306.4 → 0.307.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/{auth-L3WGSGDX.js → auth-TVOOHL4Q.js} +45 -106
  2. package/dist/boot/short-circuit-flags.d.ts +2 -2
  3. package/dist/chimera-cascade-evidence.d.ts +1 -1
  4. package/dist/chunk-2VMJ3E5Z.js +71 -0
  5. package/dist/{chunk-RHLQT3EV.js → chunk-CB35UVXO.js} +1636 -1528
  6. package/dist/{chunk-YKBRFSGL.js → chunk-DOJLAULS.js} +28 -28
  7. package/dist/{chunk-KXN5HZDL.js → chunk-PKHGLWUJ.js} +24 -6
  8. package/dist/{chunk-HITHEXE3.js → chunk-TOG7OMKJ.js} +2 -2
  9. package/dist/{chunk-ARWGQUB3.js → chunk-XSG33WHN.js} +15 -5
  10. package/dist/{cli-main-4TZCCZR6.js → cli-main-YDOZZOZA.js} +21606 -20849
  11. package/dist/cli-main.d.ts +0 -20
  12. package/dist/{execution-547PM3NI.js → execution-CGT6J5ZN.js} +304 -272
  13. package/dist/fleet/host-learning-scheduler.d.ts +27 -0
  14. package/dist/fleet/host-shadow-manager.d.ts +64 -0
  15. package/dist/fleet/host.d.ts +5 -140
  16. package/dist/{hq-ZK6PGN3W.js → hq-PA6RH2UW.js} +2 -2
  17. package/dist/hq-server/mailbox-gateway-manager.d.ts +32 -0
  18. package/dist/hq-server/routes/auth/bootstrap-routes.d.ts +5 -0
  19. package/dist/hq-server/routes/auth/common.d.ts +11 -0
  20. package/dist/hq-server/routes/auth/password-routes.d.ts +9 -0
  21. package/dist/hq-server/routes/auth/session-audit-routes.d.ts +6 -0
  22. package/dist/hq-server/routes/auth/totp-routes.d.ts +9 -0
  23. package/dist/hq-server/routes/auth-handlers.d.ts +5 -132
  24. package/dist/hq-server/routes/command-handlers.d.ts +7 -0
  25. package/dist/hq-server/routes/data-handlers.d.ts +8 -0
  26. package/dist/hq-server/routes/mailbox-handlers.d.ts +22 -0
  27. package/dist/hq-server/routes.d.ts +3 -3
  28. package/dist/hq-server/server-lifecycle.d.ts +37 -0
  29. package/dist/hq-server/snapshot.d.ts +6 -5
  30. package/dist/hq-server/types.d.ts +4 -0
  31. package/dist/hq-server/upgrade-handler.d.ts +34 -0
  32. package/dist/hq-server/ws-client-events.d.ts +25 -0
  33. package/dist/hq-server/ws-leader.d.ts +47 -0
  34. package/dist/hq-server/ws-resume.d.ts +27 -0
  35. package/dist/hq-server/ws.d.ts +4 -71
  36. package/dist/{hq-server-IVZLVCFV.js → hq-server-PBRU275L.js} +2 -2
  37. package/dist/hq-server.d.ts +0 -38
  38. package/dist/index.js +1267 -122
  39. package/dist/{mcp-W7HHN7IA.js → mcp-CMLFHRG2.js} +14 -7
  40. package/dist/mcp-serve.d.ts +12 -1
  41. package/dist/{modeldiag-6VS5KDP5.js → modeldiag-ICMPHT5L.js} +868 -831
  42. package/dist/{providers-models-HQN3AT3K.js → providers-models-4FAKM2WO.js} +4 -4
  43. package/dist/repl-eternal-loop.d.ts +8 -0
  44. package/dist/repl-goal-banner.d.ts +21 -0
  45. package/dist/slash-commands/brain-council.d.ts +36 -0
  46. package/dist/slash-commands/brain-status.d.ts +12 -0
  47. package/dist/slash-commands/kanban-board-handlers.d.ts +13 -0
  48. package/dist/slash-commands/kanban-lifecycle-diagnostics.d.ts +16 -0
  49. package/dist/slash-commands/kanban-task-subcommands.d.ts +8 -0
  50. package/dist/slash-commands/memory-audience.d.ts +14 -0
  51. package/dist/slash-commands/memory-gather.d.ts +9 -0
  52. package/dist/slash-commands/memory-stats.d.ts +5 -0
  53. package/dist/slash-commands/settings-mutations.d.ts +6 -0
  54. package/dist/slash-commands/settings-view.d.ts +5 -0
  55. package/dist/subcommands/handlers/modeldiag-bench.d.ts +10 -0
  56. package/dist/subcommands/handlers/modeldiag-eval.d.ts +27 -0
  57. package/dist/subcommands/handlers/modeldiag-test.d.ts +8 -0
  58. package/dist/{version-help-ASKQYXDJ.js → version-help-TFD6VPF3.js} +2 -2
  59. package/dist/vibe-protocol-wiring.d.ts +10 -0
  60. package/dist/webui-server/credential-watcher.d.ts +15 -0
  61. package/dist/webui-server/domain-handlers.d.ts +21 -0
  62. package/dist/webui-server/route-contexts.d.ts +41 -0
  63. package/dist/{webui-server-FTG7JAZU.js → webui-server-IPHGJGXE.js} +515 -437
  64. package/dist/wiring/cli-execute-builder.d.ts +88 -0
  65. package/dist/wiring/cli-heap-watchdog.d.ts +33 -0
  66. package/dist/wiring/cli-prompt-and-tools-setup.d.ts +25 -0
  67. package/dist/wiring/cli-slash-commands-setup.d.ts +79 -0
  68. package/dist/wiring/heap-watchdog-setup.d.ts +53 -0
  69. package/dist/wiring/metrics.d.ts +1 -0
  70. package/dist/wiring/replay-governance-setup.d.ts +31 -0
  71. package/package.json +27 -27
package/dist/index.js CHANGED
@@ -6,25 +6,18 @@ import {
6
6
  makePromptDelegate,
7
7
  renderAgentsTemplate,
8
8
  renderDiff
9
- } from "./chunk-YKBRFSGL.js";
9
+ } from "./chunk-DOJLAULS.js";
10
10
  import {
11
11
  theme
12
12
  } from "./chunk-QD544J2B.js";
13
- import {
14
- fmtTok,
15
- patchConfig
16
- } from "./chunk-TYO2OVAD.js";
17
13
  import {
18
14
  parseWebuiSessionChildOptions,
19
15
  writeWebuiSessionChildError
20
16
  } from "./chunk-3JPTNADJ.js";
21
17
  import {
22
- helpCmd,
23
- versionCmd
24
- } from "./chunk-ARWGQUB3.js";
25
- import {
26
- CLI_VERSION
27
- } from "./chunk-XJXDOF63.js";
18
+ fmtTok,
19
+ patchConfig
20
+ } from "./chunk-TYO2OVAD.js";
28
21
  import {
29
22
  discoverAndMergeProviders
30
23
  } from "./chunk-52C7PD2H.js";
@@ -35,28 +28,38 @@ import "./chunk-U3SS4NRH.js";
35
28
  import "./chunk-NUIHRGPY.js";
36
29
  import {
37
30
  DEFAULT_PORT
38
- } from "./chunk-RHLQT3EV.js";
31
+ } from "./chunk-CB35UVXO.js";
39
32
  import "./chunk-KE7E7DPX.js";
40
33
  import "./chunk-Q5GTM25S.js";
34
+ import {
35
+ helpCmd,
36
+ versionCmd
37
+ } from "./chunk-XSG33WHN.js";
38
+ import {
39
+ CLI_VERSION
40
+ } from "./chunk-XJXDOF63.js";
41
+ import {
42
+ renderAuthLocalHelpToString
43
+ } from "./chunk-2VMJ3E5Z.js";
41
44
  import {
42
45
  parseArgs,
43
46
  runPicker,
44
47
  saveToGlobalConfig
45
- } from "./chunk-KXN5HZDL.js";
48
+ } from "./chunk-PKHGLWUJ.js";
49
+ import "./chunk-B4JLSXZB.js";
46
50
  import {
47
51
  isKeylessLocalProvider,
48
52
  visibleModelIds
49
53
  } from "./chunk-VUVOMXWP.js";
54
+ import {
55
+ activeProfileConfigPath
56
+ } from "./chunk-YMXXOOFN.js";
50
57
  import {
51
58
  mutateConfigProviders,
52
59
  normalizeKeys,
53
60
  resolveActiveApiKey,
54
61
  writeKeysBack
55
62
  } from "./chunk-SZ42FYPT.js";
56
- import "./chunk-B4JLSXZB.js";
57
- import {
58
- activeProfileConfigPath
59
- } from "./chunk-YMXXOOFN.js";
60
63
  import "./chunk-7OCVIDC7.js";
61
64
 
62
65
  // src/cli-context.ts
@@ -714,11 +717,1126 @@ async function launchDesktop(args) {
714
717
  });
715
718
  }
716
719
 
720
+ // src/subcommands/handlers/per-subcommand-help.ts
721
+ import { color as color5 } from "@wrongstack/core/utils";
722
+
723
+ // src/subcommands/handlers/bench-run-help.ts
724
+ import { color as color3 } from "@wrongstack/core/utils";
725
+ var BENCH_RUN_FLAGS = [
726
+ // -- Suite selection ------------------------------------------------
727
+ {
728
+ name: "suite",
729
+ flag: "--suite <id>",
730
+ description: "Benchmark suite id (`polyglot` or `swebench`).",
731
+ group: "suite",
732
+ kind: "value",
733
+ defaultValue: "polyglot"
734
+ },
735
+ {
736
+ name: "polyglot-dir",
737
+ flag: "--polyglot-dir <path>",
738
+ description: "Path to the Aider polyglot dataset (required when --suite polyglot).",
739
+ group: "suite",
740
+ kind: "value",
741
+ required: true
742
+ },
743
+ {
744
+ name: "languages",
745
+ flag: "--languages <csv>",
746
+ description: "Comma-separated language list to filter the polyglot suite (e.g. `python,go`).",
747
+ group: "suite",
748
+ kind: "value"
749
+ },
750
+ {
751
+ name: "dataset-dir",
752
+ flag: "--dataset-dir <path>",
753
+ description: "Path to the SWE-bench Verified dataset (optional, defaults to the official cache).",
754
+ group: "suite",
755
+ kind: "value"
756
+ },
757
+ {
758
+ name: "docker",
759
+ flag: "--docker",
760
+ description: "Enable the SWE-bench Docker runtime (required for live grading).",
761
+ group: "suite",
762
+ kind: "boolean"
763
+ },
764
+ // -- Model matrix ---------------------------------------------------
765
+ {
766
+ name: "models",
767
+ flag: "--models <config>",
768
+ description: "Path to the model-cells config (JSON).",
769
+ group: "models",
770
+ kind: "value",
771
+ defaultValue: "bench.config.json"
772
+ },
773
+ // -- Run control ----------------------------------------------------
774
+ {
775
+ name: "limit",
776
+ flag: "--limit <N>",
777
+ description: "Cap the number of tasks per cell (useful for smoke tests).",
778
+ group: "control",
779
+ kind: "value"
780
+ },
781
+ {
782
+ name: "out",
783
+ flag: "--out <dir>",
784
+ description: "Base directory for run output (each run gets a timestamped subdir).",
785
+ group: "control",
786
+ kind: "value",
787
+ defaultValue: "bench-results"
788
+ },
789
+ {
790
+ name: "concurrency",
791
+ flag: "--concurrency <N>",
792
+ description: "Override the per-cell concurrency from the model config.",
793
+ group: "control",
794
+ kind: "value"
795
+ }
796
+ ];
797
+ var BENCH_RUN_BOOLEAN_FLAG_NAMES = BENCH_RUN_FLAGS.filter(
798
+ (f) => f.kind === "boolean"
799
+ ).map((f) => f.name);
800
+ var BENCH_RUN_VALUE_FLAG_NAMES = BENCH_RUN_FLAGS.filter(
801
+ (f) => f.kind === "value"
802
+ ).map((f) => f.name);
803
+ var BENCH_RUN_FLAG_COLUMN_WIDTH = 28;
804
+ function renderBenchRunHelpToString() {
805
+ const lines = [
806
+ color3.bold("wstack bench run \u2014 execute a benchmark suite across a model matrix"),
807
+ color3.dim(" Runs a benchmark suite (polyglot or swebench) across every model cell"),
808
+ color3.dim(" in the config. Output is a per-run directory with `report.md`, JSON"),
809
+ color3.dim(" artifacts, and (for swebench) per-cell predictions for the official"),
810
+ color3.dim(" harness."),
811
+ "",
812
+ color3.bold("Usage"),
813
+ ` ${buildUsageLine()}`,
814
+ "",
815
+ color3.bold("Flags"),
816
+ ...buildFlagBlock(),
817
+ "",
818
+ color3.dim(
819
+ "See also: wstack bench list (show available suites + cells); wstack bench report <dir>"
820
+ )
821
+ ];
822
+ return lines.join("\n") + "\n";
823
+ }
824
+ function buildUsageLine() {
825
+ const parts = ["wstack bench run"];
826
+ for (const f of BENCH_RUN_FLAGS) {
827
+ if (f.kind === "value") {
828
+ parts.push(`[${f.flag}]`);
829
+ } else {
830
+ parts.push(`[${f.flag}]`);
831
+ }
832
+ }
833
+ return parts.join(" ");
834
+ }
835
+ function buildFlagBlock() {
836
+ const rows = [];
837
+ let currentGroup;
838
+ for (const f of BENCH_RUN_FLAGS) {
839
+ if (f.group !== currentGroup) {
840
+ const header = f.group === "suite" ? "Suite selection:" : f.group === "models" ? "Model matrix:" : "Run control:";
841
+ rows.push(color3.dim(` ${header}`));
842
+ currentGroup = f.group;
843
+ }
844
+ const paddedFlag = f.flag.padEnd(BENCH_RUN_FLAG_COLUMN_WIDTH, " ");
845
+ let desc = f.description;
846
+ if (f.required) {
847
+ desc = desc + " " + color3.bold("(required)");
848
+ } else if (f.defaultValue !== void 0) {
849
+ desc = desc + " " + color3.dim(`(default: ${f.defaultValue})`);
850
+ }
851
+ rows.push(` ${paddedFlag} ${desc}`);
852
+ }
853
+ return rows;
854
+ }
855
+
856
+ // src/subcommands/handlers/models-add-help.ts
857
+ import { color as color4 } from "@wrongstack/core/utils";
858
+ var MODELS_ADD_FLAGS = [
859
+ // -- Identity --------------------------------------------------------
860
+ {
861
+ name: "provider",
862
+ flag: "--provider <id>",
863
+ description: "Provider id the model belongs to (defaults to the saved alias).",
864
+ group: "identity",
865
+ kind: "value"
866
+ },
867
+ {
868
+ name: "name",
869
+ flag: "--name <name>",
870
+ description: "Human-readable display name (defaults to <mid>).",
871
+ group: "identity",
872
+ kind: "value"
873
+ },
874
+ // -- Capabilities ---------------------------------------------------
875
+ {
876
+ name: "max-context",
877
+ flag: "--max-context <N>",
878
+ description: "Context window in tokens (e.g. 200000 for 200k, or `128k`).",
879
+ group: "capabilities",
880
+ kind: "value"
881
+ },
882
+ {
883
+ name: "max-output",
884
+ flag: "--max-output <N>",
885
+ description: "Max output tokens per request.",
886
+ group: "capabilities",
887
+ kind: "value"
888
+ },
889
+ {
890
+ name: "tools",
891
+ flag: "--tools / --no-tools",
892
+ description: "Toggle tool/function-calling support.",
893
+ group: "capabilities",
894
+ kind: "boolean"
895
+ },
896
+ {
897
+ name: "vision",
898
+ flag: "--vision / --no-vision",
899
+ description: "Toggle image-input support.",
900
+ group: "capabilities",
901
+ kind: "boolean"
902
+ },
903
+ {
904
+ name: "reasoning",
905
+ flag: "--reasoning / --no-reasoning",
906
+ description: "Mark the model as a reasoning model.",
907
+ group: "capabilities",
908
+ kind: "boolean"
909
+ },
910
+ {
911
+ name: "streaming",
912
+ flag: "--streaming / --no-streaming",
913
+ description: "Toggle streaming response support.",
914
+ group: "capabilities",
915
+ kind: "boolean"
916
+ },
917
+ {
918
+ name: "json-mode",
919
+ flag: "--json-mode",
920
+ description: "Mark the model as supporting native JSON output.",
921
+ group: "capabilities",
922
+ kind: "boolean"
923
+ }
924
+ ];
925
+ var MODELS_ADD_BOOLEAN_FLAG_NAMES = MODELS_ADD_FLAGS.filter(
926
+ (f) => f.kind === "boolean"
927
+ ).map((f) => f.name);
928
+ var MODELS_ADD_VALUE_FLAG_NAMES = MODELS_ADD_FLAGS.filter(
929
+ (f) => f.kind === "value"
930
+ ).map((f) => f.name);
931
+ var MODELS_ADD_FLAG_COLUMN_WIDTH = 30;
932
+ function renderModelsAddHelpToString() {
933
+ const lines = [
934
+ color4.bold("wstack models add <mid> \u2014 register a custom model"),
935
+ color4.dim(" Add or override a custom model (for self-hosted endpoints, fine-tuned"),
936
+ color4.dim(" weights, or models not in the public models.dev catalog). The flags are"),
937
+ color4.dim(" organized into two groups: identity (`--provider`, `--name`) and"),
938
+ color4.dim(" capabilities (`--max-context`, `--tools`, `--vision`, etc.)."),
939
+ "",
940
+ color4.bold("Usage"),
941
+ ` ${buildUsageLine2()}`,
942
+ "",
943
+ color4.bold("Flags"),
944
+ ...buildFlagBlock2(),
945
+ "",
946
+ color4.dim("See also: wstack models list (verify the entry); wstack models remove")
947
+ ];
948
+ return lines.join("\n") + "\n";
949
+ }
950
+ function buildUsageLine2() {
951
+ const parts = ["wstack models add <mid>"];
952
+ for (const f of MODELS_ADD_FLAGS) {
953
+ if (f.kind === "value") {
954
+ parts.push(`[${f.flag}]`);
955
+ } else {
956
+ parts.push(`[${f.flag}]`);
957
+ }
958
+ }
959
+ return parts.join(" ");
960
+ }
961
+ function buildFlagBlock2() {
962
+ const rows = [];
963
+ let currentGroup;
964
+ for (const f of MODELS_ADD_FLAGS) {
965
+ if (f.group !== currentGroup) {
966
+ const header = f.group === "identity" ? "Identity:" : "Capabilities:";
967
+ rows.push(color4.dim(` ${header}`));
968
+ currentGroup = f.group;
969
+ }
970
+ const paddedFlag = f.flag.padEnd(MODELS_ADD_FLAG_COLUMN_WIDTH, " ");
971
+ rows.push(` ${paddedFlag} ${f.description}`);
972
+ }
973
+ return rows;
974
+ }
975
+
976
+ // src/subcommands/handlers/per-subcommand-deep-help-table.ts
977
+ var deepHelpTable = {
978
+ // -- mcp -----------------------------------------------------------------
979
+ "mcp:add": {
980
+ name: "mcp:add",
981
+ title: "wstack mcp add <name> \u2014 register a built-in MCP server",
982
+ description: "Register a built-in MCP server by alias (e.g. `github`, `playwright`) and write the entry to the global config. The server is added in `disabled` state by default; pass `--enable` to register it active immediately.",
983
+ usage: "wstack mcp add <name> [--enable]",
984
+ subcommands: [
985
+ {
986
+ name: "<name>",
987
+ description: "The built-in server alias (run `wstack mcp add` for the list)."
988
+ },
989
+ {
990
+ name: "--enable / -e",
991
+ description: "Register the server enabled (default: disabled until you opt in)."
992
+ }
993
+ ],
994
+ seeAlso: "wstack mcp list (verify the entry landed); wstack mcp remove"
995
+ },
996
+ "mcp:remove": {
997
+ name: "mcp:remove",
998
+ title: "wstack mcp remove <name> \u2014 unregister an MCP server",
999
+ description: "Unregister an MCP server by alias. Removes the entry from the global config; the server process is not killed (REPL restart required to fully tear down the running process).",
1000
+ usage: "wstack mcp remove <name>",
1001
+ subcommands: [{ name: "<name>", description: "The server alias to unregister." }]
1002
+ },
1003
+ // -- plugin --------------------------------------------------------------
1004
+ "plugin:add": {
1005
+ name: "plugin:add",
1006
+ title: "wstack plugin add <spec> \u2014 install a tool plugin",
1007
+ description: "Add a tool plugin by specifier (npm package name) or official alias (`telegram`, `lsp`). Pass `--disabled` to install the plugin but leave it off until you explicitly enable it. The plugin requires a restart of the wrongstack process to take effect.",
1008
+ usage: "wstack plugin add <spec|alias> [--disabled]",
1009
+ subcommands: [
1010
+ {
1011
+ name: "<spec|alias>",
1012
+ description: "NPM specifier (e.g. `@org/wrongstack-x`) or official alias."
1013
+ },
1014
+ {
1015
+ name: "--disabled",
1016
+ description: "Install the plugin but leave it disabled until you enable it."
1017
+ }
1018
+ ],
1019
+ seeAlso: "wstack plugin official (list the official registry); wstack plugin enable"
1020
+ },
1021
+ "plugin:remove": {
1022
+ name: "plugin:remove",
1023
+ title: "wstack plugin remove <spec> \u2014 uninstall a tool plugin",
1024
+ description: "Remove a tool plugin from the config. The plugin requires a restart of the wrongstack process to take effect. Aliases: `rm`, `uninstall`.",
1025
+ usage: "wstack plugin remove <spec|alias>",
1026
+ subcommands: [
1027
+ { name: "<spec|alias>", description: "The specifier or official alias to remove." }
1028
+ ]
1029
+ },
1030
+ "plugin:enable": {
1031
+ name: "plugin:enable",
1032
+ title: "wstack plugin enable <spec> \u2014 re-enable a previously-disabled plugin",
1033
+ description: "Re-enable a plugin that was installed with `--disabled` or toggled off with `wstack plugin disable`. Requires a restart.",
1034
+ usage: "wstack plugin enable <spec|alias>",
1035
+ subcommands: [
1036
+ { name: "<spec|alias>", description: "The specifier or official alias to enable." }
1037
+ ]
1038
+ },
1039
+ "plugin:disable": {
1040
+ name: "plugin:disable",
1041
+ title: "wstack plugin disable <spec> \u2014 temporarily disable a plugin",
1042
+ description: "Temporarily disable a plugin without removing it from the config. Use `wstack plugin enable` to re-enable. Requires a restart.",
1043
+ usage: "wstack plugin disable <spec|alias>",
1044
+ subcommands: [
1045
+ { name: "<spec|alias>", description: "The specifier or official alias to disable." }
1046
+ ]
1047
+ },
1048
+ "plugin:toggle": {
1049
+ name: "plugin:toggle",
1050
+ title: "wstack plugin toggle <name> \u2014 toggle an audit-list plugin row",
1051
+ description: "Toggle one built-in audit-list plugin by its runtime name. Default-active plugins are disabled by writing `{ enabled: false }` overrides; enabling them again removes that override. All bundled audit-list rows are toggleable; future non-toggleable rows are reported as locked. Requires a restart for loaded plugin code to change in the current session.",
1052
+ usage: "wstack plugin toggle <name>",
1053
+ subcommands: [
1054
+ { name: "<name>", description: "Audit-list runtime name, e.g. `format-on-save`." }
1055
+ ],
1056
+ seeAlso: "wstack plugin report (see effective state and toggle policy)"
1057
+ },
1058
+ "plugin:report": {
1059
+ name: "plugin:report",
1060
+ title: "wstack plugin report \u2014 show the plugin audit table",
1061
+ description: "Print the built-in plugin audit table. Each row shows effective state, whether that state came from config or default boot behavior, risk, and the toggle policy for that row.",
1062
+ usage: "wstack plugin report (alias: wstack plugin audit)",
1063
+ seeAlso: "wstack plugin toggle <name> (toggle audit-list rows); wstack plugin list"
1064
+ },
1065
+ "plugin:menu": {
1066
+ name: "plugin:menu",
1067
+ title: "wstack plugin menu \u2014 open or describe the plugin picker",
1068
+ description: "In the TUI, `/plugin menu` opens the interactive plugin picker. From the non-interactive `wstack plugin menu` surface, the command prints the same audit report as `wstack plugin report`.",
1069
+ usage: "wstack plugin menu",
1070
+ seeAlso: "/plugin menu (interactive picker in the TUI); wstack plugin report"
1071
+ },
1072
+ // -- models --------------------------------------------------------------
1073
+ // The `models:add` deep entry delegates its body to
1074
+ // `models-add-help.ts` via the `customBody` field. The flag
1075
+ // list lives in exactly one place (`MODELS_ADD_FLAGS`), and
1076
+ // every surface that renders the help — `wstack models add --help`,
1077
+ // `/models add help`, `/help models add` — produces the same
1078
+ // string. The `title` / `description` / `usage` / `seeAlso`
1079
+ // fields below are required by the `PerSubcommandHelp` shape
1080
+ // but never rendered (the `customBody` thunk owns the full
1081
+ // layout). They're filled in with sensible defaults so a
1082
+ // future refactor that drops `customBody` (e.g. to use the
1083
+ // standard layout) still has a coherent fallback.
1084
+ "models:add": {
1085
+ name: "models:add",
1086
+ title: "wstack models add <mid> \u2014 register a custom model",
1087
+ description: "See renderModelsAddHelpToString() in models-add-help.ts for the full block.",
1088
+ usage: "wstack models add <mid> [...flags]",
1089
+ customBody: renderModelsAddHelpToString
1090
+ },
1091
+ "models:remove": {
1092
+ name: "models:remove",
1093
+ title: "wstack models remove <mid> \u2014 unregister a custom model",
1094
+ description: "Remove a custom model from the config. The catalog is unaffected (catalog models are managed by `wstack models refresh`).",
1095
+ usage: "wstack models remove <mid>",
1096
+ subcommands: [{ name: "<mid>", description: "The model id to remove." }]
1097
+ },
1098
+ // -- audit / replay (--list deep-subcommand) ---------------------------
1099
+ "audit:list": {
1100
+ name: "audit:list",
1101
+ title: "wstack audit --list \u2014 list every session with an audit log",
1102
+ description: "Scan the project sessions dir for `.audit.jsonl` sidecars and print a one-line summary per session (entry count + chain status). Useful for finding a session to inspect with `wstack audit <id>`.",
1103
+ usage: "wstack audit --list / wstack audit -l",
1104
+ seeAlso: "wstack audit <id> (inspect a single session's chain)"
1105
+ },
1106
+ "replay:list": {
1107
+ name: "replay:list",
1108
+ title: "wstack replay --list \u2014 list every session with a replay log",
1109
+ description: "Scan the project sessions dir for `.replay.jsonl` sidecars and print a one-line summary per session (entry count + log path). Useful for finding a session to inspect with `wstack replay <id>`.",
1110
+ usage: "wstack replay --list / wstack replay -l",
1111
+ seeAlso: "wstack replay <id> (inspect a single session's recorded responses)"
1112
+ },
1113
+ // -- sessions (deep subcommands) ---------------------------------------
1114
+ "sessions:resume": {
1115
+ name: "sessions:resume",
1116
+ title: "wstack sessions resume [<id>] \u2014 resume a prior session",
1117
+ description: `Resume a session by id, or the most recent one if no id is given. The REPL replays the session's history into the new run so context is preserved. Use the most recent id when the user just asked "pick up where we left off" without naming a specific session.`,
1118
+ usage: "wstack sessions resume [<id>]",
1119
+ subcommands: [
1120
+ { name: "[<id>]", description: "Session id to resume (defaults to the most recent)." }
1121
+ ],
1122
+ seeAlso: "wstack sessions list (find a recent id); wstack sessions show <id> (preview before resuming)"
1123
+ },
1124
+ "sessions:fork": {
1125
+ name: "sessions:fork",
1126
+ title: "wstack sessions fork [<id>] [--to N] \u2014 branch a session journal",
1127
+ description: "Create a non-destructive child JSONL journal from the latest persisted boundary or checkpoint N. The parent is unchanged and the returned checkpoint hash identifies the exact parent event prefix. New Git-backed checkpoints also report a content-addressed workspace manifest, but the fork command does not apply it automatically: files remain shared until a host materializes that manifest into a separate clean checkout.",
1128
+ usage: "wstack sessions fork [<id>] [--to N]",
1129
+ subcommands: [
1130
+ { name: "[<id>]", description: "Parent session id (defaults to the most recent)." },
1131
+ { name: "--to N", description: "Fork at checkpoint prompt index N." }
1132
+ ],
1133
+ seeAlso: "wstack rewind --list (find checkpoints); wstack sessions resume <child-id>"
1134
+ },
1135
+ "sessions:fleet": {
1136
+ name: "sessions:fleet",
1137
+ title: "wstack sessions fleet \u2014 list the active fleet of sessions",
1138
+ description: "List the active multi-agent fleet runs (the director, the subagent set, the iteration count, the journal size). Distinct from `wstack sessions list` which only shows single-agent sessions.",
1139
+ usage: "wstack sessions fleet",
1140
+ seeAlso: "wstack sessions list (single-agent sessions); /fleet (the in-REPL equivalent)"
1141
+ },
1142
+ "sessions:show": {
1143
+ name: "sessions:show",
1144
+ title: "wstack sessions show <id> \u2014 preview a session in detail",
1145
+ description: "Print the session metadata, the first N turns, the token/cost totals, and any errors. Use this to decide whether to resume a session before committing to it.",
1146
+ usage: "wstack sessions show <id>",
1147
+ subcommands: [{ name: "<id>", description: "The session id to show." }]
1148
+ },
1149
+ "sessions:list": {
1150
+ name: "sessions:list",
1151
+ title: "wstack sessions list \u2014 list recent single-agent sessions",
1152
+ description: "Print a one-line summary per recorded session (id, timestamp, last prompt, model, token totals). Distinct from `wstack sessions fleet` which shows active multi-agent runs. Use this to find a session id to resume, show, or export.",
1153
+ usage: "wstack sessions list",
1154
+ seeAlso: "wstack sessions fleet (active runs); wstack sessions resume <id> (resume one)"
1155
+ },
1156
+ "sessions:config": {
1157
+ name: "sessions:config",
1158
+ title: "wstack sessions config \u2014 session-specific config",
1159
+ description: "Show or edit the session-specific config overrides (e.g. per-session provider + model). Subcommand: see the underlying config-history commands for the full surface \u2014 this is the shortcut alias.",
1160
+ usage: "wstack sessions config"
1161
+ },
1162
+ // -- config (subcommands of the top-level config) ---------------------
1163
+ "config:show": {
1164
+ name: "config:show",
1165
+ title: "wstack config show \u2014 print the resolved config",
1166
+ description: "Print the resolved config (active profile plus all on-disk overrides applied) to stdout. Secrets are masked. The default subcommand \u2014 `wstack config` without a sub invokes this.",
1167
+ usage: "wstack config show",
1168
+ seeAlso: "wstack config edit (interactive); wstack auth (most config edits are auth/key changes)"
1169
+ },
1170
+ "config:edit": {
1171
+ name: "config:edit",
1172
+ title: "wstack config edit \u2014 open the active profile config in $EDITOR",
1173
+ description: "Print the active profile config path (typically `~/.wrongstack/profiles/default/config.json`) and the command to open it. Does not spawn the editor itself \u2014 the user runs the printed command (or sets `$EDITOR` and re-runs). Useful for offline edits when you want to see the full file at once.",
1174
+ usage: "wstack config edit",
1175
+ seeAlso: "wstack config show (verify after edit); wstack config history (audit trail)"
1176
+ },
1177
+ "config:history": {
1178
+ name: "config:history",
1179
+ title: "wstack config history \u2014 list recent config-history entries",
1180
+ description: "List every recent change to the active profile config, with a one-line description and a snapshot id. Pass `--id <id>` to see the full diff + masked snapshot. The audit trail is append-only (entries are never modified post-creation).",
1181
+ usage: "wstack config history [--id <id>]",
1182
+ subcommands: [
1183
+ { name: "<no subcommand>", description: "List every history entry (newest first)." },
1184
+ { name: "--id <id>", description: "Show the full diff + masked snapshot for one entry." }
1185
+ ],
1186
+ seeAlso: "wstack config restore <id>|--latest (revert); wstack config show (current state)"
1187
+ },
1188
+ "config:restore": {
1189
+ name: "config:restore",
1190
+ title: "wstack config restore <id>|--latest \u2014 revert to a prior config",
1191
+ description: "Restore a previous config-history entry. Pass either the history id (from `wstack config history`) or `--latest` to revert to the most recent prior version. A backup of the current config is created before the restore, so the change is itself recorded in the history (a history of histories).",
1192
+ usage: "wstack config restore <id> | --latest / -l",
1193
+ subcommands: [
1194
+ {
1195
+ name: "<id>",
1196
+ description: "The history id to restore (from `wstack config history` output)."
1197
+ },
1198
+ {
1199
+ name: "--latest / -l",
1200
+ description: "Restore to the most recent prior version (without naming an id)."
1201
+ }
1202
+ ],
1203
+ seeAlso: "wstack config history (list entries); wstack config show (verify the restore)"
1204
+ },
1205
+ // -- rewind (flag-shaped deep subcommands) ----------------------------
1206
+ "rewind:list": {
1207
+ name: "rewind:list",
1208
+ title: "wstack rewind --list \u2014 list rewind checkpoints for a session",
1209
+ description: "Print every checkpoint for the session (default: latest). Each checkpoint is a snapshot of the working tree + session history at a given prompt index. Use the checkpoint index as the value for `--to <idx>` when rewinding. Default `wstack rewind` (no flags) is an error \u2014 pair `--list` with a session id (positional) to discover available checkpoints first.",
1210
+ usage: "wstack rewind [<sessionId>] --list",
1211
+ seeAlso: "wstack rewind --to <idx> (rewind to a specific checkpoint); wstack rewind --all"
1212
+ },
1213
+ "rewind:all": {
1214
+ name: "rewind:all",
1215
+ title: "wstack rewind --all \u2014 rewind to the start of the session",
1216
+ description: "Rewind the working tree + session state to the very start of the session (the first prompt). Every file modified since the start is reverted. Pair with `--resume` to also truncate the session history at the start (so a fresh `wstack` invocation begins from there).",
1217
+ usage: "wstack rewind [<sessionId>] --all [--resume]",
1218
+ seeAlso: "wstack rewind --last N (rewind fewer steps); wstack rewind --to <idx> (specific checkpoint)"
1219
+ },
1220
+ "rewind:last": {
1221
+ name: "rewind:last",
1222
+ title: "wstack rewind --last N \u2014 rewind the last N prompts",
1223
+ description: "Rewind the last `N` prompts. For a session that was on track for prompts 1..10 and went off the rails at 11..15, `--last 5` rewinds to the state at the end of prompt 10. Pair with `--resume` to truncate the history at the rewound point.",
1224
+ usage: "wstack rewind [<sessionId>] --last <N> [--resume]",
1225
+ subcommands: [
1226
+ { name: "<N>", description: "Number of recent prompts to rewind (must be \u2265 1)." }
1227
+ ],
1228
+ seeAlso: "wstack rewind --all (rewind further); wstack rewind --to <idx> (precise checkpoint)"
1229
+ },
1230
+ "rewind:to": {
1231
+ name: "rewind:to",
1232
+ title: "wstack rewind --to <idx> \u2014 rewind to a specific checkpoint",
1233
+ description: "Rewind to checkpoint at the given prompt index (from `wstack rewind --list`). The most precise rewind form \u2014 lets you step back to exactly the state at a specific prompt rather than the bulk `--all` or approximate `--last N`.",
1234
+ usage: "wstack rewind [<sessionId>] --to <idx> [--resume]",
1235
+ subcommands: [
1236
+ {
1237
+ name: "<idx>",
1238
+ description: "Prompt index to rewind to (must be \u2265 0). Use `wstack rewind --list` to find indices."
1239
+ }
1240
+ ],
1241
+ seeAlso: "wstack rewind --list (find checkpoint indices); wstack rewind --resume (truncate history at the checkpoint)"
1242
+ },
1243
+ "rewind:resume": {
1244
+ name: "rewind:resume",
1245
+ title: "wstack rewind --resume \u2014 truncate session history at the checkpoint",
1246
+ description: "After the rewind (any of `--all` / `--last N` / `--to N`), also truncate the session's recorded history at the rewound checkpoint so the next `wstack` invocation begins fresh from there. Without `--resume`, the rewind only reverts the working tree \u2014 the session history is preserved (you'd see the rewind point as a checkpoint in subsequent runs).",
1247
+ usage: "wstack rewind [<sessionId>] {--all|--last <N>|--to <idx>} --resume",
1248
+ seeAlso: "wstack rewind --list (find checkpoints); wstack sessions resume <id> (resume a rewound session)"
1249
+ },
1250
+ // -- mcp:restart (REPL-only) -----------------------------------------
1251
+ "mcp:restart": {
1252
+ name: "mcp:restart",
1253
+ title: "wstack mcp restart \u2014 restart a running MCP server (REPL only)",
1254
+ description: "Restart a single running MCP server by alias. This subcommand is only meaningful inside the REPL (`wstack` with no `<task>` argument) \u2014 from the top-level CLI it prints a warning and exits 0 because there's no live process to restart. Use the `/mcp restart <name>` slash command from inside the REPL.",
1255
+ usage: "wstack mcp restart <name> (REPL only)",
1256
+ seeAlso: "/mcp restart <name> (the in-REPL slash command); wstack mcp remove + wstack mcp add (replace the server config)"
1257
+ },
1258
+ // -- plugin (list / official) -----------------------------------------
1259
+ "plugin:list": {
1260
+ name: "plugin:list",
1261
+ title: "wstack plugin list \u2014 list configured plugins",
1262
+ description: "Print every plugin registered in the config, grouped by enabled vs disabled. Alias: `plugin status`. For the official registry (a curated list maintained by the WrongStack project), use `wstack plugin official` instead.",
1263
+ usage: "wstack plugin list (alias: wstack plugin status)",
1264
+ seeAlso: "wstack plugin official (curated registry); wstack plugin enable / disable (toggle state)"
1265
+ },
1266
+ "plugin:official": {
1267
+ name: "plugin:official",
1268
+ title: "wstack plugin official \u2014 list the curated official registry",
1269
+ description: "Print every plugin in the official registry (currently `telegram` and `lsp`). Each row shows the alias (for shorthand on the command line) and the full NPM specifier (what `wstack plugin add <spec>` actually installs). Aliases: `plugin officials` (plural).",
1270
+ usage: "wstack plugin official (alias: wstack plugin officials)",
1271
+ seeAlso: "wstack plugin add <alias> (install one); wstack plugin list (what you have)"
1272
+ },
1273
+ "plugin:officials": {
1274
+ // The plural form `plugin officials` is accepted as an
1275
+ // alias of `plugin official` in the underlying dispatch
1276
+ // (`plugin-management.ts`). The deep-help table mirrors
1277
+ // the alias so `wstack plugin officials --help` and
1278
+ // `wstack plugin official --help` both render the same
1279
+ // focused block.
1280
+ name: "plugin:officials",
1281
+ title: "wstack plugin officials \u2014 list the curated official registry (plural alias)",
1282
+ description: "Alias of `wstack plugin official`. Prints every plugin in the official registry. Same output as the singular form.",
1283
+ usage: "wstack plugin officials (plural alias of `wstack plugin official`)",
1284
+ seeAlso: "wstack plugin official (the singular form)"
1285
+ },
1286
+ // -- models (refresh + list) -----------------------------------------
1287
+ "models:refresh": {
1288
+ name: "models:refresh",
1289
+ title: "wstack models refresh \u2014 force-refresh the models.dev cache",
1290
+ description: "Re-fetch the models.dev catalog and replace the cached `models.json` in the global config dir. Useful when a new model is published mid-session and you want to see it in `wstack providers` / `wstack models` without restarting. The cache age is shown in the footer of every `wstack models` listing so you know when to refresh.",
1291
+ usage: "wstack models refresh",
1292
+ seeAlso: "wstack models <provider> (list models after refresh); wstack providers (force-refresh the provider catalog)"
1293
+ },
1294
+ "models:list": {
1295
+ name: "models:list",
1296
+ title: "wstack models list \u2014 list custom models registered locally",
1297
+ description: "Print every model that's been added via `wstack models add` (i.e. the entries in `config.json`'s `models` section, not the catalog). Distinct from `wstack models <provider>` which lists the catalog for a specific provider. The list is the audit surface for self-hosted / fine-tuned / overridden models.",
1298
+ usage: "wstack models list",
1299
+ seeAlso: "wstack models <provider> (catalog); wstack models add <mid> (register a custom model)"
1300
+ },
1301
+ // -- auth (list / status / remove) -------------------------------------
1302
+ // The top-level `wstack auth` entry in `helpTable` lists the
1303
+ // subcommands; these deep entries give each one its own focused
1304
+ // block so `wstack auth list --help`, `/help auth status`, and
1305
+ // `/auth status help` all render the same string the underlying
1306
+ // handler would emit. The descriptions match the actual
1307
+ // handler behavior in `packages/cli/src/subcommands/handlers/auth.ts`
1308
+ // — note that the `remove` subcommand is always interactive
1309
+ // (prompts for confirmation); the `[--force]` token in the
1310
+ // handler's error message is a documented hint that is not
1311
+ // yet wired up in the parser.
1312
+ "auth:list": {
1313
+ name: "auth:list",
1314
+ title: "wstack auth list \u2014 list saved providers and key status",
1315
+ description: "Read-only listing of every provider in the active profile config. Each provider block shows the family, baseUrl, model-allowlist size, and the saved API keys (the active key is marked with a green `\u25CF`, inactive keys with a dim `\u25CB`; all values are masked). Alias: `wstack auth ls`.",
1316
+ usage: "wstack auth list (alias: wstack auth ls)",
1317
+ subcommands: [
1318
+ { name: "list", description: "List every saved provider (this command)." },
1319
+ { name: "ls", description: "Alias of list." }
1320
+ ],
1321
+ seeAlso: "wstack auth status <id> (detail for one provider); wstack auth remove <id> (delete one)"
1322
+ },
1323
+ "auth:status": {
1324
+ name: "auth:status",
1325
+ title: "wstack auth status <provider> \u2014 show detail for one provider",
1326
+ description: "Print the full `config.json` entry for a single provider: type, family, baseUrl, the `models` allowlist, the `envVars` list, and every saved key (active key marked with a green `\u25CF`, masked value, ISO timestamp). The provider id is required as a positional \u2014 `wstack auth status` with no id prints the usage hint and exits 1.",
1327
+ usage: "wstack auth status <provider>",
1328
+ subcommands: [
1329
+ {
1330
+ name: "<provider>",
1331
+ description: "The provider id to inspect (e.g. `openai`, `anthropic`)."
1332
+ }
1333
+ ],
1334
+ seeAlso: "wstack auth list (find the id); wstack auth remove <id> (delete it); wstack auth (interactive edit)"
1335
+ },
1336
+ "auth:remove": {
1337
+ name: "auth:remove",
1338
+ title: "wstack auth remove <provider> \u2014 delete a provider and its keys",
1339
+ description: "Remove a provider entry and all its saved API keys from the active profile config. The flow is always interactive: after printing a confirmation prompt the handler waits for a `y` / `yes` answer (default `N`). The active session's in-memory provider is NOT reloaded \u2014 restart the REPL to fully tear down a running provider. Alias: `wstack auth rm`.",
1340
+ usage: "wstack auth remove <provider> (alias: wstack auth rm <provider>)",
1341
+ subcommands: [
1342
+ { name: "<provider>", description: "The provider id to remove." },
1343
+ { name: "rm", description: "Alias of remove." }
1344
+ ],
1345
+ seeAlso: "wstack auth list (find the id); wstack auth status <id> (inspect before removing); wstack auth <provider> (re-add a different one)"
1346
+ },
1347
+ // The `auth:local` deep entry delegates its body to
1348
+ // `auth-local-help.ts` via the `customBody` field. The flag
1349
+ // list lives in exactly one place (`LOCAL_AUTH_FLAGS`), and
1350
+ // every surface that renders the help — `wstack auth local --help`,
1351
+ // `/auth local help`, `/help auth local` — produces the same
1352
+ // string. The `title` / `description` / `usage` / `seeAlso` fields
1353
+ // below are required by the `PerSubcommandHelp` shape but
1354
+ // never rendered (the `customBody` thunk owns the full layout).
1355
+ // They're filled in with sensible defaults so a future refactor
1356
+ // that drops `customBody` (e.g. to use the standard layout)
1357
+ // still has a coherent fallback.
1358
+ "auth:local": {
1359
+ name: "auth:local",
1360
+ title: "wstack auth local \u2014 quick-add Ollama / vLLM / LM Studio",
1361
+ description: "Pre-fills the base URL, runs a health probe, and persists the allowlist so you can `wstack --provider <id>` right away. Use `--no-probe` to skip the probe when the server is not running yet; `--audit <file>` captures the save lifecycle as JSONL.",
1362
+ usage: "wstack auth local [--name <id>] [--base-url <url>] [--no-key] [--no-probe|--probe-only] [--model <spec>] [--audit [target]]",
1363
+ seeAlso: "wstack auth (interactive menu); wstack auth <provider> (catalog add)",
1364
+ customBody: renderAuthLocalHelpToString
1365
+ },
1366
+ // -- bench (run — delegated to bench-run-help.ts via customBody) ------
1367
+ // The `bench:run` deep entry delegates its body to
1368
+ // `bench-run-help.ts` via the `customBody` field. The flag
1369
+ // list lives in exactly one place (`BENCH_RUN_FLAGS`), and
1370
+ // every surface that renders the help — `wstack bench run --help`,
1371
+ // `/bench run help`, `/help bench run` — produces the same
1372
+ // string. The `title` / `description` / `usage` / `seeAlso`
1373
+ // fields below are required by the `PerSubcommandHelp` shape
1374
+ // but never rendered (the `customBody` thunk owns the full
1375
+ // layout). They're filled in with sensible defaults so a
1376
+ // future refactor that drops `customBody` (e.g. to use the
1377
+ // standard layout) still has a coherent fallback.
1378
+ "bench:run": {
1379
+ name: "bench:run",
1380
+ title: "wstack bench run \u2014 execute a benchmark suite across a model matrix",
1381
+ description: "See renderBenchRunHelpToString() in bench-run-help.ts for the full block.",
1382
+ usage: "wstack bench run [...flags]",
1383
+ customBody: renderBenchRunHelpToString
1384
+ }
1385
+ };
1386
+
1387
+ // src/subcommands/handlers/per-subcommand-help-table.ts
1388
+ var helpTable = {
1389
+ init: {
1390
+ name: "init",
1391
+ title: "wstack init \u2014 DEPRECATED (use wstack auth)",
1392
+ description: "\u26A0 This command is deprecated. Use wstack auth for setup, key management, and model selection in one interactive workflow.",
1393
+ usage: "wstack init (deprecated)",
1394
+ seeAlso: "wstack auth (interactive setup + key manager)"
1395
+ },
1396
+ version: {
1397
+ name: "version",
1398
+ title: "wstack version \u2014 print the CLI version",
1399
+ description: "Prints the WrongStack CLI version, the apiVersion, the Node.js version, and the host platform. Useful for bug reports and CI logs.",
1400
+ usage: "wstack version"
1401
+ },
1402
+ mcp: {
1403
+ name: "mcp",
1404
+ title: "wstack mcp \u2014 manage Model Context Protocol servers",
1405
+ description: "List, add, remove, restart, and serve MCP servers registered in the global config. Servers are referenced by id and use the stdio, SSE, or streamable-HTTP transports.",
1406
+ usage: "wstack mcp [list|add|remove|restart|serve] [...]",
1407
+ subcommands: [
1408
+ { name: "list", description: "List all configured MCP servers." },
1409
+ { name: "add <id> <command>", description: "Register a new stdio MCP server." },
1410
+ { name: "remove <id>", description: "Unregister an MCP server." },
1411
+ { name: "restart <id>", description: "Restart a running MCP server." },
1412
+ {
1413
+ name: "serve",
1414
+ description: "Run the wstack MCP server; --resources/--prompts explicitly expose selected files."
1415
+ }
1416
+ ],
1417
+ seeAlso: "wstack plugin (manage tool plugins similarly)"
1418
+ },
1419
+ plugin: {
1420
+ name: "plugin",
1421
+ title: "wstack plugin \u2014 manage tool plugins",
1422
+ description: "List, inspect, install, add, remove, enable, disable, and toggle tool plugins. Plugins extend the agent with custom tool packs (e.g. GitHub, Playwright, project-local helpers).",
1423
+ usage: "wstack plugin [list|status|report|menu|official|add|install|toggle|remove|enable|disable|manager] [...]",
1424
+ subcommands: [
1425
+ { name: "list", description: "List installed plugins (alias: status)." },
1426
+ { name: "report", description: "Show effective state, risk, and lock/toggle policy." },
1427
+ { name: "menu", description: "Print the audit report outside the TUI plugin picker." },
1428
+ { name: "official", description: "List plugins from the official registry." },
1429
+ { name: "add <id>", description: "Add a plugin by id (alias: install)." },
1430
+ { name: "toggle <id>", description: "Toggle a safe audit-list plugin row." },
1431
+ { name: "remove <id>", description: "Remove an installed plugin (aliases: rm, uninstall)." },
1432
+ { name: "enable <id>", description: "Re-enable a previously-disabled plugin." },
1433
+ { name: "disable <id>", description: "Temporarily disable a plugin without removing it." },
1434
+ {
1435
+ name: "manager [lock|unlock] <id|*>",
1436
+ description: "Control whether the LLM may enable/disable individual plugins."
1437
+ }
1438
+ ],
1439
+ seeAlso: "wstack mcp (MCP servers are registered as tool plugins)"
1440
+ },
1441
+ models: {
1442
+ name: "models",
1443
+ title: "wstack models \u2014 list and override models",
1444
+ description: "List models from the models.dev catalog, or override the default model for a provider with a custom id (for self-hosted or fine-tuned models not in the public catalog).",
1445
+ usage: "wstack models [<provider>] [add|remove|list|refresh] [...]",
1446
+ subcommands: [
1447
+ { name: "<no-subcommand>", description: "List models for the default provider." },
1448
+ { name: "<provider>", description: "List models for a specific provider." },
1449
+ {
1450
+ name: "add <mid>",
1451
+ description: "Add or override a custom model (--max-context, --tools, --vision, \u2026)."
1452
+ },
1453
+ { name: "remove <mid>", description: "Remove a custom model." },
1454
+ { name: "list", description: "List all custom models registered locally." },
1455
+ { name: "refresh", description: "Force-refresh the models.dev cache." }
1456
+ ],
1457
+ seeAlso: "wstack providers (list provider families and their defaults)"
1458
+ },
1459
+ config: {
1460
+ name: "config",
1461
+ title: "wstack config \u2014 show or edit effective config",
1462
+ description: "Print the resolved config (with the on-disk overrides merged on top), or open the active profile config in $EDITOR for interactive edits. Also exposes a small audit log of recent config-history changes for diagnostics.",
1463
+ usage: "wstack config [show|edit|history|restore] [...]",
1464
+ subcommands: [
1465
+ { name: "show", description: "Print the resolved config to stdout (default)." },
1466
+ { name: "edit", description: "Open the active profile config in $EDITOR." },
1467
+ { name: "history", description: "List recent config-history entries." },
1468
+ { name: "restore <id>", description: "Restore a previous config-history entry." }
1469
+ ],
1470
+ seeAlso: "wstack auth (most config edits are auth/key changes)"
1471
+ },
1472
+ // -- API key / auth management -----------------------------------------
1473
+ auth: {
1474
+ name: "auth",
1475
+ title: "wstack auth \u2014 manage API keys and provider credentials",
1476
+ description: "Add, view, and remove provider API keys. The interactive menu supports a custom-URL path for self-hosted / local servers, a quick-shortcut path for Ollama / vLLM / LM Studio, and a catalog path for the well-known providers.",
1477
+ usage: "wstack auth [list|status|remove] [...] | wstack auth <provider> | wstack auth local [...]",
1478
+ subcommands: [
1479
+ { name: "list", description: "List saved providers and key status." },
1480
+ { name: "status <id>", description: "Show detail for one provider." },
1481
+ { name: "remove <id>", description: "Remove a provider and its keys." },
1482
+ { name: "<provider>", description: "Add a key for a named provider (--label, --family, \u2026)." },
1483
+ {
1484
+ name: "local",
1485
+ description: "Pre-fill Ollama / vLLM / LM Studio (--name, --base-url, --no-probe, --model, --audit \u2026)."
1486
+ },
1487
+ {
1488
+ name: "login <chatgpt|claude|copilot>",
1489
+ description: "Subscription OAuth login: chatgpt (\u2192 openai-codex), claude (\u2192 anthropic-oauth), or copilot (\u2192 github-copilot). Opens browser; no API key. \u26A0 Using subscriptions outside official clients may violate provider ToS (account ban risk); an API key is the sanctioned path."
1490
+ }
1491
+ ],
1492
+ seeAlso: "wstack auth local (pre-fill Ollama / vLLM / LM Studio)"
1493
+ },
1494
+ // -- Session list / resume / show / fork --------------------------------
1495
+ sessions: {
1496
+ name: "sessions",
1497
+ title: "wstack sessions \u2014 list and resume recent sessions",
1498
+ description: "List recent sessions, show one session in detail, resume a session, or inspect a session's audit log. The audit log is stored as JSONL next to each session's recording.",
1499
+ usage: "wstack sessions [list|show|resume|fork|config|fleet] [...]",
1500
+ subcommands: [
1501
+ { name: "list", description: "List the most recent sessions." },
1502
+ { name: "show <id>", description: "Show one session in detail." },
1503
+ { name: "resume [<id>]", description: "Resume a session (latest if no id given)." },
1504
+ {
1505
+ name: "fork [<id>] [--to N]",
1506
+ description: "Create an isolated child journal at a persisted boundary."
1507
+ },
1508
+ { name: "config", description: "Show or edit session-specific config." },
1509
+ { name: "fleet", description: "List the active fleet of sessions." }
1510
+ ],
1511
+ seeAlso: "wstack audit (the session-level audit log reader)"
1512
+ },
1513
+ // -- Diagnostics --------------------------------------------------------
1514
+ doctor: {
1515
+ name: "doctor",
1516
+ title: "wstack doctor \u2014 health checks",
1517
+ description: "Run a series of health checks (provider + key + models cache + secret vault + sessions dir + MCP server config) and exit non-zero if any check fails. Use as a CI gate or a post-install smoke test. With --daemons, inspect this project\u2019s IPC daemons instead: each is reported live, stale, or stopped. A stale endpoint is one whose owner died without releasing it; daemons reclaim it on their next start, or --clear-stale removes it now. Listing never spawns a daemon.",
1518
+ usage: "wstack doctor [--daemons [--clear-stale]]",
1519
+ seeAlso: "wstack diag (read-only environment dump for bug reports)"
1520
+ },
1521
+ diag: {
1522
+ name: "diag",
1523
+ title: "wstack diag \u2014 read-only environment dump",
1524
+ description: "Print a key=value environment snapshot (apiVersion, cwd, project info, paths, cache age, configured provider + model, tool/plugin counts, MCP server count). Never modifies state \u2014 safe to paste into bug reports.",
1525
+ usage: "wstack diag",
1526
+ seeAlso: "wstack doctor (pass/fail health checks vs. this is a dump)"
1527
+ },
1528
+ // -- Session audit / replay / rewind -----------------------------------
1529
+ audit: {
1530
+ name: "audit",
1531
+ title: "wstack audit \u2014 inspect a session's tamper-evident audit log",
1532
+ description: "Show the chained-hash entries for a recorded session and run a verification pass to surface any post-hoc modification. Each entry is SHA-256-chained to the previous; any tampering breaks the chain and is reported.",
1533
+ usage: "wstack audit [<sessionId>] [--list]",
1534
+ subcommands: [
1535
+ { name: "<sessionId>", description: "Show entries + verify chain (positional)." },
1536
+ { name: "--list / -l", description: "List every session that has an audit log." }
1537
+ ],
1538
+ seeAlso: "wstack replay (the corresponding provider-response log)"
1539
+ },
1540
+ replay: {
1541
+ name: "replay",
1542
+ title: "wstack replay \u2014 inspect a session's recorded provider responses",
1543
+ description: "Show the recorded request/response pairs for a session \u2014 the frozen inputs the agent saw, in order. This is the inspection surface; to actually re-run the agent with those responses, use `wstack --replay <sessionId>`.",
1544
+ usage: "wstack replay [<sessionId>] [--list]",
1545
+ subcommands: [
1546
+ { name: "<sessionId>", description: "Show the recorded entries (positional)." },
1547
+ { name: "--list / -l", description: "List every session that has a replay log." }
1548
+ ],
1549
+ seeAlso: "wstack audit (the tamper-evident tool-call log)"
1550
+ },
1551
+ rewind: {
1552
+ name: "rewind",
1553
+ title: "wstack rewind \u2014 rewind a session to an earlier state",
1554
+ description: "Restore a session's in-memory state to a previous point in its recording. The rewind is non-destructive: the original session is preserved, and a new resumed session picks up from the rewound point. Useful for re-running a fork of an exploration without losing the original.",
1555
+ usage: "wstack rewind [<sessionId>] [--all|--last <n>|--to <id>] [--list] [--resume]",
1556
+ subcommands: [
1557
+ { name: "<sessionId>", description: "Session id (positional; defaults to the latest)." },
1558
+ { name: "--all", description: "Rewind to the start of the session." },
1559
+ { name: "--last <n>", description: "Rewind to `n` steps back from the end." },
1560
+ { name: "--to <id>", description: "Rewind to a specific step id." },
1561
+ { name: "--list", description: "List available rewind points for the session." },
1562
+ { name: "--resume", description: "Resume the rewound session after the rewind." }
1563
+ ],
1564
+ seeAlso: "wstack replay (the underlying provider-response log)"
1565
+ },
1566
+ // -- Export & usage ----------------------------------------------------
1567
+ export: {
1568
+ name: "export",
1569
+ title: "wstack export \u2014 render a session to a portable format",
1570
+ description: "Render a recorded session to Markdown, JSON, or plain text. Use Markdown for human-readable share/audit artifacts, JSON for downstream tooling, or text for grep-friendly search. Tools and diagnostics are included by default; toggle either off with `--no-tools` or `--no-diagnostics`.",
1571
+ usage: "wstack export <sessionId> [--format markdown|json|text] [--out <file>] [--no-tools] [--no-diagnostics]",
1572
+ subcommands: [
1573
+ { name: "<sessionId>", description: "The session id to render (positional)." },
1574
+ {
1575
+ name: "--format <f> / -f <f>",
1576
+ description: "Output format: markdown (default), json, or text."
1577
+ },
1578
+ { name: "--out <file> / -o <file>", description: "Write to <file> instead of stdout." },
1579
+ { name: "--no-tools", description: "Omit tool-call entries from the output." },
1580
+ {
1581
+ name: "--no-diagnostics",
1582
+ description: "Omit diagnostic entries (errors, retries) from the output."
1583
+ }
1584
+ ],
1585
+ seeAlso: "wstack replay (the recorded provider-response log)"
1586
+ },
1587
+ usage: {
1588
+ name: "usage",
1589
+ title: "wstack usage \u2014 token + cost summary",
1590
+ description: "Print a per-session token + cost summary from the audit log. Useful for cost reviews and the post-session billing recap. Aggregates input/output tokens and the per-model cost; requires the session to have been recorded with audit enabled.",
1591
+ usage: "wstack usage",
1592
+ seeAlso: "wstack export (full session render for archival)"
1593
+ },
1594
+ // -- Listing subcommands -----------------------------------------------
1595
+ providers: {
1596
+ name: "providers",
1597
+ title: "wstack providers \u2014 list providers from models.dev",
1598
+ description: "List provider families from the live models.dev catalog. Default view shows the popular three (Anthropic, OpenAI, Google); pass `--all` to include every supported family, or `--unsupported` to surface the ones without a built-in transport (which require a plugin).",
1599
+ usage: "wstack providers [--all] [--unsupported]",
1600
+ subcommands: [
1601
+ { name: "--all", description: "Include every supported family, not just the popular three." },
1602
+ {
1603
+ name: "--unsupported",
1604
+ description: "Include families without a built-in transport (need a plugin)."
1605
+ }
1606
+ ],
1607
+ seeAlso: "wstack models (list models within a provider)"
1608
+ },
1609
+ tools: {
1610
+ name: "tools",
1611
+ title: "wstack tools \u2014 list registered tools",
1612
+ description: "List every tool the agent can invoke, with its owner (built-in / plugin) and permission level. Useful for auditing what a session can do, especially after installing a new plugin.",
1613
+ usage: "wstack tools",
1614
+ seeAlso: "wstack skills (list skills; tools + skills are the two extension surfaces)"
1615
+ },
1616
+ skills: {
1617
+ name: "skills",
1618
+ title: "wstack skills \u2014 list discovered skills",
1619
+ description: "List every skill the agent can invoke, grouped by source (bundled / user-installed / project-local). Skills are on-demand context packs that load only when triggered.",
1620
+ usage: "wstack skills",
1621
+ seeAlso: "wstack tools (tools are always-loaded; skills are on-demand)"
1622
+ },
1623
+ projects: {
1624
+ name: "projects",
1625
+ title: "wstack projects \u2014 list tracked projects",
1626
+ description: "List every project WrongStack has seen (tracked by a hashed root). Each entry shows the project root and the last-seen timestamp. Useful for cleaning up the global projects dir after a workspace migration.",
1627
+ usage: "wstack projects"
1628
+ },
1629
+ // -- Lifecycle ---------------------------------------------------------
1630
+ update: {
1631
+ name: "update",
1632
+ title: "wstack update \u2014 self-update the CLI",
1633
+ description: "Check the latest npm version and update the globally-installed `wrongstack` package. Use `--check-only` to just print the current/latest without installing. The update is global; run from any project root.",
1634
+ usage: "wstack update [--check-only]",
1635
+ seeAlso: "wstack version (read-only version info)"
1636
+ },
1637
+ // -- ACP (Agent Client Protocol) --------------------------------------
1638
+ acp: {
1639
+ name: "acp",
1640
+ title: "wstack acp \u2014 Agent Client Protocol (ACP) integration",
1641
+ description: "Run WrongStack as an ACP server (stdio) for editor clients (Zed, JetBrains, VS Code ACP), or orchestrate external ACP agents through spawn, probe, bench, and parallel fan-out.",
1642
+ usage: "wstack acp [server|list|sync|spawn|parallel|probe|bench] [...]",
1643
+ subcommands: [
1644
+ { name: "server / serve", description: "Start WrongStack as an ACP stdio server (default)." },
1645
+ { name: "list", description: "List available ACP agents from the cache." },
1646
+ { name: "sync", description: "Sync the official ACP agent registry into local cache." },
1647
+ { name: "spawn <id> <task>", description: "Spawn an ACP agent and wait for results." },
1648
+ { name: "parallel <csv> <task>", description: "Fan a task out to multiple ACP agents in parallel." },
1649
+ { name: "probe [csv]", description: "Handshake-test installed ACP agents." },
1650
+ { name: "bench [csv] [--fs]", description: "End-to-end benchmark and grade ACP agents." }
1651
+ ],
1652
+ seeAlso: "wstack mcp serve (the MCP equivalent; pick the protocol your client speaks)"
1653
+ },
1654
+ // -- Model diagnostics (read-only) -----------------------------------
1655
+ modeldiag: {
1656
+ name: "modeldiag",
1657
+ title: "wstack modeldiag \u2014 model benchmarks + heuristic diagnostics",
1658
+ description: "Read-only diagnostics for the configured model: key check, capability scan (vision / tools / context window), heuristic strengths/weaknesses (bestFor / avoidFor), sequential live provider/model smoke tests, and real benchmarks against a small prompt suite. Smoke tests use tiny prompts and never print credentials.",
1659
+ usage: "wstack modeldiag [test|eval] [...]",
1660
+ subcommands: [
1661
+ {
1662
+ name: "<no subcommand>",
1663
+ description: "Print configured model capabilities, context limits, and recommendations."
1664
+ },
1665
+ {
1666
+ name: "test [--plan|--all-models|--json]",
1667
+ description: "Run live sequential smoke tests across configured models."
1668
+ },
1669
+ {
1670
+ name: "eval [--providers <csv>]",
1671
+ description: "Run model competency matrix evaluation across tasks."
1672
+ }
1673
+ ],
1674
+ seeAlso: "wstack modeldiag test --plan; wstack modeldiag test; wstack modeldiag test --all-models"
1675
+ },
1676
+ // -- Bench (developer / CI only) -------------------------------------
1677
+ bench: {
1678
+ name: "bench",
1679
+ title: "wstack bench \u2014 run model-independent agentic benchmarks",
1680
+ description: "Run WrongStack against the Aider polyglot or SWE-bench Verified suites with deterministic graders. Used internally to compare model quality across releases; also useful for evaluating a new model before adopting it.",
1681
+ usage: "wstack bench [run|report|list] [...]",
1682
+ subcommands: [
1683
+ { name: "run", description: "Run a benchmark suite (--suite <id> --models <config>)." },
1684
+ { name: "report <dir>", description: "Render the Markdown report for a prior run." },
1685
+ { name: "list", description: "List available suites and the model configs in the catalog." }
1686
+ ],
1687
+ seeAlso: "wstack modeldiag (read-only diagnostics; bench actually runs the model)"
1688
+ },
1689
+ // -- Quick launch ------------------------------------------------------
1690
+ quick: {
1691
+ name: "quick",
1692
+ title: "wstack quick \u2014 launch the TUI with sensible defaults",
1693
+ description: "Accept every default, list installed plugins, and open the TUI with the agents-monitor panel pre-shown. Equivalent to `wstack --tui --quick`; the dedicated subcommand is for discoverability and tab-completion. The actual TUI launch is intercepted in `boot()` before this handler runs.",
1694
+ usage: "wstack quick",
1695
+ seeAlso: "wstack --tui (the underlying flag; quick is just a shortcut)"
1696
+ },
1697
+ // -- Aliases and meta commands ───────────────────────────────────────
1698
+ plugins: {
1699
+ name: "plugins",
1700
+ title: "wstack plugins \u2014 alias for wstack plugin",
1701
+ description: "Alias for `wstack plugin`. See `wstack plugin --help` for the full set of subcommands.",
1702
+ usage: "wstack plugins (alias for wstack plugin)",
1703
+ seeAlso: "wstack plugin (the canonical command)"
1704
+ },
1705
+ help: {
1706
+ name: "help",
1707
+ title: "wstack help \u2014 print top-level help",
1708
+ description: "Print the top-level help text listing every subcommand with a one-line summary. Equivalent to `wstack --help`.",
1709
+ usage: "wstack help",
1710
+ seeAlso: "wstack --help"
1711
+ },
1712
+ // -- HQ (dashboard server) ──────────────────────────────────────────
1713
+ hq: {
1714
+ name: "hq",
1715
+ title: "wstack hq \u2014 start HQ command center or manage tokens",
1716
+ description: "Start the HQ server \u2014 a web dashboard for monitoring sessions, fleet status, and agent activity across projects \u2014 or manage browser and client authentication tokens.",
1717
+ usage: "wstack hq [serve] [--port <n>] [--password <secret>] [--tunnel] [--open] | wstack hq token [create|list|revoke]",
1718
+ subcommands: [
1719
+ { name: "serve", description: "Start the HQ dashboard server (default)." },
1720
+ { name: "token create [label]", description: "Mint a browser or client authentication token." },
1721
+ { name: "token list", description: "List active HQ authentication tokens." },
1722
+ { name: "token revoke <id>", description: "Revoke an issued HQ authentication token." }
1723
+ ],
1724
+ seeAlso: "wstack sessions fleet (CLI equivalent for fleet status)"
1725
+ },
1726
+ // -- Mailbox (external agent bridge) ────────────────────────────────
1727
+ mailbox: {
1728
+ name: "mailbox",
1729
+ title: "wstack mailbox \u2014 serve the external-agent mailbox HTTP bridge",
1730
+ description: "Start the mailbox HTTP bridge that lets external coding agents (Claude Code, Aider, custom scripts) communicate with the shared project mailbox. The server exposes a REST + SSE API for sending, checking, and acknowledging messages. Use `wstack mailbox serve` to start the listener.",
1731
+ usage: "wstack mailbox serve [--port <n>]",
1732
+ subcommands: [{ name: "serve", description: "Start the mailbox HTTP bridge listener." }],
1733
+ seeAlso: "wstack hq (the HQ server includes mailbox routing)"
1734
+ },
1735
+ // -- Permissions ────────────────────────────────────────────────────
1736
+ permissions: {
1737
+ name: "permissions",
1738
+ title: "wstack permissions \u2014 explain tool permission decisions",
1739
+ description: "Side-effect-free permission decision explainer. Evaluates the effective permission rules for a tool and input arguments without prompting, modifying trust files, or mutating state.",
1740
+ usage: "wstack permissions explain <tool> [--input '<json>'] [--json]",
1741
+ subcommands: [
1742
+ {
1743
+ name: "explain <tool>",
1744
+ description: "Explain how the permission policy evaluates a tool call."
1745
+ }
1746
+ ],
1747
+ seeAlso: "wstack tools (list available tools)"
1748
+ },
1749
+ // -- Project management ─────────────────────────────────────────────
1750
+ project: {
1751
+ name: "project",
1752
+ title: "wstack project \u2014 manage committed repository identity",
1753
+ description: "Manage the committed repository identity (project.json) used to scope HQ dashboards, Kanban state, and multi-agent coordination. Commit the generated ID file so every clone shares the same project.",
1754
+ usage: "wstack project [id|init|rekey] [--yes]",
1755
+ subcommands: [
1756
+ { name: "id", description: "Show the current project ID and config path (default)." },
1757
+ { name: "init", description: "Initialize a project ID if not already present." },
1758
+ { name: "rekey", description: "Generate a new project ID for a fork (requires --yes)." }
1759
+ ],
1760
+ seeAlso: "wstack projects (list all tracked projects)"
1761
+ },
1762
+ governance: {
1763
+ name: "governance",
1764
+ title: "wstack governance \u2014 inspect deterministic project-daemon health",
1765
+ description: "Read token-free attachment-broker health from the current project daemon. Warnings are advisory: they surface deterministic operator escalation signals without stopping active tasks or model execution.",
1766
+ usage: "wstack governance status [--json]",
1767
+ subcommands: [{ name: "status", description: "Show daemon and attachment-broker health." }],
1768
+ seeAlso: "wstack doctor (broader environment diagnostics)"
1769
+ },
1770
+ // -- Chronicle ──────────────────────────────────────────────────────
1771
+ chronicle: {
1772
+ name: "chronicle",
1773
+ title: "wstack chronicle \u2014 query cross-session provenance ledger",
1774
+ description: "Query the cross-session event ledger, inspect daemon status, compute facet aggregations, view token/cost metrics, or purge old retention entries.",
1775
+ usage: "wstack chronicle [query|status|facet|metrics|prune|compact] [...]",
1776
+ subcommands: [
1777
+ { name: "query [field=value ...]", description: "Query recorded provenance events." },
1778
+ { name: "status", description: "Check the Chronicle daemon and pipeline status." },
1779
+ { name: "facet <field>", description: "Group and count events across a facet." },
1780
+ { name: "metrics [providers|tasks|files|summary]", description: "Query aggregated metrics from metrics.db." },
1781
+ { name: "prune [--days N] [--dry-run]", description: "Purge journal entries older than N days." },
1782
+ { name: "compact", description: "Defragment and compact SQLite ledger." }
1783
+ ],
1784
+ seeAlso: "wstack audit (per-session audit log); wstack usage (cost summary)"
1785
+ }
1786
+ };
1787
+
1788
+ // src/subcommands/handlers/per-subcommand-help.ts
1789
+ var COLUMN_WIDTH = 28;
1790
+ function renderBlockToString(help) {
1791
+ if (help.customBody) {
1792
+ return help.customBody();
1793
+ }
1794
+ const lines = [
1795
+ color5.bold(help.title),
1796
+ color5.dim(` ${help.description}`),
1797
+ "",
1798
+ color5.bold("Usage"),
1799
+ ` ${help.usage}`
1800
+ ];
1801
+ if (help.subcommands && help.subcommands.length > 0) {
1802
+ lines.push("");
1803
+ lines.push(color5.bold("Subcommands"));
1804
+ for (const { name, description } of help.subcommands) {
1805
+ const padded = name.padEnd(COLUMN_WIDTH, " ");
1806
+ lines.push(` ${color5.cyan(padded)}${description}`);
1807
+ }
1808
+ }
1809
+ if (help.seeAlso) {
1810
+ lines.push("");
1811
+ lines.push(color5.dim(` See also: ${help.seeAlso}`));
1812
+ }
1813
+ lines.push("");
1814
+ lines.push(color5.dim(" Tip: `wstack --help` lists every top-level command."));
1815
+ return lines.join("\n") + "\n";
1816
+ }
1817
+ function renderBlock(help, renderer) {
1818
+ renderer.write(renderBlockToString(help));
1819
+ }
1820
+ function renderDeepHelp(key, renderer) {
1821
+ const help = deepHelpTable[key];
1822
+ if (!help) return false;
1823
+ renderBlock(help, renderer);
1824
+ return true;
1825
+ }
1826
+ var deepSubcommandsWithFocusedHelp = Object.keys(deepHelpTable);
1827
+ function renderFocusedHelp(subcommand, renderer) {
1828
+ const help = helpTable[subcommand];
1829
+ if (!help) return false;
1830
+ renderBlock(help, renderer);
1831
+ return true;
1832
+ }
1833
+ var subcommandsWithFocusedHelp = Object.keys(helpTable);
1834
+
717
1835
  // src/subcommands/index.ts
718
1836
  var loaders = {
719
1837
  acp: async () => (await import("./acp-5ZLGFHWP.js")).acpCmd,
720
1838
  init: async () => (await import("./init-E2NDDOHI.js")).initCmd,
721
- auth: async () => (await import("./auth-L3WGSGDX.js")).authCmd,
1839
+ auth: async () => (await import("./auth-TVOOHL4Q.js")).authCmd,
722
1840
  update: async () => (await import("./update-VZSOZGYC.js")).updateCmd,
723
1841
  sessions: async () => (await import("./sessions-config-YX2ZPAFM.js")).sessionsCmd,
724
1842
  config: async () => (await import("./sessions-config-YX2ZPAFM.js")).configCmd,
@@ -727,23 +1845,23 @@ var loaders = {
727
1845
  audit: async () => (await import("./audit-BBR22QH3.js")).auditCmd,
728
1846
  tools: async () => (await import("./tools-skills-UNKLOB7M.js")).toolsCmd,
729
1847
  skills: async () => (await import("./tools-skills-UNKLOB7M.js")).skillsCmd,
730
- providers: async () => (await import("./providers-models-HQN3AT3K.js")).providersCmd,
731
- models: async () => (await import("./providers-models-HQN3AT3K.js")).modelsCmd,
732
- mcp: async () => (await import("./mcp-W7HHN7IA.js")).mcpCmd,
1848
+ providers: async () => (await import("./providers-models-4FAKM2WO.js")).providersCmd,
1849
+ models: async () => (await import("./providers-models-4FAKM2WO.js")).modelsCmd,
1850
+ mcp: async () => (await import("./mcp-CMLFHRG2.js")).mcpCmd,
733
1851
  plugin: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
734
1852
  plugins: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
735
1853
  diag: async () => (await import("./diag-doctor-WTBHPOMB.js")).diagCmd,
736
1854
  doctor: async () => (await import("./diag-doctor-WTBHPOMB.js")).doctorCmd,
737
1855
  export: async () => (await import("./export-CCUXRJOU.js")).exportCmd,
738
1856
  usage: async () => (await import("./plugin-usage-PTEETL3J.js")).usageCmd,
739
- version: async () => (await import("./version-help-ASKQYXDJ.js")).versionCmd,
740
- help: async () => (await import("./version-help-ASKQYXDJ.js")).helpCmd,
1857
+ version: async () => (await import("./version-help-TFD6VPF3.js")).versionCmd,
1858
+ help: async () => (await import("./version-help-TFD6VPF3.js")).helpCmd,
741
1859
  projects: async () => (await import("./projects-XE76NFNZ.js")).projectsCmd,
742
- modeldiag: async () => (await import("./modeldiag-6VS5KDP5.js")).modeldiagCmd,
1860
+ modeldiag: async () => (await import("./modeldiag-ICMPHT5L.js")).modeldiagCmd,
743
1861
  quick: async () => (await import("./quick-VIO2BEHS.js")).quickCmd,
744
1862
  bench: async () => (await import("./bench-XNDUJOSZ.js")).benchCmd,
745
1863
  chronicle: async () => (await import("./chronicle-63MFCZN6.js")).chronicleCmd,
746
- hq: async () => (await import("./hq-ZK6PGN3W.js")).hqCmd,
1864
+ hq: async () => (await import("./hq-PA6RH2UW.js")).hqCmd,
747
1865
  mailbox: async () => (await import("./mailbox-serve-V3QIJBDH.js")).mailboxServeCmd,
748
1866
  permissions: async () => (await import("./permissions-2PWBL4YU.js")).permissionsCmd,
749
1867
  project: async () => (await import("./project-BLQ3ALVL.js")).projectCmd,
@@ -763,16 +1881,28 @@ async function handleHelpVersionShortCircuit(argv) {
763
1881
  if (earlyFlags["help"] !== true && earlyFlags["version"] !== true) {
764
1882
  return null;
765
1883
  }
766
- if (earlyFlags["help"] === true && positional.length > 0 && subcommandNames.includes(positional[0])) {
767
- return null;
768
- }
769
1884
  const stubRenderer = {
770
1885
  write: (line) => {
771
1886
  process.stdout.write(line);
772
1887
  }
773
1888
  };
774
- const handler = earlyFlags["help"] === true ? helpCmd : versionCmd;
775
- return await handler([], { renderer: stubRenderer });
1889
+ if (earlyFlags["version"] === true) {
1890
+ return await versionCmd([], { renderer: stubRenderer });
1891
+ }
1892
+ if (earlyFlags["help"] === true) {
1893
+ if (positional.length > 0 && subcommandNames.includes(positional[0])) {
1894
+ const first = positional[0];
1895
+ const deep = positional[1];
1896
+ if (deep && renderDeepHelp(`${first}:${deep}`, stubRenderer)) {
1897
+ return 0;
1898
+ }
1899
+ if (renderFocusedHelp(first, stubRenderer)) {
1900
+ return 0;
1901
+ }
1902
+ }
1903
+ return await helpCmd([], { renderer: stubRenderer });
1904
+ }
1905
+ return null;
776
1906
  }
777
1907
 
778
1908
  // src/boot/short-circuit-hq.ts
@@ -783,7 +1913,7 @@ import {
783
1913
  readHqRuntimeFileSync,
784
1914
  resolveHqDataDir
785
1915
  } from "@wrongstack/core/hq";
786
- import { color as color3, isPidAlive } from "@wrongstack/core/utils";
1916
+ import { color as color6, isPidAlive } from "@wrongstack/core/utils";
787
1917
  async function isHqAlreadyRunning(dataDir) {
788
1918
  const marker = readHqRuntimeFileSync(dataDir);
789
1919
  if (!marker) return null;
@@ -808,12 +1938,12 @@ async function isPortInUse(host, port) {
808
1938
  }
809
1939
  async function handleHqShortCircuit(flags) {
810
1940
  if (flags["hq"] !== true) return null;
811
- const { startHqServer } = await import("./hq-server-IVZLVCFV.js");
1941
+ const { startHqServer } = await import("./hq-server-PBRU275L.js");
812
1942
  const tunnelRequested = flags["tunnel"] === true;
813
1943
  const host = typeof flags["host"] === "string" ? flags["host"] : tunnelRequested ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST2;
814
1944
  if (tunnelRequested && !isLoopbackHost(host)) {
815
1945
  process.stderr.write(
816
- `${color3.red("\u2717")} --tunnel requires a loopback origin. Remove --host or use --host 127.0.0.1.
1946
+ `${color6.red("\u2717")} --tunnel requires a loopback origin. Remove --host or use --host 127.0.0.1.
817
1947
  `
818
1948
  );
819
1949
  return 1;
@@ -824,7 +1954,7 @@ async function handleHqShortCircuit(flags) {
824
1954
  if (Number.isFinite(parsed) && parsed > 0 && parsed < 65536) {
825
1955
  port = parsed;
826
1956
  } else {
827
- process.stderr.write(`${color3.red("\u2717")} Invalid --port value: ${flags["port"]}
1957
+ process.stderr.write(`${color6.red("\u2717")} Invalid --port value: ${flags["port"]}
828
1958
  `);
829
1959
  return 1;
830
1960
  }
@@ -832,7 +1962,7 @@ async function handleHqShortCircuit(flags) {
832
1962
  const dataDir = typeof flags["data-dir"] === "string" ? flags["data-dir"] : void 0;
833
1963
  const password = typeof flags["password"] === "string" ? flags["password"] : process.env.WRONGSTACK_HQ_PASSWORD;
834
1964
  if (password !== void 0 && password.length < 8) {
835
- process.stderr.write(`${color3.red("\u2717")} HQ password must be at least 8 characters.
1965
+ process.stderr.write(`${color6.red("\u2717")} HQ password must be at least 8 characters.
836
1966
  `);
837
1967
  return 1;
838
1968
  }
@@ -841,14 +1971,14 @@ async function handleHqShortCircuit(flags) {
841
1971
  const existing = await isHqAlreadyRunning(resolvedDataDir);
842
1972
  if (existing) {
843
1973
  process.stderr.write(
844
- `${color3.red("\u2717")} HQ is already running at ${existing.url} (PID ${existing.pid}). Stop it first or use a different --data-dir.
1974
+ `${color6.red("\u2717")} HQ is already running at ${existing.url} (PID ${existing.pid}). Stop it first or use a different --data-dir.
845
1975
  `
846
1976
  );
847
1977
  return 1;
848
1978
  }
849
1979
  if (await isPortInUse(host, port)) {
850
1980
  process.stderr.write(
851
- `${color3.red("\u2717")} Port ${port} is already in use. Choose a different port or stop the process using it.
1981
+ `${color6.red("\u2717")} Port ${port} is already in use. Choose a different port or stop the process using it.
852
1982
  `
853
1983
  );
854
1984
  return 1;
@@ -859,7 +1989,7 @@ async function handleHqShortCircuit(flags) {
859
1989
  const { parseTokenTtlValue } = await import("./hq-ttl-U2FAYFAT.js");
860
1990
  const parsed = parseTokenTtlValue(rawTtl);
861
1991
  if (parsed.error) {
862
- process.stderr.write(`${color3.red("\u2717")} Invalid --hq-token-ttl: ${parsed.error}
1992
+ process.stderr.write(`${color6.red("\u2717")} Invalid --hq-token-ttl: ${parsed.error}
863
1993
  `);
864
1994
  return 1;
865
1995
  }
@@ -883,11 +2013,11 @@ async function handleHqShortCircuit(flags) {
883
2013
  const msg = err instanceof Error ? err.message : String(err);
884
2014
  if (err instanceof Error && "code" in err && err.code === "EADDRINUSE") {
885
2015
  process.stderr.write(
886
- `${color3.red("\u2717")} Port ${port} is already in use. Please choose a different port.
2016
+ `${color6.red("\u2717")} Port ${port} is already in use. Please choose a different port.
887
2017
  `
888
2018
  );
889
2019
  } else {
890
- process.stderr.write(`${color3.red("\u2717")} Failed to start HQ server: ${msg}
2020
+ process.stderr.write(`${color6.red("\u2717")} Failed to start HQ server: ${msg}
891
2021
  `);
892
2022
  }
893
2023
  return 1;
@@ -898,7 +2028,7 @@ async function handleHqShortCircuit(flags) {
898
2028
  if (handle.firstRunSetup !== void 0 && !handle.firstRunSetup.browserTokenMode && !handle.firstRunSetup.passwordMode) {
899
2029
  await handle.close();
900
2030
  process.stderr.write(
901
- `${color3.red("\u2717")} Refusing to publish HQ in open mode. Set --password or create a browser token first.
2031
+ `${color6.red("\u2717")} Refusing to publish HQ in open mode. Set --password or create a browser token first.
902
2032
  `
903
2033
  );
904
2034
  return 1;
@@ -907,7 +2037,7 @@ async function handleHqShortCircuit(flags) {
907
2037
  const { buildPublicHqUrl, startHqQuickTunnel } = await import("./hq-tunnel-RFKGC4HI.js");
908
2038
  const originHost = handle.host === "::1" ? "[::1]" : handle.host;
909
2039
  tunnel = await startHqQuickTunnel(`http://${originHost}:${handle.port}`, {
910
- onUnexpectedExit: (message) => process.stderr.write(`${color3.yellow("!")} ${message}
2040
+ onUnexpectedExit: (message) => process.stderr.write(`${color6.yellow("!")} ${message}
911
2041
  `)
912
2042
  });
913
2043
  handle.trustPublicOrigin(new URL(tunnel.url).origin);
@@ -917,16 +2047,16 @@ async function handleHqShortCircuit(flags) {
917
2047
  handle.firstRunSetup?.passwordMode !== true
918
2048
  );
919
2049
  process.stdout.write(`
920
- ${color3.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
2050
+ ${color6.green("Cloudflare Quick Tunnel ready:")} ${browserUrl}
921
2051
  `);
922
2052
  process.stdout.write(
923
- `${color3.dim("Temporary development URL; DNS may need a few seconds, it changes on restart and ends when HQ stops.")}
2053
+ `${color6.dim("Temporary development URL; DNS may need a few seconds, it changes on restart and ends when HQ stops.")}
924
2054
  `
925
2055
  );
926
2056
  } catch (err) {
927
2057
  await handle.close();
928
2058
  process.stderr.write(
929
- `${color3.red("\u2717")} Failed to start Cloudflare Quick Tunnel: ${err instanceof Error ? err.message : String(err)}
2059
+ `${color6.red("\u2717")} Failed to start Cloudflare Quick Tunnel: ${err instanceof Error ? err.message : String(err)}
930
2060
  `
931
2061
  );
932
2062
  return 1;
@@ -978,14 +2108,14 @@ import { TOKENS as TOKENS2 } from "@wrongstack/core/kernel";
978
2108
  import { DefaultModelsRegistry } from "@wrongstack/core/models";
979
2109
  import { ToolRegistry } from "@wrongstack/core/registry";
980
2110
  import { normalizeTokenSavingTier } from "@wrongstack/core/types";
981
- import { color as color10, isStdinTTY as isStdinTTY2, writeErr } from "@wrongstack/core/utils";
2111
+ import { color as color13, isStdinTTY as isStdinTTY2, writeErr } from "@wrongstack/core/utils";
982
2112
  import { createDefaultContainer as createDefaultContainer2 } from "@wrongstack/runtime";
983
2113
  import { registerBuiltinToolTier } from "@wrongstack/tools/tool-tier";
984
2114
 
985
2115
  // src/boot/config-backup-recovery.ts
986
2116
  import * as fs2 from "node:fs/promises";
987
2117
  import * as path4 from "node:path";
988
- import { atomicWrite as atomicWrite2, backupConfigFile, color as color4, toErrorMessage } from "@wrongstack/core/utils";
2118
+ import { atomicWrite as atomicWrite2, backupConfigFile, color as color7, toErrorMessage } from "@wrongstack/core/utils";
989
2119
  function isRecord(value) {
990
2120
  return value !== null && typeof value === "object" && !Array.isArray(value);
991
2121
  }
@@ -1069,12 +2199,12 @@ async function maybeRestoreDefaultProfileFromBackup(opts) {
1069
2199
  const providerSummary = remainder > 0 ? `${shownProviders} +${remainder}` : shownProviders;
1070
2200
  opts.renderer.write(
1071
2201
  `
1072
- ${color4.amber("\u25CB")} ${color4.bold("default")} profile has no saved providers.
1073
- ${color4.dim("Latest usable backup:")} ${color4.bold(backup.fileName)} ${color4.dim(`(${backup.providerIds.length} provider: ${providerSummary})`)}
2202
+ ${color7.amber("\u25CB")} ${color7.bold("default")} profile has no saved providers.
2203
+ ${color7.dim("Latest usable backup:")} ${color7.bold(backup.fileName)} ${color7.dim(`(${backup.providerIds.length} provider: ${providerSummary})`)}
1074
2204
  `
1075
2205
  );
1076
2206
  const answer = (await opts.reader.readLine(
1077
- ` ${color4.amber("?")} Restore all settings from this backup? ${color4.dim("[Y/n]")} `
2207
+ ` ${color7.amber("?")} Restore all settings from this backup? ${color7.dim("[Y/n]")} `
1078
2208
  )).trim().toLowerCase();
1079
2209
  if (answer === "n" || answer === "no") return false;
1080
2210
  try {
@@ -1084,7 +2214,7 @@ async function maybeRestoreDefaultProfileFromBackup(opts) {
1084
2214
  profilePath: opts.profilePath
1085
2215
  });
1086
2216
  opts.renderer.write(
1087
- ` ${color4.green("\u2713")} Restored all settings from ${color4.dim(backup.fileName)}
2217
+ ` ${color7.green("\u2713")} Restored all settings from ${color7.dim(backup.fileName)}
1088
2218
  `
1089
2219
  );
1090
2220
  return true;
@@ -1101,11 +2231,11 @@ import {
1101
2231
  buildIdentityLayer,
1102
2232
  loadInstructionBundle
1103
2233
  } from "@wrongstack/core/agent";
1104
- import { atomicWrite as atomicWrite4, color as color7, estimateTextTokens } from "@wrongstack/core/utils";
2234
+ import { atomicWrite as atomicWrite4, color as color10, estimateTextTokens } from "@wrongstack/core/utils";
1105
2235
 
1106
2236
  // src/pre-launch/launch-prompts.ts
1107
2237
  import * as fs3 from "node:fs/promises";
1108
- import { atomicWrite as atomicWrite3, color as color5 } from "@wrongstack/core/utils";
2238
+ import { atomicWrite as atomicWrite3, color as color8 } from "@wrongstack/core/utils";
1109
2239
  var LaunchAbortedError = class extends Error {
1110
2240
  exitCode = 0;
1111
2241
  constructor() {
@@ -1136,19 +2266,19 @@ async function runLaunchPrompts(opts) {
1136
2266
  yolo: yoloPinned ?? lastChoices.yolo,
1137
2267
  autonomy: autonomyPinned ?? lastChoices.autonomy
1138
2268
  };
1139
- const onOff = (v) => v ? color5.green("on") : color5.dim("off");
2269
+ const onOff = (v) => v ? color8.green("on") : color8.dim("off");
1140
2270
  const modeLabel = effective.mode.toUpperCase();
1141
2271
  renderer.write(
1142
2272
  `
1143
- ${color5.dim("Last settings:")} ${color5.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color5.green("auto") : color5.dim("off")}
2273
+ ${color8.dim("Last settings:")} ${color8.bold(modeLabel)} \xB7 YOLO ${onOff(effective.yolo)} \xB7 Autonomy ${effective.autonomy === "auto" ? color8.green("auto") : color8.dim("off")}
1144
2274
  `
1145
2275
  );
1146
2276
  const answer = (await reader.readLine(
1147
- ` ${color5.amber("?")} Continue with these? ${color5.dim("[Y/n/q]")} ${color5.dim("(auto Y in 5s)")} `,
2277
+ ` ${color8.amber("?")} Continue with these? ${color8.dim("[Y/n/q]")} ${color8.dim("(auto Y in 5s)")} `,
1148
2278
  { timeoutMs: 5e3, defaultAnswer: "y" }
1149
2279
  )).trim().toLowerCase();
1150
2280
  if (answer === "q") {
1151
- renderer.write(color5.dim(" Goodbye!\n"));
2281
+ renderer.write(color8.dim(" Goodbye!\n"));
1152
2282
  throw new LaunchAbortedError();
1153
2283
  }
1154
2284
  if (answer !== "n" && answer !== "no") {
@@ -1156,7 +2286,7 @@ async function runLaunchPrompts(opts) {
1156
2286
  const badgeStr2 = badges2.length > 0 ? ` (${badges2.join(" \xB7 ")})` : "";
1157
2287
  renderer.write(
1158
2288
  `
1159
- ${color5.green("\u25B6")} Launching in ${color5.bold(modeLabel)} mode${badgeStr2}
2289
+ ${color8.green("\u25B6")} Launching in ${color8.bold(modeLabel)} mode${badgeStr2}
1160
2290
 
1161
2291
  `
1162
2292
  );
@@ -1169,10 +2299,10 @@ async function runLaunchPrompts(opts) {
1169
2299
  } else {
1170
2300
  const answer = (await reader.readLine(
1171
2301
  `
1172
- ${color5.amber("?")} Interactive mode: ${color5.bold("T")}UI / ${color5.bold("R")}EPL ${color5.dim("[T/r/q]")} `
2302
+ ${color8.amber("?")} Interactive mode: ${color8.bold("T")}UI / ${color8.bold("R")}EPL ${color8.dim("[T/r/q]")} `
1173
2303
  )).trim().toLowerCase();
1174
2304
  if (answer === "q") {
1175
- renderer.write(color5.dim(" Goodbye!\n"));
2305
+ renderer.write(color8.dim(" Goodbye!\n"));
1176
2306
  throw new LaunchAbortedError();
1177
2307
  }
1178
2308
  mode = answer === "r" || answer === "repl" ? "repl" : "tui";
@@ -1182,10 +2312,10 @@ async function runLaunchPrompts(opts) {
1182
2312
  yolo = yoloPinned;
1183
2313
  } else {
1184
2314
  const answer = (await reader.readLine(
1185
- ` ${color5.amber("?")} YOLO mode ${color5.dim("(auto-approve tool calls)")} ${color5.dim("[Y/n/q]")} `
2315
+ ` ${color8.amber("?")} YOLO mode ${color8.dim("(auto-approve tool calls)")} ${color8.dim("[Y/n/q]")} `
1186
2316
  )).trim().toLowerCase();
1187
2317
  if (answer === "q") {
1188
- renderer.write(color5.dim(" Goodbye!\n"));
2318
+ renderer.write(color8.dim(" Goodbye!\n"));
1189
2319
  throw new LaunchAbortedError();
1190
2320
  }
1191
2321
  yolo = answer !== "n" && answer !== "no";
@@ -1195,10 +2325,10 @@ async function runLaunchPrompts(opts) {
1195
2325
  autonomy = autonomyPinned;
1196
2326
  } else {
1197
2327
  const answer = (await reader.readLine(
1198
- ` ${color5.amber("?")} Autonomy mode ${color5.dim("(auto-continue \u2014 agent picks next step)")} ${color5.dim("[Y/n/q]")} `
2328
+ ` ${color8.amber("?")} Autonomy mode ${color8.dim("(auto-continue \u2014 agent picks next step)")} ${color8.dim("[Y/n/q]")} `
1199
2329
  )).trim().toLowerCase();
1200
2330
  if (answer === "q") {
1201
- renderer.write(color5.dim(" Goodbye!\n"));
2331
+ renderer.write(color8.dim(" Goodbye!\n"));
1202
2332
  throw new LaunchAbortedError();
1203
2333
  }
1204
2334
  autonomy = answer !== "n" && answer !== "no" ? "auto" : "off";
@@ -1207,7 +2337,7 @@ async function runLaunchPrompts(opts) {
1207
2337
  const badgeStr = badges.length > 0 ? ` (${badges.join(" \xB7 ")})` : "";
1208
2338
  renderer.write(
1209
2339
  `
1210
- ${color5.green("\u25B6")} Launching in ${color5.bold(mode.toUpperCase())} mode${badgeStr}
2340
+ ${color8.green("\u25B6")} Launching in ${color8.bold(mode.toUpperCase())} mode${badgeStr}
1211
2341
 
1212
2342
  `
1213
2343
  );
@@ -1215,9 +2345,9 @@ async function runLaunchPrompts(opts) {
1215
2345
  }
1216
2346
  function buildBadges(chosen) {
1217
2347
  const badges = [];
1218
- if (chosen.yolo) badges.push(color5.yellow("YOLO"));
2348
+ if (chosen.yolo) badges.push(color8.yellow("YOLO"));
1219
2349
  if (chosen.autonomy !== "off")
1220
- badges.push(color5.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
2350
+ badges.push(color8.magenta(`AUTONOMY:${chosen.autonomy.toUpperCase()}`));
1221
2351
  return badges;
1222
2352
  }
1223
2353
  async function persistLaunchChoices(configPath, choices) {
@@ -1251,7 +2381,7 @@ async function persistLaunchChoices(configPath, choices) {
1251
2381
  // src/pre-launch/project-check.ts
1252
2382
  import * as fs4 from "node:fs/promises";
1253
2383
  import * as path5 from "node:path";
1254
- import { color as color6, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
2384
+ import { color as color9, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
1255
2385
  var MANIFESTS = [
1256
2386
  "package.json",
1257
2387
  "pyproject.toml",
@@ -1294,7 +2424,7 @@ async function runProjectCheck(opts) {
1294
2424
  if (kind === "initialized") {
1295
2425
  renderer.write(
1296
2426
  `
1297
- ${color6.green("\u2713")} Project initialized ${color6.dim(`(${path5.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
2427
+ ${color9.green("\u2713")} Project initialized ${color9.dim(`(${path5.join(projectRoot, ".wrongstack", "AGENTS.md")})`)}
1298
2428
  `
1299
2429
  );
1300
2430
  return true;
@@ -1302,20 +2432,20 @@ async function runProjectCheck(opts) {
1302
2432
  if (kind === "project") {
1303
2433
  renderer.write(
1304
2434
  `
1305
- ${color6.amber("\u25CF")} Project detected ${color6.dim(`(${projectRoot})`)} but ${color6.bold(".wrongstack/AGENTS.md")} is missing.
2435
+ ${color9.amber("\u25CF")} Project detected ${color9.dim(`(${projectRoot})`)} but ${color9.bold(".wrongstack/AGENTS.md")} is missing.
1306
2436
  `
1307
2437
  );
1308
2438
  const answer2 = (await reader.readLine(
1309
- ` ${color6.amber("?")} Scaffold ${color6.bold("AGENTS.md")} now? ${color6.dim("[y/N/q]")} `
2439
+ ` ${color9.amber("?")} Scaffold ${color9.bold("AGENTS.md")} now? ${color9.dim("[y/N/q]")} `
1310
2440
  )).trim().toLowerCase();
1311
2441
  if (answer2 === "q") {
1312
- renderer.write(color6.dim(" Cancelled.\n"));
2442
+ renderer.write(color9.dim(" Cancelled.\n"));
1313
2443
  return false;
1314
2444
  }
1315
2445
  if (answer2 === "y" || answer2 === "yes") {
1316
2446
  try {
1317
2447
  const file = await scaffoldAgentsMd(projectRoot);
1318
- renderer.write(` ${color6.green("\u2713")} Wrote ${color6.dim(file)}
2448
+ renderer.write(` ${color9.green("\u2713")} Wrote ${color9.dim(file)}
1319
2449
  `);
1320
2450
  } catch (err) {
1321
2451
  renderer.writeError(`Failed to scaffold AGENTS.md: ${toErrorMessage2(err)}`);
@@ -1333,14 +2463,14 @@ async function runProjectCheck(opts) {
1333
2463
  if (!hasGit) {
1334
2464
  renderer.write(
1335
2465
  `
1336
- ${color6.dim("\u25CB")} ${color6.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
2466
+ ${color9.dim("\u25CB")} ${color9.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1337
2467
  `
1338
2468
  );
1339
2469
  const answer2 = (await reader.readLine(
1340
- ` ${color6.amber("?")} No git repo found. ${color6.bold("Initialize git?")} ${color6.dim("[y/N/q]")} `
2470
+ ` ${color9.amber("?")} No git repo found. ${color9.bold("Initialize git?")} ${color9.dim("[y/N/q]")} `
1341
2471
  )).trim().toLowerCase();
1342
2472
  if (answer2 === "q") {
1343
- renderer.write(color6.dim(" Cancelled.\n"));
2473
+ renderer.write(color9.dim(" Cancelled.\n"));
1344
2474
  return false;
1345
2475
  }
1346
2476
  if (answer2 === "y" || answer2 === "yes") {
@@ -1358,7 +2488,7 @@ async function runProjectCheck(opts) {
1358
2488
  (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
1359
2489
  );
1360
2490
  });
1361
- renderer.write(` ${color6.green("\u2713")} Git repository initialized
2491
+ renderer.write(` ${color9.green("\u2713")} Git repository initialized
1362
2492
  `);
1363
2493
  } catch (err) {
1364
2494
  renderer.writeError(`git init failed: ${toErrorMessage2(err)}
@@ -1368,13 +2498,13 @@ async function runProjectCheck(opts) {
1368
2498
  } else {
1369
2499
  renderer.write(
1370
2500
  `
1371
- ${color6.dim("\u25CB")} ${color6.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
2501
+ ${color9.dim("\u25CB")} ${color9.dim(`No project manifest in ${projectRoot} \u2014 running in a scratch directory.`)}
1372
2502
  `
1373
2503
  );
1374
2504
  }
1375
- const answer = (await reader.readLine(` ${color6.amber("?")} Continue anyway? ${color6.dim("[Y/n/q]")} `)).trim().toLowerCase();
2505
+ const answer = (await reader.readLine(` ${color9.amber("?")} Continue anyway? ${color9.dim("[Y/n/q]")} `)).trim().toLowerCase();
1376
2506
  if (answer === "q" || answer === "n" || answer === "no") {
1377
- renderer.write(color6.dim(" Cancelled.\n"));
2507
+ renderer.write(color9.dim(" Cancelled.\n"));
1378
2508
  return false;
1379
2509
  }
1380
2510
  return true;
@@ -1447,28 +2577,28 @@ async function runSystemPromptMenu(deps) {
1447
2577
  const defaultVariant = lastVariant ?? "default";
1448
2578
  if (lastVariant) {
1449
2579
  const answer2 = (await reader.readLine(
1450
- ` ${color7.amber("?")} Continue with ${color7.bold(labelFor(lastVariant))} system prompt ${color7.dim(`(~${fmtTok(tokens[lastVariant])} tokens)`)}? ${color7.dim("[Y/n/q]")} ${color7.dim("(auto Y in 5s)")} `,
2580
+ ` ${color10.amber("?")} Continue with ${color10.bold(labelFor(lastVariant))} system prompt ${color10.dim(`(~${fmtTok(tokens[lastVariant])} tokens)`)}? ${color10.dim("[Y/n/q]")} ${color10.dim("(auto Y in 5s)")} `,
1451
2581
  { timeoutMs: SUMMARY_TIMEOUT_MS2, defaultAnswer: "y" }
1452
2582
  )).trim().toLowerCase();
1453
2583
  if (answer2 === "q" || answer2 === "quit") throw new LaunchAbortedError();
1454
2584
  if (answer2 !== "n" && answer2 !== "no") return lastVariant;
1455
2585
  }
1456
2586
  renderer.write(`
1457
- ${color7.amber("?")} System prompt:
2587
+ ${color10.amber("?")} System prompt:
1458
2588
  `);
1459
2589
  for (const [index, opt] of SYSTEM_PROMPT_OPTIONS.entries()) {
1460
2590
  const num2 = index + 1;
1461
2591
  const isDefault = opt.variant === defaultVariant;
1462
- const marker = isDefault ? color7.cyan("\u25CF") : color7.dim("\u25CB");
1463
- const label = isDefault ? color7.bold(opt.label) : opt.label;
2592
+ const marker = isDefault ? color10.cyan("\u25CF") : color10.dim("\u25CB");
2593
+ const label = isDefault ? color10.bold(opt.label) : opt.label;
1464
2594
  renderer.write(
1465
- ` ${color7.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color7.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color7.dim(opt.hint)}
2595
+ ` ${color10.dim(`${num2}.`)} ${marker} ${label.padEnd(9)} ${color10.dim(`~${fmtTok(tokens[opt.variant])} tokens`)} ${color10.dim(opt.hint)}
1466
2596
  `
1467
2597
  );
1468
2598
  }
1469
2599
  const answer = (await reader.readLine(
1470
2600
  `
1471
- ${color7.amber("?")} Select system prompt ${color7.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
2601
+ ${color10.amber("?")} Select system prompt ${color10.dim(`[1-${SYSTEM_PROMPT_OPTIONS.length}, Enter = ${labelFor(defaultVariant)}, q to quit]`)}: `
1472
2602
  )).trim().toLowerCase();
1473
2603
  if (answer === "q" || answer === "quit") throw new LaunchAbortedError();
1474
2604
  if (!answer) return defaultVariant;
@@ -1828,7 +2958,7 @@ function dim(s) {
1828
2958
  // src/launch-hints.ts
1829
2959
  import * as fs7 from "node:fs/promises";
1830
2960
  import * as path7 from "node:path";
1831
- import { color as color8 } from "@wrongstack/core/utils";
2961
+ import { color as color11 } from "@wrongstack/core/utils";
1832
2962
  var GROUPS = [
1833
2963
  {
1834
2964
  title: "Autonomy",
@@ -1988,7 +3118,7 @@ function wrapWords(value, firstWidth, continuationWidth = firstWidth) {
1988
3118
  function renderHintLines(item, termWidth) {
1989
3119
  const inline = `${HINT_INDENT}${item.key} \u2014 ${item.blurb}`;
1990
3120
  if (displayWidth(inline) <= termWidth) {
1991
- return [`${HINT_INDENT}${color8.bold(item.key)} ${color8.dim("\u2014")} ${color8.dim(item.blurb)}`];
3121
+ return [`${HINT_INDENT}${color11.bold(item.key)} ${color11.dim("\u2014")} ${color11.dim(item.blurb)}`];
1992
3122
  }
1993
3123
  const lines = [];
1994
3124
  const keyLines = wrapWords(
@@ -1998,13 +3128,13 @@ function renderHintLines(item, termWidth) {
1998
3128
  );
1999
3129
  keyLines.forEach((line, index) => {
2000
3130
  const indent = index === 0 ? HINT_INDENT : HINT_CONTINUATION_INDENT;
2001
- lines.push(`${indent}${color8.bold(line)}`);
3131
+ lines.push(`${indent}${color11.bold(line)}`);
2002
3132
  });
2003
3133
  const blurbLines = wrapWords(
2004
3134
  `\u2014 ${item.blurb}`,
2005
3135
  termWidth - displayWidth(HINT_CONTINUATION_INDENT)
2006
3136
  );
2007
- for (const line of blurbLines) lines.push(`${HINT_CONTINUATION_INDENT}${color8.dim(line)}`);
3137
+ for (const line of blurbLines) lines.push(`${HINT_CONTINUATION_INDENT}${color11.dim(line)}`);
2008
3138
  return lines;
2009
3139
  }
2010
3140
  function renderHeaderLines(group, groupIndex, termWidth) {
@@ -2012,24 +3142,24 @@ function renderHeaderLines(group, groupIndex, termWidth) {
2012
3142
  const plain = ` ${group.title} ${progress}`;
2013
3143
  if (displayWidth(plain) <= termWidth) {
2014
3144
  return [
2015
- ` ${color8.cyan("\u25C7")} ${color8.bold(group.title)} ${color8.dim(progress)}`,
2016
- ` ${color8.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`
3145
+ ` ${color11.cyan("\u25C7")} ${color11.bold(group.title)} ${color11.dim(progress)}`,
3146
+ ` ${color11.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`
2017
3147
  ];
2018
3148
  }
2019
3149
  return [
2020
- ` ${color8.cyan("\u25C7")} ${color8.bold(group.title)}`,
2021
- ` ${color8.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`
3150
+ ` ${color11.cyan("\u25C7")} ${color11.bold(group.title)}`,
3151
+ ` ${color11.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`
2022
3152
  ];
2023
3153
  }
2024
3154
  function renderFooterLines(termWidth) {
2025
3155
  const footer = "/help lists everything \xB7 hide with --no-hints";
2026
3156
  if (displayWidth(` ${footer}`) <= termWidth) {
2027
3157
  return [
2028
- ` ${color8.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`,
2029
- ` ${color8.dim(`${color8.bold("/help")} lists everything \xB7 hide with ${color8.bold("--no-hints")}`)}`
3158
+ ` ${color11.dim("\u2500".repeat(Math.min(termWidth - 2, 48)))}`,
3159
+ ` ${color11.dim(`${color11.bold("/help")} lists everything \xB7 hide with ${color11.bold("--no-hints")}`)}`
2030
3160
  ];
2031
3161
  }
2032
- return [...wrapWords(footer, termWidth - 2).map((line) => ` ${color8.dim(line)}`)];
3162
+ return [...wrapWords(footer, termWidth - 2).map((line) => ` ${color11.dim(line)}`)];
2033
3163
  }
2034
3164
  async function pickGroupIndex(opts) {
2035
3165
  if (typeof opts.groupIndex === "number") return wrap(opts.groupIndex);
@@ -2071,7 +3201,7 @@ async function printLaunchHints(renderer, flags, opts = {}) {
2071
3201
  }
2072
3202
 
2073
3203
  // src/renderer.ts
2074
- import { color as color9 } from "@wrongstack/core/utils";
3204
+ import { color as color12 } from "@wrongstack/core/utils";
2075
3205
  var TerminalRenderer = class _TerminalRenderer {
2076
3206
  out;
2077
3207
  err;
@@ -2184,7 +3314,7 @@ var TerminalRenderer = class _TerminalRenderer {
2184
3314
  if (!this.lineStart) this.out.write("\n");
2185
3315
  const arrow = theme.primary("\u2192");
2186
3316
  const display = formatInputSummary(input);
2187
- this.out.write(`${arrow} ${theme.bold(name)}${display ? color9.dim(` ${display}`) : ""}
3317
+ this.out.write(`${arrow} ${theme.bold(name)}${display ? color12.dim(` ${display}`) : ""}
2188
3318
  `);
2189
3319
  this.lineStart = true;
2190
3320
  }
@@ -2201,7 +3331,7 @@ var TerminalRenderer = class _TerminalRenderer {
2201
3331
  if (isError) {
2202
3332
  const firstLine = txt.split("\n")[0] ?? "";
2203
3333
  const truncated = firstLine.length > 200 ? `${firstLine.slice(0, 197)}\u2026` : firstLine;
2204
- this.out.write(` ${prefix} ${color9.dim(truncated)}
3334
+ this.out.write(` ${prefix} ${color12.dim(truncated)}
2205
3335
  `);
2206
3336
  this.lineStart = true;
2207
3337
  return;
@@ -2209,7 +3339,7 @@ var TerminalRenderer = class _TerminalRenderer {
2209
3339
  const isEditLike = name === "edit" || name === "write";
2210
3340
  const diff = extractDiff(content);
2211
3341
  if (isEditLike && diff) {
2212
- this.out.write(` ${prefix} ${color9.dim(summarize(content, name))}
3342
+ this.out.write(` ${prefix} ${color12.dim(summarize(content, name))}
2213
3343
  `);
2214
3344
  const rendered = renderDiff(diff).split("\n").map((l) => ` ${l}`).join("\n");
2215
3345
  this.out.write(`${rendered}
@@ -2220,7 +3350,7 @@ var TerminalRenderer = class _TerminalRenderer {
2220
3350
  const summary = summarize(content, name);
2221
3351
  const isReadLike = name === "read" || name === "grep" || name === "glob" || name === "bash" || name === "exec";
2222
3352
  if (renderMode === "simple") {
2223
- this.out.write(` ${prefix} ${color9.dim(summary || compactSingleLine(bodyText))}
3353
+ this.out.write(` ${prefix} ${color12.dim(summary || compactSingleLine(bodyText))}
2224
3354
  `);
2225
3355
  this.lineStart = true;
2226
3356
  return;
@@ -2229,16 +3359,16 @@ var TerminalRenderer = class _TerminalRenderer {
2229
3359
  const lines = bodyText.split("\n");
2230
3360
  const head = lines.slice(0, previewLines).map((l) => l.replace(/\s+$/, ""));
2231
3361
  const moreCount = Math.max(0, lines.length - head.length);
2232
- this.out.write(` ${prefix} ${color9.dim(summary)}
3362
+ this.out.write(` ${prefix} ${color12.dim(summary)}
2233
3363
  `);
2234
3364
  for (const l of head) {
2235
3365
  const capped = l.length > 200 ? `${l.slice(0, 197)}\u2026` : l;
2236
- this.out.write(` ${color9.dim(capped)}
3366
+ this.out.write(` ${color12.dim(capped)}
2237
3367
  `);
2238
3368
  }
2239
3369
  if (moreCount > 0) {
2240
3370
  this.out.write(
2241
- ` ${color9.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
3371
+ ` ${color12.dim(`+${moreCount} more line${moreCount === 1 ? "" : "s"}`)}
2242
3372
  `
2243
3373
  );
2244
3374
  }
@@ -2358,7 +3488,7 @@ function renderMarkdown(s) {
2358
3488
  return theme.primary(theme.bold(`${hashes} ${text}`));
2359
3489
  });
2360
3490
  out = out.replace(/```([a-zA-Z0-9_+-]*)\n([\s\S]*?)```/g, (_m, _lang, code) => {
2361
- return color9.gray(`
3491
+ return color12.gray(`
2362
3492
  \u250C\u2500
2363
3493
  ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2364
3494
  });
@@ -2366,7 +3496,7 @@ ${code.replace(/^/gm, "\u2502 ")}\u2514\u2500`);
2366
3496
  out = out.replace(/\*\*([^*]+)\*\*/g, (_m, text) => theme.bold(text));
2367
3497
  out = out.replace(
2368
3498
  /(^|[^*])\*([^*\n]+)\*([^*]|$)/g,
2369
- (_m, l, t, r) => `${l}${color9.italic(t)}${r}`
3499
+ (_m, l, t, r) => `${l}${color12.italic(t)}${r}`
2370
3500
  );
2371
3501
  return out;
2372
3502
  }
@@ -2708,6 +3838,17 @@ async function boot(argv) {
2708
3838
  });
2709
3839
  const subcommandHandler = first ? subcommands[first] : void 0;
2710
3840
  if (first && subcommandHandler) {
3841
+ if (flags["help"] === true || flags["h"] === true) {
3842
+ const deepSub = positional[1];
3843
+ if (deepSub && renderDeepHelp(`${first}:${deepSub}`, renderer)) {
3844
+ await reader.close();
3845
+ return 0;
3846
+ }
3847
+ if (renderFocusedHelp(first, renderer)) {
3848
+ await reader.close();
3849
+ return 0;
3850
+ }
3851
+ }
2711
3852
  const container = createDefaultContainer2({
2712
3853
  config,
2713
3854
  wpaths,
@@ -2744,8 +3885,8 @@ async function boot(argv) {
2744
3885
  if (isHomeDirectory(cwd, userHome)) {
2745
3886
  writeErr(
2746
3887
  `
2747
- ${color10.red(color10.bold("\u26A0 This is not a working directory."))}
2748
- ${color10.red("Please open wstack in a project folder.")}
3888
+ ${color13.red(color13.bold("\u26A0 This is not a working directory."))}
3889
+ ${color13.red("Please open wstack in a project folder.")}
2749
3890
 
2750
3891
  `
2751
3892
  );
@@ -2793,8 +3934,12 @@ async function boot(argv) {
2793
3934
  const modelFlag = typeof flags["model"] === "string" ? flags["model"] : void 0;
2794
3935
  const noInteractiveMode = flags["webui"] || flags["no-interactive"];
2795
3936
  if (noInteractiveMode && (!config.provider || !config.model)) {
2796
- const picked = await autoSelectSavedProvider(config, modelsRegistry);
2797
- if (picked) config = patchConfig(config, picked);
3937
+ if (providerFlag && modelFlag) {
3938
+ config = patchConfig(config, { provider: providerFlag, model: modelFlag });
3939
+ } else {
3940
+ const picked = await autoSelectSavedProvider(config, modelsRegistry);
3941
+ if (picked) config = patchConfig(config, picked);
3942
+ }
2798
3943
  }
2799
3944
  if (!(!!providerFlag && !!modelFlag)) {
2800
3945
  if (isStdinTTY2() && !noInteractiveMode) {
@@ -2806,7 +3951,7 @@ async function boot(argv) {
2806
3951
  const savedStatus = await validateSavedProviderModel(config, modelsRegistry);
2807
3952
  renderer.write(
2808
3953
  `
2809
- ${color10.dim("Last settings:")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3954
+ ${color13.dim("Last settings:")} ${color13.bold(savedProvider)} / ${color13.bold(savedModel)}
2810
3955
  `
2811
3956
  );
2812
3957
  if (!savedStatus.ok) {
@@ -2816,11 +3961,11 @@ async function boot(argv) {
2816
3961
  );
2817
3962
  } else {
2818
3963
  const answer = (await reader.readLine(
2819
- ` ${color10.amber("?")} Continue with these? ${color10.dim("[Y/n/q]")} ${color10.dim("(auto Y in 5s)")} `,
3964
+ ` ${color13.amber("?")} Continue with these? ${color13.dim("[Y/n/q]")} ${color13.dim("(auto Y in 5s)")} `,
2820
3965
  { timeoutMs: 5e3, defaultAnswer: "y" }
2821
3966
  )).trim().toLowerCase();
2822
3967
  if (answer === "q") {
2823
- renderer.write(color10.dim(" Goodbye!\n"));
3968
+ renderer.write(color13.dim(" Goodbye!\n"));
2824
3969
  await reader.close();
2825
3970
  return 0;
2826
3971
  }
@@ -2828,7 +3973,7 @@ async function boot(argv) {
2828
3973
  skipPicker = true;
2829
3974
  renderer.write(
2830
3975
  `
2831
- ${color10.green("\u25B6")} ${color10.bold(savedProvider)} / ${color10.bold(savedModel)}
3976
+ ${color13.green("\u25B6")} ${color13.bold(savedProvider)} / ${color13.bold(savedModel)}
2832
3977
 
2833
3978
  `
2834
3979
  );
@@ -2963,8 +4108,8 @@ async function boot(argv) {
2963
4108
  if (shouldPrintYoloNotice(lastChoices, yoloPinned, choices.yolo)) {
2964
4109
  writeErr(
2965
4110
  `
2966
- ${color10.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
2967
- ${color10.dim("Explicit deny rules still apply. Use")} --no-yolo ${color10.dim("or")} /yolo off ${color10.dim("to require prompts.")}
4111
+ ${color13.yellow("YOLO is on")}: non-denied tool calls, including shell and file writes, run without confirmation.
4112
+ ${color13.dim("Explicit deny rules still apply. Use")} --no-yolo ${color13.dim("or")} /yolo off ${color13.dim("to require prompts.")}
2968
4113
 
2969
4114
  `
2970
4115
  );
@@ -3030,10 +4175,10 @@ async function checkGitInCwd(opts) {
3030
4175
  if (!hasCwdGit) {
3031
4176
  renderer.write(
3032
4177
  `
3033
- ${color10.amber("\u25CB")} This folder has no ${color10.bold(".git")} repository.
4178
+ ${color13.amber("\u25CB")} This folder has no ${color13.bold(".git")} repository.
3034
4179
  `
3035
4180
  );
3036
- const answer = (await reader.readLine(` ${color10.amber("?")} Initialize one here? ${color10.dim("[y/N]")} `)).trim().toLowerCase();
4181
+ const answer = (await reader.readLine(` ${color13.amber("?")} Initialize one here? ${color13.dim("[y/N]")} `)).trim().toLowerCase();
3037
4182
  if (answer === "y" || answer === "yes") {
3038
4183
  try {
3039
4184
  const { spawn: spawn2 } = await import("node:child_process");
@@ -3049,7 +4194,7 @@ async function checkGitInCwd(opts) {
3049
4194
  (code) => code === 0 ? resolve2() : reject(new Error(`git init failed with ${code}`))
3050
4195
  );
3051
4196
  });
3052
- renderer.write(` ${color10.green("\u2713")} Git repository initialized
4197
+ renderer.write(` ${color13.green("\u2713")} Git repository initialized
3053
4198
  `);
3054
4199
  hasCwdGit = true;
3055
4200
  } catch (err) {
@@ -3063,7 +4208,7 @@ async function checkGitInCwd(opts) {
3063
4208
  try {
3064
4209
  await fs8.access(path8.join(parentDir, ".git"));
3065
4210
  renderer.write(
3066
- ` ${color10.dim("\u2139")} A ${color10.bold(".git")} repo exists in the parent directory: ${color10.dim(parentDir)}
4211
+ ` ${color13.dim("\u2139")} A ${color13.bold(".git")} repo exists in the parent directory: ${color13.dim(parentDir)}
3067
4212
  `
3068
4213
  );
3069
4214
  } catch {
@@ -3302,7 +4447,7 @@ async function initializeCli(argv) {
3302
4447
  async function main(argv) {
3303
4448
  const cliCtx = await initializeCli(argv);
3304
4449
  if (typeof cliCtx === "number") return cliCtx;
3305
- const { runInteractive } = await import("./cli-main-4TZCCZR6.js");
4450
+ const { runInteractive } = await import("./cli-main-YDOZZOZA.js");
3306
4451
  return runInteractive(cliCtx);
3307
4452
  }
3308
4453