switchroom 0.15.45 → 0.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/agent-scheduler/index.js +56 -15
  2. package/dist/auth-broker/index.js +383 -97
  3. package/dist/cli/autoaccept-poll.js +4842 -35
  4. package/dist/cli/drive-write-pretool.mjs +7 -4
  5. package/dist/cli/notion-write-pretool.mjs +35 -4
  6. package/dist/cli/self-improve-apply-guard-pretool.mjs +626 -0
  7. package/dist/cli/self-improve-stop.mjs +428 -0
  8. package/dist/cli/switchroom.js +2894 -841
  9. package/dist/host-control/main.js +2685 -207
  10. package/dist/vault/approvals/kernel-server.js +7453 -7413
  11. package/dist/vault/broker/server.js +11428 -11388
  12. package/examples/minimal.yaml +1 -0
  13. package/examples/switchroom.yaml +1 -0
  14. package/package.json +3 -3
  15. package/profiles/_base/start.sh.hbs +97 -1
  16. package/profiles/_shared/execution-discipline.md.hbs +18 -0
  17. package/profiles/default/CLAUDE.md.hbs +0 -19
  18. package/telegram-plugin/.claude-plugin/plugin.json +2 -2
  19. package/telegram-plugin/answer-stream-flag.ts +12 -49
  20. package/telegram-plugin/answer-stream.ts +5 -150
  21. package/telegram-plugin/auth-snapshot-format.ts +280 -48
  22. package/telegram-plugin/auto-fallback-fleet.ts +44 -1
  23. package/telegram-plugin/context-exhaustion.ts +12 -0
  24. package/telegram-plugin/demo-mask.ts +154 -0
  25. package/telegram-plugin/dist/bridge/bridge.js +55 -12
  26. package/telegram-plugin/dist/gateway/gateway.js +2938 -977
  27. package/telegram-plugin/dist/server.js +55 -12
  28. package/telegram-plugin/docs/waiting-ux-spec.md +2 -2
  29. package/telegram-plugin/draft-stream.ts +47 -410
  30. package/telegram-plugin/final-answer-detect.ts +17 -12
  31. package/telegram-plugin/fleet-fallback-resume.ts +131 -0
  32. package/telegram-plugin/format.ts +56 -19
  33. package/telegram-plugin/gateway/auth-add-flow.ts +332 -127
  34. package/telegram-plugin/gateway/auth-broker-client.ts +2 -2
  35. package/telegram-plugin/gateway/auth-command.ts +70 -14
  36. package/telegram-plugin/gateway/clean-shutdown-marker.ts +44 -0
  37. package/telegram-plugin/gateway/config-approval-handler.test.ts +91 -4
  38. package/telegram-plugin/gateway/config-approval-handler.ts +94 -13
  39. package/telegram-plugin/gateway/current-turn-map.ts +188 -0
  40. package/telegram-plugin/gateway/disconnect-flush.ts +3 -1
  41. package/telegram-plugin/gateway/effort-command.ts +8 -3
  42. package/telegram-plugin/gateway/emission-authority.ts +369 -0
  43. package/telegram-plugin/gateway/feed-open-gate.ts +292 -0
  44. package/telegram-plugin/gateway/gateway.ts +1857 -292
  45. package/telegram-plugin/gateway/inject-handler.test.ts +2 -1
  46. package/telegram-plugin/gateway/model-command.ts +115 -4
  47. package/telegram-plugin/gateway/ms365-write-approval.test.ts +4 -4
  48. package/telegram-plugin/gateway/represent-guard.ts +72 -0
  49. package/telegram-plugin/gateway/status-surface-log.test.ts +5 -4
  50. package/telegram-plugin/gateway/status-surface-log.ts +14 -3
  51. package/telegram-plugin/history.ts +33 -11
  52. package/telegram-plugin/hooks/repo-context-pretool.mjs +26 -0
  53. package/telegram-plugin/hooks/subagent-tracker-posttool.mjs +5 -0
  54. package/telegram-plugin/hooks/subagent-tracker-pretool.mjs +8 -0
  55. package/telegram-plugin/hooks/tool-label-pretool.mjs +39 -15
  56. package/telegram-plugin/issues-card.ts +4 -0
  57. package/telegram-plugin/model-unavailable.ts +124 -0
  58. package/telegram-plugin/narrative-dedup.ts +69 -0
  59. package/telegram-plugin/over-ping-safety-net.ts +70 -4
  60. package/telegram-plugin/package.json +3 -3
  61. package/telegram-plugin/pending-work-progress.ts +12 -0
  62. package/telegram-plugin/permission-rule.ts +32 -5
  63. package/telegram-plugin/permission-title.ts +152 -9
  64. package/telegram-plugin/quota-check.ts +13 -0
  65. package/telegram-plugin/quota-watch.ts +135 -7
  66. package/telegram-plugin/registry/turns-schema.test.ts +24 -0
  67. package/telegram-plugin/registry/turns-schema.ts +9 -0
  68. package/telegram-plugin/runtime-metrics.ts +13 -0
  69. package/telegram-plugin/session-tail.ts +96 -11
  70. package/telegram-plugin/silence-poke.ts +170 -24
  71. package/telegram-plugin/slot-banner-driver.ts +3 -0
  72. package/telegram-plugin/status-no-truncate.ts +44 -0
  73. package/telegram-plugin/status-reactions.ts +20 -3
  74. package/telegram-plugin/stream-controller.ts +4 -23
  75. package/telegram-plugin/stream-reply-handler.ts +6 -24
  76. package/telegram-plugin/streaming-metrics.ts +91 -0
  77. package/telegram-plugin/subagent-watcher.ts +212 -66
  78. package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +47 -0
  79. package/telegram-plugin/tests/answer-stream-dedup.test.ts +9 -26
  80. package/telegram-plugin/tests/answer-stream-flag.test.ts +25 -58
  81. package/telegram-plugin/tests/answer-stream-silent-markers.test.ts +41 -51
  82. package/telegram-plugin/tests/answer-stream.test.ts +2 -411
  83. package/telegram-plugin/tests/auth-add-flow.test.ts +488 -253
  84. package/telegram-plugin/tests/auth-command-format2.test.ts +71 -1
  85. package/telegram-plugin/tests/auth-snapshot-format.test.ts +376 -6
  86. package/telegram-plugin/tests/auto-fallback-fleet.test.ts +120 -0
  87. package/telegram-plugin/tests/cross-turn-card-gate.test.ts +424 -0
  88. package/telegram-plugin/tests/demo-mask.test.ts +127 -0
  89. package/telegram-plugin/tests/draft-stream.test.ts +0 -827
  90. package/telegram-plugin/tests/emission-authority-card-drain-gate.test.ts +236 -0
  91. package/telegram-plugin/tests/emission-authority-facade.test.ts +488 -0
  92. package/telegram-plugin/tests/emission-authority-open-gate.test.ts +179 -0
  93. package/telegram-plugin/tests/emission-authority-ping-gate.test.ts +395 -0
  94. package/telegram-plugin/tests/emission-determinism-wiring.test.ts +177 -0
  95. package/telegram-plugin/tests/feed-heartbeat-liveness-open.test.ts +146 -0
  96. package/telegram-plugin/tests/feed-open-gate.test.ts +259 -0
  97. package/telegram-plugin/tests/feed-survival.test.ts +526 -0
  98. package/telegram-plugin/tests/fleet-fallback-resume.test.ts +197 -0
  99. package/telegram-plugin/tests/gateway-clean-shutdown-marker.test.ts +117 -0
  100. package/telegram-plugin/tests/gateway-no-reply-single-emit.test.ts +4 -11
  101. package/telegram-plugin/tests/history.test.ts +60 -0
  102. package/telegram-plugin/tests/model-command.test.ts +134 -0
  103. package/telegram-plugin/tests/model-unavailable.test.ts +118 -0
  104. package/telegram-plugin/tests/narrative-dedup.test.ts +118 -0
  105. package/telegram-plugin/tests/orphaned-reply-rearm.test.ts +285 -0
  106. package/telegram-plugin/tests/over-ping-final-answer-decoupling.test.ts +194 -0
  107. package/telegram-plugin/tests/over-ping-safety-net.test.ts +2 -2
  108. package/telegram-plugin/tests/per-topic-current-turn.test.ts +373 -0
  109. package/telegram-plugin/tests/permission-card-origin-kill-switch.test.ts +42 -0
  110. package/telegram-plugin/tests/permission-rule.test.ts +17 -0
  111. package/telegram-plugin/tests/permission-title.test.ts +206 -17
  112. package/telegram-plugin/tests/quota-watch.test.ts +252 -9
  113. package/telegram-plugin/tests/reply-terminal-reaction.test.ts +6 -1
  114. package/telegram-plugin/tests/repo-context-pretool.test.ts +62 -0
  115. package/telegram-plugin/tests/represent-guard.test.ts +162 -0
  116. package/telegram-plugin/tests/session-tail.test.ts +147 -3
  117. package/telegram-plugin/tests/silence-liveness-wiring.test.ts +18 -0
  118. package/telegram-plugin/tests/status-card-budget-parity.test.ts +72 -0
  119. package/telegram-plugin/tests/status-surface-log.test.ts +146 -0
  120. package/telegram-plugin/tests/subagent-watcher-clip-narrative.test.ts +58 -0
  121. package/telegram-plugin/tests/subagent-watcher-parent-turn-key.test.ts +102 -0
  122. package/telegram-plugin/tests/subagent-watcher-workflow-visibility.test.ts +225 -0
  123. package/telegram-plugin/tests/subagent-watcher.test.ts +147 -0
  124. package/telegram-plugin/tests/telegram-activity-visibility-integration.test.ts +597 -0
  125. package/telegram-plugin/tests/telegram-format.test.ts +101 -6
  126. package/telegram-plugin/tests/tool-activity-summary.test.ts +550 -15
  127. package/telegram-plugin/tests/tool-label-pretool.test.ts +73 -0
  128. package/telegram-plugin/tests/tool-label-sidecar.test.ts +44 -0
  129. package/telegram-plugin/tests/tool-labels.test.ts +67 -0
  130. package/telegram-plugin/tests/turn-liveness-floor.test.ts +196 -0
  131. package/telegram-plugin/tests/turn-liveness-invariant.test.ts +340 -0
  132. package/telegram-plugin/tests/welcome-text.test.ts +32 -3
  133. package/telegram-plugin/tests/worker-activity-feed.test.ts +470 -22
  134. package/telegram-plugin/tool-activity-summary.ts +375 -58
  135. package/telegram-plugin/turn-liveness-floor.ts +240 -0
  136. package/telegram-plugin/uat/assertions.ts +115 -0
  137. package/telegram-plugin/uat/driver.ts +68 -0
  138. package/telegram-plugin/uat/scenarios/bg-sub-agent-dispatch-dm.test.ts +119 -133
  139. package/telegram-plugin/uat/scenarios/jtbd-answer-pings.test.ts +94 -0
  140. package/telegram-plugin/uat/scenarios/jtbd-cross-turn-card-dm.test.ts +109 -0
  141. package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-thinkgap-dm.test.ts +478 -0
  142. package/telegram-plugin/uat/scenarios/jtbd-foreground-feed-visibility-dm.test.ts +396 -0
  143. package/telegram-plugin/uat/scenarios/jtbd-liveness-feed-open-dm.test.ts +202 -0
  144. package/telegram-plugin/uat/scenarios/jtbd-reply-is-last-dm.test.ts +202 -0
  145. package/telegram-plugin/uat/scenarios/reactions-dm.test.ts +93 -87
  146. package/telegram-plugin/welcome-text.ts +13 -1
  147. package/telegram-plugin/worker-activity-feed.ts +157 -82
  148. package/telegram-plugin/draft-transport.ts +0 -122
  149. package/telegram-plugin/tests/draft-retirement-wiring.test.ts +0 -82
  150. package/telegram-plugin/tests/draft-transport.test.ts +0 -211
@@ -9664,10 +9664,2044 @@ var init_secretlint_source = __esm(() => {
9664
9664
  init_suppressor();
9665
9665
  });
9666
9666
 
9667
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/error.js
9668
+ var require_error = __commonJS((exports2) => {
9669
+ class CommanderError extends Error {
9670
+ constructor(exitCode, code, message) {
9671
+ super(message);
9672
+ Error.captureStackTrace(this, this.constructor);
9673
+ this.name = this.constructor.name;
9674
+ this.code = code;
9675
+ this.exitCode = exitCode;
9676
+ this.nestedError = undefined;
9677
+ }
9678
+ }
9679
+
9680
+ class InvalidArgumentError extends CommanderError {
9681
+ constructor(message) {
9682
+ super(1, "commander.invalidArgument", message);
9683
+ Error.captureStackTrace(this, this.constructor);
9684
+ this.name = this.constructor.name;
9685
+ }
9686
+ }
9687
+ exports2.CommanderError = CommanderError;
9688
+ exports2.InvalidArgumentError = InvalidArgumentError;
9689
+ });
9690
+
9691
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/argument.js
9692
+ var require_argument = __commonJS((exports2) => {
9693
+ var { InvalidArgumentError } = require_error();
9694
+
9695
+ class Argument {
9696
+ constructor(name, description) {
9697
+ this.description = description || "";
9698
+ this.variadic = false;
9699
+ this.parseArg = undefined;
9700
+ this.defaultValue = undefined;
9701
+ this.defaultValueDescription = undefined;
9702
+ this.argChoices = undefined;
9703
+ switch (name[0]) {
9704
+ case "<":
9705
+ this.required = true;
9706
+ this._name = name.slice(1, -1);
9707
+ break;
9708
+ case "[":
9709
+ this.required = false;
9710
+ this._name = name.slice(1, -1);
9711
+ break;
9712
+ default:
9713
+ this.required = true;
9714
+ this._name = name;
9715
+ break;
9716
+ }
9717
+ if (this._name.length > 3 && this._name.slice(-3) === "...") {
9718
+ this.variadic = true;
9719
+ this._name = this._name.slice(0, -3);
9720
+ }
9721
+ }
9722
+ name() {
9723
+ return this._name;
9724
+ }
9725
+ _concatValue(value, previous) {
9726
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
9727
+ return [value];
9728
+ }
9729
+ return previous.concat(value);
9730
+ }
9731
+ default(value, description) {
9732
+ this.defaultValue = value;
9733
+ this.defaultValueDescription = description;
9734
+ return this;
9735
+ }
9736
+ argParser(fn) {
9737
+ this.parseArg = fn;
9738
+ return this;
9739
+ }
9740
+ choices(values) {
9741
+ this.argChoices = values.slice();
9742
+ this.parseArg = (arg, previous) => {
9743
+ if (!this.argChoices.includes(arg)) {
9744
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
9745
+ }
9746
+ if (this.variadic) {
9747
+ return this._concatValue(arg, previous);
9748
+ }
9749
+ return arg;
9750
+ };
9751
+ return this;
9752
+ }
9753
+ argRequired() {
9754
+ this.required = true;
9755
+ return this;
9756
+ }
9757
+ argOptional() {
9758
+ this.required = false;
9759
+ return this;
9760
+ }
9761
+ }
9762
+ function humanReadableArgName(arg) {
9763
+ const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
9764
+ return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
9765
+ }
9766
+ exports2.Argument = Argument;
9767
+ exports2.humanReadableArgName = humanReadableArgName;
9768
+ });
9769
+
9770
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/help.js
9771
+ var require_help = __commonJS((exports2) => {
9772
+ var { humanReadableArgName } = require_argument();
9773
+
9774
+ class Help {
9775
+ constructor() {
9776
+ this.helpWidth = undefined;
9777
+ this.minWidthToWrap = 40;
9778
+ this.sortSubcommands = false;
9779
+ this.sortOptions = false;
9780
+ this.showGlobalOptions = false;
9781
+ }
9782
+ prepareContext(contextOptions) {
9783
+ this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
9784
+ }
9785
+ visibleCommands(cmd) {
9786
+ const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
9787
+ const helpCommand = cmd._getHelpCommand();
9788
+ if (helpCommand && !helpCommand._hidden) {
9789
+ visibleCommands.push(helpCommand);
9790
+ }
9791
+ if (this.sortSubcommands) {
9792
+ visibleCommands.sort((a, b) => {
9793
+ return a.name().localeCompare(b.name());
9794
+ });
9795
+ }
9796
+ return visibleCommands;
9797
+ }
9798
+ compareOptions(a, b) {
9799
+ const getSortKey = (option) => {
9800
+ return option.short ? option.short.replace(/^-/, "") : option.long.replace(/^--/, "");
9801
+ };
9802
+ return getSortKey(a).localeCompare(getSortKey(b));
9803
+ }
9804
+ visibleOptions(cmd) {
9805
+ const visibleOptions = cmd.options.filter((option) => !option.hidden);
9806
+ const helpOption = cmd._getHelpOption();
9807
+ if (helpOption && !helpOption.hidden) {
9808
+ const removeShort = helpOption.short && cmd._findOption(helpOption.short);
9809
+ const removeLong = helpOption.long && cmd._findOption(helpOption.long);
9810
+ if (!removeShort && !removeLong) {
9811
+ visibleOptions.push(helpOption);
9812
+ } else if (helpOption.long && !removeLong) {
9813
+ visibleOptions.push(cmd.createOption(helpOption.long, helpOption.description));
9814
+ } else if (helpOption.short && !removeShort) {
9815
+ visibleOptions.push(cmd.createOption(helpOption.short, helpOption.description));
9816
+ }
9817
+ }
9818
+ if (this.sortOptions) {
9819
+ visibleOptions.sort(this.compareOptions);
9820
+ }
9821
+ return visibleOptions;
9822
+ }
9823
+ visibleGlobalOptions(cmd) {
9824
+ if (!this.showGlobalOptions)
9825
+ return [];
9826
+ const globalOptions = [];
9827
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
9828
+ const visibleOptions = ancestorCmd.options.filter((option) => !option.hidden);
9829
+ globalOptions.push(...visibleOptions);
9830
+ }
9831
+ if (this.sortOptions) {
9832
+ globalOptions.sort(this.compareOptions);
9833
+ }
9834
+ return globalOptions;
9835
+ }
9836
+ visibleArguments(cmd) {
9837
+ if (cmd._argsDescription) {
9838
+ cmd.registeredArguments.forEach((argument) => {
9839
+ argument.description = argument.description || cmd._argsDescription[argument.name()] || "";
9840
+ });
9841
+ }
9842
+ if (cmd.registeredArguments.find((argument) => argument.description)) {
9843
+ return cmd.registeredArguments;
9844
+ }
9845
+ return [];
9846
+ }
9847
+ subcommandTerm(cmd) {
9848
+ const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
9849
+ return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + (args ? " " + args : "");
9850
+ }
9851
+ optionTerm(option) {
9852
+ return option.flags;
9853
+ }
9854
+ argumentTerm(argument) {
9855
+ return argument.name();
9856
+ }
9857
+ longestSubcommandTermLength(cmd, helper) {
9858
+ return helper.visibleCommands(cmd).reduce((max, command) => {
9859
+ return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
9860
+ }, 0);
9861
+ }
9862
+ longestOptionTermLength(cmd, helper) {
9863
+ return helper.visibleOptions(cmd).reduce((max, option) => {
9864
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
9865
+ }, 0);
9866
+ }
9867
+ longestGlobalOptionTermLength(cmd, helper) {
9868
+ return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
9869
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
9870
+ }, 0);
9871
+ }
9872
+ longestArgumentTermLength(cmd, helper) {
9873
+ return helper.visibleArguments(cmd).reduce((max, argument) => {
9874
+ return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
9875
+ }, 0);
9876
+ }
9877
+ commandUsage(cmd) {
9878
+ let cmdName = cmd._name;
9879
+ if (cmd._aliases[0]) {
9880
+ cmdName = cmdName + "|" + cmd._aliases[0];
9881
+ }
9882
+ let ancestorCmdNames = "";
9883
+ for (let ancestorCmd = cmd.parent;ancestorCmd; ancestorCmd = ancestorCmd.parent) {
9884
+ ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
9885
+ }
9886
+ return ancestorCmdNames + cmdName + " " + cmd.usage();
9887
+ }
9888
+ commandDescription(cmd) {
9889
+ return cmd.description();
9890
+ }
9891
+ subcommandDescription(cmd) {
9892
+ return cmd.summary() || cmd.description();
9893
+ }
9894
+ optionDescription(option) {
9895
+ const extraInfo = [];
9896
+ if (option.argChoices) {
9897
+ extraInfo.push(`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
9898
+ }
9899
+ if (option.defaultValue !== undefined) {
9900
+ const showDefault = option.required || option.optional || option.isBoolean() && typeof option.defaultValue === "boolean";
9901
+ if (showDefault) {
9902
+ extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
9903
+ }
9904
+ }
9905
+ if (option.presetArg !== undefined && option.optional) {
9906
+ extraInfo.push(`preset: ${JSON.stringify(option.presetArg)}`);
9907
+ }
9908
+ if (option.envVar !== undefined) {
9909
+ extraInfo.push(`env: ${option.envVar}`);
9910
+ }
9911
+ if (extraInfo.length > 0) {
9912
+ return `${option.description} (${extraInfo.join(", ")})`;
9913
+ }
9914
+ return option.description;
9915
+ }
9916
+ argumentDescription(argument) {
9917
+ const extraInfo = [];
9918
+ if (argument.argChoices) {
9919
+ extraInfo.push(`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`);
9920
+ }
9921
+ if (argument.defaultValue !== undefined) {
9922
+ extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
9923
+ }
9924
+ if (extraInfo.length > 0) {
9925
+ const extraDescription = `(${extraInfo.join(", ")})`;
9926
+ if (argument.description) {
9927
+ return `${argument.description} ${extraDescription}`;
9928
+ }
9929
+ return extraDescription;
9930
+ }
9931
+ return argument.description;
9932
+ }
9933
+ formatHelp(cmd, helper) {
9934
+ const termWidth = helper.padWidth(cmd, helper);
9935
+ const helpWidth = helper.helpWidth ?? 80;
9936
+ function callFormatItem(term, description) {
9937
+ return helper.formatItem(term, termWidth, description, helper);
9938
+ }
9939
+ let output = [
9940
+ `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
9941
+ ""
9942
+ ];
9943
+ const commandDescription = helper.commandDescription(cmd);
9944
+ if (commandDescription.length > 0) {
9945
+ output = output.concat([
9946
+ helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth),
9947
+ ""
9948
+ ]);
9949
+ }
9950
+ const argumentList = helper.visibleArguments(cmd).map((argument) => {
9951
+ return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument)));
9952
+ });
9953
+ if (argumentList.length > 0) {
9954
+ output = output.concat([
9955
+ helper.styleTitle("Arguments:"),
9956
+ ...argumentList,
9957
+ ""
9958
+ ]);
9959
+ }
9960
+ const optionList = helper.visibleOptions(cmd).map((option) => {
9961
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
9962
+ });
9963
+ if (optionList.length > 0) {
9964
+ output = output.concat([
9965
+ helper.styleTitle("Options:"),
9966
+ ...optionList,
9967
+ ""
9968
+ ]);
9969
+ }
9970
+ if (helper.showGlobalOptions) {
9971
+ const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
9972
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
9973
+ });
9974
+ if (globalOptionList.length > 0) {
9975
+ output = output.concat([
9976
+ helper.styleTitle("Global Options:"),
9977
+ ...globalOptionList,
9978
+ ""
9979
+ ]);
9980
+ }
9981
+ }
9982
+ const commandList = helper.visibleCommands(cmd).map((cmd2) => {
9983
+ return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(cmd2)), helper.styleSubcommandDescription(helper.subcommandDescription(cmd2)));
9984
+ });
9985
+ if (commandList.length > 0) {
9986
+ output = output.concat([
9987
+ helper.styleTitle("Commands:"),
9988
+ ...commandList,
9989
+ ""
9990
+ ]);
9991
+ }
9992
+ return output.join(`
9993
+ `);
9994
+ }
9995
+ displayWidth(str) {
9996
+ return stripColor(str).length;
9997
+ }
9998
+ styleTitle(str) {
9999
+ return str;
10000
+ }
10001
+ styleUsage(str) {
10002
+ return str.split(" ").map((word) => {
10003
+ if (word === "[options]")
10004
+ return this.styleOptionText(word);
10005
+ if (word === "[command]")
10006
+ return this.styleSubcommandText(word);
10007
+ if (word[0] === "[" || word[0] === "<")
10008
+ return this.styleArgumentText(word);
10009
+ return this.styleCommandText(word);
10010
+ }).join(" ");
10011
+ }
10012
+ styleCommandDescription(str) {
10013
+ return this.styleDescriptionText(str);
10014
+ }
10015
+ styleOptionDescription(str) {
10016
+ return this.styleDescriptionText(str);
10017
+ }
10018
+ styleSubcommandDescription(str) {
10019
+ return this.styleDescriptionText(str);
10020
+ }
10021
+ styleArgumentDescription(str) {
10022
+ return this.styleDescriptionText(str);
10023
+ }
10024
+ styleDescriptionText(str) {
10025
+ return str;
10026
+ }
10027
+ styleOptionTerm(str) {
10028
+ return this.styleOptionText(str);
10029
+ }
10030
+ styleSubcommandTerm(str) {
10031
+ return str.split(" ").map((word) => {
10032
+ if (word === "[options]")
10033
+ return this.styleOptionText(word);
10034
+ if (word[0] === "[" || word[0] === "<")
10035
+ return this.styleArgumentText(word);
10036
+ return this.styleSubcommandText(word);
10037
+ }).join(" ");
10038
+ }
10039
+ styleArgumentTerm(str) {
10040
+ return this.styleArgumentText(str);
10041
+ }
10042
+ styleOptionText(str) {
10043
+ return str;
10044
+ }
10045
+ styleArgumentText(str) {
10046
+ return str;
10047
+ }
10048
+ styleSubcommandText(str) {
10049
+ return str;
10050
+ }
10051
+ styleCommandText(str) {
10052
+ return str;
10053
+ }
10054
+ padWidth(cmd, helper) {
10055
+ return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
10056
+ }
10057
+ preformatted(str) {
10058
+ return /\n[^\S\r\n]/.test(str);
10059
+ }
10060
+ formatItem(term, termWidth, description, helper) {
10061
+ const itemIndent = 2;
10062
+ const itemIndentStr = " ".repeat(itemIndent);
10063
+ if (!description)
10064
+ return itemIndentStr + term;
10065
+ const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term));
10066
+ const spacerWidth = 2;
10067
+ const helpWidth = this.helpWidth ?? 80;
10068
+ const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
10069
+ let formattedDescription;
10070
+ if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
10071
+ formattedDescription = description;
10072
+ } else {
10073
+ const wrappedDescription = helper.boxWrap(description, remainingWidth);
10074
+ formattedDescription = wrappedDescription.replace(/\n/g, `
10075
+ ` + " ".repeat(termWidth + spacerWidth));
10076
+ }
10077
+ return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
10078
+ ${itemIndentStr}`);
10079
+ }
10080
+ boxWrap(str, width) {
10081
+ if (width < this.minWidthToWrap)
10082
+ return str;
10083
+ const rawLines = str.split(/\r\n|\n/);
10084
+ const chunkPattern = /[\s]*[^\s]+/g;
10085
+ const wrappedLines = [];
10086
+ rawLines.forEach((line) => {
10087
+ const chunks = line.match(chunkPattern);
10088
+ if (chunks === null) {
10089
+ wrappedLines.push("");
10090
+ return;
10091
+ }
10092
+ let sumChunks = [chunks.shift()];
10093
+ let sumWidth = this.displayWidth(sumChunks[0]);
10094
+ chunks.forEach((chunk2) => {
10095
+ const visibleWidth = this.displayWidth(chunk2);
10096
+ if (sumWidth + visibleWidth <= width) {
10097
+ sumChunks.push(chunk2);
10098
+ sumWidth += visibleWidth;
10099
+ return;
10100
+ }
10101
+ wrappedLines.push(sumChunks.join(""));
10102
+ const nextChunk = chunk2.trimStart();
10103
+ sumChunks = [nextChunk];
10104
+ sumWidth = this.displayWidth(nextChunk);
10105
+ });
10106
+ wrappedLines.push(sumChunks.join(""));
10107
+ });
10108
+ return wrappedLines.join(`
10109
+ `);
10110
+ }
10111
+ }
10112
+ function stripColor(str) {
10113
+ const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
10114
+ return str.replace(sgrPattern, "");
10115
+ }
10116
+ exports2.Help = Help;
10117
+ exports2.stripColor = stripColor;
10118
+ });
10119
+
10120
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/option.js
10121
+ var require_option = __commonJS((exports2) => {
10122
+ var { InvalidArgumentError } = require_error();
10123
+
10124
+ class Option {
10125
+ constructor(flags, description) {
10126
+ this.flags = flags;
10127
+ this.description = description || "";
10128
+ this.required = flags.includes("<");
10129
+ this.optional = flags.includes("[");
10130
+ this.variadic = /\w\.\.\.[>\]]$/.test(flags);
10131
+ this.mandatory = false;
10132
+ const optionFlags = splitOptionFlags(flags);
10133
+ this.short = optionFlags.shortFlag;
10134
+ this.long = optionFlags.longFlag;
10135
+ this.negate = false;
10136
+ if (this.long) {
10137
+ this.negate = this.long.startsWith("--no-");
10138
+ }
10139
+ this.defaultValue = undefined;
10140
+ this.defaultValueDescription = undefined;
10141
+ this.presetArg = undefined;
10142
+ this.envVar = undefined;
10143
+ this.parseArg = undefined;
10144
+ this.hidden = false;
10145
+ this.argChoices = undefined;
10146
+ this.conflictsWith = [];
10147
+ this.implied = undefined;
10148
+ }
10149
+ default(value, description) {
10150
+ this.defaultValue = value;
10151
+ this.defaultValueDescription = description;
10152
+ return this;
10153
+ }
10154
+ preset(arg) {
10155
+ this.presetArg = arg;
10156
+ return this;
10157
+ }
10158
+ conflicts(names) {
10159
+ this.conflictsWith = this.conflictsWith.concat(names);
10160
+ return this;
10161
+ }
10162
+ implies(impliedOptionValues) {
10163
+ let newImplied = impliedOptionValues;
10164
+ if (typeof impliedOptionValues === "string") {
10165
+ newImplied = { [impliedOptionValues]: true };
10166
+ }
10167
+ this.implied = Object.assign(this.implied || {}, newImplied);
10168
+ return this;
10169
+ }
10170
+ env(name) {
10171
+ this.envVar = name;
10172
+ return this;
10173
+ }
10174
+ argParser(fn) {
10175
+ this.parseArg = fn;
10176
+ return this;
10177
+ }
10178
+ makeOptionMandatory(mandatory = true) {
10179
+ this.mandatory = !!mandatory;
10180
+ return this;
10181
+ }
10182
+ hideHelp(hide = true) {
10183
+ this.hidden = !!hide;
10184
+ return this;
10185
+ }
10186
+ _concatValue(value, previous) {
10187
+ if (previous === this.defaultValue || !Array.isArray(previous)) {
10188
+ return [value];
10189
+ }
10190
+ return previous.concat(value);
10191
+ }
10192
+ choices(values) {
10193
+ this.argChoices = values.slice();
10194
+ this.parseArg = (arg, previous) => {
10195
+ if (!this.argChoices.includes(arg)) {
10196
+ throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
10197
+ }
10198
+ if (this.variadic) {
10199
+ return this._concatValue(arg, previous);
10200
+ }
10201
+ return arg;
10202
+ };
10203
+ return this;
10204
+ }
10205
+ name() {
10206
+ if (this.long) {
10207
+ return this.long.replace(/^--/, "");
10208
+ }
10209
+ return this.short.replace(/^-/, "");
10210
+ }
10211
+ attributeName() {
10212
+ if (this.negate) {
10213
+ return camelcase(this.name().replace(/^no-/, ""));
10214
+ }
10215
+ return camelcase(this.name());
10216
+ }
10217
+ is(arg) {
10218
+ return this.short === arg || this.long === arg;
10219
+ }
10220
+ isBoolean() {
10221
+ return !this.required && !this.optional && !this.negate;
10222
+ }
10223
+ }
10224
+
10225
+ class DualOptions {
10226
+ constructor(options) {
10227
+ this.positiveOptions = new Map;
10228
+ this.negativeOptions = new Map;
10229
+ this.dualOptions = new Set;
10230
+ options.forEach((option) => {
10231
+ if (option.negate) {
10232
+ this.negativeOptions.set(option.attributeName(), option);
10233
+ } else {
10234
+ this.positiveOptions.set(option.attributeName(), option);
10235
+ }
10236
+ });
10237
+ this.negativeOptions.forEach((value, key) => {
10238
+ if (this.positiveOptions.has(key)) {
10239
+ this.dualOptions.add(key);
10240
+ }
10241
+ });
10242
+ }
10243
+ valueFromOption(value, option) {
10244
+ const optionKey = option.attributeName();
10245
+ if (!this.dualOptions.has(optionKey))
10246
+ return true;
10247
+ const preset = this.negativeOptions.get(optionKey).presetArg;
10248
+ const negativeValue = preset !== undefined ? preset : false;
10249
+ return option.negate === (negativeValue === value);
10250
+ }
10251
+ }
10252
+ function camelcase(str) {
10253
+ return str.split("-").reduce((str2, word) => {
10254
+ return str2 + word[0].toUpperCase() + word.slice(1);
10255
+ });
10256
+ }
10257
+ function splitOptionFlags(flags) {
10258
+ let shortFlag;
10259
+ let longFlag;
10260
+ const shortFlagExp = /^-[^-]$/;
10261
+ const longFlagExp = /^--[^-]/;
10262
+ const flagParts = flags.split(/[ |,]+/).concat("guard");
10263
+ if (shortFlagExp.test(flagParts[0]))
10264
+ shortFlag = flagParts.shift();
10265
+ if (longFlagExp.test(flagParts[0]))
10266
+ longFlag = flagParts.shift();
10267
+ if (!shortFlag && shortFlagExp.test(flagParts[0]))
10268
+ shortFlag = flagParts.shift();
10269
+ if (!shortFlag && longFlagExp.test(flagParts[0])) {
10270
+ shortFlag = longFlag;
10271
+ longFlag = flagParts.shift();
10272
+ }
10273
+ if (flagParts[0].startsWith("-")) {
10274
+ const unsupportedFlag = flagParts[0];
10275
+ const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
10276
+ if (/^-[^-][^-]/.test(unsupportedFlag))
10277
+ throw new Error(`${baseError}
10278
+ - a short flag is a single dash and a single character
10279
+ - either use a single dash and a single character (for a short flag)
10280
+ - or use a double dash for a long option (and can have two, like '--ws, --workspace')`);
10281
+ if (shortFlagExp.test(unsupportedFlag))
10282
+ throw new Error(`${baseError}
10283
+ - too many short flags`);
10284
+ if (longFlagExp.test(unsupportedFlag))
10285
+ throw new Error(`${baseError}
10286
+ - too many long flags`);
10287
+ throw new Error(`${baseError}
10288
+ - unrecognised flag format`);
10289
+ }
10290
+ if (shortFlag === undefined && longFlag === undefined)
10291
+ throw new Error(`option creation failed due to no flags found in '${flags}'.`);
10292
+ return { shortFlag, longFlag };
10293
+ }
10294
+ exports2.Option = Option;
10295
+ exports2.DualOptions = DualOptions;
10296
+ });
10297
+
10298
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/suggestSimilar.js
10299
+ var require_suggestSimilar = __commonJS((exports2) => {
10300
+ var maxDistance = 3;
10301
+ function editDistance(a, b) {
10302
+ if (Math.abs(a.length - b.length) > maxDistance)
10303
+ return Math.max(a.length, b.length);
10304
+ const d = [];
10305
+ for (let i = 0;i <= a.length; i++) {
10306
+ d[i] = [i];
10307
+ }
10308
+ for (let j = 0;j <= b.length; j++) {
10309
+ d[0][j] = j;
10310
+ }
10311
+ for (let j = 1;j <= b.length; j++) {
10312
+ for (let i = 1;i <= a.length; i++) {
10313
+ let cost = 1;
10314
+ if (a[i - 1] === b[j - 1]) {
10315
+ cost = 0;
10316
+ } else {
10317
+ cost = 1;
10318
+ }
10319
+ d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
10320
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
10321
+ d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
10322
+ }
10323
+ }
10324
+ }
10325
+ return d[a.length][b.length];
10326
+ }
10327
+ function suggestSimilar(word, candidates) {
10328
+ if (!candidates || candidates.length === 0)
10329
+ return "";
10330
+ candidates = Array.from(new Set(candidates));
10331
+ const searchingOptions = word.startsWith("--");
10332
+ if (searchingOptions) {
10333
+ word = word.slice(2);
10334
+ candidates = candidates.map((candidate) => candidate.slice(2));
10335
+ }
10336
+ let similar = [];
10337
+ let bestDistance = maxDistance;
10338
+ const minSimilarity = 0.4;
10339
+ candidates.forEach((candidate) => {
10340
+ if (candidate.length <= 1)
10341
+ return;
10342
+ const distance = editDistance(word, candidate);
10343
+ const length = Math.max(word.length, candidate.length);
10344
+ const similarity = (length - distance) / length;
10345
+ if (similarity > minSimilarity) {
10346
+ if (distance < bestDistance) {
10347
+ bestDistance = distance;
10348
+ similar = [candidate];
10349
+ } else if (distance === bestDistance) {
10350
+ similar.push(candidate);
10351
+ }
10352
+ }
10353
+ });
10354
+ similar.sort((a, b) => a.localeCompare(b));
10355
+ if (searchingOptions) {
10356
+ similar = similar.map((candidate) => `--${candidate}`);
10357
+ }
10358
+ if (similar.length > 1) {
10359
+ return `
10360
+ (Did you mean one of ${similar.join(", ")}?)`;
10361
+ }
10362
+ if (similar.length === 1) {
10363
+ return `
10364
+ (Did you mean ${similar[0]}?)`;
10365
+ }
10366
+ return "";
10367
+ }
10368
+ exports2.suggestSimilar = suggestSimilar;
10369
+ });
10370
+
10371
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/lib/command.js
10372
+ var require_command = __commonJS((exports2) => {
10373
+ var EventEmitter2 = __require("node:events").EventEmitter;
10374
+ var childProcess = __require("node:child_process");
10375
+ var path2 = __require("node:path");
10376
+ var fs2 = __require("node:fs");
10377
+ var process2 = __require("node:process");
10378
+ var { Argument, humanReadableArgName } = require_argument();
10379
+ var { CommanderError } = require_error();
10380
+ var { Help, stripColor } = require_help();
10381
+ var { Option, DualOptions } = require_option();
10382
+ var { suggestSimilar } = require_suggestSimilar();
10383
+
10384
+ class Command extends EventEmitter2 {
10385
+ constructor(name) {
10386
+ super();
10387
+ this.commands = [];
10388
+ this.options = [];
10389
+ this.parent = null;
10390
+ this._allowUnknownOption = false;
10391
+ this._allowExcessArguments = false;
10392
+ this.registeredArguments = [];
10393
+ this._args = this.registeredArguments;
10394
+ this.args = [];
10395
+ this.rawArgs = [];
10396
+ this.processedArgs = [];
10397
+ this._scriptPath = null;
10398
+ this._name = name || "";
10399
+ this._optionValues = {};
10400
+ this._optionValueSources = {};
10401
+ this._storeOptionsAsProperties = false;
10402
+ this._actionHandler = null;
10403
+ this._executableHandler = false;
10404
+ this._executableFile = null;
10405
+ this._executableDir = null;
10406
+ this._defaultCommandName = null;
10407
+ this._exitCallback = null;
10408
+ this._aliases = [];
10409
+ this._combineFlagAndOptionalValue = true;
10410
+ this._description = "";
10411
+ this._summary = "";
10412
+ this._argsDescription = undefined;
10413
+ this._enablePositionalOptions = false;
10414
+ this._passThroughOptions = false;
10415
+ this._lifeCycleHooks = {};
10416
+ this._showHelpAfterError = false;
10417
+ this._showSuggestionAfterError = true;
10418
+ this._savedState = null;
10419
+ this._outputConfiguration = {
10420
+ writeOut: (str) => process2.stdout.write(str),
10421
+ writeErr: (str) => process2.stderr.write(str),
10422
+ outputError: (str, write) => write(str),
10423
+ getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
10424
+ getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
10425
+ getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
10426
+ getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
10427
+ stripColor: (str) => stripColor(str)
10428
+ };
10429
+ this._hidden = false;
10430
+ this._helpOption = undefined;
10431
+ this._addImplicitHelpCommand = undefined;
10432
+ this._helpCommand = undefined;
10433
+ this._helpConfiguration = {};
10434
+ }
10435
+ copyInheritedSettings(sourceCommand) {
10436
+ this._outputConfiguration = sourceCommand._outputConfiguration;
10437
+ this._helpOption = sourceCommand._helpOption;
10438
+ this._helpCommand = sourceCommand._helpCommand;
10439
+ this._helpConfiguration = sourceCommand._helpConfiguration;
10440
+ this._exitCallback = sourceCommand._exitCallback;
10441
+ this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
10442
+ this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
10443
+ this._allowExcessArguments = sourceCommand._allowExcessArguments;
10444
+ this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
10445
+ this._showHelpAfterError = sourceCommand._showHelpAfterError;
10446
+ this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
10447
+ return this;
10448
+ }
10449
+ _getCommandAndAncestors() {
10450
+ const result = [];
10451
+ for (let command = this;command; command = command.parent) {
10452
+ result.push(command);
10453
+ }
10454
+ return result;
10455
+ }
10456
+ command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
10457
+ let desc = actionOptsOrExecDesc;
10458
+ let opts = execOpts;
10459
+ if (typeof desc === "object" && desc !== null) {
10460
+ opts = desc;
10461
+ desc = null;
10462
+ }
10463
+ opts = opts || {};
10464
+ const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
10465
+ const cmd = this.createCommand(name);
10466
+ if (desc) {
10467
+ cmd.description(desc);
10468
+ cmd._executableHandler = true;
10469
+ }
10470
+ if (opts.isDefault)
10471
+ this._defaultCommandName = cmd._name;
10472
+ cmd._hidden = !!(opts.noHelp || opts.hidden);
10473
+ cmd._executableFile = opts.executableFile || null;
10474
+ if (args)
10475
+ cmd.arguments(args);
10476
+ this._registerCommand(cmd);
10477
+ cmd.parent = this;
10478
+ cmd.copyInheritedSettings(this);
10479
+ if (desc)
10480
+ return this;
10481
+ return cmd;
10482
+ }
10483
+ createCommand(name) {
10484
+ return new Command(name);
10485
+ }
10486
+ createHelp() {
10487
+ return Object.assign(new Help, this.configureHelp());
10488
+ }
10489
+ configureHelp(configuration) {
10490
+ if (configuration === undefined)
10491
+ return this._helpConfiguration;
10492
+ this._helpConfiguration = configuration;
10493
+ return this;
10494
+ }
10495
+ configureOutput(configuration) {
10496
+ if (configuration === undefined)
10497
+ return this._outputConfiguration;
10498
+ Object.assign(this._outputConfiguration, configuration);
10499
+ return this;
10500
+ }
10501
+ showHelpAfterError(displayHelp = true) {
10502
+ if (typeof displayHelp !== "string")
10503
+ displayHelp = !!displayHelp;
10504
+ this._showHelpAfterError = displayHelp;
10505
+ return this;
10506
+ }
10507
+ showSuggestionAfterError(displaySuggestion = true) {
10508
+ this._showSuggestionAfterError = !!displaySuggestion;
10509
+ return this;
10510
+ }
10511
+ addCommand(cmd, opts) {
10512
+ if (!cmd._name) {
10513
+ throw new Error(`Command passed to .addCommand() must have a name
10514
+ - specify the name in Command constructor or using .name()`);
10515
+ }
10516
+ opts = opts || {};
10517
+ if (opts.isDefault)
10518
+ this._defaultCommandName = cmd._name;
10519
+ if (opts.noHelp || opts.hidden)
10520
+ cmd._hidden = true;
10521
+ this._registerCommand(cmd);
10522
+ cmd.parent = this;
10523
+ cmd._checkForBrokenPassThrough();
10524
+ return this;
10525
+ }
10526
+ createArgument(name, description) {
10527
+ return new Argument(name, description);
10528
+ }
10529
+ argument(name, description, fn, defaultValue) {
10530
+ const argument = this.createArgument(name, description);
10531
+ if (typeof fn === "function") {
10532
+ argument.default(defaultValue).argParser(fn);
10533
+ } else {
10534
+ argument.default(fn);
10535
+ }
10536
+ this.addArgument(argument);
10537
+ return this;
10538
+ }
10539
+ arguments(names) {
10540
+ names.trim().split(/ +/).forEach((detail) => {
10541
+ this.argument(detail);
10542
+ });
10543
+ return this;
10544
+ }
10545
+ addArgument(argument) {
10546
+ const previousArgument = this.registeredArguments.slice(-1)[0];
10547
+ if (previousArgument && previousArgument.variadic) {
10548
+ throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
10549
+ }
10550
+ if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
10551
+ throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);
10552
+ }
10553
+ this.registeredArguments.push(argument);
10554
+ return this;
10555
+ }
10556
+ helpCommand(enableOrNameAndArgs, description) {
10557
+ if (typeof enableOrNameAndArgs === "boolean") {
10558
+ this._addImplicitHelpCommand = enableOrNameAndArgs;
10559
+ return this;
10560
+ }
10561
+ enableOrNameAndArgs = enableOrNameAndArgs ?? "help [command]";
10562
+ const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/);
10563
+ const helpDescription = description ?? "display help for command";
10564
+ const helpCommand = this.createCommand(helpName);
10565
+ helpCommand.helpOption(false);
10566
+ if (helpArgs)
10567
+ helpCommand.arguments(helpArgs);
10568
+ if (helpDescription)
10569
+ helpCommand.description(helpDescription);
10570
+ this._addImplicitHelpCommand = true;
10571
+ this._helpCommand = helpCommand;
10572
+ return this;
10573
+ }
10574
+ addHelpCommand(helpCommand, deprecatedDescription) {
10575
+ if (typeof helpCommand !== "object") {
10576
+ this.helpCommand(helpCommand, deprecatedDescription);
10577
+ return this;
10578
+ }
10579
+ this._addImplicitHelpCommand = true;
10580
+ this._helpCommand = helpCommand;
10581
+ return this;
10582
+ }
10583
+ _getHelpCommand() {
10584
+ const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
10585
+ if (hasImplicitHelpCommand) {
10586
+ if (this._helpCommand === undefined) {
10587
+ this.helpCommand(undefined, undefined);
10588
+ }
10589
+ return this._helpCommand;
10590
+ }
10591
+ return null;
10592
+ }
10593
+ hook(event, listener) {
10594
+ const allowedValues = ["preSubcommand", "preAction", "postAction"];
10595
+ if (!allowedValues.includes(event)) {
10596
+ throw new Error(`Unexpected value for event passed to hook : '${event}'.
10597
+ Expecting one of '${allowedValues.join("', '")}'`);
10598
+ }
10599
+ if (this._lifeCycleHooks[event]) {
10600
+ this._lifeCycleHooks[event].push(listener);
10601
+ } else {
10602
+ this._lifeCycleHooks[event] = [listener];
10603
+ }
10604
+ return this;
10605
+ }
10606
+ exitOverride(fn) {
10607
+ if (fn) {
10608
+ this._exitCallback = fn;
10609
+ } else {
10610
+ this._exitCallback = (err2) => {
10611
+ if (err2.code !== "commander.executeSubCommandAsync") {
10612
+ throw err2;
10613
+ } else {}
10614
+ };
10615
+ }
10616
+ return this;
10617
+ }
10618
+ _exit(exitCode, code, message) {
10619
+ if (this._exitCallback) {
10620
+ this._exitCallback(new CommanderError(exitCode, code, message));
10621
+ }
10622
+ process2.exit(exitCode);
10623
+ }
10624
+ action(fn) {
10625
+ const listener = (args) => {
10626
+ const expectedArgsCount = this.registeredArguments.length;
10627
+ const actionArgs = args.slice(0, expectedArgsCount);
10628
+ if (this._storeOptionsAsProperties) {
10629
+ actionArgs[expectedArgsCount] = this;
10630
+ } else {
10631
+ actionArgs[expectedArgsCount] = this.opts();
10632
+ }
10633
+ actionArgs.push(this);
10634
+ return fn.apply(this, actionArgs);
10635
+ };
10636
+ this._actionHandler = listener;
10637
+ return this;
10638
+ }
10639
+ createOption(flags, description) {
10640
+ return new Option(flags, description);
10641
+ }
10642
+ _callParseArg(target, value, previous, invalidArgumentMessage) {
10643
+ try {
10644
+ return target.parseArg(value, previous);
10645
+ } catch (err2) {
10646
+ if (err2.code === "commander.invalidArgument") {
10647
+ const message = `${invalidArgumentMessage} ${err2.message}`;
10648
+ this.error(message, { exitCode: err2.exitCode, code: err2.code });
10649
+ }
10650
+ throw err2;
10651
+ }
10652
+ }
10653
+ _registerOption(option) {
10654
+ const matchingOption = option.short && this._findOption(option.short) || option.long && this._findOption(option.long);
10655
+ if (matchingOption) {
10656
+ const matchingFlag = option.long && this._findOption(option.long) ? option.long : option.short;
10657
+ throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
10658
+ - already used by option '${matchingOption.flags}'`);
10659
+ }
10660
+ this.options.push(option);
10661
+ }
10662
+ _registerCommand(command) {
10663
+ const knownBy = (cmd) => {
10664
+ return [cmd.name()].concat(cmd.aliases());
10665
+ };
10666
+ const alreadyUsed = knownBy(command).find((name) => this._findCommand(name));
10667
+ if (alreadyUsed) {
10668
+ const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
10669
+ const newCmd = knownBy(command).join("|");
10670
+ throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
10671
+ }
10672
+ this.commands.push(command);
10673
+ }
10674
+ addOption(option) {
10675
+ this._registerOption(option);
10676
+ const oname = option.name();
10677
+ const name = option.attributeName();
10678
+ if (option.negate) {
10679
+ const positiveLongFlag = option.long.replace(/^--no-/, "--");
10680
+ if (!this._findOption(positiveLongFlag)) {
10681
+ this.setOptionValueWithSource(name, option.defaultValue === undefined ? true : option.defaultValue, "default");
10682
+ }
10683
+ } else if (option.defaultValue !== undefined) {
10684
+ this.setOptionValueWithSource(name, option.defaultValue, "default");
10685
+ }
10686
+ const handleOptionValue = (val, invalidValueMessage, valueSource) => {
10687
+ if (val == null && option.presetArg !== undefined) {
10688
+ val = option.presetArg;
10689
+ }
10690
+ const oldValue = this.getOptionValue(name);
10691
+ if (val !== null && option.parseArg) {
10692
+ val = this._callParseArg(option, val, oldValue, invalidValueMessage);
10693
+ } else if (val !== null && option.variadic) {
10694
+ val = option._concatValue(val, oldValue);
10695
+ }
10696
+ if (val == null) {
10697
+ if (option.negate) {
10698
+ val = false;
10699
+ } else if (option.isBoolean() || option.optional) {
10700
+ val = true;
10701
+ } else {
10702
+ val = "";
10703
+ }
10704
+ }
10705
+ this.setOptionValueWithSource(name, val, valueSource);
10706
+ };
10707
+ this.on("option:" + oname, (val) => {
10708
+ const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;
10709
+ handleOptionValue(val, invalidValueMessage, "cli");
10710
+ });
10711
+ if (option.envVar) {
10712
+ this.on("optionEnv:" + oname, (val) => {
10713
+ const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;
10714
+ handleOptionValue(val, invalidValueMessage, "env");
10715
+ });
10716
+ }
10717
+ return this;
10718
+ }
10719
+ _optionEx(config, flags, description, fn, defaultValue) {
10720
+ if (typeof flags === "object" && flags instanceof Option) {
10721
+ throw new Error("To add an Option object use addOption() instead of option() or requiredOption()");
10722
+ }
10723
+ const option = this.createOption(flags, description);
10724
+ option.makeOptionMandatory(!!config.mandatory);
10725
+ if (typeof fn === "function") {
10726
+ option.default(defaultValue).argParser(fn);
10727
+ } else if (fn instanceof RegExp) {
10728
+ const regex = fn;
10729
+ fn = (val, def) => {
10730
+ const m = regex.exec(val);
10731
+ return m ? m[0] : def;
10732
+ };
10733
+ option.default(defaultValue).argParser(fn);
10734
+ } else {
10735
+ option.default(fn);
10736
+ }
10737
+ return this.addOption(option);
10738
+ }
10739
+ option(flags, description, parseArg, defaultValue) {
10740
+ return this._optionEx({}, flags, description, parseArg, defaultValue);
10741
+ }
10742
+ requiredOption(flags, description, parseArg, defaultValue) {
10743
+ return this._optionEx({ mandatory: true }, flags, description, parseArg, defaultValue);
10744
+ }
10745
+ combineFlagAndOptionalValue(combine = true) {
10746
+ this._combineFlagAndOptionalValue = !!combine;
10747
+ return this;
10748
+ }
10749
+ allowUnknownOption(allowUnknown = true) {
10750
+ this._allowUnknownOption = !!allowUnknown;
10751
+ return this;
10752
+ }
10753
+ allowExcessArguments(allowExcess = true) {
10754
+ this._allowExcessArguments = !!allowExcess;
10755
+ return this;
10756
+ }
10757
+ enablePositionalOptions(positional = true) {
10758
+ this._enablePositionalOptions = !!positional;
10759
+ return this;
10760
+ }
10761
+ passThroughOptions(passThrough2 = true) {
10762
+ this._passThroughOptions = !!passThrough2;
10763
+ this._checkForBrokenPassThrough();
10764
+ return this;
10765
+ }
10766
+ _checkForBrokenPassThrough() {
10767
+ if (this.parent && this._passThroughOptions && !this.parent._enablePositionalOptions) {
10768
+ throw new Error(`passThroughOptions cannot be used for '${this._name}' without turning on enablePositionalOptions for parent command(s)`);
10769
+ }
10770
+ }
10771
+ storeOptionsAsProperties(storeAsProperties = true) {
10772
+ if (this.options.length) {
10773
+ throw new Error("call .storeOptionsAsProperties() before adding options");
10774
+ }
10775
+ if (Object.keys(this._optionValues).length) {
10776
+ throw new Error("call .storeOptionsAsProperties() before setting option values");
10777
+ }
10778
+ this._storeOptionsAsProperties = !!storeAsProperties;
10779
+ return this;
10780
+ }
10781
+ getOptionValue(key) {
10782
+ if (this._storeOptionsAsProperties) {
10783
+ return this[key];
10784
+ }
10785
+ return this._optionValues[key];
10786
+ }
10787
+ setOptionValue(key, value) {
10788
+ return this.setOptionValueWithSource(key, value, undefined);
10789
+ }
10790
+ setOptionValueWithSource(key, value, source) {
10791
+ if (this._storeOptionsAsProperties) {
10792
+ this[key] = value;
10793
+ } else {
10794
+ this._optionValues[key] = value;
10795
+ }
10796
+ this._optionValueSources[key] = source;
10797
+ return this;
10798
+ }
10799
+ getOptionValueSource(key) {
10800
+ return this._optionValueSources[key];
10801
+ }
10802
+ getOptionValueSourceWithGlobals(key) {
10803
+ let source;
10804
+ this._getCommandAndAncestors().forEach((cmd) => {
10805
+ if (cmd.getOptionValueSource(key) !== undefined) {
10806
+ source = cmd.getOptionValueSource(key);
10807
+ }
10808
+ });
10809
+ return source;
10810
+ }
10811
+ _prepareUserArgs(argv, parseOptions) {
10812
+ if (argv !== undefined && !Array.isArray(argv)) {
10813
+ throw new Error("first parameter to parse must be array or undefined");
10814
+ }
10815
+ parseOptions = parseOptions || {};
10816
+ if (argv === undefined && parseOptions.from === undefined) {
10817
+ if (process2.versions?.electron) {
10818
+ parseOptions.from = "electron";
10819
+ }
10820
+ const execArgv = process2.execArgv ?? [];
10821
+ if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
10822
+ parseOptions.from = "eval";
10823
+ }
10824
+ }
10825
+ if (argv === undefined) {
10826
+ argv = process2.argv;
10827
+ }
10828
+ this.rawArgs = argv.slice();
10829
+ let userArgs;
10830
+ switch (parseOptions.from) {
10831
+ case undefined:
10832
+ case "node":
10833
+ this._scriptPath = argv[1];
10834
+ userArgs = argv.slice(2);
10835
+ break;
10836
+ case "electron":
10837
+ if (process2.defaultApp) {
10838
+ this._scriptPath = argv[1];
10839
+ userArgs = argv.slice(2);
10840
+ } else {
10841
+ userArgs = argv.slice(1);
10842
+ }
10843
+ break;
10844
+ case "user":
10845
+ userArgs = argv.slice(0);
10846
+ break;
10847
+ case "eval":
10848
+ userArgs = argv.slice(1);
10849
+ break;
10850
+ default:
10851
+ throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);
10852
+ }
10853
+ if (!this._name && this._scriptPath)
10854
+ this.nameFromFilename(this._scriptPath);
10855
+ this._name = this._name || "program";
10856
+ return userArgs;
10857
+ }
10858
+ parse(argv, parseOptions) {
10859
+ this._prepareForParse();
10860
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
10861
+ this._parseCommand([], userArgs);
10862
+ return this;
10863
+ }
10864
+ async parseAsync(argv, parseOptions) {
10865
+ this._prepareForParse();
10866
+ const userArgs = this._prepareUserArgs(argv, parseOptions);
10867
+ await this._parseCommand([], userArgs);
10868
+ return this;
10869
+ }
10870
+ _prepareForParse() {
10871
+ if (this._savedState === null) {
10872
+ this.saveStateBeforeParse();
10873
+ } else {
10874
+ this.restoreStateBeforeParse();
10875
+ }
10876
+ }
10877
+ saveStateBeforeParse() {
10878
+ this._savedState = {
10879
+ _name: this._name,
10880
+ _optionValues: { ...this._optionValues },
10881
+ _optionValueSources: { ...this._optionValueSources }
10882
+ };
10883
+ }
10884
+ restoreStateBeforeParse() {
10885
+ if (this._storeOptionsAsProperties)
10886
+ throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
10887
+ - either make a new Command for each call to parse, or stop storing options as properties`);
10888
+ this._name = this._savedState._name;
10889
+ this._scriptPath = null;
10890
+ this.rawArgs = [];
10891
+ this._optionValues = { ...this._savedState._optionValues };
10892
+ this._optionValueSources = { ...this._savedState._optionValueSources };
10893
+ this.args = [];
10894
+ this.processedArgs = [];
10895
+ }
10896
+ _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
10897
+ if (fs2.existsSync(executableFile))
10898
+ return;
10899
+ const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
10900
+ const executableMissing = `'${executableFile}' does not exist
10901
+ - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
10902
+ - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
10903
+ - ${executableDirMessage}`;
10904
+ throw new Error(executableMissing);
10905
+ }
10906
+ _executeSubCommand(subcommand, args) {
10907
+ args = args.slice();
10908
+ let launchWithNode = false;
10909
+ const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
10910
+ function findFile(baseDir, baseName) {
10911
+ const localBin = path2.resolve(baseDir, baseName);
10912
+ if (fs2.existsSync(localBin))
10913
+ return localBin;
10914
+ if (sourceExt.includes(path2.extname(baseName)))
10915
+ return;
10916
+ const foundExt = sourceExt.find((ext) => fs2.existsSync(`${localBin}${ext}`));
10917
+ if (foundExt)
10918
+ return `${localBin}${foundExt}`;
10919
+ return;
10920
+ }
10921
+ this._checkForMissingMandatoryOptions();
10922
+ this._checkForConflictingOptions();
10923
+ let executableFile = subcommand._executableFile || `${this._name}-${subcommand._name}`;
10924
+ let executableDir = this._executableDir || "";
10925
+ if (this._scriptPath) {
10926
+ let resolvedScriptPath;
10927
+ try {
10928
+ resolvedScriptPath = fs2.realpathSync(this._scriptPath);
10929
+ } catch {
10930
+ resolvedScriptPath = this._scriptPath;
10931
+ }
10932
+ executableDir = path2.resolve(path2.dirname(resolvedScriptPath), executableDir);
10933
+ }
10934
+ if (executableDir) {
10935
+ let localFile = findFile(executableDir, executableFile);
10936
+ if (!localFile && !subcommand._executableFile && this._scriptPath) {
10937
+ const legacyName = path2.basename(this._scriptPath, path2.extname(this._scriptPath));
10938
+ if (legacyName !== this._name) {
10939
+ localFile = findFile(executableDir, `${legacyName}-${subcommand._name}`);
10940
+ }
10941
+ }
10942
+ executableFile = localFile || executableFile;
10943
+ }
10944
+ launchWithNode = sourceExt.includes(path2.extname(executableFile));
10945
+ let proc;
10946
+ if (process2.platform !== "win32") {
10947
+ if (launchWithNode) {
10948
+ args.unshift(executableFile);
10949
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
10950
+ proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
10951
+ } else {
10952
+ proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
10953
+ }
10954
+ } else {
10955
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
10956
+ args.unshift(executableFile);
10957
+ args = incrementNodeInspectorPort(process2.execArgv).concat(args);
10958
+ proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
10959
+ }
10960
+ if (!proc.killed) {
10961
+ const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
10962
+ signals.forEach((signal) => {
10963
+ process2.on(signal, () => {
10964
+ if (proc.killed === false && proc.exitCode === null) {
10965
+ proc.kill(signal);
10966
+ }
10967
+ });
10968
+ });
10969
+ }
10970
+ const exitCallback = this._exitCallback;
10971
+ proc.on("close", (code) => {
10972
+ code = code ?? 1;
10973
+ if (!exitCallback) {
10974
+ process2.exit(code);
10975
+ } else {
10976
+ exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)"));
10977
+ }
10978
+ });
10979
+ proc.on("error", (err2) => {
10980
+ if (err2.code === "ENOENT") {
10981
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
10982
+ } else if (err2.code === "EACCES") {
10983
+ throw new Error(`'${executableFile}' not executable`);
10984
+ }
10985
+ if (!exitCallback) {
10986
+ process2.exit(1);
10987
+ } else {
10988
+ const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
10989
+ wrappedError.nestedError = err2;
10990
+ exitCallback(wrappedError);
10991
+ }
10992
+ });
10993
+ this.runningCommand = proc;
10994
+ }
10995
+ _dispatchSubcommand(commandName, operands, unknown) {
10996
+ const subCommand = this._findCommand(commandName);
10997
+ if (!subCommand)
10998
+ this.help({ error: true });
10999
+ subCommand._prepareForParse();
11000
+ let promiseChain;
11001
+ promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, "preSubcommand");
11002
+ promiseChain = this._chainOrCall(promiseChain, () => {
11003
+ if (subCommand._executableHandler) {
11004
+ this._executeSubCommand(subCommand, operands.concat(unknown));
11005
+ } else {
11006
+ return subCommand._parseCommand(operands, unknown);
11007
+ }
11008
+ });
11009
+ return promiseChain;
11010
+ }
11011
+ _dispatchHelpCommand(subcommandName) {
11012
+ if (!subcommandName) {
11013
+ this.help();
11014
+ }
11015
+ const subCommand = this._findCommand(subcommandName);
11016
+ if (subCommand && !subCommand._executableHandler) {
11017
+ subCommand.help();
11018
+ }
11019
+ return this._dispatchSubcommand(subcommandName, [], [this._getHelpOption()?.long ?? this._getHelpOption()?.short ?? "--help"]);
11020
+ }
11021
+ _checkNumberOfArguments() {
11022
+ this.registeredArguments.forEach((arg, i) => {
11023
+ if (arg.required && this.args[i] == null) {
11024
+ this.missingArgument(arg.name());
11025
+ }
11026
+ });
11027
+ if (this.registeredArguments.length > 0 && this.registeredArguments[this.registeredArguments.length - 1].variadic) {
11028
+ return;
11029
+ }
11030
+ if (this.args.length > this.registeredArguments.length) {
11031
+ this._excessArguments(this.args);
11032
+ }
11033
+ }
11034
+ _processArguments() {
11035
+ const myParseArg = (argument, value, previous) => {
11036
+ let parsedValue = value;
11037
+ if (value !== null && argument.parseArg) {
11038
+ const invalidValueMessage = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'.`;
11039
+ parsedValue = this._callParseArg(argument, value, previous, invalidValueMessage);
11040
+ }
11041
+ return parsedValue;
11042
+ };
11043
+ this._checkNumberOfArguments();
11044
+ const processedArgs = [];
11045
+ this.registeredArguments.forEach((declaredArg, index) => {
11046
+ let value = declaredArg.defaultValue;
11047
+ if (declaredArg.variadic) {
11048
+ if (index < this.args.length) {
11049
+ value = this.args.slice(index);
11050
+ if (declaredArg.parseArg) {
11051
+ value = value.reduce((processed, v) => {
11052
+ return myParseArg(declaredArg, v, processed);
11053
+ }, declaredArg.defaultValue);
11054
+ }
11055
+ } else if (value === undefined) {
11056
+ value = [];
11057
+ }
11058
+ } else if (index < this.args.length) {
11059
+ value = this.args[index];
11060
+ if (declaredArg.parseArg) {
11061
+ value = myParseArg(declaredArg, value, declaredArg.defaultValue);
11062
+ }
11063
+ }
11064
+ processedArgs[index] = value;
11065
+ });
11066
+ this.processedArgs = processedArgs;
11067
+ }
11068
+ _chainOrCall(promise, fn) {
11069
+ if (promise && promise.then && typeof promise.then === "function") {
11070
+ return promise.then(() => fn());
11071
+ }
11072
+ return fn();
11073
+ }
11074
+ _chainOrCallHooks(promise, event) {
11075
+ let result = promise;
11076
+ const hooks = [];
11077
+ this._getCommandAndAncestors().reverse().filter((cmd) => cmd._lifeCycleHooks[event] !== undefined).forEach((hookedCommand) => {
11078
+ hookedCommand._lifeCycleHooks[event].forEach((callback) => {
11079
+ hooks.push({ hookedCommand, callback });
11080
+ });
11081
+ });
11082
+ if (event === "postAction") {
11083
+ hooks.reverse();
11084
+ }
11085
+ hooks.forEach((hookDetail) => {
11086
+ result = this._chainOrCall(result, () => {
11087
+ return hookDetail.callback(hookDetail.hookedCommand, this);
11088
+ });
11089
+ });
11090
+ return result;
11091
+ }
11092
+ _chainOrCallSubCommandHook(promise, subCommand, event) {
11093
+ let result = promise;
11094
+ if (this._lifeCycleHooks[event] !== undefined) {
11095
+ this._lifeCycleHooks[event].forEach((hook) => {
11096
+ result = this._chainOrCall(result, () => {
11097
+ return hook(this, subCommand);
11098
+ });
11099
+ });
11100
+ }
11101
+ return result;
11102
+ }
11103
+ _parseCommand(operands, unknown) {
11104
+ const parsed = this.parseOptions(unknown);
11105
+ this._parseOptionsEnv();
11106
+ this._parseOptionsImplied();
11107
+ operands = operands.concat(parsed.operands);
11108
+ unknown = parsed.unknown;
11109
+ this.args = operands.concat(unknown);
11110
+ if (operands && this._findCommand(operands[0])) {
11111
+ return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);
11112
+ }
11113
+ if (this._getHelpCommand() && operands[0] === this._getHelpCommand().name()) {
11114
+ return this._dispatchHelpCommand(operands[1]);
11115
+ }
11116
+ if (this._defaultCommandName) {
11117
+ this._outputHelpIfRequested(unknown);
11118
+ return this._dispatchSubcommand(this._defaultCommandName, operands, unknown);
11119
+ }
11120
+ if (this.commands.length && this.args.length === 0 && !this._actionHandler && !this._defaultCommandName) {
11121
+ this.help({ error: true });
11122
+ }
11123
+ this._outputHelpIfRequested(parsed.unknown);
11124
+ this._checkForMissingMandatoryOptions();
11125
+ this._checkForConflictingOptions();
11126
+ const checkForUnknownOptions = () => {
11127
+ if (parsed.unknown.length > 0) {
11128
+ this.unknownOption(parsed.unknown[0]);
11129
+ }
11130
+ };
11131
+ const commandEvent = `command:${this.name()}`;
11132
+ if (this._actionHandler) {
11133
+ checkForUnknownOptions();
11134
+ this._processArguments();
11135
+ let promiseChain;
11136
+ promiseChain = this._chainOrCallHooks(promiseChain, "preAction");
11137
+ promiseChain = this._chainOrCall(promiseChain, () => this._actionHandler(this.processedArgs));
11138
+ if (this.parent) {
11139
+ promiseChain = this._chainOrCall(promiseChain, () => {
11140
+ this.parent.emit(commandEvent, operands, unknown);
11141
+ });
11142
+ }
11143
+ promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
11144
+ return promiseChain;
11145
+ }
11146
+ if (this.parent && this.parent.listenerCount(commandEvent)) {
11147
+ checkForUnknownOptions();
11148
+ this._processArguments();
11149
+ this.parent.emit(commandEvent, operands, unknown);
11150
+ } else if (operands.length) {
11151
+ if (this._findCommand("*")) {
11152
+ return this._dispatchSubcommand("*", operands, unknown);
11153
+ }
11154
+ if (this.listenerCount("command:*")) {
11155
+ this.emit("command:*", operands, unknown);
11156
+ } else if (this.commands.length) {
11157
+ this.unknownCommand();
11158
+ } else {
11159
+ checkForUnknownOptions();
11160
+ this._processArguments();
11161
+ }
11162
+ } else if (this.commands.length) {
11163
+ checkForUnknownOptions();
11164
+ this.help({ error: true });
11165
+ } else {
11166
+ checkForUnknownOptions();
11167
+ this._processArguments();
11168
+ }
11169
+ }
11170
+ _findCommand(name) {
11171
+ if (!name)
11172
+ return;
11173
+ return this.commands.find((cmd) => cmd._name === name || cmd._aliases.includes(name));
11174
+ }
11175
+ _findOption(arg) {
11176
+ return this.options.find((option) => option.is(arg));
11177
+ }
11178
+ _checkForMissingMandatoryOptions() {
11179
+ this._getCommandAndAncestors().forEach((cmd) => {
11180
+ cmd.options.forEach((anOption) => {
11181
+ if (anOption.mandatory && cmd.getOptionValue(anOption.attributeName()) === undefined) {
11182
+ cmd.missingMandatoryOptionValue(anOption);
11183
+ }
11184
+ });
11185
+ });
11186
+ }
11187
+ _checkForConflictingLocalOptions() {
11188
+ const definedNonDefaultOptions = this.options.filter((option) => {
11189
+ const optionKey = option.attributeName();
11190
+ if (this.getOptionValue(optionKey) === undefined) {
11191
+ return false;
11192
+ }
11193
+ return this.getOptionValueSource(optionKey) !== "default";
11194
+ });
11195
+ const optionsWithConflicting = definedNonDefaultOptions.filter((option) => option.conflictsWith.length > 0);
11196
+ optionsWithConflicting.forEach((option) => {
11197
+ const conflictingAndDefined = definedNonDefaultOptions.find((defined) => option.conflictsWith.includes(defined.attributeName()));
11198
+ if (conflictingAndDefined) {
11199
+ this._conflictingOption(option, conflictingAndDefined);
11200
+ }
11201
+ });
11202
+ }
11203
+ _checkForConflictingOptions() {
11204
+ this._getCommandAndAncestors().forEach((cmd) => {
11205
+ cmd._checkForConflictingLocalOptions();
11206
+ });
11207
+ }
11208
+ parseOptions(argv) {
11209
+ const operands = [];
11210
+ const unknown = [];
11211
+ let dest = operands;
11212
+ const args = argv.slice();
11213
+ function maybeOption(arg) {
11214
+ return arg.length > 1 && arg[0] === "-";
11215
+ }
11216
+ let activeVariadicOption = null;
11217
+ while (args.length) {
11218
+ const arg = args.shift();
11219
+ if (arg === "--") {
11220
+ if (dest === unknown)
11221
+ dest.push(arg);
11222
+ dest.push(...args);
11223
+ break;
11224
+ }
11225
+ if (activeVariadicOption && !maybeOption(arg)) {
11226
+ this.emit(`option:${activeVariadicOption.name()}`, arg);
11227
+ continue;
11228
+ }
11229
+ activeVariadicOption = null;
11230
+ if (maybeOption(arg)) {
11231
+ const option = this._findOption(arg);
11232
+ if (option) {
11233
+ if (option.required) {
11234
+ const value = args.shift();
11235
+ if (value === undefined)
11236
+ this.optionMissingArgument(option);
11237
+ this.emit(`option:${option.name()}`, value);
11238
+ } else if (option.optional) {
11239
+ let value = null;
11240
+ if (args.length > 0 && !maybeOption(args[0])) {
11241
+ value = args.shift();
11242
+ }
11243
+ this.emit(`option:${option.name()}`, value);
11244
+ } else {
11245
+ this.emit(`option:${option.name()}`);
11246
+ }
11247
+ activeVariadicOption = option.variadic ? option : null;
11248
+ continue;
11249
+ }
11250
+ }
11251
+ if (arg.length > 2 && arg[0] === "-" && arg[1] !== "-") {
11252
+ const option = this._findOption(`-${arg[1]}`);
11253
+ if (option) {
11254
+ if (option.required || option.optional && this._combineFlagAndOptionalValue) {
11255
+ this.emit(`option:${option.name()}`, arg.slice(2));
11256
+ } else {
11257
+ this.emit(`option:${option.name()}`);
11258
+ args.unshift(`-${arg.slice(2)}`);
11259
+ }
11260
+ continue;
11261
+ }
11262
+ }
11263
+ if (/^--[^=]+=/.test(arg)) {
11264
+ const index = arg.indexOf("=");
11265
+ const option = this._findOption(arg.slice(0, index));
11266
+ if (option && (option.required || option.optional)) {
11267
+ this.emit(`option:${option.name()}`, arg.slice(index + 1));
11268
+ continue;
11269
+ }
11270
+ }
11271
+ if (maybeOption(arg)) {
11272
+ dest = unknown;
11273
+ }
11274
+ if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
11275
+ if (this._findCommand(arg)) {
11276
+ operands.push(arg);
11277
+ if (args.length > 0)
11278
+ unknown.push(...args);
11279
+ break;
11280
+ } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
11281
+ operands.push(arg);
11282
+ if (args.length > 0)
11283
+ operands.push(...args);
11284
+ break;
11285
+ } else if (this._defaultCommandName) {
11286
+ unknown.push(arg);
11287
+ if (args.length > 0)
11288
+ unknown.push(...args);
11289
+ break;
11290
+ }
11291
+ }
11292
+ if (this._passThroughOptions) {
11293
+ dest.push(arg);
11294
+ if (args.length > 0)
11295
+ dest.push(...args);
11296
+ break;
11297
+ }
11298
+ dest.push(arg);
11299
+ }
11300
+ return { operands, unknown };
11301
+ }
11302
+ opts() {
11303
+ if (this._storeOptionsAsProperties) {
11304
+ const result = {};
11305
+ const len = this.options.length;
11306
+ for (let i = 0;i < len; i++) {
11307
+ const key = this.options[i].attributeName();
11308
+ result[key] = key === this._versionOptionName ? this._version : this[key];
11309
+ }
11310
+ return result;
11311
+ }
11312
+ return this._optionValues;
11313
+ }
11314
+ optsWithGlobals() {
11315
+ return this._getCommandAndAncestors().reduce((combinedOptions, cmd) => Object.assign(combinedOptions, cmd.opts()), {});
11316
+ }
11317
+ error(message, errorOptions) {
11318
+ this._outputConfiguration.outputError(`${message}
11319
+ `, this._outputConfiguration.writeErr);
11320
+ if (typeof this._showHelpAfterError === "string") {
11321
+ this._outputConfiguration.writeErr(`${this._showHelpAfterError}
11322
+ `);
11323
+ } else if (this._showHelpAfterError) {
11324
+ this._outputConfiguration.writeErr(`
11325
+ `);
11326
+ this.outputHelp({ error: true });
11327
+ }
11328
+ const config = errorOptions || {};
11329
+ const exitCode = config.exitCode || 1;
11330
+ const code = config.code || "commander.error";
11331
+ this._exit(exitCode, code, message);
11332
+ }
11333
+ _parseOptionsEnv() {
11334
+ this.options.forEach((option) => {
11335
+ if (option.envVar && option.envVar in process2.env) {
11336
+ const optionKey = option.attributeName();
11337
+ if (this.getOptionValue(optionKey) === undefined || ["default", "config", "env"].includes(this.getOptionValueSource(optionKey))) {
11338
+ if (option.required || option.optional) {
11339
+ this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
11340
+ } else {
11341
+ this.emit(`optionEnv:${option.name()}`);
11342
+ }
11343
+ }
11344
+ }
11345
+ });
11346
+ }
11347
+ _parseOptionsImplied() {
11348
+ const dualHelper = new DualOptions(this.options);
11349
+ const hasCustomOptionValue = (optionKey) => {
11350
+ return this.getOptionValue(optionKey) !== undefined && !["default", "implied"].includes(this.getOptionValueSource(optionKey));
11351
+ };
11352
+ this.options.filter((option) => option.implied !== undefined && hasCustomOptionValue(option.attributeName()) && dualHelper.valueFromOption(this.getOptionValue(option.attributeName()), option)).forEach((option) => {
11353
+ Object.keys(option.implied).filter((impliedKey) => !hasCustomOptionValue(impliedKey)).forEach((impliedKey) => {
11354
+ this.setOptionValueWithSource(impliedKey, option.implied[impliedKey], "implied");
11355
+ });
11356
+ });
11357
+ }
11358
+ missingArgument(name) {
11359
+ const message = `error: missing required argument '${name}'`;
11360
+ this.error(message, { code: "commander.missingArgument" });
11361
+ }
11362
+ optionMissingArgument(option) {
11363
+ const message = `error: option '${option.flags}' argument missing`;
11364
+ this.error(message, { code: "commander.optionMissingArgument" });
11365
+ }
11366
+ missingMandatoryOptionValue(option) {
11367
+ const message = `error: required option '${option.flags}' not specified`;
11368
+ this.error(message, { code: "commander.missingMandatoryOptionValue" });
11369
+ }
11370
+ _conflictingOption(option, conflictingOption) {
11371
+ const findBestOptionFromValue = (option2) => {
11372
+ const optionKey = option2.attributeName();
11373
+ const optionValue = this.getOptionValue(optionKey);
11374
+ const negativeOption = this.options.find((target) => target.negate && optionKey === target.attributeName());
11375
+ const positiveOption = this.options.find((target) => !target.negate && optionKey === target.attributeName());
11376
+ if (negativeOption && (negativeOption.presetArg === undefined && optionValue === false || negativeOption.presetArg !== undefined && optionValue === negativeOption.presetArg)) {
11377
+ return negativeOption;
11378
+ }
11379
+ return positiveOption || option2;
11380
+ };
11381
+ const getErrorMessage = (option2) => {
11382
+ const bestOption = findBestOptionFromValue(option2);
11383
+ const optionKey = bestOption.attributeName();
11384
+ const source = this.getOptionValueSource(optionKey);
11385
+ if (source === "env") {
11386
+ return `environment variable '${bestOption.envVar}'`;
11387
+ }
11388
+ return `option '${bestOption.flags}'`;
11389
+ };
11390
+ const message = `error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;
11391
+ this.error(message, { code: "commander.conflictingOption" });
11392
+ }
11393
+ unknownOption(flag) {
11394
+ if (this._allowUnknownOption)
11395
+ return;
11396
+ let suggestion = "";
11397
+ if (flag.startsWith("--") && this._showSuggestionAfterError) {
11398
+ let candidateFlags = [];
11399
+ let command = this;
11400
+ do {
11401
+ const moreFlags = command.createHelp().visibleOptions(command).filter((option) => option.long).map((option) => option.long);
11402
+ candidateFlags = candidateFlags.concat(moreFlags);
11403
+ command = command.parent;
11404
+ } while (command && !command._enablePositionalOptions);
11405
+ suggestion = suggestSimilar(flag, candidateFlags);
11406
+ }
11407
+ const message = `error: unknown option '${flag}'${suggestion}`;
11408
+ this.error(message, { code: "commander.unknownOption" });
11409
+ }
11410
+ _excessArguments(receivedArgs) {
11411
+ if (this._allowExcessArguments)
11412
+ return;
11413
+ const expected = this.registeredArguments.length;
11414
+ const s = expected === 1 ? "" : "s";
11415
+ const forSubcommand = this.parent ? ` for '${this.name()}'` : "";
11416
+ const message = `error: too many arguments${forSubcommand}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;
11417
+ this.error(message, { code: "commander.excessArguments" });
11418
+ }
11419
+ unknownCommand() {
11420
+ const unknownName = this.args[0];
11421
+ let suggestion = "";
11422
+ if (this._showSuggestionAfterError) {
11423
+ const candidateNames = [];
11424
+ this.createHelp().visibleCommands(this).forEach((command) => {
11425
+ candidateNames.push(command.name());
11426
+ if (command.alias())
11427
+ candidateNames.push(command.alias());
11428
+ });
11429
+ suggestion = suggestSimilar(unknownName, candidateNames);
11430
+ }
11431
+ const message = `error: unknown command '${unknownName}'${suggestion}`;
11432
+ this.error(message, { code: "commander.unknownCommand" });
11433
+ }
11434
+ version(str, flags, description) {
11435
+ if (str === undefined)
11436
+ return this._version;
11437
+ this._version = str;
11438
+ flags = flags || "-V, --version";
11439
+ description = description || "output the version number";
11440
+ const versionOption = this.createOption(flags, description);
11441
+ this._versionOptionName = versionOption.attributeName();
11442
+ this._registerOption(versionOption);
11443
+ this.on("option:" + versionOption.name(), () => {
11444
+ this._outputConfiguration.writeOut(`${str}
11445
+ `);
11446
+ this._exit(0, "commander.version", str);
11447
+ });
11448
+ return this;
11449
+ }
11450
+ description(str, argsDescription) {
11451
+ if (str === undefined && argsDescription === undefined)
11452
+ return this._description;
11453
+ this._description = str;
11454
+ if (argsDescription) {
11455
+ this._argsDescription = argsDescription;
11456
+ }
11457
+ return this;
11458
+ }
11459
+ summary(str) {
11460
+ if (str === undefined)
11461
+ return this._summary;
11462
+ this._summary = str;
11463
+ return this;
11464
+ }
11465
+ alias(alias) {
11466
+ if (alias === undefined)
11467
+ return this._aliases[0];
11468
+ let command = this;
11469
+ if (this.commands.length !== 0 && this.commands[this.commands.length - 1]._executableHandler) {
11470
+ command = this.commands[this.commands.length - 1];
11471
+ }
11472
+ if (alias === command._name)
11473
+ throw new Error("Command alias can't be the same as its name");
11474
+ const matchingCommand = this.parent?._findCommand(alias);
11475
+ if (matchingCommand) {
11476
+ const existingCmd = [matchingCommand.name()].concat(matchingCommand.aliases()).join("|");
11477
+ throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`);
11478
+ }
11479
+ command._aliases.push(alias);
11480
+ return this;
11481
+ }
11482
+ aliases(aliases) {
11483
+ if (aliases === undefined)
11484
+ return this._aliases;
11485
+ aliases.forEach((alias) => this.alias(alias));
11486
+ return this;
11487
+ }
11488
+ usage(str) {
11489
+ if (str === undefined) {
11490
+ if (this._usage)
11491
+ return this._usage;
11492
+ const args = this.registeredArguments.map((arg) => {
11493
+ return humanReadableArgName(arg);
11494
+ });
11495
+ return [].concat(this.options.length || this._helpOption !== null ? "[options]" : [], this.commands.length ? "[command]" : [], this.registeredArguments.length ? args : []).join(" ");
11496
+ }
11497
+ this._usage = str;
11498
+ return this;
11499
+ }
11500
+ name(str) {
11501
+ if (str === undefined)
11502
+ return this._name;
11503
+ this._name = str;
11504
+ return this;
11505
+ }
11506
+ nameFromFilename(filename) {
11507
+ this._name = path2.basename(filename, path2.extname(filename));
11508
+ return this;
11509
+ }
11510
+ executableDir(path3) {
11511
+ if (path3 === undefined)
11512
+ return this._executableDir;
11513
+ this._executableDir = path3;
11514
+ return this;
11515
+ }
11516
+ helpInformation(contextOptions) {
11517
+ const helper = this.createHelp();
11518
+ const context = this._getOutputContext(contextOptions);
11519
+ helper.prepareContext({
11520
+ error: context.error,
11521
+ helpWidth: context.helpWidth,
11522
+ outputHasColors: context.hasColors
11523
+ });
11524
+ const text = helper.formatHelp(this, helper);
11525
+ if (context.hasColors)
11526
+ return text;
11527
+ return this._outputConfiguration.stripColor(text);
11528
+ }
11529
+ _getOutputContext(contextOptions) {
11530
+ contextOptions = contextOptions || {};
11531
+ const error = !!contextOptions.error;
11532
+ let baseWrite;
11533
+ let hasColors;
11534
+ let helpWidth;
11535
+ if (error) {
11536
+ baseWrite = (str) => this._outputConfiguration.writeErr(str);
11537
+ hasColors = this._outputConfiguration.getErrHasColors();
11538
+ helpWidth = this._outputConfiguration.getErrHelpWidth();
11539
+ } else {
11540
+ baseWrite = (str) => this._outputConfiguration.writeOut(str);
11541
+ hasColors = this._outputConfiguration.getOutHasColors();
11542
+ helpWidth = this._outputConfiguration.getOutHelpWidth();
11543
+ }
11544
+ const write = (str) => {
11545
+ if (!hasColors)
11546
+ str = this._outputConfiguration.stripColor(str);
11547
+ return baseWrite(str);
11548
+ };
11549
+ return { error, write, hasColors, helpWidth };
11550
+ }
11551
+ outputHelp(contextOptions) {
11552
+ let deprecatedCallback;
11553
+ if (typeof contextOptions === "function") {
11554
+ deprecatedCallback = contextOptions;
11555
+ contextOptions = undefined;
11556
+ }
11557
+ const outputContext = this._getOutputContext(contextOptions);
11558
+ const eventContext = {
11559
+ error: outputContext.error,
11560
+ write: outputContext.write,
11561
+ command: this
11562
+ };
11563
+ this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
11564
+ this.emit("beforeHelp", eventContext);
11565
+ let helpInformation = this.helpInformation({ error: outputContext.error });
11566
+ if (deprecatedCallback) {
11567
+ helpInformation = deprecatedCallback(helpInformation);
11568
+ if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
11569
+ throw new Error("outputHelp callback must return a string or a Buffer");
11570
+ }
11571
+ }
11572
+ outputContext.write(helpInformation);
11573
+ if (this._getHelpOption()?.long) {
11574
+ this.emit(this._getHelpOption().long);
11575
+ }
11576
+ this.emit("afterHelp", eventContext);
11577
+ this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", eventContext));
11578
+ }
11579
+ helpOption(flags, description) {
11580
+ if (typeof flags === "boolean") {
11581
+ if (flags) {
11582
+ this._helpOption = this._helpOption ?? undefined;
11583
+ } else {
11584
+ this._helpOption = null;
11585
+ }
11586
+ return this;
11587
+ }
11588
+ flags = flags ?? "-h, --help";
11589
+ description = description ?? "display help for command";
11590
+ this._helpOption = this.createOption(flags, description);
11591
+ return this;
11592
+ }
11593
+ _getHelpOption() {
11594
+ if (this._helpOption === undefined) {
11595
+ this.helpOption(undefined, undefined);
11596
+ }
11597
+ return this._helpOption;
11598
+ }
11599
+ addHelpOption(option) {
11600
+ this._helpOption = option;
11601
+ return this;
11602
+ }
11603
+ help(contextOptions) {
11604
+ this.outputHelp(contextOptions);
11605
+ let exitCode = Number(process2.exitCode ?? 0);
11606
+ if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
11607
+ exitCode = 1;
11608
+ }
11609
+ this._exit(exitCode, "commander.help", "(outputHelp)");
11610
+ }
11611
+ addHelpText(position, text) {
11612
+ const allowedValues = ["beforeAll", "before", "after", "afterAll"];
11613
+ if (!allowedValues.includes(position)) {
11614
+ throw new Error(`Unexpected value for position to addHelpText.
11615
+ Expecting one of '${allowedValues.join("', '")}'`);
11616
+ }
11617
+ const helpEvent = `${position}Help`;
11618
+ this.on(helpEvent, (context) => {
11619
+ let helpStr;
11620
+ if (typeof text === "function") {
11621
+ helpStr = text({ error: context.error, command: context.command });
11622
+ } else {
11623
+ helpStr = text;
11624
+ }
11625
+ if (helpStr) {
11626
+ context.write(`${helpStr}
11627
+ `);
11628
+ }
11629
+ });
11630
+ return this;
11631
+ }
11632
+ _outputHelpIfRequested(args) {
11633
+ const helpOption = this._getHelpOption();
11634
+ const helpRequested = helpOption && args.find((arg) => helpOption.is(arg));
11635
+ if (helpRequested) {
11636
+ this.outputHelp();
11637
+ this._exit(0, "commander.helpDisplayed", "(outputHelp)");
11638
+ }
11639
+ }
11640
+ }
11641
+ function incrementNodeInspectorPort(args) {
11642
+ return args.map((arg) => {
11643
+ if (!arg.startsWith("--inspect")) {
11644
+ return arg;
11645
+ }
11646
+ let debugOption;
11647
+ let debugHost = "127.0.0.1";
11648
+ let debugPort = "9229";
11649
+ let match;
11650
+ if ((match = arg.match(/^(--inspect(-brk)?)$/)) !== null) {
11651
+ debugOption = match[1];
11652
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/)) !== null) {
11653
+ debugOption = match[1];
11654
+ if (/^\d+$/.test(match[3])) {
11655
+ debugPort = match[3];
11656
+ } else {
11657
+ debugHost = match[3];
11658
+ }
11659
+ } else if ((match = arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/)) !== null) {
11660
+ debugOption = match[1];
11661
+ debugHost = match[3];
11662
+ debugPort = match[4];
11663
+ }
11664
+ if (debugOption && debugPort !== "0") {
11665
+ return `${debugOption}=${debugHost}:${parseInt(debugPort) + 1}`;
11666
+ }
11667
+ return arg;
11668
+ });
11669
+ }
11670
+ function useColor() {
11671
+ if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
11672
+ return false;
11673
+ if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== undefined)
11674
+ return true;
11675
+ return;
11676
+ }
11677
+ exports2.Command = Command;
11678
+ exports2.useColor = useColor;
11679
+ });
11680
+
11681
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/index.js
11682
+ var require_commander = __commonJS((exports2) => {
11683
+ var { Argument } = require_argument();
11684
+ var { Command } = require_command();
11685
+ var { CommanderError, InvalidArgumentError } = require_error();
11686
+ var { Help } = require_help();
11687
+ var { Option } = require_option();
11688
+ exports2.program = new Command;
11689
+ exports2.createCommand = (name) => new Command(name);
11690
+ exports2.createOption = (flags, description) => new Option(flags, description);
11691
+ exports2.createArgument = (name, description) => new Argument(name, description);
11692
+ exports2.Command = Command;
11693
+ exports2.Option = Option;
11694
+ exports2.Argument = Argument;
11695
+ exports2.Help = Help;
11696
+ exports2.CommanderError = CommanderError;
11697
+ exports2.InvalidArgumentError = InvalidArgumentError;
11698
+ exports2.InvalidOptionArgumentError = InvalidArgumentError;
11699
+ });
11700
+
9667
11701
  // src/host-control/main.ts
9668
- import { homedir as homedir3 } from "node:os";
9669
- import { existsSync as existsSync8 } from "node:fs";
9670
- import { join as join4, resolve as resolve6 } from "node:path";
11702
+ import { homedir as homedir4 } from "node:os";
11703
+ import { existsSync as existsSync9 } from "node:fs";
11704
+ import { join as join6, resolve as resolve7 } from "node:path";
9671
11705
 
9672
11706
  // src/config/loader.ts
9673
11707
  import { readFileSync as readFileSync2, existsSync as existsSync3 } from "node:fs";
@@ -13885,7 +15919,7 @@ var TelegramChannelSchema = exports_external.object({
13885
15919
  format: exports_external.enum(["html", "markdownv2", "text"]).optional().describe("Default reply format passed to the plugin"),
13886
15920
  rate_limit_ms: exports_external.number().optional().describe("Minimum delay between outgoing messages in ms"),
13887
15921
  stream_mode: exports_external.enum(["pty", "checklist"]).optional().describe("How live progress is streamed to Telegram during a turn. " + "'pty' (default) surfaces text snapshots of Claude Code's TUI — " + "compatible but can flicker as Ink re-renders. 'checklist' drives " + "a structured progress card from session-tail events — stable " + "order, per-tool status emojis, fires only on semantic transitions."),
13888
- stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive stream edits (or " + "sendMessageDraft tics) during a turn. Lower = more responsive " + "stream, higher = fewer API calls. Floored at 250 by draft-stream " + "itself. Default 300 for draft transport (DMs) and 1000 for " + "message transport (groups/forums). Override per-agent if a " + "particular agent needs snappier or quieter streaming."),
15922
+ stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive in-place stream edits " + "during a turn. Lower = more responsive stream, higher = fewer API " + "calls. Floored at 250 by draft-stream itself. Default 400 ms for DMs " + "and 1000 ms for groups/forums (respects Telegram's ~1 edit/sec/message " + "practical ceiling). Override per-agent if a particular agent needs " + "snappier or quieter streaming."),
13889
15923
  clear_status_on_completion: exports_external.boolean().optional().describe("When true, the live activity/status feed (the in-place 'what it's " + "doing' message — Reading X, Searching the web for Y, …) is DELETED " + "when the turn's final answer lands, so only the reply remains. " + "Default false: the status message is left in the chat as a record " + "(its last step marked done) — no post-then-delete. Per-agent " + "override; cascades defaults → profile → agent (per-key)."),
13890
15924
  hotReloadStable: exports_external.boolean().optional().describe("If true, the stable workspace prefix (AGENTS.md, SOUL.md, USER.md, " + "IDENTITY.md, TOOLS.md) is re-injected on every turn via " + "the UserPromptSubmit hook instead of baked into --append-system-prompt " + "at session start. Lets workspace edits propagate without a restart. " + "Costs ~5-10% per-turn latency/spend since the stable prefix is no " + "longer prompt-cached."),
13891
15925
  inject_on_change: exports_external.boolean().optional().describe("Context-efficiency gate for per-turn hook injection (default true). " + "When true (the default), the turn-pacing directive and dynamic " + "workspace content are only re-emitted when their content changes or " + "the session_id changes — suppressing redundant injection that " + "otherwise triples compaction frequency. Set to false to revert to " + "the legacy always-emit behaviour (every turn injects the full " + "content regardless of whether it changed)."),
@@ -13973,6 +16007,14 @@ var GoogleWorkspaceConfigSchema = exports_external.object({
13973
16007
  approvers: exports_external.array(ApproverIdSchema).min(1).describe("Array of numeric Telegram user IDs authorized to approve drive onboarding. " + "At least one must be specified."),
13974
16008
  tier: GoogleWorkspaceTierSchema.optional().describe("RFC G Phase 1: which upstream MCP tier to expose. " + "core (default) = ~16 tools (Drive+Docs+Sheets+Calendar). " + "extended = ~40 tools (+Slides, Forms, Tasks, Chat). " + "complete = ~60+ tools (+Gmail; not recommended yet — see RFC G §5).")
13975
16009
  }).optional();
16010
+ var LiteLLMConfigSchema = exports_external.object({
16011
+ enabled: exports_external.boolean().optional().describe("Opt-in toggle. When true, `switchroom apply` provisions a per-agent " + "LiteLLM virtual key and injects routing env into the container. " + "Default OFF."),
16012
+ base_url: exports_external.string().optional().describe("LiteLLM proxy base URL the agent's claude CLI routes through, e.g. " + "'http://127.0.0.1:4010'. Agents use network_mode:host, so loopback " + "reaches a host-bound proxy. Exported as ANTHROPIC_BASE_URL."),
16013
+ admin_key: exports_external.string().optional().describe("LiteLLM master/admin key used at apply time to provision the team + " + "virtual key. Supports a vault reference (e.g. " + "'vault:litellm/master-key') — resolution happens at apply time via " + "the vault-broker. Never injected into the agent container."),
16014
+ team: exports_external.string().optional().describe("LiteLLM team alias the per-agent key is created under. Defaults to " + "'switchroom' (applied in code, not as a schema default)."),
16015
+ small_fast_model: exports_external.string().optional().describe("Model id exported as ANTHROPIC_SMALL_FAST_MODEL for the claude CLI's " + "background/fast lane, e.g. 'claude-haiku-4-5-20251001'."),
16016
+ tags: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Extra key/value metadata tags attached to the provisioned LiteLLM " + "virtual key. Merged per-key across cascade layers (agent wins).")
16017
+ }).optional().describe("LiteLLM routing config — opt-in per-agent virtual-key auto-provisioning " + "+ routing env. Default OFF. See LiteLLMConfigSchema doc for the full flow.");
13976
16018
  var MicrosoftWorkspaceConfigSchema = exports_external.object({
13977
16019
  microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL — omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
13978
16020
  microsoft_client_secret: exports_external.string().min(1).optional().describe("Microsoft OAuth client secret. Optional — public-client apps " + "(Mobile + Desktop platform with 'Allow public client flows' " + "enabled) work without a secret; confidential clients pass " + "one. Either literal or vault reference e.g. " + "'vault:microsoft-oauth-client-secret'."),
@@ -14069,6 +16111,7 @@ var profileFields = {
14069
16111
  mcp_servers: exports_external.record(exports_external.string(), exports_external.unknown()).optional(),
14070
16112
  hooks: AgentHooksSchema,
14071
16113
  env: exports_external.record(exports_external.string(), exports_external.string()).optional(),
16114
+ litellm: LiteLLMConfigSchema,
14072
16115
  system_prompt_append: exports_external.string().optional(),
14073
16116
  skills: exports_external.array(exports_external.string()).optional(),
14074
16117
  bundled_skills: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Opt-out map for switchroom's bundled-default skills " + "(e.g. skill-creator, mcp-builder, webapp-testing, pdf, docx, " + "xlsx, pptx, switchroom-cli, switchroom-status, switchroom-health). " + "Set a key to `false` to suppress that default for this agent. " + "Cascades from defaults.bundled_skills."),
@@ -14141,6 +16184,7 @@ var AgentSchema = exports_external.object({
14141
16184
  mcp_servers: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Additional MCP server configurations"),
14142
16185
  hooks: AgentHooksSchema.describe("Claude Code lifecycle hooks (SessionStart, UserPromptSubmit, Stop, etc). " + "Written to settings.json.hooks in Claude Code's native shape."),
14143
16186
  env: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Environment variables exported in start.sh before claude runs"),
16187
+ litellm: LiteLLMConfigSchema.describe("Per-agent LiteLLM routing override. Presence with `enabled: true` opts " + "this agent IN to per-agent virtual-key auto-provisioning + routing env " + "(falls back to the top-level `litellm:` block for base_url/admin_key/" + "team/small_fast_model). Deep-merges one level over defaults/profile; " + "`tags` merge per-key, agent wins. Default OFF."),
14144
16188
  system_prompt_append: exports_external.string().optional().describe("Text passed via claude's --append-system-prompt flag. " + "Appended to the default or CLAUDE.md-derived system prompt."),
14145
16189
  skills: exports_external.array(exports_external.string()).optional().describe("Names of skills from switchroom.skills_dir to symlink into this " + "agent's skills/ directory. Unioned with defaults.skills."),
14146
16190
  bundled_skills: exports_external.record(exports_external.string(), exports_external.boolean()).optional().describe("Per-agent override of switchroom's bundled-default skills " + "(skill-creator, mcp-builder, webapp-testing, pdf, docx, xlsx, " + "pptx, switchroom-cli/status/health). Set a key to `false` to " + "opt out for this agent. Per-agent value wins over defaults.bundled_skills."),
@@ -14266,7 +16310,7 @@ var WebServiceConfigSchema = exports_external.object({
14266
16310
  });
14267
16311
  var HostdConfigSchema = exports_external.object({
14268
16312
  config_edit_enabled: exports_external.boolean().default(false).describe("Opt-in toggle for the `config_propose_edit` hostd verb (RFC " + "admin-agent-config-edit §3). Default false — the verb returns " + "`E_CONFIG_EDIT_DISABLED` until the operator explicitly flips " + "this to true. When true, admin agents can propose unified-diff " + "patches against " + "`/state/config/switchroom.yaml`, gated by an operator approval " + "card in the primary chat. Same trust posture as `update_apply` " + "and `agent_restart`: the human-in-the-loop tap is the security " + "boundary, not the agent's judgement."),
14269
- config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. Configurable now, but the rate limiter is not yet enforced " + "(no `E_RATE_LIMITED` is currently raised); the field is reserved so " + "operators can pin the cap ahead of the limiter going live.")
16313
+ config_edit_rate_per_hour: exports_external.number().int().min(1).max(20).default(3).describe("Per-requesting-agent rate cap for `config_propose_edit` cards " + "(RFC admin-agent-config-edit §5). Default 3 cards/hour; min 1, " + "max 20. ENFORCED server-side: a caller exceeding this in a sliding " + "1-hour window is rejected with `E_RATE_LIMITED` (carrying a " + "`retry_after` fix) instead of posting another operator approval " + "card so a looping agent is throttled rather than spamming the chat.")
14270
16314
  });
14271
16315
  var CronEgressSchema = exports_external.object({
14272
16316
  allowed_hosts: exports_external.array(exports_external.string().min(1)).default([]).describe("Hosts a poll may reach (exact, https-only). loopback/private/IP-literal are always rejected."),
@@ -14299,11 +16343,14 @@ var SwitchroomConfigSchema = exports_external.object({
14299
16343
  message: "Consumer name must be a path-safe slug (letters, digits, underscore, hyphen)"
14300
16344
  }).describe("Socket-path identity; binds at /run/switchroom/auth-broker/<name>/sock"),
14301
16345
  account: exports_external.string().min(1).describe("Pinned account label for this consumer. `get-credentials` returns " + "this account's credentials; `mark-exhausted` from this consumer " + "only affects this account."),
14302
- uid: exports_external.number().int().nonnegative().optional().describe("Optional UID to chown the consumer socket to (defaults to 0 = root, " + "suitable for sibling containers running as root).")
14303
- })).optional().describe("Non-agent peers that hold a broker socket (RFC H §4.8). Each gets " + "its own `/run/switchroom/auth-broker/<name>/sock` chowned to its UID. " + "Consumers cannot be admins; a consumer name that collides with an " + "agent (whether that agent has `admin: true` or not) is a config " + "error caught at schema validation.")
16346
+ uid: exports_external.number().int().nonnegative().optional().describe("Optional UID to chown the consumer socket to (defaults to 0 = root, " + "suitable for sibling containers running as root)."),
16347
+ mirror_dir: exports_external.string().optional().describe("Optional host-side directory path. When set, the broker actively " + "writes the consumer's effective-account `.credentials.json` mirror " + "here — in addition to serving creds on demand via `get-credentials`. " + "Use this to eliminate the pull-latency gap: without a mirror the " + "consumer only gets failover creds at its next scheduled re-fetch " + "(up to 30 min). With a mirror the broker pushes failover creds " + "immediately when it detects exhaustion (consumer-quota-sensor tick, " + "or a mark-exhausted RPC on the pinned account). The directory must " + "be accessible to the broker container (bind-mounted from the host) " + "and to the consumer container; the broker writes " + "`<mirror_dir>/.credentials.json` atomically. Chown is attempted to " + "`uid` (default 0) swallowed when CAP_CHOWN is absent.")
16348
+ })).optional().describe("Non-agent peers that hold a broker socket (RFC H §4.8). Each gets " + "its own `/run/switchroom/auth-broker/<name>/sock` chowned to its UID. " + "Consumers cannot be admins; a consumer name that collides with an " + "agent (whether that agent has `admin: true` or not) is a config " + "error caught at schema validation."),
16349
+ allow_overage_accounts: exports_external.array(exports_external.string().min(1)).optional().describe("Opt-in list of account labels (bare strings matching `auth.active` / " + "`auth.fallback_order` entries) that may be served PAST the weekly " + "utilization wall when Anthropic overage billing is available for the " + "account (`overageStatus === 'allowed'`). Overage is REAL MONEY — " + "default is empty (no account gets this). An account in this list is " + "only kept eligible when its fresh quota snapshot reports " + "`overageStatus: 'allowed'` AND `overageDisabledReason` is NOT " + "'out_of_credits' (i.e. the overage credit has not been exhausted). " + "As soon as `overageDisabledReason` becomes 'out_of_credits', the " + "account is blocked immediately regardless of this flag. Overage lifts " + "ONLY the utilization wall — it cannot lift an active exhaustion mark " + "written by a real 429 (`mark-exhausted`).")
14304
16350
  }).optional().describe("Switchroom-auth-broker configuration (RFC H). Fleet-wide active account, " + "fallback order, admin-agent ACL, and ephemeral-consumer surface. " + "Required from the v0.8+ schema onwards; pre-v0.8 fleets are migrated " + "in-place by `switchroom apply` (see src/auth/migrate-schema.ts)."),
14305
16351
  drive: GoogleWorkspaceConfigSchema.describe("RFC D legacy key — use `google_workspace:` instead. Optional Google " + "Workspace onboarding configuration. When set, supplies Google OAuth " + "client credentials, the approver allowlist for `switchroom drive " + "connect`, and the optional tier knob. Env vars " + "(SWITCHROOM_GOOGLE_CLIENT_ID, SWITCHROOM_GOOGLE_CLIENT_SECRET, " + "SWITCHROOM_APPROVER_USER_ID) take precedence over this block when " + "set, preserving back-compat with the env-only flow shipped in #766."),
14306
16352
  google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration — " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
16353
+ litellm: LiteLLMConfigSchema.describe("Top-level LiteLLM routing infra — global base_url, admin_key (the " + "LiteLLM master key, supports a `vault:` ref), team alias, and " + "small_fast_model shared by every agent that opts in. Set `enabled: " + "true` here to default the whole fleet on (each agent can still set " + "`litellm.enabled: false` to opt out). Default OFF."),
14307
16354
  microsoft_workspace: MicrosoftWorkspaceConfigSchema.describe("RFC #1873 (Microsoft 365 integration). Top-level Microsoft Workspace " + "configuration — OAuth client credentials (Entra app), authority " + "endpoint (defaults to /common for personal MSA + work), and the " + "org_mode opt-in for Teams/SharePoint surfaces. Block is optional; " + "when omitted the broker does not register the Microsoft provider."),
14308
16355
  notion_workspace: NotionWorkspaceConfigSchema.describe("RFC reference/rfcs/notion-integration.md. Top-level Notion integration " + "config — vault key for the integration token, friendly-name → " + "database UUID map, optional MCP-package version pin, and optional " + "global rate-limit override (default 3 rps, Notion's documented " + "public-API limit). Block is optional; when omitted no agent gets a " + "Notion MCP entry regardless of per-agent config."),
14309
16356
  quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
@@ -14733,6 +16780,24 @@ function mergeAgentConfig(defaultsIn, agentIn) {
14733
16780
  ...merged.env ?? {}
14734
16781
  };
14735
16782
  }
16783
+ if (defaults.litellm || merged.litellm) {
16784
+ const base = defaults.litellm ?? {};
16785
+ const override = merged.litellm ?? {};
16786
+ const combined = { ...base };
16787
+ for (const [k, v] of Object.entries(override)) {
16788
+ if (v === undefined)
16789
+ continue;
16790
+ if (k === "tags" && base.tags && typeof v === "object" && v !== null && !Array.isArray(v)) {
16791
+ combined.tags = {
16792
+ ...base.tags,
16793
+ ...v
16794
+ };
16795
+ } else {
16796
+ combined[k] = v;
16797
+ }
16798
+ }
16799
+ merged.litellm = combined;
16800
+ }
14736
16801
  if (defaults.subagents || merged.subagents) {
14737
16802
  const dSub = defaults.subagents ?? {};
14738
16803
  const mSub = merged.subagents ?? {};
@@ -15082,6 +17147,14 @@ function resolveAgentsDir(config) {
15082
17147
  // src/agents/compose.ts
15083
17148
  import { createHash } from "node:crypto";
15084
17149
 
17150
+ // src/config/timezone.ts
17151
+ var CONTAINER_DEFAULT_UTC_ZONES = new Set([
17152
+ "UTC",
17153
+ "Etc/UTC",
17154
+ "Etc/Universal",
17155
+ "Universal"
17156
+ ]);
17157
+
15085
17158
  // src/vault/broker/peercred.ts
15086
17159
  var RESERVED_AGENT_NAMES = new Set(["operator", "hostd"]);
15087
17160
  function isReservedAgentName(name) {
@@ -15114,18 +17187,18 @@ import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
15114
17187
  import { mkdir, chmod, chown, unlink, appendFile } from "node:fs/promises";
15115
17188
  import {
15116
17189
  readdirSync as readdirSync2,
15117
- existsSync as existsSync7,
15118
- readFileSync as readFileSync5,
17190
+ existsSync as existsSync8,
17191
+ readFileSync as readFileSync6,
15119
17192
  writeFileSync as writeFileSync3,
15120
- renameSync,
17193
+ renameSync as renameSync2,
15121
17194
  mkdirSync as mkdirSync2,
15122
- openSync as openSync2,
17195
+ openSync as openSync3,
15123
17196
  ftruncateSync,
15124
- writeSync,
15125
- fsyncSync,
15126
- closeSync as closeSync2
17197
+ writeSync as writeSync2,
17198
+ fsyncSync as fsyncSync2,
17199
+ closeSync as closeSync3
15127
17200
  } from "node:fs";
15128
- import { join as join3, dirname as dirname4, resolve as resolve5 } from "node:path";
17201
+ import { join as join5, dirname as dirname6, resolve as resolve6 } from "node:path";
15129
17202
  import { createHash as createHash5, randomUUID as randomUUID2, randomBytes } from "node:crypto";
15130
17203
 
15131
17204
  // src/host-control/protocol.ts
@@ -15178,6 +17251,16 @@ var ApplyRequestSchema = exports_external.object({
15178
17251
  op: exports_external.literal("apply"),
15179
17252
  args: exports_external.object({}).optional()
15180
17253
  });
17254
+ var RolloutRequestSchema = exports_external.object({
17255
+ ...RequestEnvelope,
17256
+ op: exports_external.literal("rollout"),
17257
+ args: exports_external.object({
17258
+ pin: exports_external.string().regex(/^v\d+\.\d+\.\d+$/),
17259
+ agents: exports_external.array(AgentNameSchema).min(1).optional(),
17260
+ skip_web: exports_external.boolean().optional(),
17261
+ allow_downgrade: exports_external.boolean().optional()
17262
+ }).required({ pin: true })
17263
+ });
15181
17264
  var AgentStartRequestSchema = exports_external.object({
15182
17265
  ...RequestEnvelope,
15183
17266
  op: exports_external.literal("agent_start"),
@@ -15251,6 +17334,7 @@ var RequestSchema = exports_external.discriminatedUnion("op", [
15251
17334
  UpdateCheckRequestSchema,
15252
17335
  UpdateApplyRequestSchema,
15253
17336
  ApplyRequestSchema,
17337
+ RolloutRequestSchema,
15254
17338
  AgentStartRequestSchema,
15255
17339
  AgentStopRequestSchema,
15256
17340
  AgentLogsRequestSchema,
@@ -20442,63 +22526,309 @@ function redactedMarker(ruleId) {
20442
22526
  if (!trimmed || trimmed === "key_value" || trimmed === "kv_entropy") {
20443
22527
  return REDACTED_MARKER;
20444
22528
  }
20445
- return `[REDACTED:${trimmed}]`;
20446
- }
20447
- // src/cli/install-detect.ts
20448
- import * as fs from "node:fs";
20449
- import * as path from "node:path";
20450
- import * as os from "node:os";
20451
- var BIN_PATH = "/usr/local/bin/switchroom";
20452
- function sourceArtifactPath() {
20453
- return path.join(os.homedir(), "code", "switchroom", "dist", "cli", "switchroom.js");
20454
- }
20455
- function sourceDistPrefix() {
20456
- return path.join(os.homedir(), "code", "switchroom", "dist") + path.sep;
22529
+ return `[REDACTED:${trimmed}]`;
22530
+ }
22531
+ // src/cli/install-detect.ts
22532
+ import * as fs from "node:fs";
22533
+ import * as path from "node:path";
22534
+ import * as os from "node:os";
22535
+ var BIN_PATH = "/usr/local/bin/switchroom";
22536
+ function sourceArtifactPath() {
22537
+ return path.join(os.homedir(), "code", "switchroom", "dist", "cli", "switchroom.js");
22538
+ }
22539
+ function sourceDistPrefix() {
22540
+ return path.join(os.homedir(), "code", "switchroom", "dist") + path.sep;
22541
+ }
22542
+ function detectInstallType() {
22543
+ try {
22544
+ const repoArtifact = sourceArtifactPath();
22545
+ const distPrefix = sourceDistPrefix();
22546
+ const binExists = fs.existsSync(BIN_PATH);
22547
+ const repoExists = fs.existsSync(repoArtifact);
22548
+ if (binExists) {
22549
+ const lst = fs.lstatSync(BIN_PATH);
22550
+ if (lst.isSymbolicLink()) {
22551
+ const target = fs.readlinkSync(BIN_PATH);
22552
+ const resolved = path.isAbsolute(target) ? target : path.resolve(path.dirname(BIN_PATH), target);
22553
+ if (resolved.startsWith(distPrefix)) {
22554
+ return {
22555
+ install_type: "source",
22556
+ source_paths: { bin: BIN_PATH, repo: repoExists ? repoArtifact : undefined }
22557
+ };
22558
+ }
22559
+ return {
22560
+ install_type: "binary",
22561
+ source_paths: { bin: BIN_PATH }
22562
+ };
22563
+ }
22564
+ return {
22565
+ install_type: "binary",
22566
+ source_paths: { bin: BIN_PATH }
22567
+ };
22568
+ }
22569
+ if (repoExists) {
22570
+ return {
22571
+ install_type: "source-unlinked",
22572
+ source_paths: { repo: repoArtifact }
22573
+ };
22574
+ }
22575
+ return { install_type: "docker", source_paths: {} };
22576
+ } catch {
22577
+ return { install_type: "unknown", source_paths: {} };
22578
+ }
22579
+ }
22580
+
22581
+ // src/util/atomic.ts
22582
+ import { closeSync as closeSync2, constants, fsyncSync, openSync as openSync2, renameSync, rmSync, writeSync } from "node:fs";
22583
+ var TMP_OPEN_FLAGS = constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0);
22584
+
22585
+ // src/cli/resolve-version.ts
22586
+ import { existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
22587
+ import { dirname as dirname4, join as join2 } from "node:path";
22588
+
22589
+ // src/build-info.ts
22590
+ var VERSION = "0.16.5";
22591
+
22592
+ // src/cli/resolve-version.ts
22593
+ function readPackageVersion() {
22594
+ let dir = import.meta.dirname;
22595
+ for (let i = 0;i < 12 && dir && dir !== "/"; i++) {
22596
+ const p = join2(dir, "package.json");
22597
+ if (existsSync6(p)) {
22598
+ try {
22599
+ const pkg = JSON.parse(readFileSync4(p, "utf-8"));
22600
+ if (pkg?.name === "switchroom" && typeof pkg.version === "string") {
22601
+ return pkg.version;
22602
+ }
22603
+ } catch {}
22604
+ }
22605
+ dir = dirname4(dir);
22606
+ }
22607
+ return null;
22608
+ }
22609
+ var SWITCHROOM_VERSION = (() => {
22610
+ const pkgVersion = readPackageVersion();
22611
+ if (pkgVersion !== null && pkgVersion === VERSION) {
22612
+ return VERSION;
22613
+ }
22614
+ return VERSION ?? pkgVersion ?? "0.0.0";
22615
+ })();
22616
+
22617
+ // src/host-control/audit-reader.ts
22618
+ function parseAuditLine(line) {
22619
+ const trimmed = line.trim();
22620
+ if (trimmed.length === 0)
22621
+ return null;
22622
+ let obj;
22623
+ try {
22624
+ obj = JSON.parse(trimmed);
22625
+ } catch {
22626
+ return null;
22627
+ }
22628
+ if (typeof obj !== "object" || obj === null)
22629
+ return null;
22630
+ const o = obj;
22631
+ if (typeof o.ts !== "string" || typeof o.op !== "string")
22632
+ return null;
22633
+ if (typeof o.request_id !== "string" || typeof o.result !== "string")
22634
+ return null;
22635
+ if (typeof o.duration_ms !== "number")
22636
+ return null;
22637
+ const callerRaw = o.caller;
22638
+ let caller;
22639
+ if (callerRaw && callerRaw.kind === "agent" && typeof callerRaw.name === "string") {
22640
+ caller = { kind: "agent", name: callerRaw.name };
22641
+ } else if (callerRaw && callerRaw.kind === "operator") {
22642
+ caller = { kind: "operator" };
22643
+ } else {
22644
+ return null;
22645
+ }
22646
+ const exit_code = o.exit_code === null || typeof o.exit_code === "number" ? o.exit_code : null;
22647
+ const entry = {
22648
+ ts: o.ts,
22649
+ op: o.op,
22650
+ caller,
22651
+ request_id: o.request_id,
22652
+ result: o.result,
22653
+ exit_code,
22654
+ duration_ms: o.duration_ms
22655
+ };
22656
+ if (typeof o.error === "string")
22657
+ entry.error = o.error;
22658
+ if (typeof o.phase === "string")
22659
+ entry.phase = o.phase;
22660
+ if (typeof o.stdout_tail === "string")
22661
+ entry.stdout_tail = o.stdout_tail;
22662
+ if (typeof o.stderr_tail === "string")
22663
+ entry.stderr_tail = o.stderr_tail;
22664
+ if (typeof o.channel === "string")
22665
+ entry.channel = o.channel;
22666
+ if (typeof o.pin === "string")
22667
+ entry.pin = o.pin;
22668
+ if (o.resolved_sha && typeof o.resolved_sha === "object" && !Array.isArray(o.resolved_sha)) {
22669
+ const rs = {};
22670
+ for (const [k, v] of Object.entries(o.resolved_sha)) {
22671
+ if (typeof v === "string")
22672
+ rs[k] = v;
22673
+ }
22674
+ if (Object.keys(rs).length > 0)
22675
+ entry.resolved_sha = rs;
22676
+ }
22677
+ if (o.install_context && typeof o.install_context === "object" && !Array.isArray(o.install_context)) {
22678
+ const ic = o.install_context;
22679
+ if (typeof ic.install_type === "string" && typeof ic.detected_at === "string") {
22680
+ entry.install_context = {
22681
+ install_type: ic.install_type,
22682
+ detected_at: ic.detected_at
22683
+ };
22684
+ }
22685
+ }
22686
+ if (Array.isArray(o.rolled) && o.rolled.every((x) => typeof x === "string")) {
22687
+ entry.rolled = o.rolled;
22688
+ }
22689
+ if (typeof o.failed_step === "string")
22690
+ entry.failed_step = o.failed_step;
22691
+ if (typeof o.failed_agent === "string")
22692
+ entry.failed_agent = o.failed_agent;
22693
+ if (typeof o.prior_pin === "string")
22694
+ entry.prior_pin = o.prior_pin;
22695
+ return entry;
22696
+ }
22697
+
22698
+ // src/cli/rollout.ts
22699
+ function isVersionAssertable(target) {
22700
+ return /^v?\d+\.\d+\.\d+$/.test(target.trim());
22701
+ }
22702
+ var ROLLOUT_RESULT_SENTINEL = "SWITCHROOM_ROLLOUT_RESULT:";
22703
+ function parseRolloutResultLine(stdout) {
22704
+ const lines = stdout.split(`
22705
+ `);
22706
+ for (let i = lines.length - 1;i >= 0; i--) {
22707
+ const line = lines[i].trim();
22708
+ if (line.startsWith(ROLLOUT_RESULT_SENTINEL)) {
22709
+ try {
22710
+ return JSON.parse(line.slice(ROLLOUT_RESULT_SENTINEL.length));
22711
+ } catch {
22712
+ return null;
22713
+ }
22714
+ }
22715
+ }
22716
+ return null;
22717
+ }
22718
+
22719
+ // node_modules/.bun/commander@13.1.0/node_modules/commander/esm.mjs
22720
+ var import__3 = __toESM(require_commander(), 1);
22721
+
22722
+ // src/cli/update.ts
22723
+ import { join as join3, dirname as dirname5, resolve as resolve5 } from "node:path";
22724
+ import { homedir as homedir3 } from "node:os";
22725
+
22726
+ // src/agents/lifecycle.ts
22727
+ import { execFileSync, spawn, spawnSync } from "node:child_process";
22728
+
22729
+ // src/agents/tmux.ts
22730
+ var MAX_BYTES = 10 * 1024 * 1024;
22731
+
22732
+ // src/agents/lifecycle.ts
22733
+ function containerName(name) {
22734
+ return `switchroom-${name}`;
22735
+ }
22736
+ function getAllAgentStatuses(config) {
22737
+ const agentNames = Object.keys(config.agents);
22738
+ const statuses = {};
22739
+ if (agentNames.length === 0)
22740
+ return statuses;
22741
+ const cnByAgent = new Map;
22742
+ const agentByCn = new Map;
22743
+ for (const a of agentNames) {
22744
+ const cn = containerName(a);
22745
+ cnByAgent.set(a, cn);
22746
+ agentByCn.set(cn, a);
22747
+ statuses[a] = { active: "inactive", uptime: null, memory: null, pid: null };
22748
+ }
22749
+ const insp = spawnSync("docker", [
22750
+ "inspect",
22751
+ "--format",
22752
+ "{{.Name}}|{{.State.Status}}|{{.State.StartedAt}}|{{.State.Pid}}",
22753
+ ...cnByAgent.values()
22754
+ ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15000 });
22755
+ for (const line of (insp.stdout ?? "").split(`
22756
+ `)) {
22757
+ const t = line.trim();
22758
+ if (!t)
22759
+ continue;
22760
+ const [rawName, status, startedAt, pidStr] = t.split("|");
22761
+ const cn = (rawName ?? "").replace(/^\//, "");
22762
+ const agent = agentByCn.get(cn);
22763
+ if (!agent)
22764
+ continue;
22765
+ const pidNum = parseInt(pidStr ?? "", 10);
22766
+ statuses[agent] = {
22767
+ active: status === "running" ? "active" : status || "inactive",
22768
+ uptime: startedAt && startedAt !== "0001-01-01T00:00:00Z" ? startedAt : null,
22769
+ memory: null,
22770
+ pid: Number.isFinite(pidNum) && pidNum > 0 ? pidNum : null
22771
+ };
22772
+ }
22773
+ const stats = spawnSync("docker", ["stats", "--no-stream", "--format", "{{.Name}}|{{.MemUsage}}"], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15000 });
22774
+ if (stats.status === 0) {
22775
+ for (const line of (stats.stdout ?? "").split(`
22776
+ `)) {
22777
+ const t = line.trim();
22778
+ if (!t)
22779
+ continue;
22780
+ const [cn, memUsage] = t.split("|");
22781
+ const agent = cn ? agentByCn.get(cn) : undefined;
22782
+ if (!agent || statuses[agent].active !== "active")
22783
+ continue;
22784
+ const first = (memUsage ?? "").split("/")[0]?.trim();
22785
+ if (!first)
22786
+ continue;
22787
+ const m = first.match(/([\d.]+)\s*([KMG]i?B)/i);
22788
+ if (m) {
22789
+ const val = parseFloat(m[1]);
22790
+ const unit = m[2].toUpperCase();
22791
+ let mb = val;
22792
+ if (unit.startsWith("K"))
22793
+ mb = val / 1024;
22794
+ else if (unit.startsWith("G"))
22795
+ mb = val * 1024;
22796
+ statuses[agent].memory = `${Math.round(mb)}MB`;
22797
+ } else {
22798
+ statuses[agent].memory = first;
22799
+ }
22800
+ }
22801
+ }
22802
+ return statuses;
20457
22803
  }
20458
- function detectInstallType() {
22804
+
22805
+ // src/cli/update.ts
22806
+ var DEFAULT_COMPOSE_PATH = join3(homedir3(), ".switchroom", "compose", "docker-compose.yml");
22807
+ var UPDATE_RESULT_SENTINEL = "SWITCHROOM_UPDATE_RESULT:";
22808
+ function parseUpdateResultLine(stdout) {
22809
+ const idx = stdout.lastIndexOf(UPDATE_RESULT_SENTINEL);
22810
+ if (idx === -1)
22811
+ return null;
22812
+ const raw = stdout.slice(idx + UPDATE_RESULT_SENTINEL.length).split(`
22813
+ `)[0];
22814
+ if (!raw)
22815
+ return null;
20459
22816
  try {
20460
- const repoArtifact = sourceArtifactPath();
20461
- const distPrefix = sourceDistPrefix();
20462
- const binExists = fs.existsSync(BIN_PATH);
20463
- const repoExists = fs.existsSync(repoArtifact);
20464
- if (binExists) {
20465
- const lst = fs.lstatSync(BIN_PATH);
20466
- if (lst.isSymbolicLink()) {
20467
- const target = fs.readlinkSync(BIN_PATH);
20468
- const resolved = path.isAbsolute(target) ? target : path.resolve(path.dirname(BIN_PATH), target);
20469
- if (resolved.startsWith(distPrefix)) {
20470
- return {
20471
- install_type: "source",
20472
- source_paths: { bin: BIN_PATH, repo: repoExists ? repoArtifact : undefined }
20473
- };
20474
- }
20475
- return {
20476
- install_type: "binary",
20477
- source_paths: { bin: BIN_PATH }
20478
- };
20479
- }
20480
- return {
20481
- install_type: "binary",
20482
- source_paths: { bin: BIN_PATH }
20483
- };
20484
- }
20485
- if (repoExists) {
20486
- return {
20487
- install_type: "source-unlinked",
20488
- source_paths: { repo: repoArtifact }
20489
- };
22817
+ const parsed = JSON.parse(raw);
22818
+ if (parsed !== null && typeof parsed === "object" && "ok" in parsed && "deferred" in parsed && typeof parsed.ok === "boolean" && Array.isArray(parsed.deferred)) {
22819
+ return parsed;
20490
22820
  }
20491
- return { install_type: "docker", source_paths: {} };
22821
+ return null;
20492
22822
  } catch {
20493
- return { install_type: "unknown", source_paths: {} };
22823
+ return null;
20494
22824
  }
20495
22825
  }
20496
22826
 
20497
22827
  // src/host-control/config-edit-validator.ts
20498
- import { mkdtempSync, writeFileSync as writeFileSync2, rmSync, existsSync as existsSync6, readFileSync as readFileSync4 } from "node:fs";
22828
+ import { mkdtempSync, writeFileSync as writeFileSync2, rmSync as rmSync2, existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
20499
22829
  import { tmpdir } from "node:os";
20500
- import { join as join2, isAbsolute as isAbsolute2, normalize } from "node:path";
20501
- import { spawnSync } from "node:child_process";
22830
+ import { join as join4, isAbsolute as isAbsolute2, normalize } from "node:path";
22831
+ import { spawnSync as spawnSync2 } from "node:child_process";
20502
22832
  import { isDeepStrictEqual } from "node:util";
20503
22833
  var MAX_PATCH_BYTES = 1024 * 1024;
20504
22834
  var UNLOCK_CARD_YAML_ALLOWLIST = new Set([
@@ -20583,20 +22913,20 @@ function validateShape(unifiedDiff, targetPath) {
20583
22913
  return null;
20584
22914
  }
20585
22915
  function applyPatch(unifiedDiff, configPath, gitBin) {
20586
- if (!existsSync6(configPath)) {
22916
+ if (!existsSync7(configPath)) {
20587
22917
  return {
20588
22918
  ok: false,
20589
22919
  code: "E_PATCH_APPLY_FAILED",
20590
22920
  detail: `target config not found at ${configPath}`
20591
22921
  };
20592
22922
  }
20593
- const liveContent = readFileSync4(configPath, "utf8");
20594
- const scratchDir = mkdtempSync(join2(tmpdir(), "config-propose-edit-"));
22923
+ const liveContent = readFileSync5(configPath, "utf8");
22924
+ const scratchDir = mkdtempSync(join4(tmpdir(), "config-propose-edit-"));
20595
22925
  try {
20596
22926
  const basename2 = configPath.split("/").pop() ?? "switchroom.yaml";
20597
- const scratchFile = join2(scratchDir, basename2);
22927
+ const scratchFile = join4(scratchDir, basename2);
20598
22928
  writeFileSync2(scratchFile, liveContent);
20599
- const patchFile = join2(scratchDir, "proposal.patch");
22929
+ const patchFile = join4(scratchDir, "proposal.patch");
20600
22930
  writeFileSync2(patchFile, unifiedDiff);
20601
22931
  const bin = gitBin ?? "git";
20602
22932
  const baseArgs = [
@@ -20605,10 +22935,10 @@ function applyPatch(unifiedDiff, configPath, gitBin) {
20605
22935
  "--recount",
20606
22936
  "--unidiff-zero"
20607
22937
  ];
20608
- const checkP1 = spawnSync(bin, [...baseArgs.slice(0, 1), "--check", ...baseArgs.slice(1), "-p1", patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
22938
+ const checkP1 = spawnSync2(bin, [...baseArgs.slice(0, 1), "--check", ...baseArgs.slice(1), "-p1", patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
20609
22939
  let pStrip = "-p1";
20610
22940
  if (checkP1.status !== 0) {
20611
- const checkP0 = spawnSync(bin, [...baseArgs.slice(0, 1), "--check", ...baseArgs.slice(1), "-p0", patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
22941
+ const checkP0 = spawnSync2(bin, [...baseArgs.slice(0, 1), "--check", ...baseArgs.slice(1), "-p0", patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
20612
22942
  if (checkP0.status !== 0) {
20613
22943
  const stderr = (checkP1.stderr || "") + (checkP0.stderr || "");
20614
22944
  return {
@@ -20619,7 +22949,7 @@ function applyPatch(unifiedDiff, configPath, gitBin) {
20619
22949
  }
20620
22950
  pStrip = "-p0";
20621
22951
  }
20622
- const real = spawnSync(bin, [...baseArgs, pStrip, patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
22952
+ const real = spawnSync2(bin, [...baseArgs, pStrip, patchFile], { cwd: scratchDir, encoding: "utf8", timeout: 1e4 });
20623
22953
  if (real.status !== 0) {
20624
22954
  return {
20625
22955
  ok: false,
@@ -20627,10 +22957,10 @@ function applyPatch(unifiedDiff, configPath, gitBin) {
20627
22957
  detail: `git apply failed: ${(real.stderr || "").trim().slice(0, 500)}`
20628
22958
  };
20629
22959
  }
20630
- const after = readFileSync4(scratchFile, "utf8");
22960
+ const after = readFileSync5(scratchFile, "utf8");
20631
22961
  return { ok: true, after };
20632
22962
  } finally {
20633
- rmSync(scratchDir, { recursive: true, force: true });
22963
+ rmSync2(scratchDir, { recursive: true, force: true });
20634
22964
  }
20635
22965
  }
20636
22966
  function failsafeParse(source) {
@@ -20825,7 +23155,7 @@ function validateConfigEdit(opts) {
20825
23155
  return schemaErr;
20826
23156
  let beforeData = {};
20827
23157
  try {
20828
- const beforeRaw = existsSync6(opts.configPath) ? readFileSync4(opts.configPath, "utf8") : "";
23158
+ const beforeRaw = existsSync7(opts.configPath) ? readFileSync5(opts.configPath, "utf8") : "";
20829
23159
  const beforeDoc = $parseDocument(beforeRaw, { merge: false, strict: false });
20830
23160
  beforeData = beforeDoc.toJS();
20831
23161
  } catch {
@@ -20978,85 +23308,6 @@ function classifyBlastRadius(beforeYaml, afterYaml) {
20978
23308
  };
20979
23309
  }
20980
23310
 
20981
- // src/agents/lifecycle.ts
20982
- import { execFileSync, spawn, spawnSync as spawnSync2 } from "node:child_process";
20983
-
20984
- // src/agents/tmux.ts
20985
- var MAX_BYTES = 10 * 1024 * 1024;
20986
-
20987
- // src/agents/lifecycle.ts
20988
- function containerName(name) {
20989
- return `switchroom-${name}`;
20990
- }
20991
- function getAllAgentStatuses(config) {
20992
- const agentNames = Object.keys(config.agents);
20993
- const statuses = {};
20994
- if (agentNames.length === 0)
20995
- return statuses;
20996
- const cnByAgent = new Map;
20997
- const agentByCn = new Map;
20998
- for (const a of agentNames) {
20999
- const cn = containerName(a);
21000
- cnByAgent.set(a, cn);
21001
- agentByCn.set(cn, a);
21002
- statuses[a] = { active: "inactive", uptime: null, memory: null, pid: null };
21003
- }
21004
- const insp = spawnSync2("docker", [
21005
- "inspect",
21006
- "--format",
21007
- "{{.Name}}|{{.State.Status}}|{{.State.StartedAt}}|{{.State.Pid}}",
21008
- ...cnByAgent.values()
21009
- ], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15000 });
21010
- for (const line of (insp.stdout ?? "").split(`
21011
- `)) {
21012
- const t = line.trim();
21013
- if (!t)
21014
- continue;
21015
- const [rawName, status, startedAt, pidStr] = t.split("|");
21016
- const cn = (rawName ?? "").replace(/^\//, "");
21017
- const agent = agentByCn.get(cn);
21018
- if (!agent)
21019
- continue;
21020
- const pidNum = parseInt(pidStr ?? "", 10);
21021
- statuses[agent] = {
21022
- active: status === "running" ? "active" : status || "inactive",
21023
- uptime: startedAt && startedAt !== "0001-01-01T00:00:00Z" ? startedAt : null,
21024
- memory: null,
21025
- pid: Number.isFinite(pidNum) && pidNum > 0 ? pidNum : null
21026
- };
21027
- }
21028
- const stats = spawnSync2("docker", ["stats", "--no-stream", "--format", "{{.Name}}|{{.MemUsage}}"], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15000 });
21029
- if (stats.status === 0) {
21030
- for (const line of (stats.stdout ?? "").split(`
21031
- `)) {
21032
- const t = line.trim();
21033
- if (!t)
21034
- continue;
21035
- const [cn, memUsage] = t.split("|");
21036
- const agent = cn ? agentByCn.get(cn) : undefined;
21037
- if (!agent || statuses[agent].active !== "active")
21038
- continue;
21039
- const first = (memUsage ?? "").split("/")[0]?.trim();
21040
- if (!first)
21041
- continue;
21042
- const m = first.match(/([\d.]+)\s*([KMG]i?B)/i);
21043
- if (m) {
21044
- const val = parseFloat(m[1]);
21045
- const unit = m[2].toUpperCase();
21046
- let mb = val;
21047
- if (unit.startsWith("K"))
21048
- mb = val / 1024;
21049
- else if (unit.startsWith("G"))
21050
- mb = val * 1024;
21051
- statuses[agent].memory = `${Math.round(mb)}MB`;
21052
- } else {
21053
- statuses[agent].memory = first;
21054
- }
21055
- }
21056
- }
21057
- return statuses;
21058
- }
21059
-
21060
23311
  // src/scheduler/dispatch.ts
21061
23312
  import { createHash as createHash4 } from "node:crypto";
21062
23313
  function collectScheduleEntries(config) {
@@ -21139,11 +23390,11 @@ function resolveDigests(imageRefs) {
21139
23390
  return out;
21140
23391
  }
21141
23392
  function readCachedInstallType(bindRoot) {
21142
- const cacheDir = join3(bindRoot, ".switchroom");
21143
- const cachePath = join3(cacheDir, "install-type.json");
21144
- if (existsSync7(cachePath)) {
23393
+ const cacheDir = join5(bindRoot, ".switchroom");
23394
+ const cachePath = join5(cacheDir, "install-type.json");
23395
+ if (existsSync8(cachePath)) {
21145
23396
  try {
21146
- const raw = readFileSync5(cachePath, "utf-8");
23397
+ const raw = readFileSync6(cachePath, "utf-8");
21147
23398
  const parsed = JSON.parse(raw);
21148
23399
  if (parsed && typeof parsed.install_type === "string" && typeof parsed.detected_at === "string") {
21149
23400
  return parsed;
@@ -21163,7 +23414,7 @@ function readCachedInstallType(bindRoot) {
21163
23414
  mkdirSync2(cacheDir, { recursive: true });
21164
23415
  const tmp = `${cachePath}.tmp`;
21165
23416
  writeFileSync3(tmp, JSON.stringify(payload, null, 2), { mode: 420 });
21166
- renameSync(tmp, cachePath);
23417
+ renameSync2(tmp, cachePath);
21167
23418
  } catch {}
21168
23419
  return payload;
21169
23420
  }
@@ -21181,18 +23432,18 @@ function formatConfigApprovalDenyError(approval, approvalId) {
21181
23432
  }
21182
23433
  function writeFileInPlacePreservingInode(targetPath, content) {
21183
23434
  const buf = Buffer.from(content, "utf-8");
21184
- const fd = openSync2(targetPath, "r+");
23435
+ const fd = openSync3(targetPath, "r+");
21185
23436
  try {
21186
23437
  ftruncateSync(fd, 0);
21187
23438
  let off = 0;
21188
23439
  while (off < buf.length) {
21189
- off += writeSync(fd, buf, off, buf.length - off, off);
23440
+ off += writeSync2(fd, buf, off, buf.length - off, off);
21190
23441
  }
21191
- fsyncSync(fd);
23442
+ fsyncSync2(fd);
21192
23443
  } finally {
21193
- closeSync2(fd);
23444
+ closeSync3(fd);
21194
23445
  }
21195
- const readBack = readFileSync5(targetPath);
23446
+ const readBack = readFileSync6(targetPath);
21196
23447
  if (readBack.length !== buf.length) {
21197
23448
  throw new Error(`in-place write short: wrote ${buf.length} bytes but read back ${readBack.length}`);
21198
23449
  }
@@ -21200,6 +23451,7 @@ function writeFileInPlacePreservingInode(targetPath, content) {
21200
23451
  var STATUS_RETENTION_MS = 10 * 60 * 1000;
21201
23452
  var STATUS_MAX_ENTRIES = 256;
21202
23453
  var TAIL_BYTES = 4096;
23454
+ var ORPHAN_RECONCILE_AGE_MS = 15 * 60 * 1000;
21203
23455
 
21204
23456
  class HostdServer {
21205
23457
  opts;
@@ -21213,7 +23465,7 @@ class HostdServer {
21213
23465
  this.opts = opts;
21214
23466
  }
21215
23467
  async start() {
21216
- const hostdDir = join3(this.opts.homeDir, ".switchroom", "hostd");
23468
+ const hostdDir = join5(this.opts.homeDir, ".switchroom", "hostd");
21217
23469
  await mkdir(hostdDir, { recursive: true });
21218
23470
  await chmod(hostdDir, 493).catch(() => {
21219
23471
  return;
@@ -21224,13 +23476,13 @@ class HostdServer {
21224
23476
  }
21225
23477
  try {
21226
23478
  for (const name of agentNames) {
21227
- const dir = join3(hostdDir, name);
21228
- const sockPath = join3(dir, "sock");
23479
+ const dir = join5(hostdDir, name);
23480
+ const sockPath = join5(dir, "sock");
21229
23481
  await mkdir(dir, { recursive: true });
21230
23482
  await chmod(dir, 493).catch(() => {
21231
23483
  return;
21232
23484
  });
21233
- if (existsSync7(sockPath))
23485
+ if (existsSync8(sockPath))
21234
23486
  await unlink(sockPath).catch(() => {
21235
23487
  return;
21236
23488
  });
@@ -21239,8 +23491,8 @@ class HostdServer {
21239
23491
  process.stderr.write(`hostd: server error on ${sockPath}: ${err2.message}
21240
23492
  `);
21241
23493
  });
21242
- await new Promise((resolve6, reject) => {
21243
- server.listen(sockPath, () => resolve6());
23494
+ await new Promise((resolve7, reject) => {
23495
+ server.listen(sockPath, () => resolve7());
21244
23496
  server.once("error", reject);
21245
23497
  });
21246
23498
  await chmod(sockPath, 432).catch(() => {
@@ -21261,13 +23513,13 @@ class HostdServer {
21261
23513
  process.stderr.write(`hostd: SWITCHROOM_HOSTD_OPERATOR_UID='${opUidStr}' is not a positive integer; skipping operator listener
21262
23514
  `);
21263
23515
  } else {
21264
- const dir = join3(hostdDir, "operator");
21265
- const sockPath = join3(dir, "sock");
23516
+ const dir = join5(hostdDir, "operator");
23517
+ const sockPath = join5(dir, "sock");
21266
23518
  await mkdir(dir, { recursive: true });
21267
23519
  await chmod(dir, 493).catch(() => {
21268
23520
  return;
21269
23521
  });
21270
- if (existsSync7(sockPath))
23522
+ if (existsSync8(sockPath))
21271
23523
  await unlink(sockPath).catch(() => {
21272
23524
  return;
21273
23525
  });
@@ -21276,8 +23528,8 @@ class HostdServer {
21276
23528
  process.stderr.write(`hostd: server error on ${sockPath}: ${err2.message}
21277
23529
  `);
21278
23530
  });
21279
- await new Promise((resolve6, reject) => {
21280
- server.listen(sockPath, () => resolve6());
23531
+ await new Promise((resolve7, reject) => {
23532
+ server.listen(sockPath, () => resolve7());
21281
23533
  server.once("error", reject);
21282
23534
  });
21283
23535
  await chmod(sockPath, 384).catch(() => {
@@ -21296,11 +23548,72 @@ class HostdServer {
21296
23548
  await this.stop();
21297
23549
  throw err2;
21298
23550
  }
23551
+ await this.reconcileOrphanedFleetMutations().catch((e) => {
23552
+ process.stderr.write(`hostd: orphan-reconcile sweep failed (non-fatal): ${e.message}
23553
+ `);
23554
+ });
23555
+ }
23556
+ async reconcileOrphanedFleetMutations() {
23557
+ const path2 = this.auditLogPath();
23558
+ if (!existsSync8(path2))
23559
+ return;
23560
+ let raw;
23561
+ try {
23562
+ raw = readFileSync6(path2, "utf-8");
23563
+ } catch {
23564
+ return;
23565
+ }
23566
+ const FLEET_OPS = new Set(["update_apply", "apply", "rollout"]);
23567
+ const startedRows = new Map;
23568
+ for (const line of raw.split(`
23569
+ `)) {
23570
+ const e = parseAuditLine(line);
23571
+ if (!e)
23572
+ continue;
23573
+ if (e.phase === "orphan_reconciled") {
23574
+ startedRows.delete(e.request_id);
23575
+ continue;
23576
+ }
23577
+ if (!FLEET_OPS.has(e.op))
23578
+ continue;
23579
+ if (e.phase === "terminal") {
23580
+ startedRows.delete(e.request_id);
23581
+ continue;
23582
+ }
23583
+ if (e.result === "started" && e.phase === undefined) {
23584
+ const tsMs = Date.parse(e.ts);
23585
+ startedRows.set(e.request_id, {
23586
+ op: e.op,
23587
+ ts: Number.isFinite(tsMs) ? tsMs : Date.now(),
23588
+ caller_name: e.caller.kind === "agent" ? e.caller.name : undefined
23589
+ });
23590
+ }
23591
+ }
23592
+ const now = Date.now();
23593
+ for (const [request_id, info] of startedRows) {
23594
+ if (now - info.ts < ORPHAN_RECONCILE_AGE_MS)
23595
+ continue;
23596
+ const synthOp = info.op === "rollout" ? "rollout_orphaned" : "update_failed";
23597
+ process.stderr.write(`hostd: ORPHANED ${info.op} (request_id=${request_id}, ` + `started ${Math.floor((now - info.ts) / 60000)}m ago, no terminal ` + `row) — emitting ${synthOp}. The fleet may be half-rolled; verify ` + `host-side.
23598
+ `);
23599
+ await this.appendAuditRow({
23600
+ ts: new Date().toISOString(),
23601
+ op: synthOp,
23602
+ phase: "orphan_reconciled",
23603
+ request_id,
23604
+ original_op: info.op,
23605
+ caller: info.caller_name ? { kind: "agent", name: info.caller_name } : { kind: "operator" },
23606
+ result: "error",
23607
+ exit_code: null,
23608
+ duration_ms: now - info.ts,
23609
+ error: `${info.op} left a perpetual 'started' status with no terminal row ` + `(hostd likely SIGKILLed mid-mutation — brick scenario #1). ` + `Reconciled to a failure on hostd boot. The fleet may be ` + `half-rolled; verify versions host-side and re-run if needed.`
23610
+ });
23611
+ }
21299
23612
  }
21300
23613
  async stop() {
21301
23614
  const paths = [...this.servers.keys()];
21302
23615
  for (const [, server] of this.servers) {
21303
- await new Promise((resolve6) => server.close(() => resolve6()));
23616
+ await new Promise((resolve7) => server.close(() => resolve7()));
21304
23617
  }
21305
23618
  this.servers.clear();
21306
23619
  for (const s of paths) {
@@ -21406,6 +23719,9 @@ class HostdServer {
21406
23719
  case "apply":
21407
23720
  resp = this.handleApply(req, caller, started);
21408
23721
  break;
23722
+ case "rollout":
23723
+ resp = this.handleRollout(req, caller, started);
23724
+ break;
21409
23725
  case "agent_start":
21410
23726
  resp = await this.handleAgentStart(req, started);
21411
23727
  break;
@@ -21468,6 +23784,7 @@ class HostdServer {
21468
23784
  return null;
21469
23785
  case "update_apply":
21470
23786
  case "apply":
23787
+ case "rollout":
21471
23788
  return callerAdmin ? null : `${req.op} requires admin: true on caller "${caller.name}"`;
21472
23789
  case "agent_start":
21473
23790
  case "agent_stop":
@@ -21567,12 +23884,12 @@ class HostdServer {
21567
23884
  };
21568
23885
  }
21569
23886
  missingApplyAssets() {
21570
- const root = this.opts.applyAssetsRoot ?? resolve5(import.meta.dirname, "../..");
23887
+ const root = this.opts.applyAssetsRoot ?? resolve6(import.meta.dirname, "../..");
21571
23888
  return [
21572
- join3(root, "profiles"),
21573
- join3(root, "profiles", "default"),
21574
- join3(root, "vendor", "hindsight-memory")
21575
- ].filter((p) => !existsSync7(p));
23889
+ join5(root, "profiles"),
23890
+ join5(root, "profiles", "default"),
23891
+ join5(root, "vendor", "hindsight-memory")
23892
+ ].filter((p) => !existsSync8(p));
21576
23893
  }
21577
23894
  applyAssetPreflight(request_id, started) {
21578
23895
  const missing = this.missingApplyAssets();
@@ -21629,7 +23946,7 @@ class HostdServer {
21629
23946
  request_id: req.request_id,
21630
23947
  started_at: started
21631
23948
  };
21632
- this.spawnFleetMutation(req.op, args, entry);
23949
+ this.spawnFleetMutation(req.op, args, entry, { SWITCHROOM_HOSTD_CONTEXT: "1" });
21633
23950
  return {
21634
23951
  v: 1,
21635
23952
  request_id: req.request_id,
@@ -21672,6 +23989,62 @@ class HostdServer {
21672
23989
  duration_ms: Date.now() - started
21673
23990
  };
21674
23991
  }
23992
+ handleRollout(req, caller, started) {
23993
+ const denied = this.checkFleetMutationLock(req.op, req.request_id, started);
23994
+ if (denied)
23995
+ return denied;
23996
+ const assetDenied = this.applyAssetPreflight(req.request_id, started);
23997
+ if (assetDenied)
23998
+ return assetDenied;
23999
+ const args = ["rollout", "--pin", req.args.pin];
24000
+ if (req.args.agents && req.args.agents.length > 0) {
24001
+ args.push("--agents", req.args.agents.join(","));
24002
+ }
24003
+ if (req.args.skip_web)
24004
+ args.push("--skip-web");
24005
+ if (req.args.allow_downgrade)
24006
+ args.push("--allow-downgrade");
24007
+ const installCtx = readCachedInstallType(this.opts.bindRoot ?? this.opts.homeDir);
24008
+ let priorPin;
24009
+ try {
24010
+ const cfg = loadConfig(this.opts.configPath);
24011
+ const cfgPin = cfg.release?.pin;
24012
+ if (cfgPin && isVersionAssertable(cfgPin)) {
24013
+ priorPin = cfgPin.startsWith("v") ? cfgPin : `v${cfgPin}`;
24014
+ }
24015
+ } catch {}
24016
+ const entry = {
24017
+ request_id: req.request_id,
24018
+ caller,
24019
+ op: req.op,
24020
+ result: "started",
24021
+ exit_code: null,
24022
+ started_at: started,
24023
+ finished_at: null,
24024
+ stdout_tail: "",
24025
+ stderr_tail: "",
24026
+ pin: req.args.pin,
24027
+ install_context: {
24028
+ install_type: installCtx.install_type,
24029
+ detected_at: installCtx.detected_at
24030
+ },
24031
+ ...priorPin ? { prior_pin: priorPin } : {}
24032
+ };
24033
+ this.recordStatus(entry);
24034
+ this.fleetMutationInFlight = {
24035
+ op: "rollout",
24036
+ request_id: req.request_id,
24037
+ started_at: started
24038
+ };
24039
+ this.spawnRollout(args, entry);
24040
+ return {
24041
+ v: 1,
24042
+ request_id: req.request_id,
24043
+ result: "started",
24044
+ exit_code: null,
24045
+ duration_ms: Date.now() - started
24046
+ };
24047
+ }
21675
24048
  async handleAgentStart(req, started) {
21676
24049
  const res = await this.runSwitchroom(["agent", "start", req.args.name]);
21677
24050
  return {
@@ -21753,7 +24126,7 @@ class HostdServer {
21753
24126
  if (caller.kind === "agent" && this.opts.config.agents[caller.name]?.admin !== true) {
21754
24127
  let beforeContent;
21755
24128
  try {
21756
- beforeContent = readFileSync5(configPath, "utf-8");
24129
+ beforeContent = readFileSync6(configPath, "utf-8");
21757
24130
  } catch {
21758
24131
  beforeContent = "";
21759
24132
  }
@@ -21775,6 +24148,34 @@ class HostdServer {
21775
24148
  `);
21776
24149
  return await pending;
21777
24150
  }
24151
+ const rate = this.checkConfigEditRate(callerName, Date.now());
24152
+ if (!rate.ok) {
24153
+ const retryAtIso = new Date(rate.retryAtMs).toISOString();
24154
+ process.stderr.write(`hostd: config_propose_edit — RATE-LIMITED ${callerName} ` + `(>${rate.limit}/hour); next slot ${retryAtIso}
24155
+ `);
24156
+ this.appendAuditRow({
24157
+ ts: new Date().toISOString(),
24158
+ op: "config_propose_edit",
24159
+ phase: "rate_limited",
24160
+ request_id: req.request_id,
24161
+ caller: caller.kind === "agent" ? { kind: "agent", name: caller.name } : { kind: "operator" },
24162
+ result: "denied",
24163
+ exit_code: null,
24164
+ duration_ms: Date.now() - started,
24165
+ error: `E_RATE_LIMITED: >${rate.limit} config_propose_edit cards/hour`
24166
+ });
24167
+ return err("E_RATE_LIMITED", `config_propose_edit rate limit exceeded (max ${rate.limit}/hour for this agent)`).why(`next slot opens at ${retryAtIso}`).fixRetryAfter(retryAtIso).op("config_propose_edit").caller(caller.kind === "agent" ? "agent" : "operator").agentName(caller.kind === "agent" ? caller.name : undefined).asDenied().build(req.request_id, Date.now() - started);
24168
+ }
24169
+ this.appendAuditRow({
24170
+ ts: new Date().toISOString(),
24171
+ op: "config_propose_edit",
24172
+ phase: "requested",
24173
+ request_id: req.request_id,
24174
+ caller: caller.kind === "agent" ? { kind: "agent", name: caller.name } : { kind: "operator" },
24175
+ result: "started",
24176
+ exit_code: null,
24177
+ duration_ms: Date.now() - started
24178
+ });
21778
24179
  const run = this.runConfigProposeApprovalAndApply(req, caller, callerName, configPath, verdict.postApplyContent, started);
21779
24180
  this.inflightConfigProposals.set(dedupeKey, run);
21780
24181
  try {
@@ -21784,6 +24185,22 @@ class HostdServer {
21784
24185
  }
21785
24186
  }
21786
24187
  inflightConfigProposals = new Map;
24188
+ configEditPostTimes = new Map;
24189
+ static DEFAULT_CONFIG_EDIT_RATE_PER_HOUR = 3;
24190
+ checkConfigEditRate(callerName, now) {
24191
+ const limit = this.opts.config.hostd?.config_edit_rate_per_hour ?? HostdServer.DEFAULT_CONFIG_EDIT_RATE_PER_HOUR;
24192
+ const windowMs = 60 * 60 * 1000;
24193
+ const cutoff = now - windowMs;
24194
+ const prior = (this.configEditPostTimes.get(callerName) ?? []).filter((t) => t > cutoff);
24195
+ if (prior.length >= limit) {
24196
+ const retryAtMs = prior[0] + windowMs;
24197
+ this.configEditPostTimes.set(callerName, prior);
24198
+ return { ok: false, limit, retryAtMs };
24199
+ }
24200
+ prior.push(now);
24201
+ this.configEditPostTimes.set(callerName, prior);
24202
+ return { ok: true };
24203
+ }
21787
24204
  async runConfigProposeApprovalAndApply(req, caller, callerName, configPath, postApply, started) {
21788
24205
  const approvalId = (this.opts.generateApprovalId ?? defaultApprovalId)();
21789
24206
  const approval = await this.opts.approvalGateway.requestApproval({
@@ -21813,7 +24230,7 @@ class HostdServer {
21813
24230
  try {
21814
24231
  let snapshot;
21815
24232
  try {
21816
- snapshot = readFileSync5(configPath, "utf-8");
24233
+ snapshot = readFileSync6(configPath, "utf-8");
21817
24234
  } catch (e) {
21818
24235
  await approval.finalize({
21819
24236
  outcome: "reconcile_failed_rolled_back",
@@ -22007,7 +24424,7 @@ class HostdServer {
22007
24424
  const agentsDir = resolveAgentsDir(cfg);
22008
24425
  const recentByAgent = {};
22009
24426
  for (const agent of new Set(entries.map((e) => e.agent))) {
22010
- const rows = readRecentFires(resolve5(agentsDir, agent, "scheduler.jsonl"));
24427
+ const rows = readRecentFires(resolve6(agentsDir, agent, "scheduler.jsonl"));
22011
24428
  if (rows.length > 0)
22012
24429
  recentByAgent[agent] = rows;
22013
24430
  }
@@ -22032,7 +24449,7 @@ class HostdServer {
22032
24449
  }
22033
24450
  }
22034
24451
  runDocker(args) {
22035
- return new Promise((resolve6, reject) => {
24452
+ return new Promise((resolve7, reject) => {
22036
24453
  const bin = this.opts.dockerBin ?? "docker";
22037
24454
  const child = spawn2(bin, args, {
22038
24455
  stdio: ["ignore", "pipe", "pipe"],
@@ -22047,15 +24464,15 @@ class HostdServer {
22047
24464
  stderr += d.toString("utf8");
22048
24465
  });
22049
24466
  child.on("error", (err2) => reject(err2));
22050
- child.on("close", (code) => resolve6({ exit_code: code ?? -1, stdout, stderr }));
24467
+ child.on("close", (code) => resolve7({ exit_code: code ?? -1, stdout, stderr }));
22051
24468
  });
22052
24469
  }
22053
24470
  imageRefsForDigestCapture() {
22054
24471
  if (this.opts.imageRefsForDigests)
22055
24472
  return this.opts.imageRefsForDigests();
22056
24473
  try {
22057
- const composePath = join3(this.opts.bindRoot ?? this.opts.homeDir, ".switchroom", "compose", "docker-compose.yml");
22058
- if (!existsSync7(composePath))
24474
+ const composePath = join5(this.opts.bindRoot ?? this.opts.homeDir, ".switchroom", "compose", "docker-compose.yml");
24475
+ if (!existsSync8(composePath))
22059
24476
  return [];
22060
24477
  const r = spawnSync3("docker", [
22061
24478
  "compose",
@@ -22081,18 +24498,59 @@ class HostdServer {
22081
24498
  const ageMs = Date.now() - inFlight.started_at;
22082
24499
  return deniedResponse(request_id, `${op}: fleet-mutation lock held by ${inFlight.op} ` + `(request_id "${inFlight.request_id}", running ${Math.floor(ageMs / 1000)}s). ` + `Wait for it to complete (poll get_status with target_request_id="${inFlight.request_id}") ` + `before issuing another fleet mutation.`, Date.now() - started);
22083
24500
  }
22084
- spawnFleetMutation(op, args, entry) {
22085
- this.runSwitchroom(args).then((res) => {
24501
+ spawnFleetMutation(op, args, entry, extraEnv) {
24502
+ this.runSwitchroom(args, extraEnv).then((res) => {
22086
24503
  entry.result = res.exit_code === 0 ? "completed" : "error";
22087
24504
  entry.exit_code = res.exit_code;
22088
24505
  entry.finished_at = Date.now();
22089
24506
  entry.stdout_tail = tail(res.stdout);
22090
24507
  entry.stderr_tail = tail(res.stderr);
24508
+ if (op === "update_apply") {
24509
+ const parsed = parseUpdateResultLine(res.stdout);
24510
+ if (parsed && parsed.deferred.length > 0) {
24511
+ entry.deferred = parsed.deferred;
24512
+ }
24513
+ }
24514
+ }).catch((err2) => {
24515
+ entry.result = "error";
24516
+ entry.exit_code = null;
24517
+ entry.finished_at = Date.now();
24518
+ entry.error = err2.message;
24519
+ }).finally(() => {
24520
+ this.writeTerminalAudit(entry);
24521
+ if (this.fleetMutationInFlight && this.fleetMutationInFlight.request_id === entry.request_id) {
24522
+ this.fleetMutationInFlight = null;
24523
+ }
24524
+ });
24525
+ }
24526
+ spawnRollout(args, entry) {
24527
+ this.runSwitchroom(args, { SWITCHROOM_HOSTD_CONTEXT: "1" }).then((res) => {
24528
+ entry.exit_code = res.exit_code;
24529
+ entry.finished_at = Date.now();
24530
+ entry.stdout_tail = tail(res.stdout);
24531
+ entry.stderr_tail = tail(res.stderr);
24532
+ const parsed = parseRolloutResultLine(res.stdout);
24533
+ if (parsed) {
24534
+ entry.rolled = parsed.rolled;
24535
+ if (parsed.failedStep)
24536
+ entry.failed_step = parsed.failedStep;
24537
+ if (parsed.failedAgent)
24538
+ entry.failed_agent = parsed.failedAgent;
24539
+ if (parsed.got !== undefined)
24540
+ entry.got = parsed.got;
24541
+ entry.result = parsed.ok ? "completed" : "error";
24542
+ } else {
24543
+ entry.result = res.exit_code === 0 ? "completed" : "error";
24544
+ }
24545
+ if (entry.result !== "completed") {
24546
+ delete entry.prior_pin;
24547
+ }
22091
24548
  }).catch((err2) => {
22092
24549
  entry.result = "error";
22093
24550
  entry.exit_code = null;
22094
24551
  entry.finished_at = Date.now();
22095
24552
  entry.error = err2.message;
24553
+ delete entry.prior_pin;
22096
24554
  }).finally(() => {
22097
24555
  this.writeTerminalAudit(entry);
22098
24556
  if (this.fleetMutationInFlight && this.fleetMutationInFlight.request_id === entry.request_id) {
@@ -22110,6 +24568,19 @@ class HostdServer {
22110
24568
  return this.statusEntryToResponse(req.request_id, entry);
22111
24569
  }
22112
24570
  statusEntryToResponse(request_id, entry) {
24571
+ const rolloutPayload = entry.op === "rollout" && (entry.rolled !== undefined || entry.failed_step !== undefined || entry.failed_agent !== undefined) ? JSON.stringify({
24572
+ rolled: entry.rolled ?? [],
24573
+ ...entry.failed_step ? { failedStep: entry.failed_step } : {},
24574
+ ...entry.failed_agent ? { failedAgent: entry.failed_agent } : {},
24575
+ ...entry.got !== undefined ? { got: entry.got } : {},
24576
+ ...entry.pin ? { pin: entry.pin } : {}
24577
+ }) : undefined;
24578
+ const updatePayload = entry.op === "update_apply" && (entry.deferred !== undefined || entry.channel !== undefined || entry.pin !== undefined) ? {
24579
+ ...entry.deferred !== undefined ? { deferred: entry.deferred } : {},
24580
+ ...entry.pin !== undefined ? { pin: entry.pin } : {},
24581
+ ...entry.channel !== undefined ? { channel: entry.channel } : {}
24582
+ } : null;
24583
+ const payload = rolloutPayload ?? (updatePayload ? JSON.stringify(updatePayload) : undefined);
22113
24584
  return {
22114
24585
  v: 1,
22115
24586
  request_id,
@@ -22118,6 +24589,7 @@ class HostdServer {
22118
24589
  duration_ms: (entry.finished_at ?? Date.now()) - entry.started_at,
22119
24590
  stdout_tail: entry.stdout_tail || undefined,
22120
24591
  stderr_tail: entry.stderr_tail || undefined,
24592
+ ...payload ? { payload } : {},
22121
24593
  error: entry.error
22122
24594
  };
22123
24595
  }
@@ -22141,12 +24613,12 @@ class HostdServer {
22141
24613
  }
22142
24614
  }
22143
24615
  auditLogPath() {
22144
- return this.opts.auditLogPath ?? join3(this.opts.homeDir, ".switchroom", "host-control-audit.log");
24616
+ return this.opts.auditLogPath ?? join5(this.opts.homeDir, ".switchroom", "host-control-audit.log");
22145
24617
  }
22146
24618
  appendAuditRow(row) {
22147
24619
  const path2 = this.auditLogPath();
22148
24620
  this.auditAppendChain = this.auditAppendChain.then(async () => {
22149
- await mkdir(dirname4(path2), { recursive: true }).catch(() => {
24621
+ await mkdir(dirname6(path2), { recursive: true }).catch(() => {
22150
24622
  return;
22151
24623
  });
22152
24624
  if (this.auditChainState === undefined) {
@@ -22194,15 +24666,21 @@ class HostdServer {
22194
24666
  ...entry.channel ? { channel: entry.channel } : {},
22195
24667
  ...entry.pin ? { pin: entry.pin } : {},
22196
24668
  ...entry.resolved_sha ? { resolved_sha: entry.resolved_sha } : {},
22197
- ...entry.install_context ? { install_context: entry.install_context } : {}
24669
+ ...entry.install_context ? { install_context: entry.install_context } : {},
24670
+ ...entry.rolled ? { rolled: entry.rolled } : {},
24671
+ ...entry.failed_step ? { failed_step: entry.failed_step } : {},
24672
+ ...entry.failed_agent ? { failed_agent: entry.failed_agent } : {},
24673
+ ...entry.got !== undefined ? { got: entry.got } : {},
24674
+ ...entry.deferred ? { deferred: entry.deferred } : {},
24675
+ ...entry.prior_pin ? { prior_pin: entry.prior_pin } : {}
22198
24676
  });
22199
24677
  }
22200
- runSwitchroom(args) {
22201
- return new Promise((resolve6, reject) => {
24678
+ runSwitchroom(args, extraEnv) {
24679
+ return new Promise((resolve7, reject) => {
22202
24680
  const bin = this.opts.switchroomBin ?? "switchroom";
22203
24681
  const child = spawn2(bin, args, {
22204
24682
  stdio: ["ignore", "pipe", "pipe"],
22205
- env: { ...process.env }
24683
+ env: { ...process.env, ...extraEnv ?? {} }
22206
24684
  });
22207
24685
  let stdout = "";
22208
24686
  let stderr = "";
@@ -22213,7 +24691,7 @@ class HostdServer {
22213
24691
  stderr += d.toString("utf8");
22214
24692
  });
22215
24693
  child.on("error", (err2) => reject(err2));
22216
- child.on("close", (code) => resolve6({ exit_code: code ?? -1, stdout, stderr }));
24694
+ child.on("close", (code) => resolve7({ exit_code: code ?? -1, stdout, stderr }));
22217
24695
  });
22218
24696
  }
22219
24697
  }
@@ -22341,7 +24819,7 @@ class SocketApprovalGateway {
22341
24819
  finalize: async () => {}
22342
24820
  };
22343
24821
  }
22344
- return await new Promise((resolve6) => {
24822
+ return await new Promise((resolve7) => {
22345
24823
  const client2 = connect({ path: sockPath });
22346
24824
  let buffer = "";
22347
24825
  let resolved = false;
@@ -22380,7 +24858,7 @@ class SocketApprovalGateway {
22380
24858
  return;
22381
24859
  resolved = true;
22382
24860
  log(`request_config_approval write failed (requestId=${req.requestId}): ${err2.message}`);
22383
- resolve6({
24861
+ resolve7({
22384
24862
  verdict: "deny",
22385
24863
  reason: `request_config_approval write failed: ${err2.message}`,
22386
24864
  denySource: "dispatch_failure",
@@ -22409,7 +24887,7 @@ class SocketApprovalGateway {
22409
24887
  const verdict = obj.verdict;
22410
24888
  const reasonField = typeof obj.reason === "string" ? obj.reason : undefined;
22411
24889
  const denySource = verdict === "deny" ? obj.denySource === "dispatch_failure" ? "dispatch_failure" : "operator" : undefined;
22412
- resolve6({
24890
+ resolve7({
22413
24891
  verdict,
22414
24892
  ...reasonField !== undefined ? { reason: reasonField } : {},
22415
24893
  ...denySource !== undefined ? { denySource } : {},
@@ -22423,7 +24901,7 @@ class SocketApprovalGateway {
22423
24901
  return;
22424
24902
  resolved = true;
22425
24903
  log(`gateway socket error (requestId=${req.requestId}): ${err2.message}`);
22426
- resolve6({
24904
+ resolve7({
22427
24905
  verdict: "deny",
22428
24906
  reason: `gateway socket error: ${err2.message}`,
22429
24907
  denySource: "dispatch_failure",
@@ -22434,7 +24912,7 @@ class SocketApprovalGateway {
22434
24912
  if (resolved)
22435
24913
  return;
22436
24914
  resolved = true;
22437
- resolve6({
24915
+ resolve7({
22438
24916
  verdict: "deny",
22439
24917
  reason: "gateway socket closed before verdict",
22440
24918
  denySource: "dispatch_failure",
@@ -22709,17 +25187,17 @@ async function main() {
22709
25187
  `);
22710
25188
  process.exit(2);
22711
25189
  }
22712
- const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? join4(homedir3(), ".switchroom", "agents");
25190
+ const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? join6(homedir4(), ".switchroom", "agents");
22713
25191
  const approvalGateway = new SocketApprovalGateway({
22714
25192
  resolveGatewaySocket: (agentName) => {
22715
- const sock = resolve6(agentsDir, agentName, "telegram", "gateway.sock");
22716
- return existsSync8(sock) ? sock : null;
25193
+ const sock = resolve7(agentsDir, agentName, "telegram", "gateway.sock");
25194
+ return existsSync9(sock) ? sock : null;
22717
25195
  },
22718
25196
  log: (m) => process.stderr.write(`hostd: approval-gateway — ${m}
22719
25197
  `)
22720
25198
  });
22721
25199
  const server = new HostdServer({
22722
- homeDir: homedir3(),
25200
+ homeDir: homedir4(),
22723
25201
  agentUids,
22724
25202
  config: {
22725
25203
  agents: Object.fromEntries(Object.entries(config.agents).map(([n, a]) => [
@@ -22741,7 +25219,7 @@ async function main() {
22741
25219
  let releaseWatcher = null;
22742
25220
  const autoRel = config.host_control?.auto_release_check;
22743
25221
  if (autoRel?.enabled === true) {
22744
- const eventsLog = join4(homedir3(), ".switchroom", "release-watcher-events.jsonl");
25222
+ const eventsLog = join6(homedir4(), ".switchroom", "release-watcher-events.jsonl");
22745
25223
  releaseWatcher = new ReleaseWatcher({
22746
25224
  intervalMs: autoRel.interval_minutes * 60000,
22747
25225
  checkFn: makeReleaseCheck({