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
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../../lib/storage/migrations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG,cAAc,GAAG,eAAe,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,CAAC;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,UAAU,CAAC;IACzD,mBAAmB,CAAC,EAAE,gBAAgB,CAAC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3D;AAMD,wBAAgB,aAAa,CAAC,EAAE,EAAE,gBAAgB,GAAG,gBAAgB,CAoCpE"}
1
+ {"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../../../lib/storage/migrations.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,43 @@
3
3
  * Extracted from storage.ts to reduce module size.
4
4
  */
5
5
  import { MODEL_FAMILIES } from "../prompts/codex.js";
6
+ /**
7
+ * StorageError code emitted when a `version: 2` account file is loaded.
8
+ *
9
+ * V2 is an intermediate account schema produced by legacy 4.x plugin builds
10
+ * that never shipped with a documented shape nor a forward-migrator to V3.
11
+ * The safe behaviour is to refuse to load V2 explicitly so the user's
12
+ * credentials are not silently discarded; callers surface this code to the
13
+ * user alongside a recovery hint.
14
+ */
15
+ export const UNKNOWN_V2_FORMAT_CODE = "UNKNOWN_V2_FORMAT";
16
+ /**
17
+ * Diagnostic message shown when the loader refuses a V2 storage file.
18
+ * Pulled into a helper so storage.ts, import paths, and tests produce
19
+ * identical copy without drifting.
20
+ */
21
+ export function buildV2RejectionMessage() {
22
+ return ("Unsupported account storage schema version 2; this plugin only ships " +
23
+ "migrations for v1 and v3. V2 files were produced by an intermediate " +
24
+ "4.x build that never documented its shape, so migrating blindly would " +
25
+ "risk silent account corruption.");
26
+ }
27
+ /**
28
+ * Recovery hint shown alongside the V2 rejection message.
29
+ * @param path - Absolute path of the offending storage file, or a placeholder
30
+ * when the caller cannot determine the source (e.g. in-memory normalization).
31
+ */
32
+ export function buildV2RecoveryHint(path) {
33
+ const resolvedPath = path || "<unknown>";
34
+ return (`The storage file at ${resolvedPath} uses account schema v2, which ` +
35
+ "this plugin cannot migrate automatically. To recover: " +
36
+ "(1) back up the file outside the .opencode directory, " +
37
+ "(2) remove or rename the original so the plugin can start fresh, " +
38
+ "(3) run `opencode auth login` to create a v3 account pool, then " +
39
+ "(4) if you need the old credentials, open each account manually or " +
40
+ "re-run login per account. If you believe this file was produced by " +
41
+ "the current plugin, please open an issue so V2 can be documented.");
42
+ }
6
43
  function nowMs() {
7
44
  return Date.now();
8
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../../lib/storage/migrations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAC;AAkEvE,SAAS,KAAK;IACb,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAoB;IACjD,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IACpB,OAAO;QACN,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACrC,MAAM,mBAAmB,GAAqB,EAAE,CAAC;YACjD,IAAI,OAAO,OAAO,CAAC,kBAAkB,KAAK,QAAQ,IAAI,OAAO,CAAC,kBAAkB,GAAG,GAAG,EAAE,CAAC;gBACxF,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;oBACrC,mBAAmB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;gBAC1D,CAAC;YACF,CAAC;YACD,OAAO;gBACN,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS;gBAClG,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,cAAc,EAAE,OAAO,CAAC,cAAc;aACtC,CAAC;QACH,CAAC,CAAC;QACF,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,mBAAmB,EAAE,MAAM,CAAC,WAAW,CACtC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAChB;KACzC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../../lib/storage/migrations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAoB,MAAM,qBAAqB,CAAC;AAKvE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAgB1D;;;;GAIG;AACH,MAAM,UAAU,uBAAuB;IACtC,OAAO,CACN,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,iCAAiC,CACjC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC/C,MAAM,YAAY,GAAG,IAAI,IAAI,WAAW,CAAC;IACzC,OAAO,CACN,uBAAuB,YAAY,iCAAiC;QACpE,wDAAwD;QACxD,wDAAwD;QACxD,mEAAmE;QACnE,kEAAkE;QAClE,qEAAqE;QACrE,qEAAqE;QACrE,mEAAmE,CACnE,CAAC;AACH,CAAC;AA+DD,SAAS,KAAK;IACb,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAoB;IACjD,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IACpB,OAAO;QACN,OAAO,EAAE,CAAC;QACV,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACrC,MAAM,mBAAmB,GAAqB,EAAE,CAAC;YACjD,IAAI,OAAO,OAAO,CAAC,kBAAkB,KAAK,QAAQ,IAAI,OAAO,CAAC,kBAAkB,GAAG,GAAG,EAAE,CAAC;gBACxF,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;oBACrC,mBAAmB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC;gBAC1D,CAAC;YACF,CAAC;YACD,OAAO;gBACN,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,SAAS;gBAClG,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,cAAc,EAAE,OAAO,CAAC,cAAc;aACtC,CAAC;QACH,CAAC,CAAC;QACF,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,mBAAmB,EAAE,MAAM,CAAC,WAAW,CACtC,cAAc,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAChB;KACzC,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Schema normalization, forward-compat guard, and V2 detection for account
3
+ * storage files.
4
+ *
5
+ * Split out of `lib/storage.ts` in RC-2. This module does not touch disk: it
6
+ * takes already-parsed JSON and returns a canonical `AccountStorageV3` (or
7
+ * throws a typed `StorageError` for schemas we can't safely read).
8
+ */
9
+ import { type AccountStorageV3 } from "./migrations.js";
10
+ /**
11
+ * Normalizes and validates account storage data, migrating from v1 to v3 if needed.
12
+ * Handles deduplication, index clamping, and per-family active index mapping.
13
+ * @param data - Raw storage data (unknown format)
14
+ * @param sourcePath - Optional origin path used for error diagnostics
15
+ * @returns Normalized AccountStorageV3 or null if invalid
16
+ * @throws StorageError (code `UNSUPPORTED_SCHEMA_VERSION`) when `data.version`
17
+ * is a finite number greater than the newest format this plugin understands.
18
+ * Throwing prevents a downgraded plugin from silently discarding future
19
+ * schemas that still contain valid credentials.
20
+ */
21
+ export declare function normalizeAccountStorage(data: unknown, sourcePath?: string): AccountStorageV3 | null;
22
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../lib/storage/normalize.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,OAAO,EAOL,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAMzB;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,UAAU,CAAC,EAAE,MAAM,GAClB,gBAAgB,GAAG,IAAI,CAwHzB"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Schema normalization, forward-compat guard, and V2 detection for account
3
+ * storage files.
4
+ *
5
+ * Split out of `lib/storage.ts` in RC-2. This module does not touch disk: it
6
+ * takes already-parsed JSON and returns a canonical `AccountStorageV3` (or
7
+ * throws a typed `StorageError` for schemas we can't safely read).
8
+ */
9
+ import { createLogger } from "../logger.js";
10
+ import { MODEL_FAMILIES } from "../prompts/codex.js";
11
+ import { AccountStorageV2DetectionSchema } from "../schemas.js";
12
+ import { StorageError } from "./errors.js";
13
+ import { clampIndex, deduplicateAccountsForStorage, extractActiveKeys, findAccountIndexByIdentityKeys, isRecord, } from "./identity.js";
14
+ import { buildV2RecoveryHint, buildV2RejectionMessage, migrateV1ToV3, UNKNOWN_V2_FORMAT_CODE, } from "./migrations.js";
15
+ const log = createLogger("storage");
16
+ /**
17
+ * Normalizes and validates account storage data, migrating from v1 to v3 if needed.
18
+ * Handles deduplication, index clamping, and per-family active index mapping.
19
+ * @param data - Raw storage data (unknown format)
20
+ * @param sourcePath - Optional origin path used for error diagnostics
21
+ * @returns Normalized AccountStorageV3 or null if invalid
22
+ * @throws StorageError (code `UNSUPPORTED_SCHEMA_VERSION`) when `data.version`
23
+ * is a finite number greater than the newest format this plugin understands.
24
+ * Throwing prevents a downgraded plugin from silently discarding future
25
+ * schemas that still contain valid credentials.
26
+ */
27
+ export function normalizeAccountStorage(data, sourcePath) {
28
+ if (!isRecord(data)) {
29
+ log.warn("Invalid storage format, ignoring");
30
+ return null;
31
+ }
32
+ const rawVersion = data.version;
33
+ // Forward-compat guard: a finite version above the newest supported schema
34
+ // signals a file written by a newer plugin build. Returning null here would
35
+ // make the caller treat the data as corrupt and overwrite it with an empty
36
+ // or downgraded payload, permanently destroying the user's accounts.
37
+ if (typeof rawVersion === "number" && Number.isFinite(rawVersion) && rawVersion > 3) {
38
+ const resolvedPath = sourcePath ?? "<unknown>";
39
+ const hint = `The storage file at ${resolvedPath} was written by a newer version ` +
40
+ `of this plugin (schema v${rawVersion}). Upgrade the plugin to a build ` +
41
+ `that understands schema v${rawVersion}, or back up and remove the ` +
42
+ `file to start fresh.`;
43
+ throw new StorageError(`Unsupported account storage schema version ${rawVersion}; this plugin supports up to version 3.`, "UNSUPPORTED_SCHEMA_VERSION", resolvedPath, hint);
44
+ }
45
+ // V2 files were produced by an intermediate 4.x build whose shape was never
46
+ // documented and for which no forward-migrator shipped. Silently treating
47
+ // them as "unknown version" (the previous behaviour) meant users with a V2
48
+ // file had their credentials discarded without any signal. Detect V2
49
+ // explicitly and throw a typed StorageError so the caller can surface the
50
+ // recovery hint to the user. Audit top-20 #8; see
51
+ // `lib/storage/migrations.ts:buildV2RejectionMessage` for copy.
52
+ if (AccountStorageV2DetectionSchema.safeParse(data).success) {
53
+ throw new StorageError(buildV2RejectionMessage(), UNKNOWN_V2_FORMAT_CODE, "", buildV2RecoveryHint(""));
54
+ }
55
+ if (data.version !== 1 && data.version !== 3) {
56
+ log.warn("Unknown storage version, ignoring", {
57
+ version: rawVersion,
58
+ });
59
+ return null;
60
+ }
61
+ const rawAccounts = data.accounts;
62
+ if (!Array.isArray(rawAccounts)) {
63
+ log.warn("Invalid storage format, ignoring");
64
+ return null;
65
+ }
66
+ const activeIndexValue = typeof data.activeIndex === "number" && Number.isFinite(data.activeIndex)
67
+ ? data.activeIndex
68
+ : 0;
69
+ const rawActiveIndex = clampIndex(activeIndexValue, rawAccounts.length);
70
+ const activeKeys = extractActiveKeys(rawAccounts, rawActiveIndex);
71
+ const fromVersion = data.version;
72
+ const baseStorage = fromVersion === 1
73
+ ? migrateV1ToV3(data)
74
+ : data;
75
+ const validAccounts = rawAccounts.filter((account) => isRecord(account) && typeof account.refreshToken === "string" && !!account.refreshToken.trim());
76
+ const deduplicatedAccounts = deduplicateAccountsForStorage(validAccounts);
77
+ const activeIndex = (() => {
78
+ if (deduplicatedAccounts.length === 0)
79
+ return 0;
80
+ if (activeKeys.length > 0) {
81
+ const mappedIndex = findAccountIndexByIdentityKeys(deduplicatedAccounts, activeKeys);
82
+ if (mappedIndex >= 0)
83
+ return mappedIndex;
84
+ }
85
+ return clampIndex(rawActiveIndex, deduplicatedAccounts.length);
86
+ })();
87
+ const activeIndexByFamily = {};
88
+ const rawFamilyIndices = isRecord(baseStorage.activeIndexByFamily)
89
+ ? baseStorage.activeIndexByFamily
90
+ : {};
91
+ for (const family of MODEL_FAMILIES) {
92
+ const rawIndexValue = rawFamilyIndices[family];
93
+ const rawIndex = typeof rawIndexValue === "number" && Number.isFinite(rawIndexValue)
94
+ ? rawIndexValue
95
+ : rawActiveIndex;
96
+ const clampedRawIndex = clampIndex(rawIndex, rawAccounts.length);
97
+ const familyKeys = extractActiveKeys(rawAccounts, clampedRawIndex);
98
+ let mappedIndex = clampIndex(rawIndex, deduplicatedAccounts.length);
99
+ if (familyKeys.length > 0 && deduplicatedAccounts.length > 0) {
100
+ const idx = findAccountIndexByIdentityKeys(deduplicatedAccounts, familyKeys);
101
+ if (idx >= 0) {
102
+ mappedIndex = idx;
103
+ }
104
+ }
105
+ activeIndexByFamily[family] = mappedIndex;
106
+ }
107
+ return {
108
+ version: 3,
109
+ accounts: deduplicatedAccounts,
110
+ activeIndex,
111
+ activeIndexByFamily,
112
+ };
113
+ }
114
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../lib/storage/normalize.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../lib/storage/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAgBD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB/D;AAcD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBpD"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../lib/storage/paths.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE/D;AAgBD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAQhE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB/D;AAcD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAyBpD"}
@@ -6,6 +6,7 @@ import { existsSync } from "node:fs";
6
6
  import { createHash } from "node:crypto";
7
7
  import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
8
8
  import { homedir, tmpdir } from "node:os";
9
+ import { StorageError } from "../errors.js";
9
10
  const PROJECT_MARKERS = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".opencode"];
10
11
  const PROJECTS_DIR = "projects";
11
12
  const PROJECT_KEY_HASH_LENGTH = 12;
@@ -85,7 +86,7 @@ export function resolvePath(filePath) {
85
86
  if (!isWithinDirectory(home, resolved) &&
86
87
  !isWithinDirectory(cwd, resolved) &&
87
88
  !isWithinDirectory(tmp, resolved)) {
88
- throw new Error(`Access denied: path must be within home directory, project directory, or temp directory`);
89
+ throw new StorageError(`Access denied: path must be within home directory, project directory, or temp directory`, "PATH_ACCESS_DENIED", resolved, "The requested path is outside the allowed roots (home, project, temp). Pick a path inside one of those directories.");
89
90
  }
90
91
  return resolved;
91
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../lib/storage/paths.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../lib/storage/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Module-scoped storage state and the single shared mutex that serializes
3
+ * every read-modify-write against the accounts files.
4
+ *
5
+ * Split out of `lib/storage.ts` in RC-2 so the identity helpers, normalize,
6
+ * load/save, flagged, and export-import modules can all share the same
7
+ * resolved path and the same lock without creating circular imports.
8
+ *
9
+ * Invariants this module preserves:
10
+ * - `currentStoragePath` is either `null` (use global fallback) or an
11
+ * absolute path to a project-scoped accounts file.
12
+ * - `currentProjectRoot` is only non-null when `currentStoragePath` is
13
+ * project-scoped; `setStoragePathDirect` deliberately clears it so
14
+ * ad-hoc overrides (tests, one-off CLI paths) never look like a real
15
+ * project.
16
+ * - `withStorageLock` chains every critical section through a single
17
+ * promise so nothing can interleave between a load and its paired save.
18
+ */
19
+ /**
20
+ * Serializes storage I/O to keep account file reads/writes lock-step and avoid
21
+ * cross-request races during migration/seeding flows.
22
+ */
23
+ export declare function withStorageLock<T>(fn: () => Promise<T>): Promise<T>;
24
+ export declare function setStoragePath(projectPath: string | null): void;
25
+ export declare function setStoragePathDirect(path: string | null): void;
26
+ /**
27
+ * Returns the file path for the account storage JSON file.
28
+ * @returns Absolute path to the accounts.json file
29
+ */
30
+ export declare function getStoragePath(): string;
31
+ export declare function getCurrentStoragePath(): string | null;
32
+ export declare function getCurrentLegacyProjectStoragePath(): string | null;
33
+ export declare function getCurrentProjectRoot(): string | null;
34
+ /**
35
+ * Returns the project storage key (e.g. `my-project-abc123def456`) that the
36
+ * active project storage path is rooted under, or `null` when no per-project
37
+ * root is active (global storage is in use). Used by the opt-in keychain
38
+ * backend as the account identifier so each project's credentials live
39
+ * under a distinct (service, account) pair in the OS keychain.
40
+ *
41
+ * When `setStoragePathDirect` overrode the path to something outside the
42
+ * standard per-project layout (tests, custom CLI override), we fall back to
43
+ * `null` because there is no meaningful project identity to key off.
44
+ */
45
+ export declare function getCurrentProjectStorageKey(): string | null;
46
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../lib/storage/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAcH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnE;AAMD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkB/D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAI9D;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAKvC;AAMD,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED,wBAAgB,kCAAkC,IAAI,MAAM,GAAG,IAAI,CAElE;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAG3D"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Module-scoped storage state and the single shared mutex that serializes
3
+ * every read-modify-write against the accounts files.
4
+ *
5
+ * Split out of `lib/storage.ts` in RC-2 so the identity helpers, normalize,
6
+ * load/save, flagged, and export-import modules can all share the same
7
+ * resolved path and the same lock without creating circular imports.
8
+ *
9
+ * Invariants this module preserves:
10
+ * - `currentStoragePath` is either `null` (use global fallback) or an
11
+ * absolute path to a project-scoped accounts file.
12
+ * - `currentProjectRoot` is only non-null when `currentStoragePath` is
13
+ * project-scoped; `setStoragePathDirect` deliberately clears it so
14
+ * ad-hoc overrides (tests, one-off CLI paths) never look like a real
15
+ * project.
16
+ * - `withStorageLock` chains every critical section through a single
17
+ * promise so nothing can interleave between a load and its paired save.
18
+ */
19
+ import { join } from "node:path";
20
+ import { ACCOUNTS_FILE_NAME, LEGACY_ACCOUNTS_FILE_NAME } from "../constants.js";
21
+ import { findProjectRoot, getConfigDir, getProjectConfigDir, getProjectGlobalConfigDir, getProjectStorageKey, } from "./paths.js";
22
+ let storageMutex = Promise.resolve();
23
+ /**
24
+ * Serializes storage I/O to keep account file reads/writes lock-step and avoid
25
+ * cross-request races during migration/seeding flows.
26
+ */
27
+ export function withStorageLock(fn) {
28
+ const previousMutex = storageMutex;
29
+ let releaseLock;
30
+ storageMutex = new Promise((resolve) => {
31
+ releaseLock = resolve;
32
+ });
33
+ return previousMutex.then(fn).finally(() => releaseLock());
34
+ }
35
+ let currentStoragePath = null;
36
+ let currentLegacyProjectStoragePath = null;
37
+ let currentProjectRoot = null;
38
+ export function setStoragePath(projectPath) {
39
+ if (!projectPath) {
40
+ currentStoragePath = null;
41
+ currentLegacyProjectStoragePath = null;
42
+ currentProjectRoot = null;
43
+ return;
44
+ }
45
+ const projectRoot = findProjectRoot(projectPath);
46
+ if (projectRoot) {
47
+ currentProjectRoot = projectRoot;
48
+ currentStoragePath = join(getProjectGlobalConfigDir(projectRoot), ACCOUNTS_FILE_NAME);
49
+ currentLegacyProjectStoragePath = join(getProjectConfigDir(projectRoot), LEGACY_ACCOUNTS_FILE_NAME);
50
+ }
51
+ else {
52
+ currentStoragePath = null;
53
+ currentLegacyProjectStoragePath = null;
54
+ currentProjectRoot = null;
55
+ }
56
+ }
57
+ export function setStoragePathDirect(path) {
58
+ currentStoragePath = path;
59
+ currentLegacyProjectStoragePath = null;
60
+ currentProjectRoot = null;
61
+ }
62
+ /**
63
+ * Returns the file path for the account storage JSON file.
64
+ * @returns Absolute path to the accounts.json file
65
+ */
66
+ export function getStoragePath() {
67
+ if (currentStoragePath) {
68
+ return currentStoragePath;
69
+ }
70
+ return join(getConfigDir(), ACCOUNTS_FILE_NAME);
71
+ }
72
+ // Internal accessors used by sibling storage modules. Not re-exported from the
73
+ // top-level barrel: callers outside `lib/storage/` should use the public
74
+ // `setStoragePath` / `getStoragePath` APIs.
75
+ export function getCurrentStoragePath() {
76
+ return currentStoragePath;
77
+ }
78
+ export function getCurrentLegacyProjectStoragePath() {
79
+ return currentLegacyProjectStoragePath;
80
+ }
81
+ export function getCurrentProjectRoot() {
82
+ return currentProjectRoot;
83
+ }
84
+ /**
85
+ * Returns the project storage key (e.g. `my-project-abc123def456`) that the
86
+ * active project storage path is rooted under, or `null` when no per-project
87
+ * root is active (global storage is in use). Used by the opt-in keychain
88
+ * backend as the account identifier so each project's credentials live
89
+ * under a distinct (service, account) pair in the OS keychain.
90
+ *
91
+ * When `setStoragePathDirect` overrode the path to something outside the
92
+ * standard per-project layout (tests, custom CLI override), we fall back to
93
+ * `null` because there is no meaningful project identity to key off.
94
+ */
95
+ export function getCurrentProjectStorageKey() {
96
+ if (!currentProjectRoot)
97
+ return null;
98
+ return getProjectStorageKey(currentProjectRoot);
99
+ }
100
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../lib/storage/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAChF,OAAO,EACL,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAEpB,IAAI,YAAY,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;AAEpD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAI,EAAoB;IACrD,MAAM,aAAa,GAAG,YAAY,CAAC;IACnC,IAAI,WAAuB,CAAC;IAC5B,YAAY,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC3C,WAAW,GAAG,OAAO,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,OAAO,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED,IAAI,kBAAkB,GAAkB,IAAI,CAAC;AAC7C,IAAI,+BAA+B,GAAkB,IAAI,CAAC;AAC1D,IAAI,kBAAkB,GAAkB,IAAI,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,WAA0B;IACvD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,kBAAkB,GAAG,IAAI,CAAC;QAC1B,+BAA+B,GAAG,IAAI,CAAC;QACvC,kBAAkB,GAAG,IAAI,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,WAAW,EAAE,CAAC;QAChB,kBAAkB,GAAG,WAAW,CAAC;QACjC,kBAAkB,GAAG,IAAI,CAAC,yBAAyB,CAAC,WAAW,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACtF,+BAA+B,GAAG,IAAI,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,yBAAyB,CAAC,CAAC;IACtG,CAAC;SAAM,CAAC;QACN,kBAAkB,GAAG,IAAI,CAAC;QAC1B,+BAA+B,GAAG,IAAI,CAAC;QACvC,kBAAkB,GAAG,IAAI,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,kBAAkB,GAAG,IAAI,CAAC;IAC1B,+BAA+B,GAAG,IAAI,CAAC;IACvC,kBAAkB,GAAG,IAAI,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,IAAI,kBAAkB,EAAE,CAAC;QACvB,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC,YAAY,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,yEAAyE;AACzE,4CAA4C;AAE5C,MAAM,UAAU,qBAAqB;IACnC,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,kCAAkC;IAChD,OAAO,+BAA+B,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B;IACzC,IAAI,CAAC,kBAAkB;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,79 @@
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
+ /**
35
+ * Time after which a lock whose owner never refreshed it is considered
36
+ * abandoned, regardless of PID liveness. One hour matches the roadmap spec
37
+ * and is long enough to avoid stealing a lock from a session that is merely
38
+ * idle between saves.
39
+ */
40
+ export declare const STALE_THRESHOLD_MS: number;
41
+ /**
42
+ * Persisted lock-file payload. Written as pretty-printed JSON so a human
43
+ * inspecting the file can immediately tell which worktree holds the lock.
44
+ */
45
+ export interface WorktreeLockInfo {
46
+ pid: number;
47
+ hostname: string;
48
+ cwd: string;
49
+ startedAt: string;
50
+ lastActive: string;
51
+ }
52
+ export interface AcquireLockResult {
53
+ /** True when we now own the lock on disk. */
54
+ acquired: boolean;
55
+ /** Populated only when a foreign live lock was detected. */
56
+ foreign?: WorktreeLockInfo;
57
+ }
58
+ /**
59
+ * Checks ownership of the worktree lock and acquires it when possible.
60
+ *
61
+ * Contract:
62
+ * - Never throws on lock I/O errors *other than* propagating read/write
63
+ * failures the caller needs to know about (disk full, EACCES).
64
+ * - Always returns a discriminated result: either `acquired: true` (we
65
+ * now own or refreshed the lock) or `acquired: false` with `foreign`
66
+ * populated (another live worktree owns it; caller should warn).
67
+ * - Never blocks. This is advisory locking by design.
68
+ */
69
+ export declare function acquireOrDetectLock(storagePath: string): Promise<AcquireLockResult>;
70
+ export declare function releaseLock(storagePath: string): Promise<void>;
71
+ /**
72
+ * Test-only reset hook. Vitest reuses a single Node process across files,
73
+ * so `ownedLockPaths` state would leak between suites and confuse the
74
+ * "no lock on disk" acquire branch. Not re-exported from the barrel.
75
+ */
76
+ export declare function __resetWorktreeLockForTests(): void;
77
+ /** Test-only: inspect owned paths without exposing the internal Set. */
78
+ export declare function __getOwnedLockPathsForTests(): readonly string[];
79
+ //# sourceMappingURL=worktree-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-lock.d.ts","sourceRoot":"","sources":["../../../lib/storage/worktree-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AASH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AAEjD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,CAAC;IAClB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAqID;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACxC,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAkD5B;AAyBD,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,IAAI,CAGlD;AAED,wEAAwE;AACxE,wBAAgB,2BAA2B,IAAI,SAAS,MAAM,EAAE,CAE/D"}