@wrongstack/cli 1.1.2 → 1.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/{acp-HCGUTFNE.js → acp-NKUEYJDZ.js} +14 -5
  2. package/dist/acp-leader/acp-leader-confirm.d.ts +20 -0
  3. package/dist/acp-leader/acp-leader-context.d.ts +29 -0
  4. package/dist/acp-leader/acp-leader-fleet.d.ts +26 -0
  5. package/dist/acp-leader/acp-leader-host-binding.d.ts +17 -0
  6. package/dist/acp-leader/acp-leader-host.d.ts +82 -0
  7. package/dist/acp-leader/acp-leader-picker.d.ts +24 -0
  8. package/dist/acp-leader/acp-leader-provider.d.ts +85 -0
  9. package/dist/acp-leader/acp-leader-resume.d.ts +10 -0
  10. package/dist/acp-leader/acp-leader-stream.d.ts +83 -0
  11. package/dist/{auth-ANOVZVHE.js → auth-2ZG5DBHS.js} +62 -66
  12. package/dist/auth-menu/index.d.ts +1 -2
  13. package/dist/boot/dispatch-webui.d.ts +16 -0
  14. package/dist/boot/launch-menu-arrow.d.ts +20 -0
  15. package/dist/boot/launch-menu-types.d.ts +36 -0
  16. package/dist/boot/launch-menu.d.ts +1 -57
  17. package/dist/boot/tui-session-resume-rollback.d.ts +31 -0
  18. package/dist/{boot-auto-thin-7D4OVEWA.js → boot-auto-thin-N2CIGTXE.js} +3 -3
  19. package/dist/{chunk-TZPKOS5G.js → chunk-2XQ6SRKG.js} +2 -2
  20. package/dist/chunk-3LEIFO5D.js +65 -0
  21. package/dist/chunk-5SGMUDP5.js +752 -0
  22. package/dist/{chunk-3EXRPTAU.js → chunk-5TQ65PXQ.js} +17 -17
  23. package/dist/{chunk-GRAGMA4B.js → chunk-7BM4LGKQ.js} +18 -18
  24. package/dist/{chunk-VAQXOZKP.js → chunk-AJM4EFCM.js} +139 -136
  25. package/dist/{chunk-C2BBH4S4.js → chunk-E3MJFAFR.js} +2 -2
  26. package/dist/{chunk-5TRZZHMN.js → chunk-JCZ2D3VV.js} +4 -65
  27. package/dist/{chunk-AWRZWPJ3.js → chunk-JFYQGMMM.js} +99 -75
  28. package/dist/{chunk-BIGSVBPI.js → chunk-KNYIEQAY.js} +64 -61
  29. package/dist/chunk-LUEO5HLZ.js +50 -0
  30. package/dist/chunk-LYWOV4OX.js +252 -0
  31. package/dist/chunk-M7FNHCE3.js +2070 -0
  32. package/dist/{chunk-75OLD563.js → chunk-M7PSENGF.js} +3 -1
  33. package/dist/{chunk-NMXQFQ26.js → chunk-MEBXWI7U.js} +5 -5
  34. package/dist/{chunk-RAWHRRUJ.js → chunk-MKMM5RIW.js} +209 -201
  35. package/dist/{chunk-3R3OADC5.js → chunk-P7MEEUGT.js} +281 -252
  36. package/dist/chunk-QLYPIJ7X.js +258 -0
  37. package/dist/chunk-RN5CFAVQ.js +292 -0
  38. package/dist/{chunk-WDXNBYGD.js → chunk-TDP7CZGE.js} +6 -1
  39. package/dist/{chunk-6VPWQ4TG.js → chunk-UROB7MK5.js} +2 -1
  40. package/dist/chunk-VEESMPTX.js +254 -0
  41. package/dist/{chunk-IJLIAPCW.js → chunk-VPSAKGLK.js} +47 -47
  42. package/dist/{cli-context-YIT4FEDM.js → cli-context-CQYGIWOU.js} +254 -237
  43. package/dist/{cli-main-JIADJ5OL.js → cli-main-VRUJNUBX.js} +2081 -1594
  44. package/dist/cli-main-boot.d.ts +1 -1
  45. package/dist/config-doctor-known-keys.d.ts +33 -0
  46. package/dist/config-doctor.d.ts +2 -47
  47. package/dist/config-history-support.d.ts +36 -0
  48. package/dist/config-history.d.ts +1 -1
  49. package/dist/{config-transfer-Y7XJMJRN.js → config-transfer-B4GOZTFC.js} +2 -2
  50. package/dist/{execution-BAP566QC.js → execution-IV72RUSM.js} +5354 -5258
  51. package/dist/execution-tui.d.ts +30 -0
  52. package/dist/fleet/acp-live-steer.d.ts +28 -0
  53. package/dist/fleet/acp-permission-bridge.d.ts +49 -0
  54. package/dist/fleet/acp-quota-hold.d.ts +3 -0
  55. package/dist/fleet/acp-quota-reading.d.ts +3 -0
  56. package/dist/fleet/acp-turn-reminders.d.ts +15 -0
  57. package/dist/fleet/acp-wrongstack-bridge.d.ts +50 -0
  58. package/dist/fleet/host-acp.d.ts +23 -2
  59. package/dist/fleet/wrongforge-client.d.ts +116 -0
  60. package/dist/fleet/wrongforge-gateway.d.ts +20 -0
  61. package/dist/fleet/wrongforge-info.d.ts +32 -0
  62. package/dist/fleet/wrongforge-quota.d.ts +10 -0
  63. package/dist/fleet/wrongforge-runner.d.ts +37 -0
  64. package/dist/fleet/wrongforge-runtime.d.ts +10 -0
  65. package/dist/{hq-JD5AZVMG.js → hq-54PQYR5O.js} +311 -307
  66. package/dist/hq-server/sweeps.d.ts +28 -0
  67. package/dist/{hq-server-BI23EPM7.js → hq-server-YK7FBLL6.js} +3 -3
  68. package/dist/index.js +8 -5
  69. package/dist/mcp-22CFBX4H.js +236 -0
  70. package/dist/mcp-serve-project.d.ts +18 -0
  71. package/dist/mcp-serve.d.ts +0 -63
  72. package/dist/{modeldiag-HDIKG37X.js → modeldiag-5PBB777J.js} +4 -4
  73. package/dist/{per-subcommand-help-D6J4ZXW2.js → per-subcommand-help-MQGERD4E.js} +2 -2
  74. package/dist/plugin-llm-command.d.ts +9 -0
  75. package/dist/{plugin-usage-TYF5HY4K.js → plugin-usage-UWKYMNQU.js} +3 -3
  76. package/dist/{plugins-XGAXDLPT.js → plugins-VP7JQH47.js} +4 -4
  77. package/dist/{sdd-runtime-6MFUXWJK.js → sdd-runtime-HIJ4Z5TF.js} +2 -2
  78. package/dist/services/sdd/state.d.ts +2 -0
  79. package/dist/session-event-wiring-types.d.ts +62 -0
  80. package/dist/session-event-wiring.d.ts +2 -52
  81. package/dist/{sessions-config-SJVQXCIE.js → sessions-config-7MK742OW.js} +2 -2
  82. package/dist/short-circuit-flags-AGHURHMQ.js +11 -0
  83. package/dist/slash-commands/command-context-fleet.d.ts +187 -0
  84. package/dist/slash-commands/command-context-sdd-goal.d.ts +102 -0
  85. package/dist/slash-commands/command-context.d.ts +3 -282
  86. package/dist/slash-commands/project-switch-interactive.d.ts +11 -0
  87. package/dist/slash-commands/setmodel-helpers.d.ts +36 -0
  88. package/dist/subcommands/handlers/hq-token.d.ts +3 -0
  89. package/dist/subcommands/handlers/hq.d.ts +0 -21
  90. package/dist/subcommands/handlers/per-subcommand-help-operations.d.ts +8 -0
  91. package/dist/subcommands/handlers/tools-cli-args.d.ts +57 -0
  92. package/dist/subcommands/handlers/tools-cli.d.ts +5 -0
  93. package/dist/subcommands/handlers/tools-serve.d.ts +4 -0
  94. package/dist/{subcommands-VTMIZQBP.js → subcommands-OCJNO57E.js} +2 -2
  95. package/dist/tool-gateway-http.d.ts +30 -0
  96. package/dist/tool-gateway.d.ts +185 -0
  97. package/dist/tools-cli-44MLIUQO.js +509 -0
  98. package/dist/tools-serve-TRCET2M7.js +102 -0
  99. package/dist/{tools-skills-55QVTMSK.js → tools-skills-WDTMCE46.js} +7 -2
  100. package/dist/tuneup-runtime-checks.d.ts +7 -0
  101. package/dist/tuneup-types.d.ts +118 -0
  102. package/dist/tuneup.d.ts +3 -122
  103. package/dist/{typesafe-YBEADNAH.js → typesafe-QLSMFU7J.js} +1 -1
  104. package/dist/{version-help-RBZC5GZZ.js → version-help-X6CC4CFY.js} +2 -2
  105. package/dist/{webui-server-HIUY3RHD.js → webui-server-V2R5WQUK.js} +79 -3
  106. package/dist/wiring/provider-runtime-setup.d.ts +3 -1
  107. package/dist/wiring/session-runtime.d.ts +1 -1
  108. package/dist/wrongforge-gateway-UOFBK56J.js +92 -0
  109. package/dist/wrongforge-leader/wrongforge-leader-gateway.d.ts +9 -0
  110. package/dist/wrongforge-leader/wrongforge-leader-picker.d.ts +12 -0
  111. package/dist/wrongforge-leader/wrongforge-leader-provider.d.ts +49 -0
  112. package/package.json +34 -30
  113. package/dist/auth-menu/anthropic-oauth.d.ts +0 -43
  114. package/dist/chunk-XT3NAHRX.js +0 -337
  115. package/dist/chunk-ZNNFEKDZ.js +0 -319
  116. package/dist/mcp-2XWBJEQN.js +0 -464
  117. package/dist/short-circuit-flags-CPCT5MWB.js +0 -11
@@ -24,7 +24,7 @@ import {
24
24
  sanitizeApiError,
25
25
  truncateHqSummary,
26
26
  writeInvalidBody
27
- } from "./chunk-3EXRPTAU.js";
27
+ } from "./chunk-5TQ65PXQ.js";
28
28
  import {
29
29
  createHqIpAllowlist
30
30
  } from "./chunk-OGVSKS4Q.js";
@@ -3839,9 +3839,6 @@ function createHqSocketCredentialEnforcer(state) {
3839
3839
  };
3840
3840
  }
3841
3841
 
3842
- // src/hq-server/upgrade-handler.ts
3843
- import { hqTokenVerifier as hqTokenVerifier2, isLoopbackHost as isLoopbackHost3, isTokenExpired as isTokenExpired5 } from "@wrongstack/core/hq";
3844
-
3845
3842
  // src/hq-server/ws.ts
3846
3843
  import { randomUUID as randomUUID5 } from "node:crypto";
3847
3844
  import {
@@ -4706,7 +4703,91 @@ function handleClient(ws, clients, browsers, eventLog, auth, snapshotBroadcaster
4706
4703
  });
4707
4704
  }
4708
4705
 
4706
+ // src/hq-server/sweeps.ts
4707
+ var HQ_SESSION_MAX_AGE_MS2 = 7 * 24 * 60 * 60 * 1e3;
4708
+ var HQ_SESSION_IDLE_TIMEOUT_MS2 = 30 * 6e4;
4709
+ var PENDING_2FA_TTL_MS2 = 5 * 6e4;
4710
+ var HQ_SESSION_CLEANUP_INTERVAL_MS = 6e4;
4711
+ function sweepHqBrowserSessions(sessions, loginAttempts, socketCredentials) {
4712
+ const now = Date.now();
4713
+ const maxAgeCutoff = now - HQ_SESSION_MAX_AGE_MS2;
4714
+ const idleCutoff = now - HQ_SESSION_IDLE_TIMEOUT_MS2;
4715
+ const pending2faCutoff = now - PENDING_2FA_TTL_MS2;
4716
+ for (const [id, session] of sessions) {
4717
+ if (session.createdAt < maxAgeCutoff) {
4718
+ sessions.delete(id);
4719
+ socketCredentials.closeSessionSockets(id, "Browser session expired");
4720
+ continue;
4721
+ }
4722
+ if (session.pending2fa) {
4723
+ if (session.createdAt < pending2faCutoff) sessions.delete(id);
4724
+ continue;
4725
+ }
4726
+ if (session.lastSeenAt < idleCutoff) {
4727
+ sessions.delete(id);
4728
+ }
4729
+ }
4730
+ for (const [ip, entry] of loginAttempts.entries()) {
4731
+ if (now - entry.lastAttempt > 15 * 6e4) loginAttempts.delete(ip);
4732
+ }
4733
+ }
4734
+ function sweepStaleHqClients({
4735
+ clients,
4736
+ browsers,
4737
+ auditLog,
4738
+ eventLog,
4739
+ persistence,
4740
+ clientTtlMs,
4741
+ sessionSnapshotTtlMs
4742
+ }) {
4743
+ const cutoff = Date.now() - clientTtlMs;
4744
+ const sessionCutoff = Date.now() - sessionSnapshotTtlMs;
4745
+ let changed = false;
4746
+ for (const [ws, client] of clients.entries()) {
4747
+ if (new Date(client.lastSeenAt).getTime() < cutoff) {
4748
+ const lostClient = client;
4749
+ ws.terminate();
4750
+ clients.delete(ws);
4751
+ failUndeliveredCommands(lostClient, browsers, auditLog);
4752
+ detectLeaderLoss(lostClient, clients, browsers, "heartbeat-timeout", {
4753
+ eventLog,
4754
+ persistence
4755
+ });
4756
+ changed = true;
4757
+ continue;
4758
+ }
4759
+ const expiredSessions = /* @__PURE__ */ new Set();
4760
+ for (const [sessionId, tracked] of client.sessions.entries()) {
4761
+ if (tracked.receivedAt < sessionCutoff) {
4762
+ client.sessions.delete(sessionId);
4763
+ client.mcpSnapshots.delete(sessionId);
4764
+ expiredSessions.add(sessionId);
4765
+ changed = true;
4766
+ }
4767
+ }
4768
+ for (const [runId, fleet] of client.fleets) {
4769
+ if (fleet.sessionId !== void 0 && expiredSessions.has(fleet.sessionId)) {
4770
+ client.fleets.delete(runId);
4771
+ changed = true;
4772
+ }
4773
+ }
4774
+ if (client.capabilities.includes("session.summary") && client.sessions.size === 0 && Date.now() - Date.parse(client.connectedAt) > sessionSnapshotTtlMs) {
4775
+ const lostClient = client;
4776
+ ws.terminate();
4777
+ clients.delete(ws);
4778
+ failUndeliveredCommands(lostClient, browsers, auditLog);
4779
+ detectLeaderLoss(lostClient, clients, browsers, "crash", {
4780
+ eventLog,
4781
+ persistence
4782
+ });
4783
+ changed = true;
4784
+ }
4785
+ }
4786
+ return changed;
4787
+ }
4788
+
4709
4789
  // src/hq-server/upgrade-handler.ts
4790
+ import { hqTokenVerifier as hqTokenVerifier2, isLoopbackHost as isLoopbackHost3, isTokenExpired as isTokenExpired5 } from "@wrongstack/core/hq";
4710
4791
  function handleHqUpgrade(req, socket, head, deps) {
4711
4792
  const url = new URL(req.url ?? "/", `http://${deps.host}:${deps.port}`);
4712
4793
  const pathname = url.pathname;
@@ -4964,33 +5045,10 @@ async function startHqServerWithAuth(options, host, port, dataDir, firstRunAuth)
4964
5045
  mutableAuth,
4965
5046
  sessions
4966
5047
  });
4967
- const HQ_SESSION_MAX_AGE_MS2 = 7 * 24 * 60 * 60 * 1e3;
4968
- const HQ_SESSION_IDLE_TIMEOUT_MS2 = 30 * 6e4;
4969
- const SESSION_CLEANUP_INTERVAL_MS = 6e4;
4970
- const PENDING_2FA_TTL_MS2 = 5 * 6e4;
4971
- const sessionCleanupTimer = setInterval(() => {
4972
- const now = Date.now();
4973
- const maxAgeCutoff = now - HQ_SESSION_MAX_AGE_MS2;
4974
- const idleCutoff = now - HQ_SESSION_IDLE_TIMEOUT_MS2;
4975
- const pending2faCutoff = now - PENDING_2FA_TTL_MS2;
4976
- for (const [id, session] of sessions) {
4977
- if (session.createdAt < maxAgeCutoff) {
4978
- sessions.delete(id);
4979
- socketCredentials.closeSessionSockets(id, "Browser session expired");
4980
- continue;
4981
- }
4982
- if (session.pending2fa) {
4983
- if (session.createdAt < pending2faCutoff) sessions.delete(id);
4984
- continue;
4985
- }
4986
- if (session.lastSeenAt < idleCutoff) {
4987
- sessions.delete(id);
4988
- }
4989
- }
4990
- for (const [ip, entry] of loginAttempts.entries()) {
4991
- if (now - entry.lastAttempt > 15 * 6e4) loginAttempts.delete(ip);
4992
- }
4993
- }, SESSION_CLEANUP_INTERVAL_MS);
5048
+ const sessionCleanupTimer = setInterval(
5049
+ () => sweepHqBrowserSessions(sessions, loginAttempts, socketCredentials),
5050
+ HQ_SESSION_CLEANUP_INTERVAL_MS
5051
+ );
4994
5052
  sessionCleanupTimer.unref?.();
4995
5053
  const persistence = createHqPersistence(dataDir);
4996
5054
  const auditLog = new HqCommandAuditLog(1e3, (entry) => persistence.commandLog.append(entry));
@@ -5065,49 +5123,15 @@ async function startHqServerWithAuth(options, host, port, dataDir, firstRunAuth)
5065
5123
  const sessionSnapshotTtlMs = options.sessionSnapshotTtlMs ?? SESSION_SNAPSHOT_TTL_MS;
5066
5124
  const cleanupTimer = setInterval(() => {
5067
5125
  socketCredentials.sweepExpiredSocketCredentials();
5068
- const cutoff = Date.now() - clientTtlMs;
5069
- const sessionCutoff = Date.now() - sessionSnapshotTtlMs;
5070
- let changed = false;
5071
- for (const [ws, client] of clients.entries()) {
5072
- if (new Date(client.lastSeenAt).getTime() < cutoff) {
5073
- const lostClient = client;
5074
- ws.terminate();
5075
- clients.delete(ws);
5076
- failUndeliveredCommands(lostClient, browsers, auditLog);
5077
- detectLeaderLoss(lostClient, clients, browsers, "heartbeat-timeout", {
5078
- eventLog,
5079
- persistence
5080
- });
5081
- changed = true;
5082
- continue;
5083
- }
5084
- const expiredSessions = /* @__PURE__ */ new Set();
5085
- for (const [sessionId, tracked] of client.sessions.entries()) {
5086
- if (tracked.receivedAt < sessionCutoff) {
5087
- client.sessions.delete(sessionId);
5088
- client.mcpSnapshots.delete(sessionId);
5089
- expiredSessions.add(sessionId);
5090
- changed = true;
5091
- }
5092
- }
5093
- for (const [runId, fleet] of client.fleets) {
5094
- if (fleet.sessionId !== void 0 && expiredSessions.has(fleet.sessionId)) {
5095
- client.fleets.delete(runId);
5096
- changed = true;
5097
- }
5098
- }
5099
- if (client.capabilities.includes("session.summary") && client.sessions.size === 0 && Date.now() - Date.parse(client.connectedAt) > sessionSnapshotTtlMs) {
5100
- const lostClient = client;
5101
- ws.terminate();
5102
- clients.delete(ws);
5103
- failUndeliveredCommands(lostClient, browsers, auditLog);
5104
- detectLeaderLoss(lostClient, clients, browsers, "crash", {
5105
- eventLog,
5106
- persistence
5107
- });
5108
- changed = true;
5109
- }
5110
- }
5126
+ const changed = sweepStaleHqClients({
5127
+ clients,
5128
+ browsers,
5129
+ auditLog,
5130
+ eventLog,
5131
+ persistence,
5132
+ clientTtlMs,
5133
+ sessionSnapshotTtlMs
5134
+ });
5111
5135
  if (changed) snapshotBroadcaster.broadcast();
5112
5136
  }, options.clientCleanupIntervalMs ?? CLIENT_CLEANUP_INTERVAL_MS);
5113
5137
  cleanupTimer.unref?.();
@@ -5361,4 +5385,4 @@ export {
5361
5385
  startHqServer,
5362
5386
  HqInsecureExposureError2 as HqInsecureExposureError
5363
5387
  };
5364
- //# sourceMappingURL=chunk-AWRZWPJ3.js.map
5388
+ //# sourceMappingURL=chunk-JFYQGMMM.js.map
@@ -1,18 +1,19 @@
1
1
 
2
2
  // src/config-history.ts
3
3
  import { randomUUID } from "node:crypto";
4
+ import * as fs2 from "node:fs/promises";
5
+ import * as path2 from "node:path";
6
+ import { isSecretField as isSecretField2 } from "@wrongstack/core/security";
7
+ import { ERROR_CODES as ERROR_CODES2, FsError as FsError2 } from "@wrongstack/core/types";
8
+ import { atomicWrite, toErrorMessage, withFileLock, writeErr } from "@wrongstack/core/utils";
9
+
10
+ // src/config-history-support.ts
4
11
  import * as fs from "node:fs/promises";
5
12
  import os from "node:os";
6
13
  import * as path from "node:path";
7
14
  import { isSecretField } from "@wrongstack/core/security";
8
15
  import { ERROR_CODES, FsError } from "@wrongstack/core/types";
9
- import {
10
- atomicWrite,
11
- resolveWstackPaths,
12
- toErrorMessage,
13
- withFileLock,
14
- writeErr
15
- } from "@wrongstack/core/utils";
16
+ import { resolveWstackPaths } from "@wrongstack/core/utils";
16
17
  var defaultUidFn = () => os.userInfo().uid;
17
18
  async function getFileUid(filePath) {
18
19
  try {
@@ -32,8 +33,6 @@ async function checkConfigOwnership(homeFn, uidFn = defaultUidFn, targetConfigPa
32
33
  return fileUid === callerUid;
33
34
  }
34
35
  var PROTECTED_BASENAMES = /* @__PURE__ */ new Set(["config.json", ".key", "index.json"]);
35
- var MAX_CONFIG_BACKUPS = 10;
36
- var MAX_CONFIG_HISTORY_ENTRIES = 50;
37
36
  function assertSafeToDelete(filename, parentDir) {
38
37
  if (PROTECTED_BASENAMES.has(filename)) {
39
38
  throw new FsError({
@@ -72,19 +71,6 @@ function assertSafeToDelete(filename, parentDir) {
72
71
  });
73
72
  }
74
73
  }
75
- async function safeDelete(filePath) {
76
- const dir = path.dirname(filePath);
77
- const filename = path.basename(filePath);
78
- try {
79
- assertSafeToDelete(filename, dir);
80
- await fs.unlink(filePath);
81
- } catch (err) {
82
- if (err instanceof Error && err.message.startsWith("Refusing")) {
83
- writeErr(`[config-history] SAFETY: ${err.message}
84
- `);
85
- }
86
- }
87
- }
88
74
  var REDACTED = "[REDACTED]";
89
75
  function maskValue(v) {
90
76
  if (Array.isArray(v)) return v.map(maskValue);
@@ -130,6 +116,31 @@ function reviveSecrets(masked, current) {
130
116
  }
131
117
  return out;
132
118
  }
119
+ var defaultHomeDir = () => os.homedir();
120
+ function activeProfileConfigPath(homeFn) {
121
+ const paths = homeFn === defaultHomeDir ? resolveWstackPaths({ projectRoot: process.cwd() }) : resolveWstackPaths({ projectRoot: process.cwd(), userHome: homeFn() });
122
+ return paths.profileConfig(paths.profileName);
123
+ }
124
+ function configPath(homeFn = defaultHomeDir, targetConfigPath) {
125
+ return targetConfigPath ?? activeProfileConfigPath(homeFn);
126
+ }
127
+
128
+ // src/config-history.ts
129
+ var MAX_CONFIG_BACKUPS = 10;
130
+ var MAX_CONFIG_HISTORY_ENTRIES = 50;
131
+ async function safeDelete(filePath) {
132
+ const dir = path2.dirname(filePath);
133
+ const filename = path2.basename(filePath);
134
+ try {
135
+ assertSafeToDelete(filename, dir);
136
+ await fs2.unlink(filePath);
137
+ } catch (err) {
138
+ if (err instanceof Error && err.message.startsWith("Refusing")) {
139
+ writeErr(`[config-history] SAFETY: ${err.message}
140
+ `);
141
+ }
142
+ }
143
+ }
133
144
  function diffSummary(oldCfg, newCfg) {
134
145
  const changes = [];
135
146
  const allKeys = /* @__PURE__ */ new Set([...Object.keys(oldCfg), ...Object.keys(newCfg)]);
@@ -137,7 +148,7 @@ function diffSummary(oldCfg, newCfg) {
137
148
  const o = JSON.stringify(oldCfg[k]);
138
149
  const n = JSON.stringify(newCfg[k]);
139
150
  if (o !== n) {
140
- if (isSecretField(k)) {
151
+ if (isSecretField2(k)) {
141
152
  changes.push(`${k}: [CHANGED]`);
142
153
  } else if (typeof newCfg[k] !== "object") {
143
154
  changes.push(`${k}: ${oldCfg[k] ?? "(unset)"} \u2192 ${newCfg[k]}`);
@@ -148,24 +159,16 @@ function diffSummary(oldCfg, newCfg) {
148
159
  }
149
160
  return changes.length > 0 ? changes.slice(0, 5).join(", ") : "no changes";
150
161
  }
151
- var defaultHomeDir = () => os.homedir();
152
- function activeProfileConfigPath(homeFn) {
153
- const paths = homeFn === defaultHomeDir ? resolveWstackPaths({ projectRoot: process.cwd() }) : resolveWstackPaths({ projectRoot: process.cwd(), userHome: homeFn() });
154
- return paths.profileConfig(paths.profileName);
155
- }
156
162
  function historyDir(homeFn = defaultHomeDir, targetConfigPath) {
157
- return path.join(path.dirname(configPath(homeFn, targetConfigPath)), "config.history", "entries");
163
+ return path2.join(path2.dirname(configPath(homeFn, targetConfigPath)), "config.history", "entries");
158
164
  }
159
165
  function historyIndexPath(homeFn = defaultHomeDir, targetConfigPath) {
160
- return path.join(
161
- path.dirname(configPath(homeFn, targetConfigPath)),
166
+ return path2.join(
167
+ path2.dirname(configPath(homeFn, targetConfigPath)),
162
168
  "config.history",
163
169
  "index.json"
164
170
  );
165
171
  }
166
- function configPath(homeFn = defaultHomeDir, targetConfigPath) {
167
- return targetConfigPath ?? activeProfileConfigPath(homeFn);
168
- }
169
172
  function backupLastPath(homeFn = defaultHomeDir, targetConfigPath) {
170
173
  return `${configPath(homeFn, targetConfigPath)}.last`;
171
174
  }
@@ -174,11 +177,11 @@ function entryId(ts) {
174
177
  }
175
178
  async function ensureHistoryDir(homeFn = defaultHomeDir, targetConfigPath) {
176
179
  try {
177
- await fs.mkdir(historyDir(homeFn, targetConfigPath), { recursive: true });
180
+ await fs2.mkdir(historyDir(homeFn, targetConfigPath), { recursive: true });
178
181
  } catch (err) {
179
- throw new FsError({
182
+ throw new FsError2({
180
183
  message: toErrorMessage(err),
181
- code: ERROR_CODES.FS_MKDIR_FAILED,
184
+ code: ERROR_CODES2.FS_MKDIR_FAILED,
182
185
  path: historyDir(homeFn, targetConfigPath),
183
186
  cause: err
184
187
  });
@@ -187,7 +190,7 @@ async function ensureHistoryDir(homeFn = defaultHomeDir, targetConfigPath) {
187
190
  async function readIndex(homeFn = defaultHomeDir, targetConfigPath) {
188
191
  let raw;
189
192
  try {
190
- raw = await fs.readFile(historyIndexPath(homeFn, targetConfigPath), "utf8");
193
+ raw = await fs2.readFile(historyIndexPath(homeFn, targetConfigPath), "utf8");
191
194
  } catch (err) {
192
195
  if (err.code !== "ENOENT") throw err;
193
196
  return rebuildIndexFromEntries(homeFn, targetConfigPath);
@@ -208,7 +211,7 @@ async function rebuildIndexFromEntries(homeFn = defaultHomeDir, targetConfigPath
208
211
  const dir = historyDir(homeFn, targetConfigPath);
209
212
  let files;
210
213
  try {
211
- files = (await fs.readdir(dir)).filter((file) => file.endsWith(".json"));
214
+ files = (await fs2.readdir(dir)).filter((file) => file.endsWith(".json"));
212
215
  } catch (err) {
213
216
  if (err.code === "ENOENT") return { version: 1, entries: [] };
214
217
  throw err;
@@ -218,7 +221,7 @@ async function rebuildIndexFromEntries(homeFn = defaultHomeDir, targetConfigPath
218
221
  const id = file.slice(0, -".json".length);
219
222
  let raw;
220
223
  try {
221
- raw = await fs.readFile(path.join(dir, file), "utf8");
224
+ raw = await fs2.readFile(path2.join(dir, file), "utf8");
222
225
  } catch (err) {
223
226
  if (err.code === "ENOENT") continue;
224
227
  entries.push({ id, timestamp: "", description: "" });
@@ -244,9 +247,9 @@ async function writeIndex(idx, homeFn = defaultHomeDir, targetConfigPath) {
244
247
  try {
245
248
  await atomicWrite(historyIndexPath(homeFn, targetConfigPath), JSON.stringify(idx, null, 2));
246
249
  } catch (err) {
247
- throw new FsError({
250
+ throw new FsError2({
248
251
  message: toErrorMessage(err),
249
- code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
252
+ code: ERROR_CODES2.FS_ATOMIC_WRITE_FAILED,
250
253
  path: historyIndexPath(homeFn, targetConfigPath),
251
254
  cause: err
252
255
  });
@@ -258,16 +261,16 @@ async function pruneHistoryEntries(idx, homeFn = defaultHomeDir, targetConfigPat
258
261
  const dir = historyDir(homeFn, targetConfigPath);
259
262
  for (const entry of removed) {
260
263
  try {
261
- await fs.unlink(path.join(dir, `${entry.id}.json`));
264
+ await fs2.unlink(path2.join(dir, `${entry.id}.json`));
262
265
  } catch {
263
266
  }
264
267
  }
265
268
  try {
266
- const files = await fs.readdir(dir);
269
+ const files = await fs2.readdir(dir);
267
270
  await Promise.all(
268
271
  files.filter((file) => file.endsWith(".json") && !keep.has(file)).map(async (file) => {
269
272
  try {
270
- await fs.unlink(path.join(dir, file));
273
+ await fs2.unlink(path2.join(dir, file));
271
274
  } catch {
272
275
  }
273
276
  })
@@ -281,7 +284,7 @@ async function backupCurrent(homeFn = defaultHomeDir, targetConfigPath) {
281
284
  const ts = Date.now();
282
285
  let content;
283
286
  try {
284
- content = await fs.readFile(cfg, "utf8");
287
+ content = await fs2.readFile(cfg, "utf8");
285
288
  } catch {
286
289
  }
287
290
  if (content !== void 0) {
@@ -300,11 +303,11 @@ async function backupCurrent(homeFn = defaultHomeDir, targetConfigPath) {
300
303
  }
301
304
  }
302
305
  try {
303
- const dir = path.dirname(cfg);
304
- const files = await fs.readdir(dir);
306
+ const dir = path2.dirname(cfg);
307
+ const files = await fs2.readdir(dir);
305
308
  const baks = files.filter((f) => f.startsWith("config.json.") && f.endsWith(".bak")).sort().reverse();
306
309
  for (const f of baks.slice(MAX_CONFIG_BACKUPS)) {
307
- await safeDelete(path.join(dir, f));
310
+ await safeDelete(path2.join(dir, f));
308
311
  }
309
312
  } catch (err) {
310
313
  writeErr(`[config-history] backup prune failed: ${toErrorMessage(err)}`);
@@ -322,16 +325,16 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
322
325
  diffSummary: diffSummary(oldCfg, newCfg)
323
326
  };
324
327
  try {
325
- await fs.writeFile(
326
- path.join(historyDir(homeFn, targetConfigPath), `${id}.json`),
328
+ await fs2.writeFile(
329
+ path2.join(historyDir(homeFn, targetConfigPath), `${id}.json`),
327
330
  JSON.stringify(entry, null, 2),
328
331
  { encoding: "utf8", mode: 384 }
329
332
  );
330
333
  } catch (err) {
331
- throw new FsError({
334
+ throw new FsError2({
332
335
  message: toErrorMessage(err),
333
- code: ERROR_CODES.FS_WRITE_FAILED,
334
- path: path.join(historyDir(homeFn, targetConfigPath), `${id}.json`),
336
+ code: ERROR_CODES2.FS_WRITE_FAILED,
337
+ path: path2.join(historyDir(homeFn, targetConfigPath), `${id}.json`),
335
338
  cause: err
336
339
  });
337
340
  }
@@ -350,10 +353,10 @@ async function listHistory(homeFn = defaultHomeDir, targetConfigPath) {
350
353
  }
351
354
  async function getHistoryEntry(id, homeFn = defaultHomeDir, targetConfigPath) {
352
355
  const dir = historyDir(homeFn, targetConfigPath);
353
- const filePath = path.join(dir, `${id}.json`);
354
- if (path.dirname(path.resolve(filePath)) !== path.resolve(dir)) return null;
356
+ const filePath = path2.join(dir, `${id}.json`);
357
+ if (path2.dirname(path2.resolve(filePath)) !== path2.resolve(dir)) return null;
355
358
  try {
356
- const raw = await fs.readFile(filePath, "utf8");
359
+ const raw = await fs2.readFile(filePath, "utf8");
357
360
  return JSON.parse(raw);
358
361
  } catch {
359
362
  return null;
@@ -374,7 +377,7 @@ async function restoreFromHistory(id, homeFn = defaultHomeDir, targetConfigPath)
374
377
  await backupCurrent(homeFn, targetConfigPath);
375
378
  let oldCfg = {};
376
379
  try {
377
- const raw = await fs.readFile(cfg, "utf8");
380
+ const raw = await fs2.readFile(cfg, "utf8");
378
381
  oldCfg = JSON.parse(raw);
379
382
  } catch {
380
383
  }
@@ -399,7 +402,7 @@ async function restoreLast(homeFn = defaultHomeDir, targetConfigPath) {
399
402
  const cfg = configPath(homeFn, targetConfigPath);
400
403
  let lastCfg = {};
401
404
  try {
402
- const raw = await fs.readFile(last, "utf8");
405
+ const raw = await fs2.readFile(last, "utf8");
403
406
  lastCfg = JSON.parse(raw);
404
407
  } catch {
405
408
  return { ok: false, error: "No prior backup found" };
@@ -410,7 +413,7 @@ async function restoreLast(homeFn = defaultHomeDir, targetConfigPath) {
410
413
  return withFileLock(cfg, async () => {
411
414
  let oldCfg = {};
412
415
  try {
413
- const raw = await fs.readFile(cfg, "utf8");
416
+ const raw = await fs2.readFile(cfg, "utf8");
414
417
  oldCfg = JSON.parse(raw);
415
418
  } catch {
416
419
  }
@@ -439,4 +442,4 @@ export {
439
442
  restoreFromHistory,
440
443
  restoreLast
441
444
  };
442
- //# sourceMappingURL=chunk-BIGSVBPI.js.map
445
+ //# sourceMappingURL=chunk-KNYIEQAY.js.map
@@ -0,0 +1,50 @@
1
+
2
+ // src/acp-leader/acp-leader-host.ts
3
+ var ACP_LEADER_PROVIDER_ID = "acp";
4
+ var bound;
5
+ var sessionAgents;
6
+ function setAcpLeaderSessionAgents(resolve) {
7
+ sessionAgents = resolve;
8
+ }
9
+ function acpLeaderSessionAgent(sessionId) {
10
+ return sessionAgents?.(sessionId);
11
+ }
12
+ function bindAcpLeaderHost(host) {
13
+ bound = host;
14
+ }
15
+ function acpLeaderHost() {
16
+ return bound;
17
+ }
18
+ function confirmAcpLeaderThroughEvents() {
19
+ if (bound) bound = { ...bound, confirmAwaiter: void 0, confirmThroughEvents: true };
20
+ }
21
+ var liveLeaders = /* @__PURE__ */ new Set();
22
+ function trackAcpLeader(leader) {
23
+ liveLeaders.add(leader);
24
+ }
25
+ async function closeAcpLeaderSessions(timeoutMs = 1500) {
26
+ if (liveLeaders.size === 0) return;
27
+ const all = [...liveLeaders];
28
+ liveLeaders.clear();
29
+ let timer;
30
+ await Promise.race([
31
+ Promise.all(all.map((leader) => leader.closeAll().catch(() => void 0))),
32
+ new Promise((resolve) => {
33
+ timer = setTimeout(resolve, timeoutMs);
34
+ timer.unref?.();
35
+ })
36
+ ]);
37
+ if (timer) clearTimeout(timer);
38
+ }
39
+
40
+ export {
41
+ ACP_LEADER_PROVIDER_ID,
42
+ setAcpLeaderSessionAgents,
43
+ acpLeaderSessionAgent,
44
+ bindAcpLeaderHost,
45
+ acpLeaderHost,
46
+ confirmAcpLeaderThroughEvents,
47
+ trackAcpLeader,
48
+ closeAcpLeaderSessions
49
+ };
50
+ //# sourceMappingURL=chunk-LUEO5HLZ.js.map