oc-codex-multi-auth 6.0.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +58 -18
  3. package/assets/readme-hero.svg +10 -10
  4. package/config/README.md +1 -1
  5. package/config/minimal-opencode.json +1 -1
  6. package/config/opencode-legacy.json +1 -1
  7. package/config/opencode-modern.json +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +98 -2520
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/accounts/persistence.d.ts +34 -0
  13. package/dist/lib/accounts/persistence.d.ts.map +1 -0
  14. package/dist/lib/accounts/persistence.js +153 -0
  15. package/dist/lib/accounts/persistence.js.map +1 -0
  16. package/dist/lib/accounts/recovery.d.ts +59 -0
  17. package/dist/lib/accounts/recovery.d.ts.map +1 -0
  18. package/dist/lib/accounts/recovery.js +229 -0
  19. package/dist/lib/accounts/recovery.js.map +1 -0
  20. package/dist/lib/accounts/rotation.d.ts +40 -0
  21. package/dist/lib/accounts/rotation.d.ts.map +1 -0
  22. package/dist/lib/accounts/rotation.js +204 -0
  23. package/dist/lib/accounts/rotation.js.map +1 -0
  24. package/dist/lib/accounts/state.d.ts +92 -0
  25. package/dist/lib/accounts/state.d.ts.map +1 -0
  26. package/dist/lib/accounts/state.js +366 -0
  27. package/dist/lib/accounts/state.js.map +1 -0
  28. package/dist/lib/accounts.d.ts +48 -91
  29. package/dist/lib/accounts.d.ts.map +1 -1
  30. package/dist/lib/accounts.js +121 -699
  31. package/dist/lib/accounts.js.map +1 -1
  32. package/dist/lib/auth/auth.d.ts +1 -1
  33. package/dist/lib/auth/auth.d.ts.map +1 -1
  34. package/dist/lib/auth/auth.js +5 -2
  35. package/dist/lib/auth/auth.js.map +1 -1
  36. package/dist/lib/auth/login-runner.d.ts +32 -0
  37. package/dist/lib/auth/login-runner.d.ts.map +1 -1
  38. package/dist/lib/auth/login-runner.js +79 -64
  39. package/dist/lib/auth/login-runner.js.map +1 -1
  40. package/dist/lib/auth/server.d.ts.map +1 -1
  41. package/dist/lib/auth/server.js +3 -8
  42. package/dist/lib/auth/server.js.map +1 -1
  43. package/dist/lib/circuit-breaker.d.ts +53 -2
  44. package/dist/lib/circuit-breaker.d.ts.map +1 -1
  45. package/dist/lib/circuit-breaker.js +65 -6
  46. package/dist/lib/circuit-breaker.js.map +1 -1
  47. package/dist/lib/config.d.ts.map +1 -1
  48. package/dist/lib/config.js +77 -32
  49. package/dist/lib/config.js.map +1 -1
  50. package/dist/lib/error-sentinels.d.ts +20 -0
  51. package/dist/lib/error-sentinels.d.ts.map +1 -0
  52. package/dist/lib/error-sentinels.js +28 -0
  53. package/dist/lib/error-sentinels.js.map +1 -0
  54. package/dist/lib/errors.d.ts +100 -1
  55. package/dist/lib/errors.d.ts.map +1 -1
  56. package/dist/lib/errors.js +116 -1
  57. package/dist/lib/errors.js.map +1 -1
  58. package/dist/lib/logger.d.ts +14 -1
  59. package/dist/lib/logger.d.ts.map +1 -1
  60. package/dist/lib/logger.js +65 -5
  61. package/dist/lib/logger.js.map +1 -1
  62. package/dist/lib/oauth-constants.d.ts +18 -0
  63. package/dist/lib/oauth-constants.d.ts.map +1 -0
  64. package/dist/lib/oauth-constants.js +18 -0
  65. package/dist/lib/oauth-constants.js.map +1 -0
  66. package/dist/lib/oauth-success.d.ts +2 -0
  67. package/dist/lib/oauth-success.d.ts.map +1 -0
  68. package/dist/lib/oauth-success.html +711 -711
  69. package/dist/lib/oauth-success.js +714 -0
  70. package/dist/lib/oauth-success.js.map +1 -0
  71. package/dist/lib/prompts/codex.d.ts.map +1 -1
  72. package/dist/lib/prompts/codex.js +12 -3
  73. package/dist/lib/prompts/codex.js.map +1 -1
  74. package/dist/lib/prompts/opencode-codex.d.ts.map +1 -1
  75. package/dist/lib/prompts/opencode-codex.js +3 -2
  76. package/dist/lib/prompts/opencode-codex.js.map +1 -1
  77. package/dist/lib/recovery/hook.d.ts +43 -0
  78. package/dist/lib/recovery/hook.d.ts.map +1 -0
  79. package/dist/lib/recovery/hook.js +325 -0
  80. package/dist/lib/recovery/hook.js.map +1 -0
  81. package/dist/lib/recovery/index.d.ts +1 -0
  82. package/dist/lib/recovery/index.d.ts.map +1 -1
  83. package/dist/lib/recovery/index.js +1 -0
  84. package/dist/lib/recovery/index.js.map +1 -1
  85. package/dist/lib/recovery/storage.d.ts.map +1 -1
  86. package/dist/lib/recovery/storage.js +5 -1
  87. package/dist/lib/recovery/storage.js.map +1 -1
  88. package/dist/lib/recovery.d.ts +15 -30
  89. package/dist/lib/recovery.d.ts.map +1 -1
  90. package/dist/lib/recovery.js +14 -312
  91. package/dist/lib/recovery.js.map +1 -1
  92. package/dist/lib/request/fetch-helpers.js +1 -1
  93. package/dist/lib/request/fetch-helpers.js.map +1 -1
  94. package/dist/lib/request/response-handler.d.ts.map +1 -1
  95. package/dist/lib/request/response-handler.js +8 -2
  96. package/dist/lib/request/response-handler.js.map +1 -1
  97. package/dist/lib/runtime.d.ts +101 -0
  98. package/dist/lib/runtime.d.ts.map +1 -0
  99. package/dist/lib/runtime.js +77 -0
  100. package/dist/lib/runtime.js.map +1 -0
  101. package/dist/lib/schemas.d.ts +164 -1
  102. package/dist/lib/schemas.d.ts.map +1 -1
  103. package/dist/lib/schemas.js +251 -0
  104. package/dist/lib/schemas.js.map +1 -1
  105. package/dist/lib/storage/atomic-write.d.ts +31 -0
  106. package/dist/lib/storage/atomic-write.d.ts.map +1 -0
  107. package/dist/lib/storage/atomic-write.js +75 -0
  108. package/dist/lib/storage/atomic-write.js.map +1 -0
  109. package/dist/lib/storage/backup.d.ts +13 -0
  110. package/dist/lib/storage/backup.d.ts.map +1 -0
  111. package/dist/lib/storage/backup.js +59 -0
  112. package/dist/lib/storage/backup.js.map +1 -0
  113. package/dist/lib/storage/errors.d.ts +17 -0
  114. package/dist/lib/storage/errors.d.ts.map +1 -0
  115. package/dist/lib/storage/errors.js +38 -0
  116. package/dist/lib/storage/errors.js.map +1 -0
  117. package/dist/lib/storage/export-import.d.ts +84 -0
  118. package/dist/lib/storage/export-import.d.ts.map +1 -0
  119. package/dist/lib/storage/export-import.js +222 -0
  120. package/dist/lib/storage/export-import.js.map +1 -0
  121. package/dist/lib/storage/flagged.d.ts +29 -0
  122. package/dist/lib/storage/flagged.d.ts.map +1 -0
  123. package/dist/lib/storage/flagged.js +207 -0
  124. package/dist/lib/storage/flagged.js.map +1 -0
  125. package/dist/lib/storage/identity.d.ts +72 -0
  126. package/dist/lib/storage/identity.d.ts.map +1 -0
  127. package/dist/lib/storage/identity.js +230 -0
  128. package/dist/lib/storage/identity.js.map +1 -0
  129. package/dist/lib/storage/keychain.d.ts +146 -0
  130. package/dist/lib/storage/keychain.d.ts.map +1 -0
  131. package/dist/lib/storage/keychain.js +278 -0
  132. package/dist/lib/storage/keychain.js.map +1 -0
  133. package/dist/lib/storage/load-save.d.ts +61 -0
  134. package/dist/lib/storage/load-save.d.ts.map +1 -0
  135. package/dist/lib/storage/load-save.js +606 -0
  136. package/dist/lib/storage/load-save.js.map +1 -0
  137. package/dist/lib/storage/migrations.d.ts +35 -0
  138. package/dist/lib/storage/migrations.d.ts.map +1 -1
  139. package/dist/lib/storage/migrations.js +37 -0
  140. package/dist/lib/storage/migrations.js.map +1 -1
  141. package/dist/lib/storage/normalize.d.ts +22 -0
  142. package/dist/lib/storage/normalize.d.ts.map +1 -0
  143. package/dist/lib/storage/normalize.js +114 -0
  144. package/dist/lib/storage/normalize.js.map +1 -0
  145. package/dist/lib/storage/paths.d.ts.map +1 -1
  146. package/dist/lib/storage/paths.js +2 -1
  147. package/dist/lib/storage/paths.js.map +1 -1
  148. package/dist/lib/storage/state.d.ts +46 -0
  149. package/dist/lib/storage/state.d.ts.map +1 -0
  150. package/dist/lib/storage/state.js +100 -0
  151. package/dist/lib/storage/state.js.map +1 -0
  152. package/dist/lib/storage/worktree-lock.d.ts +79 -0
  153. package/dist/lib/storage/worktree-lock.d.ts.map +1 -0
  154. package/dist/lib/storage/worktree-lock.js +265 -0
  155. package/dist/lib/storage/worktree-lock.js.map +1 -0
  156. package/dist/lib/storage.d.ts +21 -155
  157. package/dist/lib/storage.d.ts.map +1 -1
  158. package/dist/lib/storage.js +24 -1167
  159. package/dist/lib/storage.js.map +1 -1
  160. package/dist/lib/tools/_shared.d.ts +16 -0
  161. package/dist/lib/tools/_shared.d.ts.map +1 -0
  162. package/dist/lib/tools/_shared.js +21 -0
  163. package/dist/lib/tools/_shared.js.map +1 -0
  164. package/dist/lib/tools/codex-dashboard.d.ts +8 -0
  165. package/dist/lib/tools/codex-dashboard.d.ts.map +1 -0
  166. package/dist/lib/tools/codex-dashboard.js +176 -0
  167. package/dist/lib/tools/codex-dashboard.js.map +1 -0
  168. package/dist/lib/tools/codex-diag.d.ts +19 -0
  169. package/dist/lib/tools/codex-diag.d.ts.map +1 -0
  170. package/dist/lib/tools/codex-diag.js +139 -0
  171. package/dist/lib/tools/codex-diag.js.map +1 -0
  172. package/dist/lib/tools/codex-diff.d.ts +44 -0
  173. package/dist/lib/tools/codex-diff.d.ts.map +1 -0
  174. package/dist/lib/tools/codex-diff.js +284 -0
  175. package/dist/lib/tools/codex-diff.js.map +1 -0
  176. package/dist/lib/tools/codex-doctor.d.ts +8 -0
  177. package/dist/lib/tools/codex-doctor.d.ts.map +1 -0
  178. package/dist/lib/tools/codex-doctor.js +284 -0
  179. package/dist/lib/tools/codex-doctor.js.map +1 -0
  180. package/dist/lib/tools/codex-export.d.ts +8 -0
  181. package/dist/lib/tools/codex-export.d.ts.map +1 -0
  182. package/dist/lib/tools/codex-export.js +63 -0
  183. package/dist/lib/tools/codex-export.js.map +1 -0
  184. package/dist/lib/tools/codex-health.d.ts +8 -0
  185. package/dist/lib/tools/codex-health.d.ts.map +1 -0
  186. package/dist/lib/tools/codex-health.js +124 -0
  187. package/dist/lib/tools/codex-health.js.map +1 -0
  188. package/dist/lib/tools/codex-help.d.ts +8 -0
  189. package/dist/lib/tools/codex-help.d.ts.map +1 -0
  190. package/dist/lib/tools/codex-help.js +127 -0
  191. package/dist/lib/tools/codex-help.js.map +1 -0
  192. package/dist/lib/tools/codex-import.d.ts +8 -0
  193. package/dist/lib/tools/codex-import.d.ts.map +1 -0
  194. package/dist/lib/tools/codex-import.js +97 -0
  195. package/dist/lib/tools/codex-import.js.map +1 -0
  196. package/dist/lib/tools/codex-keychain.d.ts +36 -0
  197. package/dist/lib/tools/codex-keychain.d.ts.map +1 -0
  198. package/dist/lib/tools/codex-keychain.js +289 -0
  199. package/dist/lib/tools/codex-keychain.js.map +1 -0
  200. package/dist/lib/tools/codex-label.d.ts +8 -0
  201. package/dist/lib/tools/codex-label.d.ts.map +1 -0
  202. package/dist/lib/tools/codex-label.js +143 -0
  203. package/dist/lib/tools/codex-label.js.map +1 -0
  204. package/dist/lib/tools/codex-limits.d.ts +8 -0
  205. package/dist/lib/tools/codex-limits.d.ts.map +1 -0
  206. package/dist/lib/tools/codex-limits.js +497 -0
  207. package/dist/lib/tools/codex-limits.js.map +1 -0
  208. package/dist/lib/tools/codex-list.d.ts +8 -0
  209. package/dist/lib/tools/codex-list.d.ts.map +1 -0
  210. package/dist/lib/tools/codex-list.js +260 -0
  211. package/dist/lib/tools/codex-list.js.map +1 -0
  212. package/dist/lib/tools/codex-metrics.d.ts +8 -0
  213. package/dist/lib/tools/codex-metrics.d.ts.map +1 -0
  214. package/dist/lib/tools/codex-metrics.js +180 -0
  215. package/dist/lib/tools/codex-metrics.js.map +1 -0
  216. package/dist/lib/tools/codex-next.d.ts +8 -0
  217. package/dist/lib/tools/codex-next.d.ts.map +1 -0
  218. package/dist/lib/tools/codex-next.js +54 -0
  219. package/dist/lib/tools/codex-next.js.map +1 -0
  220. package/dist/lib/tools/codex-note.d.ts +8 -0
  221. package/dist/lib/tools/codex-note.d.ts.map +1 -0
  222. package/dist/lib/tools/codex-note.js +79 -0
  223. package/dist/lib/tools/codex-note.js.map +1 -0
  224. package/dist/lib/tools/codex-refresh.d.ts +8 -0
  225. package/dist/lib/tools/codex-refresh.d.ts.map +1 -0
  226. package/dist/lib/tools/codex-refresh.js +78 -0
  227. package/dist/lib/tools/codex-refresh.js.map +1 -0
  228. package/dist/lib/tools/codex-remove.d.ts +8 -0
  229. package/dist/lib/tools/codex-remove.d.ts.map +1 -0
  230. package/dist/lib/tools/codex-remove.js +184 -0
  231. package/dist/lib/tools/codex-remove.js.map +1 -0
  232. package/dist/lib/tools/codex-setup.d.ts +8 -0
  233. package/dist/lib/tools/codex-setup.d.ts.map +1 -0
  234. package/dist/lib/tools/codex-setup.js +26 -0
  235. package/dist/lib/tools/codex-setup.js.map +1 -0
  236. package/dist/lib/tools/codex-status.d.ts +8 -0
  237. package/dist/lib/tools/codex-status.d.ts.map +1 -0
  238. package/dist/lib/tools/codex-status.js +263 -0
  239. package/dist/lib/tools/codex-status.js.map +1 -0
  240. package/dist/lib/tools/codex-switch.d.ts +8 -0
  241. package/dist/lib/tools/codex-switch.d.ts.map +1 -0
  242. package/dist/lib/tools/codex-switch.js +122 -0
  243. package/dist/lib/tools/codex-switch.js.map +1 -0
  244. package/dist/lib/tools/codex-tag.d.ts +8 -0
  245. package/dist/lib/tools/codex-tag.d.ts.map +1 -0
  246. package/dist/lib/tools/codex-tag.js +101 -0
  247. package/dist/lib/tools/codex-tag.js.map +1 -0
  248. package/dist/lib/tools/index.d.ts +143 -0
  249. package/dist/lib/tools/index.d.ts.map +1 -0
  250. package/dist/lib/tools/index.js +67 -0
  251. package/dist/lib/tools/index.js.map +1 -0
  252. package/dist/lib/ui/format.d.ts.map +1 -1
  253. package/dist/lib/ui/format.js +5 -0
  254. package/dist/lib/ui/format.js.map +1 -1
  255. package/dist/lib/ui/runtime.d.ts +10 -0
  256. package/dist/lib/ui/runtime.d.ts.map +1 -1
  257. package/dist/lib/ui/runtime.js +16 -11
  258. package/dist/lib/ui/runtime.js.map +1 -1
  259. package/dist/lib/ui/select.d.ts.map +1 -1
  260. package/dist/lib/ui/select.js +12 -3
  261. package/dist/lib/ui/select.js.map +1 -1
  262. package/dist/lib/ui/theme.d.ts +19 -0
  263. package/dist/lib/ui/theme.d.ts.map +1 -1
  264. package/dist/lib/ui/theme.js +27 -0
  265. package/dist/lib/ui/theme.js.map +1 -1
  266. package/package.json +24 -16
  267. package/scripts/copy-oauth-success.js +16 -6
  268. package/scripts/install-oc-codex-multi-auth-core.js +462 -381
  269. package/scripts/install-oc-codex-multi-auth.js +15 -15
  270. package/scripts/test-all-models.sh +1 -1
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Multi-worktree collision detection for per-project account storage.
3
+ *
4
+ * Problem: when multiple OpenCode sessions (tabs, IDE windows, detached
5
+ * worktrees, or CI runs) point at the same per-project accounts file, their
6
+ * writes can interleave and lose rotation updates, health-score changes, or
7
+ * rate-limit state. The in-process `withStorageLock` mutex solves intra-process
8
+ * races but cannot see another Node process mutating the same file.
9
+ *
10
+ * Strategy: sidecar lock file at `<storage>.lock`. Every `loadAccounts` /
11
+ * `saveAccounts` call verifies ownership:
12
+ *
13
+ * - No lock on disk -> write our own, proceed.
14
+ * - Lock owned by us (same pid + hostname) -> refresh `lastActive`, proceed.
15
+ * - Foreign lock with dead owner (same host, pid gone) -> take over.
16
+ * - Foreign lock stale (`lastActive` older than STALE_THRESHOLD_MS) -> take
17
+ * over. Required because a prior process that SIGKILL'd never released
18
+ * its lock, so "dead pid" detection alone leaks locks on long-lived hosts.
19
+ * - Foreign lock live -> surface a WARNING to the logger identifying both
20
+ * worktrees and proceed anyway. The locking contract here is advisory
21
+ * (Phase 4 F2 audit recommendation): blocking would strand the user when
22
+ * two legitimate sessions share a project, so we prefer visibility over
23
+ * enforcement.
24
+ *
25
+ * Cross-host note: we cannot probe a PID on a different machine, so a lock
26
+ * written from another hostname is always treated as live until its
27
+ * `lastActive` timestamp ages past STALE_THRESHOLD_MS. This is conservative
28
+ * but matches the audit requirement to "not block" — the worst case is a
29
+ * warning the user can dismiss.
30
+ *
31
+ * See `docs/audits/08-feature-recommendations.md` and
32
+ * `docs/audits/13-phased-roadmap.md#phase-4-f2` for background.
33
+ */
34
+ import { promises as fs } from "node:fs";
35
+ import os from "node:os";
36
+ import { createLogger } from "../logger.js";
37
+ import { registerCleanup } from "../shutdown.js";
38
+ const log = createLogger("storage.worktree-lock");
39
+ /**
40
+ * Time after which a lock whose owner never refreshed it is considered
41
+ * abandoned, regardless of PID liveness. One hour matches the roadmap spec
42
+ * and is long enough to avoid stealing a lock from a session that is merely
43
+ * idle between saves.
44
+ */
45
+ export const STALE_THRESHOLD_MS = 60 * 60 * 1000;
46
+ /**
47
+ * Tracks lock-file paths this process has written so a single shutdown
48
+ * cleanup can release all of them. Keyed by lock path, not storage path,
49
+ * to avoid double-registering cleanup if the same path is acquired twice.
50
+ */
51
+ const ownedLockPaths = new Set();
52
+ let shutdownCleanupRegistered = false;
53
+ function lockPath(storagePath) {
54
+ return `${storagePath}.lock`;
55
+ }
56
+ /**
57
+ * Probes whether a PID is still running. Returns `true` conservatively for
58
+ * cross-host locks: we cannot signal a remote PID, so the safe default is
59
+ * "assume alive" and let the stale-timestamp branch reclaim it instead.
60
+ *
61
+ * Intentionally synchronous: `process.kill` is non-blocking and making this
62
+ * async buys nothing while incurring a useless microtask per lock check.
63
+ */
64
+ function processAlive(pid, hostname) {
65
+ if (hostname !== os.hostname()) {
66
+ return true;
67
+ }
68
+ // Guard against invalid PIDs that would make `process.kill` throw
69
+ // EINVAL (treated as "alive" by the catch below) and leak the lock.
70
+ if (!Number.isInteger(pid) || pid <= 0) {
71
+ return false;
72
+ }
73
+ try {
74
+ // Signal 0 performs the permission + existence check without
75
+ // actually delivering a signal. ESRCH means "no such process".
76
+ process.kill(pid, 0);
77
+ return true;
78
+ }
79
+ catch (err) {
80
+ const code = err.code;
81
+ // EPERM means the process exists but we cannot signal it (different
82
+ // user). Treat as alive to avoid stealing a lock we can't verify.
83
+ if (code === "EPERM")
84
+ return true;
85
+ return false;
86
+ }
87
+ }
88
+ function buildOwnLockInfo(existingStartedAt) {
89
+ const now = new Date().toISOString();
90
+ return {
91
+ pid: process.pid,
92
+ hostname: os.hostname(),
93
+ cwd: process.cwd(),
94
+ startedAt: existingStartedAt ?? now,
95
+ lastActive: now,
96
+ };
97
+ }
98
+ async function writeOurLock(lockFile, existingStartedAt) {
99
+ const info = buildOwnLockInfo(existingStartedAt);
100
+ // mode 0o600: lock discloses pid/cwd, so restrict to owner like the
101
+ // storage file itself.
102
+ await fs.writeFile(lockFile, JSON.stringify(info, null, 2), {
103
+ encoding: "utf-8",
104
+ mode: 0o600,
105
+ });
106
+ ownedLockPaths.add(lockFile);
107
+ ensureShutdownReleaseRegistered();
108
+ }
109
+ /**
110
+ * Best-effort shutdown hook that removes every lock we still own. Failures
111
+ * are swallowed so one bad unlink cannot stall process exit.
112
+ */
113
+ function ensureShutdownReleaseRegistered() {
114
+ if (shutdownCleanupRegistered)
115
+ return;
116
+ shutdownCleanupRegistered = true;
117
+ registerCleanup(async () => {
118
+ const paths = Array.from(ownedLockPaths);
119
+ ownedLockPaths.clear();
120
+ await Promise.all(paths.map(async (lp) => {
121
+ try {
122
+ await releaseLockFile(lp);
123
+ }
124
+ catch {
125
+ // Swallow: shutdown path must not throw.
126
+ }
127
+ }));
128
+ });
129
+ }
130
+ function isOwnLock(info) {
131
+ return info.pid === process.pid && info.hostname === os.hostname();
132
+ }
133
+ /**
134
+ * Parse a lock file. Returns `null` if the file is missing, unreadable, or
135
+ * structurally invalid. Callers treat `null` the same as "no lock" so a
136
+ * corrupt sidecar never wedges storage access.
137
+ */
138
+ async function readLock(lockFile) {
139
+ let raw;
140
+ try {
141
+ raw = await fs.readFile(lockFile, "utf-8");
142
+ }
143
+ catch (err) {
144
+ if (err.code === "ENOENT") {
145
+ return null;
146
+ }
147
+ throw err;
148
+ }
149
+ try {
150
+ const parsed = JSON.parse(raw);
151
+ if (!parsed || typeof parsed !== "object")
152
+ return null;
153
+ const obj = parsed;
154
+ if (typeof obj.pid !== "number" ||
155
+ typeof obj.hostname !== "string" ||
156
+ typeof obj.cwd !== "string" ||
157
+ typeof obj.startedAt !== "string" ||
158
+ typeof obj.lastActive !== "string") {
159
+ return null;
160
+ }
161
+ return obj;
162
+ }
163
+ catch {
164
+ // Corrupt JSON: treat as absent rather than crashing the storage
165
+ // pipeline. `writeOurLock` will overwrite it on the next acquire.
166
+ return null;
167
+ }
168
+ }
169
+ /**
170
+ * Checks ownership of the worktree lock and acquires it when possible.
171
+ *
172
+ * Contract:
173
+ * - Never throws on lock I/O errors *other than* propagating read/write
174
+ * failures the caller needs to know about (disk full, EACCES).
175
+ * - Always returns a discriminated result: either `acquired: true` (we
176
+ * now own or refreshed the lock) or `acquired: false` with `foreign`
177
+ * populated (another live worktree owns it; caller should warn).
178
+ * - Never blocks. This is advisory locking by design.
179
+ */
180
+ export async function acquireOrDetectLock(storagePath) {
181
+ const lockFile = lockPath(storagePath);
182
+ const existing = await readLock(lockFile);
183
+ if (!existing) {
184
+ await writeOurLock(lockFile);
185
+ return { acquired: true };
186
+ }
187
+ // Own lock: refresh timestamp so stale-detection on a long-running
188
+ // process never accidentally reclaims its own lock from itself.
189
+ if (isOwnLock(existing)) {
190
+ await writeOurLock(lockFile, existing.startedAt);
191
+ return { acquired: true };
192
+ }
193
+ // Stale timestamp takes priority over liveness probe: on the same host
194
+ // a fresh-looking PID that was reused by the OS would otherwise mask a
195
+ // dead session that never released its lock. Timestamp age is the
196
+ // authoritative abandonment signal.
197
+ const lastActiveMs = Date.parse(existing.lastActive);
198
+ if (Number.isFinite(lastActiveMs) &&
199
+ Date.now() - lastActiveMs > STALE_THRESHOLD_MS) {
200
+ log.info("Replacing stale worktree lock", {
201
+ staleCwd: existing.cwd,
202
+ stalePid: existing.pid,
203
+ staleHost: existing.hostname,
204
+ ageMs: Date.now() - lastActiveMs,
205
+ });
206
+ await writeOurLock(lockFile);
207
+ return { acquired: true };
208
+ }
209
+ // Non-stale foreign lock. If the owner pid is gone (same host), the
210
+ // previous process crashed without cleanup and we can take over.
211
+ const alive = processAlive(existing.pid, existing.hostname);
212
+ if (!alive) {
213
+ log.info("Replacing lock from dead worktree", {
214
+ deadCwd: existing.cwd,
215
+ deadPid: existing.pid,
216
+ deadHost: existing.hostname,
217
+ });
218
+ await writeOurLock(lockFile);
219
+ return { acquired: true };
220
+ }
221
+ // Foreign live lock. Advisory protocol: surface but do not block.
222
+ return { acquired: false, foreign: existing };
223
+ }
224
+ /**
225
+ * Release a lock file, but only if we currently own it. This guards against
226
+ * a late shutdown hook racing a newer process that re-acquired the lock.
227
+ */
228
+ async function releaseLockFile(lockFile) {
229
+ ownedLockPaths.delete(lockFile);
230
+ const existing = await readLock(lockFile);
231
+ if (!existing)
232
+ return;
233
+ if (!isOwnLock(existing))
234
+ return;
235
+ try {
236
+ await fs.unlink(lockFile);
237
+ }
238
+ catch (err) {
239
+ if (err.code !== "ENOENT") {
240
+ // Degrade to warn; a leftover lock file is recoverable via the
241
+ // stale-timestamp branch on the next acquire.
242
+ log.warn("Failed to release worktree lock", {
243
+ lockFile,
244
+ error: String(err),
245
+ });
246
+ }
247
+ }
248
+ }
249
+ export async function releaseLock(storagePath) {
250
+ await releaseLockFile(lockPath(storagePath));
251
+ }
252
+ /**
253
+ * Test-only reset hook. Vitest reuses a single Node process across files,
254
+ * so `ownedLockPaths` state would leak between suites and confuse the
255
+ * "no lock on disk" acquire branch. Not re-exported from the barrel.
256
+ */
257
+ export function __resetWorktreeLockForTests() {
258
+ ownedLockPaths.clear();
259
+ shutdownCleanupRegistered = false;
260
+ }
261
+ /** Test-only: inspect owned paths without exposing the internal Set. */
262
+ export function __getOwnedLockPathsForTests() {
263
+ return Array.from(ownedLockPaths);
264
+ }
265
+ //# sourceMappingURL=worktree-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-lock.js","sourceRoot":"","sources":["../../../lib/storage/worktree-lock.ts"],"names":[],"mappings":"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"}
@@ -1,157 +1,23 @@
1
- import { type CooldownReason, type RateLimitStateV3, type AccountMetadataV1, type AccountStorageV1, type AccountMetadataV3, type AccountStorageV3 } from "./storage/migrations.js";
2
- export type { CooldownReason, RateLimitStateV3, AccountMetadataV1, AccountStorageV1, AccountMetadataV3, AccountStorageV3 };
3
- export interface FlaggedAccountMetadataV1 extends AccountMetadataV3 {
4
- flaggedAt: number;
5
- flaggedReason?: string;
6
- lastError?: string;
7
- }
8
- export interface FlaggedAccountStorageV1 {
9
- version: 1;
10
- accounts: FlaggedAccountMetadataV1[];
11
- }
12
- export declare function getWorkspaceIdentityKey(account: {
13
- organizationId?: string;
14
- accountId?: string;
15
- refreshToken: string;
16
- }): string;
17
- export type ImportBackupMode = "none" | "best-effort" | "required";
18
- export interface ImportAccountsOptions {
19
- /**
20
- * Optional prefix used for pre-import backup file names.
21
- * Only applied when backupMode is not "none".
22
- */
23
- preImportBackupPrefix?: string;
24
- /**
25
- * Backup policy before import apply:
26
- * - none: do not create a pre-import backup
27
- * - best-effort: attempt backup, continue on failure
28
- * - required: backup must succeed or import aborts
29
- */
30
- backupMode?: ImportBackupMode;
31
- }
32
- export type ImportBackupStatus = "created" | "skipped" | "failed";
33
- export interface ImportAccountsResult {
34
- imported: number;
35
- total: number;
36
- skipped: number;
37
- backupStatus: ImportBackupStatus;
38
- backupPath?: string;
39
- backupError?: string;
40
- }
41
- export interface ImportPreviewResult {
42
- imported: number;
43
- total: number;
44
- skipped: number;
45
- }
46
1
  /**
47
- * Custom error class for storage operations with platform-aware hints.
48
- */
49
- export declare class StorageError extends Error {
50
- readonly code: string;
51
- readonly path: string;
52
- readonly hint: string;
53
- constructor(message: string, code: string, path: string, hint: string, cause?: Error);
54
- }
55
- /**
56
- * Generate platform-aware troubleshooting hint based on error code.
57
- */
58
- export declare function formatStorageErrorHint(error: unknown, path: string): string;
59
- export declare function setStoragePath(projectPath: string | null): void;
60
- export declare function setStoragePathDirect(path: string | null): void;
61
- /**
62
- * Returns the file path for the account storage JSON file.
63
- * @returns Absolute path to the accounts.json file
64
- */
65
- export declare function getStoragePath(): string;
66
- export declare function getFlaggedAccountsPath(): string;
67
- /**
68
- * Removes duplicate accounts, keeping the most recently used entry for each unique key.
69
- * Deduplication identity hierarchy: organizationId -> accountId -> refreshToken.
70
- * @param accounts - Array of accounts to deduplicate
71
- * @returns New array with duplicates removed
72
- */
73
- export declare function deduplicateAccounts<T extends {
74
- organizationId?: string;
75
- accountId?: string;
76
- refreshToken: string;
77
- lastUsed?: number;
78
- addedAt?: number;
79
- }>(accounts: T[]): T[];
80
- /**
81
- * Removes duplicate legacy accounts by email, keeping the most recently used entry.
82
- * Accounts with organizationId/accountId are never merged by email to avoid collapsing workspace variants.
83
- * Accounts without email are always preserved.
84
- * @param accounts - Array of accounts to deduplicate
85
- * @returns New array with email duplicates removed
86
- */
87
- export declare function deduplicateAccountsByEmail<T extends {
88
- organizationId?: string;
89
- accountId?: string;
90
- email?: string;
91
- lastUsed?: number;
92
- addedAt?: number;
93
- }>(accounts: T[]): T[];
94
- /**
95
- * Normalizes and validates account storage data, migrating from v1 to v3 if needed.
96
- * Handles deduplication, index clamping, and per-family active index mapping.
97
- * @param data - Raw storage data (unknown format)
98
- * @returns Normalized AccountStorageV3 or null if invalid
99
- */
100
- export declare function normalizeAccountStorage(data: unknown): AccountStorageV3 | null;
101
- /**
102
- * Loads OAuth accounts from disk storage.
103
- * Automatically migrates v1 storage to v3 format if needed.
104
- * @returns AccountStorageV3 if file exists and is valid, null otherwise
105
- */
106
- export declare function loadAccounts(): Promise<AccountStorageV3 | null>;
107
- /**
108
- * Executes a read-modify-write transaction under the storage lock and exposes
109
- * an unlocked persist callback so nested save operations do not deadlock.
110
- */
111
- export declare function withAccountStorageTransaction<T>(handler: (current: AccountStorageV3 | null, persist: (storage: AccountStorageV3) => Promise<void>) => Promise<T>): Promise<T>;
112
- /**
113
- * Persists account storage to disk using atomic write (temp file + rename).
114
- * Creates the .opencode directory if it doesn't exist.
115
- * Verifies file was written correctly and provides detailed error messages.
116
- * @param storage - Account storage data to save
117
- * @throws StorageError with platform-aware hints on failure
118
- */
119
- export declare function saveAccounts(storage: AccountStorageV3): Promise<void>;
120
- /**
121
- * Deletes the account storage file from disk.
122
- * Silently ignores if file doesn't exist.
123
- */
124
- export declare function clearAccounts(): Promise<void>;
125
- export declare function loadFlaggedAccounts(): Promise<FlaggedAccountStorageV1>;
126
- /**
127
- * Executes a read-modify-write transaction for flagged account storage under the
128
- * shared storage lock so concurrent callers cannot lose updates.
129
- */
130
- export declare function withFlaggedAccountStorageTransaction<T>(handler: (current: FlaggedAccountStorageV1, persist: (storage: FlaggedAccountStorageV1) => Promise<void>) => Promise<T>): Promise<T>;
131
- export declare function saveFlaggedAccounts(storage: FlaggedAccountStorageV1): Promise<void>;
132
- export declare function clearFlaggedAccounts(): Promise<void>;
133
- export declare function createTimestampedBackupPath(prefix?: string): string;
134
- /**
135
- * Import preview/apply analysis is pure in-memory work: it does not touch disk
136
- * and it does not log token or workspace values. The surrounding
137
- * `withAccountStorageTransaction` caller keeps Windows lock-retry and
138
- * serialized read-modify-write behavior; see `test/storage.test.ts` for the
139
- * overlapping transaction regression and pre-import backup lock coverage.
140
- */
141
- export declare function previewImportAccounts(filePath: string): Promise<ImportPreviewResult>;
142
- /**
143
- * Exports current accounts to a JSON file for backup/migration.
144
- * @param filePath - Destination file path
145
- * @param force - If true, overwrite existing file (default: true)
146
- * @throws Error if file exists and force is false, or if no accounts to export
147
- */
148
- export declare function exportAccounts(filePath: string, force?: boolean): Promise<void>;
149
- /**
150
- * Imports accounts from a JSON file, merging with existing accounts.
151
- * Deduplicates by identity key first (organizationId -> accountId -> refreshToken),
152
- * then applies legacy email dedupe only to entries without organizationId/accountId.
153
- * @param filePath - Source file path
154
- * @throws Error if file is invalid or would exceed MAX_ACCOUNTS
155
- */
156
- export declare function importAccounts(filePath: string, options?: ImportAccountsOptions): Promise<ImportAccountsResult>;
2
+ * Barrel for the account-storage layer.
3
+ *
4
+ * RC-2 split the original 1400-line `lib/storage.ts` into focused modules
5
+ * under `lib/storage/`. This file exists to keep the public surface stable
6
+ * so every consumer that imports from `./storage` / `../storage` resolves
7
+ * exactly as it did before the refactor.
8
+ *
9
+ * See `docs/audits/07-refactoring-plan.md#rc-2` and
10
+ * `docs/audits/16-code-health.md` for the motivation.
11
+ */
12
+ export type { CooldownReason, RateLimitStateV3, AccountMetadataV1, AccountStorageV1, AccountMetadataV3, AccountStorageV3, } from "./storage/migrations.js";
13
+ export { StorageError, formatStorageErrorHint } from "./storage/errors.js";
14
+ export { setStoragePath, setStoragePathDirect, getStoragePath, } from "./storage/state.js";
15
+ export { getWorkspaceIdentityKey, deduplicateAccounts, deduplicateAccountsByEmail, } from "./storage/identity.js";
16
+ export { normalizeAccountStorage } from "./storage/normalize.js";
17
+ export { loadAccounts, saveAccounts, clearAccounts, withAccountStorageTransaction, } from "./storage/load-save.js";
18
+ export type { FlaggedAccountMetadataV1, FlaggedAccountStorageV1, } from "./storage/flagged.js";
19
+ export { getFlaggedAccountsPath, loadFlaggedAccounts, saveFlaggedAccounts, clearFlaggedAccounts, withFlaggedAccountStorageTransaction, } from "./storage/flagged.js";
20
+ export { createTimestampedBackupPath } from "./storage/backup.js";
21
+ export type { ImportBackupMode, ImportBackupStatus, ImportAccountsOptions, ImportAccountsResult, ImportPreviewResult, } from "./storage/export-import.js";
22
+ export { exportAccounts, importAccounts, previewImportAccounts, } from "./storage/export-import.js";
157
23
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../lib/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAG3E,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,cAAc,GACf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAGjE,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,6BAA6B,GAC9B,MAAM,wBAAwB,CAAC;AAGhC,YAAY,EACV,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,oCAAoC,GACrC,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAGlE,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,cAAc,EACd,cAAc,EACd,qBAAqB,GACtB,MAAM,4BAA4B,CAAC"}