@chances-ai/engine 24.0.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 (389) hide show
  1. package/dist/agents/discover.d.ts +30 -0
  2. package/dist/agents/discover.d.ts.map +1 -0
  3. package/dist/agents/discover.js +183 -0
  4. package/dist/agents/discover.js.map +1 -0
  5. package/dist/agents/index.d.ts +20 -0
  6. package/dist/agents/index.d.ts.map +1 -0
  7. package/dist/agents/index.js +52 -0
  8. package/dist/agents/index.js.map +1 -0
  9. package/dist/agents/parse.d.ts +61 -0
  10. package/dist/agents/parse.d.ts.map +1 -0
  11. package/dist/agents/parse.js +527 -0
  12. package/dist/agents/parse.js.map +1 -0
  13. package/dist/agents/types.d.ts +52 -0
  14. package/dist/agents/types.d.ts.map +1 -0
  15. package/dist/agents/types.js +8 -0
  16. package/dist/agents/types.js.map +1 -0
  17. package/dist/ai/adapters/ai-sdk-stream.d.ts +19 -0
  18. package/dist/ai/adapters/ai-sdk-stream.d.ts.map +1 -0
  19. package/dist/ai/adapters/ai-sdk-stream.js +125 -0
  20. package/dist/ai/adapters/ai-sdk-stream.js.map +1 -0
  21. package/dist/ai/adapters/ai-sdk.d.ts +56 -0
  22. package/dist/ai/adapters/ai-sdk.d.ts.map +1 -0
  23. package/dist/ai/adapters/ai-sdk.js +112 -0
  24. package/dist/ai/adapters/ai-sdk.js.map +1 -0
  25. package/dist/ai/adapters/mock.d.ts +13 -0
  26. package/dist/ai/adapters/mock.d.ts.map +1 -0
  27. package/dist/ai/adapters/mock.js +54 -0
  28. package/dist/ai/adapters/mock.js.map +1 -0
  29. package/dist/ai/adapters/openai-compatible.d.ts +23 -0
  30. package/dist/ai/adapters/openai-compatible.d.ts.map +1 -0
  31. package/dist/ai/adapters/openai-compatible.js +45 -0
  32. package/dist/ai/adapters/openai-compatible.js.map +1 -0
  33. package/dist/ai/cost.d.ts +3 -0
  34. package/dist/ai/cost.d.ts.map +1 -0
  35. package/dist/ai/cost.js +5 -0
  36. package/dist/ai/cost.js.map +1 -0
  37. package/dist/ai/index.d.ts +12 -0
  38. package/dist/ai/index.d.ts.map +1 -0
  39. package/dist/ai/index.js +11 -0
  40. package/dist/ai/index.js.map +1 -0
  41. package/dist/ai/known-models.d.ts +20 -0
  42. package/dist/ai/known-models.d.ts.map +1 -0
  43. package/dist/ai/known-models.js +129 -0
  44. package/dist/ai/known-models.js.map +1 -0
  45. package/dist/ai/registry.d.ts +12 -0
  46. package/dist/ai/registry.d.ts.map +1 -0
  47. package/dist/ai/registry.js +24 -0
  48. package/dist/ai/registry.js.map +1 -0
  49. package/dist/ai/retry.d.ts +11 -0
  50. package/dist/ai/retry.d.ts.map +1 -0
  51. package/dist/ai/retry.js +14 -0
  52. package/dist/ai/retry.js.map +1 -0
  53. package/dist/ai/router.d.ts +25 -0
  54. package/dist/ai/router.d.ts.map +1 -0
  55. package/dist/ai/router.js +36 -0
  56. package/dist/ai/router.js.map +1 -0
  57. package/dist/ai/setup.d.ts +23 -0
  58. package/dist/ai/setup.d.ts.map +1 -0
  59. package/dist/ai/setup.js +47 -0
  60. package/dist/ai/setup.js.map +1 -0
  61. package/dist/ai/summarizer.d.ts +24 -0
  62. package/dist/ai/summarizer.d.ts.map +1 -0
  63. package/dist/ai/summarizer.js +56 -0
  64. package/dist/ai/summarizer.js.map +1 -0
  65. package/dist/ai/types.d.ts +83 -0
  66. package/dist/ai/types.d.ts.map +1 -0
  67. package/dist/ai/types.js +2 -0
  68. package/dist/ai/types.js.map +1 -0
  69. package/dist/core/compaction/circuit-breaker.d.ts +32 -0
  70. package/dist/core/compaction/circuit-breaker.d.ts.map +1 -0
  71. package/dist/core/compaction/circuit-breaker.js +42 -0
  72. package/dist/core/compaction/circuit-breaker.js.map +1 -0
  73. package/dist/core/compaction/compactor.d.ts +75 -0
  74. package/dist/core/compaction/compactor.d.ts.map +1 -0
  75. package/dist/core/compaction/compactor.js +261 -0
  76. package/dist/core/compaction/compactor.js.map +1 -0
  77. package/dist/core/compaction/estimate.d.ts +39 -0
  78. package/dist/core/compaction/estimate.d.ts.map +1 -0
  79. package/dist/core/compaction/estimate.js +74 -0
  80. package/dist/core/compaction/estimate.js.map +1 -0
  81. package/dist/core/compaction/index.d.ts +5 -0
  82. package/dist/core/compaction/index.d.ts.map +1 -0
  83. package/dist/core/compaction/index.js +5 -0
  84. package/dist/core/compaction/index.js.map +1 -0
  85. package/dist/core/compaction/prune.d.ts +43 -0
  86. package/dist/core/compaction/prune.d.ts.map +1 -0
  87. package/dist/core/compaction/prune.js +51 -0
  88. package/dist/core/compaction/prune.js.map +1 -0
  89. package/dist/core/engine.d.ts +268 -0
  90. package/dist/core/engine.d.ts.map +1 -0
  91. package/dist/core/engine.js +767 -0
  92. package/dist/core/engine.js.map +1 -0
  93. package/dist/core/index.d.ts +6 -0
  94. package/dist/core/index.d.ts.map +1 -0
  95. package/dist/core/index.js +6 -0
  96. package/dist/core/index.js.map +1 -0
  97. package/dist/core/task-tool.d.ts +175 -0
  98. package/dist/core/task-tool.d.ts.map +1 -0
  99. package/dist/core/task-tool.js +901 -0
  100. package/dist/core/task-tool.js.map +1 -0
  101. package/dist/core/workspace-query.d.ts +83 -0
  102. package/dist/core/workspace-query.d.ts.map +1 -0
  103. package/dist/core/workspace-query.js +217 -0
  104. package/dist/core/workspace-query.js.map +1 -0
  105. package/dist/core/worktree/active-marker.d.ts +31 -0
  106. package/dist/core/worktree/active-marker.d.ts.map +1 -0
  107. package/dist/core/worktree/active-marker.js +109 -0
  108. package/dist/core/worktree/active-marker.js.map +1 -0
  109. package/dist/core/worktree/create.d.ts +40 -0
  110. package/dist/core/worktree/create.d.ts.map +1 -0
  111. package/dist/core/worktree/create.js +121 -0
  112. package/dist/core/worktree/create.js.map +1 -0
  113. package/dist/core/worktree/errors.d.ts +7 -0
  114. package/dist/core/worktree/errors.d.ts.map +1 -0
  115. package/dist/core/worktree/errors.js +11 -0
  116. package/dist/core/worktree/errors.js.map +1 -0
  117. package/dist/core/worktree/gc.d.ts +39 -0
  118. package/dist/core/worktree/gc.d.ts.map +1 -0
  119. package/dist/core/worktree/gc.js +146 -0
  120. package/dist/core/worktree/gc.js.map +1 -0
  121. package/dist/core/worktree/git.d.ts +53 -0
  122. package/dist/core/worktree/git.d.ts.map +1 -0
  123. package/dist/core/worktree/git.js +166 -0
  124. package/dist/core/worktree/git.js.map +1 -0
  125. package/dist/core/worktree/index.d.ts +8 -0
  126. package/dist/core/worktree/index.d.ts.map +1 -0
  127. package/dist/core/worktree/index.js +8 -0
  128. package/dist/core/worktree/index.js.map +1 -0
  129. package/dist/core/worktree/paths.d.ts +26 -0
  130. package/dist/core/worktree/paths.d.ts.map +1 -0
  131. package/dist/core/worktree/paths.js +57 -0
  132. package/dist/core/worktree/paths.js.map +1 -0
  133. package/dist/core/worktree/slug.d.ts +6 -0
  134. package/dist/core/worktree/slug.d.ts.map +1 -0
  135. package/dist/core/worktree/slug.js +21 -0
  136. package/dist/core/worktree/slug.js.map +1 -0
  137. package/dist/local-vault/file-store.d.ts +64 -0
  138. package/dist/local-vault/file-store.d.ts.map +1 -0
  139. package/dist/local-vault/file-store.js +225 -0
  140. package/dist/local-vault/file-store.js.map +1 -0
  141. package/dist/local-vault/index.d.ts +57 -0
  142. package/dist/local-vault/index.d.ts.map +1 -0
  143. package/dist/local-vault/index.js +68 -0
  144. package/dist/local-vault/index.js.map +1 -0
  145. package/dist/local-vault/keychain.d.ts +58 -0
  146. package/dist/local-vault/keychain.d.ts.map +1 -0
  147. package/dist/local-vault/keychain.js +200 -0
  148. package/dist/local-vault/keychain.js.map +1 -0
  149. package/dist/local-vault/mutex.d.ts +20 -0
  150. package/dist/local-vault/mutex.d.ts.map +1 -0
  151. package/dist/local-vault/mutex.js +44 -0
  152. package/dist/local-vault/mutex.js.map +1 -0
  153. package/dist/local-vault/passphrase.d.ts +30 -0
  154. package/dist/local-vault/passphrase.d.ts.map +1 -0
  155. package/dist/local-vault/passphrase.js +72 -0
  156. package/dist/local-vault/passphrase.js.map +1 -0
  157. package/dist/lsp/config.d.ts +34 -0
  158. package/dist/lsp/config.d.ts.map +1 -0
  159. package/dist/lsp/config.js +68 -0
  160. package/dist/lsp/config.js.map +1 -0
  161. package/dist/lsp/detect.d.ts +7 -0
  162. package/dist/lsp/detect.d.ts.map +1 -0
  163. package/dist/lsp/detect.js +78 -0
  164. package/dist/lsp/detect.js.map +1 -0
  165. package/dist/lsp/errors.d.ts +11 -0
  166. package/dist/lsp/errors.d.ts.map +1 -0
  167. package/dist/lsp/errors.js +11 -0
  168. package/dist/lsp/errors.js.map +1 -0
  169. package/dist/lsp/formatters.d.ts +147 -0
  170. package/dist/lsp/formatters.d.ts.map +1 -0
  171. package/dist/lsp/formatters.js +259 -0
  172. package/dist/lsp/formatters.js.map +1 -0
  173. package/dist/lsp/index.d.ts +31 -0
  174. package/dist/lsp/index.d.ts.map +1 -0
  175. package/dist/lsp/index.js +31 -0
  176. package/dist/lsp/index.js.map +1 -0
  177. package/dist/lsp/instance.d.ts +72 -0
  178. package/dist/lsp/instance.d.ts.map +1 -0
  179. package/dist/lsp/instance.js +489 -0
  180. package/dist/lsp/instance.js.map +1 -0
  181. package/dist/lsp/lazy-load.d.ts +27 -0
  182. package/dist/lsp/lazy-load.d.ts.map +1 -0
  183. package/dist/lsp/lazy-load.js +57 -0
  184. package/dist/lsp/lazy-load.js.map +1 -0
  185. package/dist/lsp/manager.d.ts +59 -0
  186. package/dist/lsp/manager.d.ts.map +1 -0
  187. package/dist/lsp/manager.js +242 -0
  188. package/dist/lsp/manager.js.map +1 -0
  189. package/dist/lsp/ops.d.ts +13 -0
  190. package/dist/lsp/ops.d.ts.map +1 -0
  191. package/dist/lsp/ops.js +225 -0
  192. package/dist/lsp/ops.js.map +1 -0
  193. package/dist/lsp/rpc.d.ts +47 -0
  194. package/dist/lsp/rpc.d.ts.map +1 -0
  195. package/dist/lsp/rpc.js +134 -0
  196. package/dist/lsp/rpc.js.map +1 -0
  197. package/dist/lsp/safe-uri.d.ts +18 -0
  198. package/dist/lsp/safe-uri.d.ts.map +1 -0
  199. package/dist/lsp/safe-uri.js +96 -0
  200. package/dist/lsp/safe-uri.js.map +1 -0
  201. package/dist/lsp/types.d.ts +70 -0
  202. package/dist/lsp/types.d.ts.map +1 -0
  203. package/dist/lsp/types.js +16 -0
  204. package/dist/lsp/types.js.map +1 -0
  205. package/dist/mcp/bridge.d.ts +57 -0
  206. package/dist/mcp/bridge.d.ts.map +1 -0
  207. package/dist/mcp/bridge.js +98 -0
  208. package/dist/mcp/bridge.js.map +1 -0
  209. package/dist/mcp/category.d.ts +22 -0
  210. package/dist/mcp/category.d.ts.map +1 -0
  211. package/dist/mcp/category.js +11 -0
  212. package/dist/mcp/category.js.map +1 -0
  213. package/dist/mcp/client.d.ts +228 -0
  214. package/dist/mcp/client.d.ts.map +1 -0
  215. package/dist/mcp/client.js +352 -0
  216. package/dist/mcp/client.js.map +1 -0
  217. package/dist/mcp/content.d.ts +86 -0
  218. package/dist/mcp/content.d.ts.map +1 -0
  219. package/dist/mcp/content.js +147 -0
  220. package/dist/mcp/content.js.map +1 -0
  221. package/dist/mcp/env.d.ts +19 -0
  222. package/dist/mcp/env.d.ts.map +1 -0
  223. package/dist/mcp/env.js +50 -0
  224. package/dist/mcp/env.js.map +1 -0
  225. package/dist/mcp/host.d.ts +199 -0
  226. package/dist/mcp/host.d.ts.map +1 -0
  227. package/dist/mcp/host.js +530 -0
  228. package/dist/mcp/host.js.map +1 -0
  229. package/dist/mcp/index.d.ts +18 -0
  230. package/dist/mcp/index.d.ts.map +1 -0
  231. package/dist/mcp/index.js +17 -0
  232. package/dist/mcp/index.js.map +1 -0
  233. package/dist/mcp/load-mcp-host.d.ts +32 -0
  234. package/dist/mcp/load-mcp-host.d.ts.map +1 -0
  235. package/dist/mcp/load-mcp-host.js +49 -0
  236. package/dist/mcp/load-mcp-host.js.map +1 -0
  237. package/dist/mcp/oauth/callback-server.d.ts +73 -0
  238. package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
  239. package/dist/mcp/oauth/callback-server.js +280 -0
  240. package/dist/mcp/oauth/callback-server.js.map +1 -0
  241. package/dist/mcp/oauth/config-hash.d.ts +24 -0
  242. package/dist/mcp/oauth/config-hash.d.ts.map +1 -0
  243. package/dist/mcp/oauth/config-hash.js +55 -0
  244. package/dist/mcp/oauth/config-hash.js.map +1 -0
  245. package/dist/mcp/oauth/error-normalize.d.ts +39 -0
  246. package/dist/mcp/oauth/error-normalize.d.ts.map +1 -0
  247. package/dist/mcp/oauth/error-normalize.js +91 -0
  248. package/dist/mcp/oauth/error-normalize.js.map +1 -0
  249. package/dist/mcp/oauth/provider.d.ts +190 -0
  250. package/dist/mcp/oauth/provider.d.ts.map +1 -0
  251. package/dist/mcp/oauth/provider.js +305 -0
  252. package/dist/mcp/oauth/provider.js.map +1 -0
  253. package/dist/mcp/oauth/refresh-coalescer.d.ts +46 -0
  254. package/dist/mcp/oauth/refresh-coalescer.d.ts.map +1 -0
  255. package/dist/mcp/oauth/refresh-coalescer.js +77 -0
  256. package/dist/mcp/oauth/refresh-coalescer.js.map +1 -0
  257. package/dist/mcp/oauth/sdk-shapes.d.ts +77 -0
  258. package/dist/mcp/oauth/sdk-shapes.d.ts.map +1 -0
  259. package/dist/mcp/oauth/sdk-shapes.js +21 -0
  260. package/dist/mcp/oauth/sdk-shapes.js.map +1 -0
  261. package/dist/mcp/parse.d.ts +28 -0
  262. package/dist/mcp/parse.d.ts.map +1 -0
  263. package/dist/mcp/parse.js +209 -0
  264. package/dist/mcp/parse.js.map +1 -0
  265. package/dist/mcp/prompts.d.ts +31 -0
  266. package/dist/mcp/prompts.d.ts.map +1 -0
  267. package/dist/mcp/prompts.js +71 -0
  268. package/dist/mcp/prompts.js.map +1 -0
  269. package/dist/mcp/redact.d.ts +62 -0
  270. package/dist/mcp/redact.d.ts.map +1 -0
  271. package/dist/mcp/redact.js +87 -0
  272. package/dist/mcp/redact.js.map +1 -0
  273. package/dist/mcp/resources.d.ts +70 -0
  274. package/dist/mcp/resources.d.ts.map +1 -0
  275. package/dist/mcp/resources.js +170 -0
  276. package/dist/mcp/resources.js.map +1 -0
  277. package/dist/mcp/types.d.ts +123 -0
  278. package/dist/mcp/types.d.ts.map +1 -0
  279. package/dist/mcp/types.js +2 -0
  280. package/dist/mcp/types.js.map +1 -0
  281. package/dist/memory/frontmatter.d.ts +18 -0
  282. package/dist/memory/frontmatter.d.ts.map +1 -0
  283. package/dist/memory/frontmatter.js +81 -0
  284. package/dist/memory/frontmatter.js.map +1 -0
  285. package/dist/memory/index.d.ts +5 -0
  286. package/dist/memory/index.d.ts.map +1 -0
  287. package/dist/memory/index.js +5 -0
  288. package/dist/memory/index.js.map +1 -0
  289. package/dist/memory/store.d.ts +44 -0
  290. package/dist/memory/store.d.ts.map +1 -0
  291. package/dist/memory/store.js +237 -0
  292. package/dist/memory/store.js.map +1 -0
  293. package/dist/memory/tools.d.ts +11 -0
  294. package/dist/memory/tools.d.ts.map +1 -0
  295. package/dist/memory/tools.js +159 -0
  296. package/dist/memory/tools.js.map +1 -0
  297. package/dist/memory/types.d.ts +32 -0
  298. package/dist/memory/types.d.ts.map +1 -0
  299. package/dist/memory/types.js +20 -0
  300. package/dist/memory/types.js.map +1 -0
  301. package/dist/plugin-api/index.d.ts +167 -0
  302. package/dist/plugin-api/index.d.ts.map +1 -0
  303. package/dist/plugin-api/index.js +151 -0
  304. package/dist/plugin-api/index.js.map +1 -0
  305. package/dist/plugin-logger/index.d.ts +21 -0
  306. package/dist/plugin-logger/index.d.ts.map +1 -0
  307. package/dist/plugin-logger/index.js +59 -0
  308. package/dist/plugin-logger/index.js.map +1 -0
  309. package/dist/session/index.d.ts +125 -0
  310. package/dist/session/index.d.ts.map +1 -0
  311. package/dist/session/index.js +202 -0
  312. package/dist/session/index.js.map +1 -0
  313. package/dist/tools/approval.d.ts +33 -0
  314. package/dist/tools/approval.d.ts.map +1 -0
  315. package/dist/tools/approval.js +53 -0
  316. package/dist/tools/approval.js.map +1 -0
  317. package/dist/tools/builtins/_shared.d.ts +94 -0
  318. package/dist/tools/builtins/_shared.d.ts.map +1 -0
  319. package/dist/tools/builtins/_shared.js +246 -0
  320. package/dist/tools/builtins/_shared.js.map +1 -0
  321. package/dist/tools/builtins/ask-user-question.d.ts +27 -0
  322. package/dist/tools/builtins/ask-user-question.d.ts.map +1 -0
  323. package/dist/tools/builtins/ask-user-question.js +191 -0
  324. package/dist/tools/builtins/ask-user-question.js.map +1 -0
  325. package/dist/tools/builtins/bash.d.ts +3 -0
  326. package/dist/tools/builtins/bash.d.ts.map +1 -0
  327. package/dist/tools/builtins/bash.js +158 -0
  328. package/dist/tools/builtins/bash.js.map +1 -0
  329. package/dist/tools/builtins/diff.d.ts +3 -0
  330. package/dist/tools/builtins/diff.d.ts.map +1 -0
  331. package/dist/tools/builtins/diff.js +83 -0
  332. package/dist/tools/builtins/diff.js.map +1 -0
  333. package/dist/tools/builtins/edit.d.ts +3 -0
  334. package/dist/tools/builtins/edit.d.ts.map +1 -0
  335. package/dist/tools/builtins/edit.js +40 -0
  336. package/dist/tools/builtins/edit.js.map +1 -0
  337. package/dist/tools/builtins/glob.d.ts +3 -0
  338. package/dist/tools/builtins/glob.d.ts.map +1 -0
  339. package/dist/tools/builtins/glob.js +37 -0
  340. package/dist/tools/builtins/glob.js.map +1 -0
  341. package/dist/tools/builtins/grep.d.ts +3 -0
  342. package/dist/tools/builtins/grep.d.ts.map +1 -0
  343. package/dist/tools/builtins/grep.js +81 -0
  344. package/dist/tools/builtins/grep.js.map +1 -0
  345. package/dist/tools/builtins/lsp.d.ts +3 -0
  346. package/dist/tools/builtins/lsp.d.ts.map +1 -0
  347. package/dist/tools/builtins/lsp.js +102 -0
  348. package/dist/tools/builtins/lsp.js.map +1 -0
  349. package/dist/tools/builtins/pty.d.ts +64 -0
  350. package/dist/tools/builtins/pty.d.ts.map +1 -0
  351. package/dist/tools/builtins/pty.js +536 -0
  352. package/dist/tools/builtins/pty.js.map +1 -0
  353. package/dist/tools/builtins/read.d.ts +3 -0
  354. package/dist/tools/builtins/read.d.ts.map +1 -0
  355. package/dist/tools/builtins/read.js +18 -0
  356. package/dist/tools/builtins/read.js.map +1 -0
  357. package/dist/tools/builtins/web-fetch.d.ts +4 -0
  358. package/dist/tools/builtins/web-fetch.d.ts.map +1 -0
  359. package/dist/tools/builtins/web-fetch.js +353 -0
  360. package/dist/tools/builtins/web-fetch.js.map +1 -0
  361. package/dist/tools/builtins/write.d.ts +3 -0
  362. package/dist/tools/builtins/write.d.ts.map +1 -0
  363. package/dist/tools/builtins/write.js +48 -0
  364. package/dist/tools/builtins/write.js.map +1 -0
  365. package/dist/tools/builtins.d.ts +9 -0
  366. package/dist/tools/builtins.d.ts.map +1 -0
  367. package/dist/tools/builtins.js +29 -0
  368. package/dist/tools/builtins.js.map +1 -0
  369. package/dist/tools/diff.d.ts +18 -0
  370. package/dist/tools/diff.d.ts.map +1 -0
  371. package/dist/tools/diff.js +57 -0
  372. package/dist/tools/diff.js.map +1 -0
  373. package/dist/tools/index.d.ts +10 -0
  374. package/dist/tools/index.d.ts.map +1 -0
  375. package/dist/tools/index.js +9 -0
  376. package/dist/tools/index.js.map +1 -0
  377. package/dist/tools/permission.d.ts +120 -0
  378. package/dist/tools/permission.d.ts.map +1 -0
  379. package/dist/tools/permission.js +208 -0
  380. package/dist/tools/permission.js.map +1 -0
  381. package/dist/tools/registry.d.ts +12 -0
  382. package/dist/tools/registry.d.ts.map +1 -0
  383. package/dist/tools/registry.js +19 -0
  384. package/dist/tools/registry.js.map +1 -0
  385. package/dist/tools/types.d.ts +244 -0
  386. package/dist/tools/types.d.ts.map +1 -0
  387. package/dist/tools/types.js +15 -0
  388. package/dist/tools/types.js.map +1 -0
  389. package/package.json +109 -0
@@ -0,0 +1,200 @@
1
+ /**
2
+ * (3.7) OS keychain adapter wrapping `@napi-rs/keyring`.
3
+ *
4
+ * Loaded via a computed-specifier dynamic import (same `bun build
5
+ * --compile` reason as 3.6 OTel) so the binary still compiles when the
6
+ * optional peer is absent. A consumer that didn't install the keyring
7
+ * package falls back to the file backend (`./file-store.ts`) — same
8
+ * graceful degradation as before, no opaque "module not found" crash
9
+ * at boot.
10
+ *
11
+ * Layout: service name `chances-cli` (fixed), account name = vault key.
12
+ * Values are JSON-stringified before storage; parsed on read.
13
+ *
14
+ * **(claude-code anti-pattern noted)** Don't store full RFC 8414 metadata
15
+ * here — Windows Credential Manager has a 4096-byte limit on stored
16
+ * values. § 4.2 of the design doc enforces "URLs only" at the higher
17
+ * (provider) layer; this adapter doesn't try to enforce shape.
18
+ */
19
+ import { KeyedMutex } from "./mutex.js";
20
+ const KEYRING_SERVICE = "chances-cli";
21
+ const KEYRING_PROBE_KEY = "__chances_probe__";
22
+ const defaultLoader = async () => {
23
+ try {
24
+ // Computed specifier — Bun's compile pass cannot statically resolve
25
+ // and therefore can't refuse to compile when the optional peer is absent.
26
+ const specifier = ["@napi-rs", "keyring"].join("/");
27
+ const mod = (await import(specifier));
28
+ if (!mod || typeof mod.Entry !== "function")
29
+ return null;
30
+ return mod;
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ };
36
+ export class KeychainStore {
37
+ mod;
38
+ mutex = new KeyedMutex();
39
+ constructor(mod) {
40
+ this.mod = mod;
41
+ }
42
+ /**
43
+ * Loads the keyring module + runs an access probe. Returns:
44
+ * - the store, when the module loaded AND the probe succeeded;
45
+ * - `null` with a reason string, otherwise.
46
+ *
47
+ * The probe is critical on macOS — the module loads fine, but the FIRST
48
+ * keychain op can throw with a user-denied dialog. We catch that here so
49
+ * the fallback path runs without hanging the consumer.
50
+ */
51
+ static async tryCreate(loader = defaultLoader) {
52
+ let mod;
53
+ try {
54
+ mod = await loader();
55
+ }
56
+ catch (e) {
57
+ return { store: null, reason: `keychain loader threw: ${e.message || String(e)}` };
58
+ }
59
+ if (!mod)
60
+ return { store: null, reason: "@napi-rs/keyring not installed" };
61
+ // Access probe — try a setPassword + getPassword round-trip against a
62
+ // probe key, then delete. The exact key is reserved.
63
+ try {
64
+ const probe = new mod.Entry(KEYRING_SERVICE, KEYRING_PROBE_KEY);
65
+ await Promise.resolve(probe.setPassword("ok"));
66
+ const got = await Promise.resolve(probe.getPassword());
67
+ if (got !== "ok") {
68
+ return { store: null, reason: `keychain probe value mismatch (got ${JSON.stringify(got)})` };
69
+ }
70
+ await Promise.resolve(probe.deletePassword());
71
+ }
72
+ catch (e) {
73
+ return { store: null, reason: `keychain probe failed: ${e.message || String(e)}` };
74
+ }
75
+ return { store: new KeychainStore(mod) };
76
+ }
77
+ async read(key) {
78
+ const release = await this.mutex.acquire(key);
79
+ try {
80
+ const entry = new this.mod.Entry(KEYRING_SERVICE, key);
81
+ const raw = await Promise.resolve(entry.getPassword());
82
+ if (raw === null || raw === undefined)
83
+ return undefined;
84
+ try {
85
+ return JSON.parse(raw);
86
+ }
87
+ catch (e) {
88
+ throw new Error(`local-vault keychain: stored value at '${key}' is not valid JSON: ${e.message}`);
89
+ }
90
+ }
91
+ finally {
92
+ release();
93
+ }
94
+ }
95
+ async list() {
96
+ // @napi-rs/keyring has no enumeration API across platforms. We track
97
+ // keys in a separate index entry stored under the reserved name
98
+ // `__chances_keys__`. This is a small lie — list() is best-effort and
99
+ // only reflects keys we've written THROUGH this adapter. Out-of-band
100
+ // entries (e.g. user-edited Keychain Access) aren't enumerable; this
101
+ // is the same constraint claude-code's LocalVault carries.
102
+ const idx = await this.read("__chances_keys__");
103
+ return idx ?? [];
104
+ }
105
+ async remove(key) {
106
+ const release = await this.mutex.acquire(key);
107
+ try {
108
+ const entry = new this.mod.Entry(KEYRING_SERVICE, key);
109
+ try {
110
+ await Promise.resolve(entry.deletePassword());
111
+ }
112
+ catch {
113
+ // The keyring throws on "not present" on some platforms. Idempotent
114
+ // remove — swallow and continue.
115
+ }
116
+ // Update the index.
117
+ const idxKey = "__chances_keys__";
118
+ const idxEntry = new this.mod.Entry(KEYRING_SERVICE, idxKey);
119
+ const raw = await Promise.resolve(idxEntry.getPassword());
120
+ if (raw !== null && raw !== undefined) {
121
+ try {
122
+ const idx = JSON.parse(raw);
123
+ const next = idx.filter((k) => k !== key);
124
+ if (next.length === 0) {
125
+ await Promise.resolve(idxEntry.deletePassword()).catch(() => { });
126
+ }
127
+ else {
128
+ await Promise.resolve(idxEntry.setPassword(JSON.stringify(next)));
129
+ }
130
+ }
131
+ catch {
132
+ // Corrupt index — leave alone; list() will return [] for it.
133
+ }
134
+ }
135
+ }
136
+ finally {
137
+ release();
138
+ }
139
+ }
140
+ async mergeMutate(key, mutator, allowDelete = false) {
141
+ const release = await this.mutex.acquire(key);
142
+ try {
143
+ const entry = new this.mod.Entry(KEYRING_SERVICE, key);
144
+ const raw = await Promise.resolve(entry.getPassword());
145
+ let current;
146
+ if (raw !== null && raw !== undefined) {
147
+ try {
148
+ current = JSON.parse(raw);
149
+ }
150
+ catch {
151
+ // Treat corrupt as missing — the mutator gets a clean slate.
152
+ current = undefined;
153
+ }
154
+ }
155
+ const next = await mutator(current);
156
+ if (next === undefined) {
157
+ if (allowDelete && current !== undefined) {
158
+ await Promise.resolve(entry.deletePassword()).catch(() => { });
159
+ }
160
+ return;
161
+ }
162
+ await Promise.resolve(entry.setPassword(JSON.stringify(next)));
163
+ // Update the index — best-effort, race tolerant.
164
+ await this.recordKey(key);
165
+ }
166
+ finally {
167
+ release();
168
+ }
169
+ }
170
+ /** (codex Round-2 NICE #3) Update the index under its OWN mutex so
171
+ * concurrent `mergeMutate("a")` / `mergeMutate("b")` can't race on
172
+ * the shared `__chances_keys__` entry. Each holds its per-key lock
173
+ * for the value write, then queues behind the index mutex for the
174
+ * list update. `list()` could otherwise drop entries. */
175
+ async recordKey(key) {
176
+ const idxKey = "__chances_keys__";
177
+ const release = await this.mutex.acquire(idxKey);
178
+ try {
179
+ const idxEntry = new this.mod.Entry(KEYRING_SERVICE, idxKey);
180
+ const raw = await Promise.resolve(idxEntry.getPassword());
181
+ let idx = [];
182
+ if (raw !== null && raw !== undefined) {
183
+ try {
184
+ idx = JSON.parse(raw);
185
+ }
186
+ catch {
187
+ idx = [];
188
+ }
189
+ }
190
+ if (!idx.includes(key)) {
191
+ idx.push(key);
192
+ await Promise.resolve(idxEntry.setPassword(JSON.stringify(idx))).catch(() => { });
193
+ }
194
+ }
195
+ finally {
196
+ release();
197
+ }
198
+ }
199
+ }
200
+ //# sourceMappingURL=keychain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/local-vault/keychain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * (3.7) Per-key async mutex. Used by `mergeMutate` to serialise
3
+ * read-modify-write cycles against a single vault key without
4
+ * blocking unrelated keys (codex Round-1 MUST-FIX #1).
5
+ *
6
+ * Implementation is a promise-chain keyed by the locked resource id.
7
+ * Each acquire returns a release fn; `finally`-release in callers.
8
+ * No timeout / no cancellation — vault writes are short, and a
9
+ * never-released lock would be a real bug, not something to paper over.
10
+ */
11
+ export declare class KeyedMutex {
12
+ private locks;
13
+ /** Acquires the lock for `key`. Returns a release fn the caller MUST
14
+ * invoke (use try/finally). Concurrent acquires for the same key
15
+ * serialise; different keys do not block each other. */
16
+ acquire(key: string): Promise<() => void>;
17
+ /** Diagnostics — number of distinct keys currently locked. Test seam. */
18
+ size(): number;
19
+ }
20
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../src/local-vault/mutex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAoC;IAEjD;;6DAEyD;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC;IAwB/C,yEAAyE;IACzE,IAAI,IAAI,MAAM;CAGf"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * (3.7) Per-key async mutex. Used by `mergeMutate` to serialise
3
+ * read-modify-write cycles against a single vault key without
4
+ * blocking unrelated keys (codex Round-1 MUST-FIX #1).
5
+ *
6
+ * Implementation is a promise-chain keyed by the locked resource id.
7
+ * Each acquire returns a release fn; `finally`-release in callers.
8
+ * No timeout / no cancellation — vault writes are short, and a
9
+ * never-released lock would be a real bug, not something to paper over.
10
+ */
11
+ export class KeyedMutex {
12
+ locks = new Map();
13
+ /** Acquires the lock for `key`. Returns a release fn the caller MUST
14
+ * invoke (use try/finally). Concurrent acquires for the same key
15
+ * serialise; different keys do not block each other. */
16
+ async acquire(key) {
17
+ const previous = this.locks.get(key) ?? Promise.resolve();
18
+ let release;
19
+ const next = new Promise((resolve) => {
20
+ release = () => {
21
+ // Only clear the slot if WE are still the head — protects
22
+ // against pathological orderings where release fires twice or
23
+ // after a logically-distinct cycle reused the same key.
24
+ if (this.locks.get(key) === next) {
25
+ this.locks.delete(key);
26
+ }
27
+ resolve();
28
+ };
29
+ });
30
+ this.locks.set(key, next);
31
+ // Swallow any rejection on the previous lock — every awaiter
32
+ // proceeds once the previous holder has FINISHED, regardless of
33
+ // outcome. (A holder that throws still runs its `finally` and
34
+ // calls release; the resolved next promise here is what callers
35
+ // chain off, so the rejection doesn't propagate to siblings.)
36
+ await previous.catch(() => { });
37
+ return release;
38
+ }
39
+ /** Diagnostics — number of distinct keys currently locked. Test seam. */
40
+ size() {
41
+ return this.locks.size;
42
+ }
43
+ }
44
+ //# sourceMappingURL=mutex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/local-vault/mutex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,OAAO,UAAU;IACb,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAEjD;;6DAEyD;IACzD,KAAK,CAAC,OAAO,CAAC,GAAW;QACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1D,IAAI,OAAoB,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACzC,OAAO,GAAG,GAAG,EAAE;gBACb,0DAA0D;gBAC1D,8DAA8D;gBAC9D,wDAAwD;gBACxD,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;oBACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1B,6DAA6D;QAC7D,gEAAgE;QAChE,8DAA8D;QAC9D,gEAAgE;QAChE,8DAA8D;QAC9D,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,yEAAyE;IACzE,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * (3.7) Passphrase resolution for the AES-GCM file backend.
3
+ *
4
+ * Order:
5
+ * 1. CHANCES_VAULT_PASSPHRASE env var (≥16 chars)
6
+ * 2. <passphraseFile> (0600), if present and ≥16 chars
7
+ * 3. Auto-generate 32 random bytes → hex; persist to passphraseFile@0600
8
+ *
9
+ * The passphrase file lives OUTSIDE the vault directory by default
10
+ * (`~/.chances-vault-passphrase`, sibling to `~/.chances/`). codex
11
+ * Round-1 SHOULD-FIX: storing the key inside the vault dir defeats
12
+ * the encryption against a full-tree backup leak.
13
+ */
14
+ export declare const MIN_PASSPHRASE_LENGTH = 16;
15
+ export declare const ENV_VAR = "CHANCES_VAULT_PASSPHRASE";
16
+ export interface ResolvePassphraseOptions {
17
+ /** Absolute path. Default caller's `~/.chances-vault-passphrase`. */
18
+ passphraseFile: string;
19
+ /** Test seam — defaults to `process.env`. */
20
+ env?: Record<string, string | undefined>;
21
+ /** Test seam — defaults to `randomBytes`. */
22
+ generateBytes?: (n: number) => Buffer;
23
+ }
24
+ export interface ResolvedPassphrase {
25
+ passphrase: string;
26
+ /** Where the passphrase came from. Surfaced via vault diagnostics. */
27
+ source: "env" | "file" | "generated";
28
+ }
29
+ export declare function resolvePassphrase(opts: ResolvePassphraseOptions): ResolvedPassphrase;
30
+ //# sourceMappingURL=passphrase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passphrase.d.ts","sourceRoot":"","sources":["../../src/local-vault/passphrase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AACxC,eAAO,MAAM,OAAO,6BAA6B,CAAC;AAElD,MAAM,WAAW,wBAAwB;IACvC,qEAAqE;IACrE,cAAc,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,6CAA6C;IAC7C,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,wBAAwB,GAAG,kBAAkB,CAmCpF"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * (3.7) Passphrase resolution for the AES-GCM file backend.
3
+ *
4
+ * Order:
5
+ * 1. CHANCES_VAULT_PASSPHRASE env var (≥16 chars)
6
+ * 2. <passphraseFile> (0600), if present and ≥16 chars
7
+ * 3. Auto-generate 32 random bytes → hex; persist to passphraseFile@0600
8
+ *
9
+ * The passphrase file lives OUTSIDE the vault directory by default
10
+ * (`~/.chances-vault-passphrase`, sibling to `~/.chances/`). codex
11
+ * Round-1 SHOULD-FIX: storing the key inside the vault dir defeats
12
+ * the encryption against a full-tree backup leak.
13
+ */
14
+ import { existsSync, readFileSync, writeFileSync, statSync, chmodSync } from "node:fs";
15
+ import { randomBytes } from "node:crypto";
16
+ export const MIN_PASSPHRASE_LENGTH = 16;
17
+ export const ENV_VAR = "CHANCES_VAULT_PASSPHRASE";
18
+ export function resolvePassphrase(opts) {
19
+ const env = opts.env ?? process.env;
20
+ const fromEnv = env[ENV_VAR];
21
+ if (fromEnv !== undefined && fromEnv.length > 0) {
22
+ if (fromEnv.length < MIN_PASSPHRASE_LENGTH) {
23
+ throw new Error(`${ENV_VAR} is too short (got ${fromEnv.length} chars, need ≥${MIN_PASSPHRASE_LENGTH}). ` +
24
+ `Use a longer secret or unset the env var to fall back to the file/generated passphrase.`);
25
+ }
26
+ return { passphrase: fromEnv, source: "env" };
27
+ }
28
+ if (existsSync(opts.passphraseFile)) {
29
+ const fileContents = readFileSync(opts.passphraseFile, "utf8").trim();
30
+ if (fileContents.length < MIN_PASSPHRASE_LENGTH) {
31
+ // Treat short file as missing — regenerate. Don't error here because
32
+ // the user may have hand-edited the file partially; we'd rather
33
+ // recover than refuse to start.
34
+ // (This is documented in tests so a future maintainer sees the choice.)
35
+ }
36
+ else {
37
+ ensure0600(opts.passphraseFile);
38
+ return { passphrase: fileContents, source: "file" };
39
+ }
40
+ }
41
+ // Generate. 32 random bytes hex = 64 chars; well above 16-char floor and
42
+ // strong enough that KDF cost is irrelevant to security analysis.
43
+ const gen = opts.generateBytes ?? randomBytes;
44
+ const passphrase = gen(32).toString("hex");
45
+ writeFileSync(opts.passphraseFile, passphrase, { mode: 0o600 });
46
+ // POSIX honors `mode` on the open() flag. On Windows, mode is largely
47
+ // a hint; ensure0600 below verifies and warns only on POSIX.
48
+ ensure0600(opts.passphraseFile);
49
+ return { passphrase, source: "generated" };
50
+ }
51
+ /**
52
+ * Best-effort: enforce 0600 mode on POSIX systems. On Windows the bit
53
+ * is largely advisory; a wholly different ACL story applies (out of
54
+ * scope for v1 — would need `windows-sys` or PowerShell hooks).
55
+ */
56
+ function ensure0600(path) {
57
+ if (process.platform === "win32")
58
+ return;
59
+ try {
60
+ const stat = statSync(path);
61
+ const mode = stat.mode & 0o777;
62
+ if (mode !== 0o600) {
63
+ chmodSync(path, 0o600);
64
+ }
65
+ }
66
+ catch {
67
+ // statSync/chmodSync can fail on a race (file deleted between writeFileSync
68
+ // and stat). Swallow — the caller's next read will surface the real issue
69
+ // with a more actionable error.
70
+ }
71
+ }
72
+ //# sourceMappingURL=passphrase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passphrase.js","sourceRoot":"","sources":["../../src/local-vault/passphrase.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACxC,MAAM,CAAC,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAiBlD,MAAM,UAAU,iBAAiB,CAAC,IAA8B;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,GAAG,OAAO,sBAAsB,OAAO,CAAC,MAAM,iBAAiB,qBAAqB,KAAK;gBACvF,yFAAyF,CAC5F,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,IAAI,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,IAAI,YAAY,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;YAChD,qEAAqE;YACrE,gEAAgE;YAChE,gCAAgC;YAChC,wEAAwE;QAC1E,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAChC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACtD,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,kEAAkE;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,IAAI,WAAW,CAAC;IAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC3C,aAAa,CAAC,IAAI,CAAC,cAAc,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChE,sEAAsE;IACtE,6DAA6D;IAC7D,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChC,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO;IACzC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAC/B,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,0EAA0E;QAC1E,gCAAgC;IAClC,CAAC;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * (4.2) Built-in default LSP server registry + user-override merger.
3
+ *
4
+ * Selection order (codex Round-1 NICE #1):
5
+ * - User-defined entries are considered BEFORE built-ins.
6
+ * - Within each group, object insertion order wins on extension
7
+ * tie-breaks.
8
+ *
9
+ * Adding a built-in is a one-entry append + extension list. The
10
+ * resolved list is the ordered union, with `enabled: false` filtered
11
+ * out at the call site so the disable flag is visible in surveys.
12
+ */
13
+ import type { LspServerConfig, ResolvedServer } from "./types.js";
14
+ /** Built-in defaults for the top 4 servers (codex Round-1 NICE #1).
15
+ * Order in this object is the tie-break order for extension claims
16
+ * among built-ins. Insertion order is stable in modern V8/Spidermonkey
17
+ * for string keys. */
18
+ export declare const BUILTIN_DEFAULTS: Readonly<Record<string, LspServerConfig>>;
19
+ /** Merges user-provided servers with built-in defaults.
20
+ *
21
+ * Per-name overlay: a user entry by the same name shallow-merges
22
+ * with the built-in (user fields win). Disabling a built-in is
23
+ * `servers.typescript = { enabled: false }`.
24
+ *
25
+ * Output order: user-defined names first (in user insertion order),
26
+ * then any built-ins not overridden by name (in built-in order).
27
+ * `enabled: false` entries are NOT filtered here — they're surfaced
28
+ * to the caller (e.g. `doctor`) so the disable is visible. */
29
+ export declare function resolveServers(builtIns?: Readonly<Record<string, LspServerConfig>>, userServers?: Readonly<Record<string, LspServerConfig>>): ResolvedServer[];
30
+ /** Picks the first ENABLED server whose `extensions` covers `ext`.
31
+ * Returns undefined when no server claims the extension OR when all
32
+ * matches are disabled. */
33
+ export declare function pickServerForExtension(servers: readonly ResolvedServer[], ext: string): ResolvedServer | undefined;
34
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lsp/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElE;;;uBAGuB;AACvB,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAqBtE,CAAC;AAEF;;;;;;;;;+DAS+D;AAC/D,wBAAgB,cAAc,CAC5B,QAAQ,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAoB,EACtE,WAAW,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAM,GAC1D,cAAc,EAAE,CAiBlB;AAED;;4BAE4B;AAC5B,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,GAAG,EAAE,MAAM,GACV,cAAc,GAAG,SAAS,CAS5B"}
@@ -0,0 +1,68 @@
1
+ /** Built-in defaults for the top 4 servers (codex Round-1 NICE #1).
2
+ * Order in this object is the tie-break order for extension claims
3
+ * among built-ins. Insertion order is stable in modern V8/Spidermonkey
4
+ * for string keys. */
5
+ export const BUILTIN_DEFAULTS = {
6
+ typescript: {
7
+ command: "typescript-language-server",
8
+ args: ["--stdio"],
9
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
10
+ },
11
+ rust: {
12
+ command: "rust-analyzer",
13
+ args: [],
14
+ extensions: [".rs"],
15
+ },
16
+ python: {
17
+ command: "pyright-langserver",
18
+ args: ["--stdio"],
19
+ extensions: [".py", ".pyi"],
20
+ },
21
+ go: {
22
+ command: "gopls",
23
+ args: ["serve"],
24
+ extensions: [".go"],
25
+ },
26
+ };
27
+ /** Merges user-provided servers with built-in defaults.
28
+ *
29
+ * Per-name overlay: a user entry by the same name shallow-merges
30
+ * with the built-in (user fields win). Disabling a built-in is
31
+ * `servers.typescript = { enabled: false }`.
32
+ *
33
+ * Output order: user-defined names first (in user insertion order),
34
+ * then any built-ins not overridden by name (in built-in order).
35
+ * `enabled: false` entries are NOT filtered here — they're surfaced
36
+ * to the caller (e.g. `doctor`) so the disable is visible. */
37
+ export function resolveServers(builtIns = BUILTIN_DEFAULTS, userServers = {}) {
38
+ const out = [];
39
+ const seen = new Set();
40
+ for (const [name, userCfg] of Object.entries(userServers)) {
41
+ seen.add(name);
42
+ const builtIn = builtIns[name];
43
+ const merged = builtIn ? { ...builtIn, ...userCfg } : userCfg;
44
+ out.push({ name, config: merged });
45
+ }
46
+ for (const [name, cfg] of Object.entries(builtIns)) {
47
+ if (seen.has(name))
48
+ continue;
49
+ out.push({ name, config: cfg });
50
+ }
51
+ return out;
52
+ }
53
+ /** Picks the first ENABLED server whose `extensions` covers `ext`.
54
+ * Returns undefined when no server claims the extension OR when all
55
+ * matches are disabled. */
56
+ export function pickServerForExtension(servers, ext) {
57
+ const norm = ext.toLowerCase();
58
+ for (const s of servers) {
59
+ if (s.config.enabled === false)
60
+ continue;
61
+ for (const e of s.config.extensions) {
62
+ if (e.toLowerCase() === norm)
63
+ return s;
64
+ }
65
+ }
66
+ return undefined;
67
+ }
68
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lsp/config.ts"],"names":[],"mappings":"AAcA;;;uBAGuB;AACvB,MAAM,CAAC,MAAM,gBAAgB,GAA8C;IACzE,UAAU,EAAE;QACV,OAAO,EAAE,4BAA4B;QACrC,IAAI,EAAE,CAAC,SAAS,CAAC;QACjB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAC3D;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,eAAe;QACxB,IAAI,EAAE,EAAE;QACR,UAAU,EAAE,CAAC,KAAK,CAAC;KACpB;IACD,MAAM,EAAE;QACN,OAAO,EAAE,oBAAoB;QAC7B,IAAI,EAAE,CAAC,SAAS,CAAC;QACjB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;KAC5B;IACD,EAAE,EAAE;QACF,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,CAAC,OAAO,CAAC;QACf,UAAU,EAAE,CAAC,KAAK,CAAC;KACpB;CACF,CAAC;AAEF;;;;;;;;;+DAS+D;AAC/D,MAAM,UAAU,cAAc,CAC5B,WAAsD,gBAAgB,EACtE,cAAyD,EAAE;IAE3D,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1D,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACf,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAoB,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/E,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7B,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;4BAE4B;AAC5B,MAAM,UAAU,sBAAsB,CACpC,OAAkC,EAClC,GAAW;IAEX,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QACzC,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACpC,IAAI,CAAC,CAAC,WAAW,EAAE,KAAK,IAAI;gBAAE,OAAO,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** Returns the absolute path of `command` resolved against `cwd`'s
2
+ * project-local bin dirs first, then PATH. Returns `null` (cached)
3
+ * when nothing was found. */
4
+ export declare function detectBinary(command: string, cwd: string, env?: NodeJS.ProcessEnv): string | null;
5
+ /** Test seam — clears the cache. */
6
+ export declare function clearDetectCache(): void;
7
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/lsp/detect.ts"],"names":[],"mappings":"AAmBA;;8BAE8B;AAC9B,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,IAAI,CA8B9G;AAyBD,oCAAoC;AACpC,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * (4.2) Binary detection (codex Round-1 SHOULD-FIX #3).
3
+ *
4
+ * Resolution order per (cwd, command):
5
+ * 1. `<cwd>/node_modules/.bin/<command>[.exe|.cmd|.bat on Windows]`
6
+ * 2. `<cwd>/.venv/bin/<command>` (POSIX)
7
+ * 3. Each `PATH` entry, with Windows suffix expansion.
8
+ *
9
+ * Cached per `(cwd, command, PATH)` so a `doctor` run that touches
10
+ * every default doesn't repeat work. Cache lifetime is the host
11
+ * instance; explicit `clearDetectCache()` for tests.
12
+ */
13
+ import { existsSync, statSync } from "node:fs";
14
+ import { delimiter as PATH_SEP, join } from "node:path";
15
+ const cache = new Map();
16
+ const WIN_SUFFIXES = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""];
17
+ /** Returns the absolute path of `command` resolved against `cwd`'s
18
+ * project-local bin dirs first, then PATH. Returns `null` (cached)
19
+ * when nothing was found. */
20
+ export function detectBinary(command, cwd, env = process.env) {
21
+ // Absolute path bypass — caller already gave us a resolved binary.
22
+ if (isAbsolute(command)) {
23
+ return fileExistsExecutable(command) ? command : null;
24
+ }
25
+ const path = env.PATH ?? env.Path ?? "";
26
+ const key = `${cwd}\u0000${command}\u0000${path}`;
27
+ const cached = cache.get(key);
28
+ if (cached !== undefined)
29
+ return cached;
30
+ const candidates = [];
31
+ // Project-local bin dirs.
32
+ candidates.push(...expand(join(cwd, "node_modules", ".bin"), command));
33
+ if (process.platform !== "win32") {
34
+ candidates.push(join(cwd, ".venv", "bin", command));
35
+ }
36
+ // PATH entries.
37
+ for (const dir of path.split(PATH_SEP)) {
38
+ if (!dir)
39
+ continue;
40
+ candidates.push(...expand(dir, command));
41
+ }
42
+ for (const c of candidates) {
43
+ if (fileExistsExecutable(c)) {
44
+ cache.set(key, c);
45
+ return c;
46
+ }
47
+ }
48
+ cache.set(key, null);
49
+ return null;
50
+ }
51
+ /** Windows: try every suffix; POSIX: just the bare name. */
52
+ function expand(dir, command) {
53
+ return WIN_SUFFIXES.map((suf) => join(dir, command + suf));
54
+ }
55
+ /** Bun's `existsSync` follows symlinks. We additionally require the
56
+ * entry to be a file (not a directory) — defends against a weird
57
+ * `node_modules/.bin/<name>` being a folder. */
58
+ function fileExistsExecutable(p) {
59
+ if (!existsSync(p))
60
+ return false;
61
+ try {
62
+ const st = statSync(p);
63
+ return st.isFile();
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ function isAbsolute(p) {
70
+ if (process.platform === "win32")
71
+ return /^[a-zA-Z]:[\\/]/.test(p) || p.startsWith("\\\\");
72
+ return p.startsWith("/");
73
+ }
74
+ /** Test seam — clears the cache. */
75
+ export function clearDetectCache() {
76
+ cache.clear();
77
+ }
78
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/lsp/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * (4.2) LSP error taxonomy. Distinct codes per failure mode so the tool
3
+ * layer renders an actionable message without parsing free-text.
4
+ */
5
+ export type LspErrorCode = "BINARY_MISSING" | "START_TIMEOUT" | "REQUEST_TIMEOUT" | "REQUEST_FAILED" | "SERVER_CRASHED" | "SERVER_STICKY_FAILED" | "UNSUPPORTED_OP" | "MAX_INSTANCES" | "FILE_TOO_LARGE" | "NO_SERVER_FOR_EXTENSION" | "DISABLED";
6
+ export declare class LspError extends Error {
7
+ readonly code: LspErrorCode;
8
+ readonly cause?: unknown;
9
+ constructor(code: LspErrorCode, message: string, cause?: unknown);
10
+ }
11
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lsp/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,YAAY,GACpB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,gBAAgB,GAChB,sBAAsB,GACtB,gBAAgB,GAChB,eAAe,GACf,gBAAgB,GAChB,yBAAyB,GACzB,UAAU,CAAC;AAEf,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,SAAkB,KAAK,CAAC,EAAE,OAAO,CAAC;gBACtB,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAMjE"}
@@ -0,0 +1,11 @@
1
+ export class LspError extends Error {
2
+ code;
3
+ cause;
4
+ constructor(code, message, cause) {
5
+ super(message);
6
+ this.name = "LspError";
7
+ this.code = code;
8
+ this.cause = cause;
9
+ }
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lsp/errors.ts"],"names":[],"mappings":"AAiBA,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAe;IACV,KAAK,CAAW;IAClC,YAAY,IAAkB,EAAE,OAAe,EAAE,KAAe;QAC9D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}