onadit 0.0.1 → 0.1.0-beta.45

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 (1085) hide show
  1. package/README.dev.md +124 -0
  2. package/README.md +194 -2
  3. package/dist/src/auth/keychain.d.ts +42 -0
  4. package/dist/src/auth/keychain.d.ts.map +1 -0
  5. package/dist/src/auth/keychain.js +177 -0
  6. package/dist/src/auth/keychain.js.map +1 -0
  7. package/dist/src/auth/middleware.d.ts +21 -0
  8. package/dist/src/auth/middleware.d.ts.map +1 -0
  9. package/dist/src/auth/middleware.js +93 -0
  10. package/dist/src/auth/middleware.js.map +1 -0
  11. package/dist/src/auth/rate-limit.d.ts +16 -0
  12. package/dist/src/auth/rate-limit.d.ts.map +1 -0
  13. package/dist/src/auth/rate-limit.js +38 -0
  14. package/dist/src/auth/rate-limit.js.map +1 -0
  15. package/dist/src/auth/rotation.d.ts +67 -0
  16. package/dist/src/auth/rotation.d.ts.map +1 -0
  17. package/dist/src/auth/rotation.js +190 -0
  18. package/dist/src/auth/rotation.js.map +1 -0
  19. package/dist/src/backfill/project-context-batch-constructor.d.ts +127 -0
  20. package/dist/src/backfill/project-context-batch-constructor.d.ts.map +1 -0
  21. package/dist/src/backfill/project-context-batch-constructor.js +210 -0
  22. package/dist/src/backfill/project-context-batch-constructor.js.map +1 -0
  23. package/dist/src/capture/assistant-text-lookup.d.ts +31 -0
  24. package/dist/src/capture/assistant-text-lookup.d.ts.map +1 -0
  25. package/dist/src/capture/assistant-text-lookup.js +222 -0
  26. package/dist/src/capture/assistant-text-lookup.js.map +1 -0
  27. package/dist/src/capture/auto-capture.d.ts +322 -0
  28. package/dist/src/capture/auto-capture.d.ts.map +1 -0
  29. package/dist/src/capture/auto-capture.js +1167 -0
  30. package/dist/src/capture/auto-capture.js.map +1 -0
  31. package/dist/src/capture/auto-repair.d.ts +125 -0
  32. package/dist/src/capture/auto-repair.d.ts.map +1 -0
  33. package/dist/src/capture/auto-repair.js +280 -0
  34. package/dist/src/capture/auto-repair.js.map +1 -0
  35. package/dist/src/capture/batch-budget.d.ts +90 -0
  36. package/dist/src/capture/batch-budget.d.ts.map +1 -0
  37. package/dist/src/capture/batch-budget.js +148 -0
  38. package/dist/src/capture/batch-budget.js.map +1 -0
  39. package/dist/src/capture/claude-cli-triage-provider.d.ts +28 -0
  40. package/dist/src/capture/claude-cli-triage-provider.d.ts.map +1 -0
  41. package/dist/src/capture/claude-cli-triage-provider.js +101 -0
  42. package/dist/src/capture/claude-cli-triage-provider.js.map +1 -0
  43. package/dist/src/capture/codex-cli-triage-provider.d.ts +17 -0
  44. package/dist/src/capture/codex-cli-triage-provider.d.ts.map +1 -0
  45. package/dist/src/capture/codex-cli-triage-provider.js +91 -0
  46. package/dist/src/capture/codex-cli-triage-provider.js.map +1 -0
  47. package/dist/src/capture/cursor-capture.d.ts +89 -0
  48. package/dist/src/capture/cursor-capture.d.ts.map +1 -0
  49. package/dist/src/capture/cursor-capture.js +121 -0
  50. package/dist/src/capture/cursor-capture.js.map +1 -0
  51. package/dist/src/capture/observability.d.ts +131 -0
  52. package/dist/src/capture/observability.d.ts.map +1 -0
  53. package/dist/src/capture/observability.js +181 -0
  54. package/dist/src/capture/observability.js.map +1 -0
  55. package/dist/src/capture/openai-triage-provider.d.ts +92 -0
  56. package/dist/src/capture/openai-triage-provider.d.ts.map +1 -0
  57. package/dist/src/capture/openai-triage-provider.js +267 -0
  58. package/dist/src/capture/openai-triage-provider.js.map +1 -0
  59. package/dist/src/capture/recover-quarantine.d.ts +273 -0
  60. package/dist/src/capture/recover-quarantine.d.ts.map +1 -0
  61. package/dist/src/capture/recover-quarantine.js +581 -0
  62. package/dist/src/capture/recover-quarantine.js.map +1 -0
  63. package/dist/src/capture/review-queue-index.d.ts +51 -0
  64. package/dist/src/capture/review-queue-index.d.ts.map +1 -0
  65. package/dist/src/capture/review-queue-index.js +204 -0
  66. package/dist/src/capture/review-queue-index.js.map +1 -0
  67. package/dist/src/capture/review-queue.d.ts +47 -0
  68. package/dist/src/capture/review-queue.d.ts.map +1 -0
  69. package/dist/src/capture/review-queue.js +116 -0
  70. package/dist/src/capture/review-queue.js.map +1 -0
  71. package/dist/src/capture/sources.d.ts +53 -0
  72. package/dist/src/capture/sources.d.ts.map +1 -0
  73. package/dist/src/capture/sources.js +55 -0
  74. package/dist/src/capture/sources.js.map +1 -0
  75. package/dist/src/capture/stored-statements.d.ts +9 -0
  76. package/dist/src/capture/stored-statements.d.ts.map +1 -0
  77. package/dist/src/capture/stored-statements.js +63 -0
  78. package/dist/src/capture/stored-statements.js.map +1 -0
  79. package/dist/src/capture/triage-classification.d.ts +92 -0
  80. package/dist/src/capture/triage-classification.d.ts.map +1 -0
  81. package/dist/src/capture/triage-classification.js +94 -0
  82. package/dist/src/capture/triage-classification.js.map +1 -0
  83. package/dist/src/capture/triage-lane.d.ts +39 -0
  84. package/dist/src/capture/triage-lane.d.ts.map +1 -0
  85. package/dist/src/capture/triage-lane.js +217 -0
  86. package/dist/src/capture/triage-lane.js.map +1 -0
  87. package/dist/src/capture/triage-provider-factory.d.ts +36 -0
  88. package/dist/src/capture/triage-provider-factory.d.ts.map +1 -0
  89. package/dist/src/capture/triage-provider-factory.js +55 -0
  90. package/dist/src/capture/triage-provider-factory.js.map +1 -0
  91. package/dist/src/capture/triage-provider.d.ts +82 -0
  92. package/dist/src/capture/triage-provider.d.ts.map +1 -0
  93. package/dist/src/capture/triage-provider.js +126 -0
  94. package/dist/src/capture/triage-provider.js.map +1 -0
  95. package/dist/src/capture/triage.d.ts +30 -0
  96. package/dist/src/capture/triage.d.ts.map +1 -0
  97. package/dist/src/capture/triage.js +50 -0
  98. package/dist/src/capture/triage.js.map +1 -0
  99. package/dist/src/capture/user-statements-recheck.d.ts +22 -0
  100. package/dist/src/capture/user-statements-recheck.d.ts.map +1 -0
  101. package/dist/src/capture/user-statements-recheck.js +181 -0
  102. package/dist/src/capture/user-statements-recheck.js.map +1 -0
  103. package/dist/src/capture/user-statements.d.ts +84 -0
  104. package/dist/src/capture/user-statements.d.ts.map +1 -0
  105. package/dist/src/capture/user-statements.js +617 -0
  106. package/dist/src/capture/user-statements.js.map +1 -0
  107. package/dist/src/cli/agent-homes.d.ts +15 -0
  108. package/dist/src/cli/agent-homes.d.ts.map +1 -0
  109. package/dist/src/cli/agent-homes.js +45 -0
  110. package/dist/src/cli/agent-homes.js.map +1 -0
  111. package/dist/src/cli/commands/backfill.d.ts +3 -0
  112. package/dist/src/cli/commands/backfill.d.ts.map +1 -0
  113. package/dist/src/cli/commands/backfill.js +1379 -0
  114. package/dist/src/cli/commands/backfill.js.map +1 -0
  115. package/dist/src/cli/commands/brief.d.ts +12 -0
  116. package/dist/src/cli/commands/brief.d.ts.map +1 -0
  117. package/dist/src/cli/commands/brief.js +131 -0
  118. package/dist/src/cli/commands/brief.js.map +1 -0
  119. package/dist/src/cli/commands/bulk-ingest.d.ts +3 -0
  120. package/dist/src/cli/commands/bulk-ingest.d.ts.map +1 -0
  121. package/dist/src/cli/commands/bulk-ingest.js +126 -0
  122. package/dist/src/cli/commands/bulk-ingest.js.map +1 -0
  123. package/dist/src/cli/commands/capture-recover.d.ts +40 -0
  124. package/dist/src/cli/commands/capture-recover.d.ts.map +1 -0
  125. package/dist/src/cli/commands/capture-recover.js +194 -0
  126. package/dist/src/cli/commands/capture-recover.js.map +1 -0
  127. package/dist/src/cli/commands/capture.d.ts +12 -0
  128. package/dist/src/cli/commands/capture.d.ts.map +1 -0
  129. package/dist/src/cli/commands/capture.js +304 -0
  130. package/dist/src/cli/commands/capture.js.map +1 -0
  131. package/dist/src/cli/commands/chunk-backfill.d.ts +13 -0
  132. package/dist/src/cli/commands/chunk-backfill.d.ts.map +1 -0
  133. package/dist/src/cli/commands/chunk-backfill.js +157 -0
  134. package/dist/src/cli/commands/chunk-backfill.js.map +1 -0
  135. package/dist/src/cli/commands/compact.d.ts +3 -0
  136. package/dist/src/cli/commands/compact.d.ts.map +1 -0
  137. package/dist/src/cli/commands/compact.js +70 -0
  138. package/dist/src/cli/commands/compact.js.map +1 -0
  139. package/dist/src/cli/commands/cursor-probe.d.ts +20 -0
  140. package/dist/src/cli/commands/cursor-probe.d.ts.map +1 -0
  141. package/dist/src/cli/commands/cursor-probe.js +162 -0
  142. package/dist/src/cli/commands/cursor-probe.js.map +1 -0
  143. package/dist/src/cli/commands/doctor.d.ts +6 -0
  144. package/dist/src/cli/commands/doctor.d.ts.map +1 -0
  145. package/dist/src/cli/commands/doctor.js +259 -0
  146. package/dist/src/cli/commands/doctor.js.map +1 -0
  147. package/dist/src/cli/commands/feedback.d.ts +34 -0
  148. package/dist/src/cli/commands/feedback.d.ts.map +1 -0
  149. package/dist/src/cli/commands/feedback.js +214 -0
  150. package/dist/src/cli/commands/feedback.js.map +1 -0
  151. package/dist/src/cli/commands/hooks-install.d.ts +66 -0
  152. package/dist/src/cli/commands/hooks-install.d.ts.map +1 -0
  153. package/dist/src/cli/commands/hooks-install.js +228 -0
  154. package/dist/src/cli/commands/hooks-install.js.map +1 -0
  155. package/dist/src/cli/commands/import.d.ts +19 -0
  156. package/dist/src/cli/commands/import.d.ts.map +1 -0
  157. package/dist/src/cli/commands/import.js +258 -0
  158. package/dist/src/cli/commands/import.js.map +1 -0
  159. package/dist/src/cli/commands/ingest.d.ts +3 -0
  160. package/dist/src/cli/commands/ingest.d.ts.map +1 -0
  161. package/dist/src/cli/commands/ingest.js +80 -0
  162. package/dist/src/cli/commands/ingest.js.map +1 -0
  163. package/dist/src/cli/commands/mcp-install.d.ts +65 -0
  164. package/dist/src/cli/commands/mcp-install.d.ts.map +1 -0
  165. package/dist/src/cli/commands/mcp-install.js +306 -0
  166. package/dist/src/cli/commands/mcp-install.js.map +1 -0
  167. package/dist/src/cli/commands/menubar.d.ts +127 -0
  168. package/dist/src/cli/commands/menubar.d.ts.map +1 -0
  169. package/dist/src/cli/commands/menubar.js +585 -0
  170. package/dist/src/cli/commands/menubar.js.map +1 -0
  171. package/dist/src/cli/commands/onboard-first-run.d.ts +5 -0
  172. package/dist/src/cli/commands/onboard-first-run.d.ts.map +1 -0
  173. package/dist/src/cli/commands/onboard-first-run.js +156 -0
  174. package/dist/src/cli/commands/onboard-first-run.js.map +1 -0
  175. package/dist/src/cli/commands/onboard.d.ts +336 -0
  176. package/dist/src/cli/commands/onboard.d.ts.map +1 -0
  177. package/dist/src/cli/commands/onboard.js +1873 -0
  178. package/dist/src/cli/commands/onboard.js.map +1 -0
  179. package/dist/src/cli/commands/rebuild.d.ts +12 -0
  180. package/dist/src/cli/commands/rebuild.d.ts.map +1 -0
  181. package/dist/src/cli/commands/rebuild.js +167 -0
  182. package/dist/src/cli/commands/rebuild.js.map +1 -0
  183. package/dist/src/cli/commands/reconcile.d.ts +3 -0
  184. package/dist/src/cli/commands/reconcile.d.ts.map +1 -0
  185. package/dist/src/cli/commands/reconcile.js +68 -0
  186. package/dist/src/cli/commands/reconcile.js.map +1 -0
  187. package/dist/src/cli/commands/reindex.d.ts +3 -0
  188. package/dist/src/cli/commands/reindex.d.ts.map +1 -0
  189. package/dist/src/cli/commands/reindex.js +66 -0
  190. package/dist/src/cli/commands/reindex.js.map +1 -0
  191. package/dist/src/cli/commands/review.d.ts +13 -0
  192. package/dist/src/cli/commands/review.d.ts.map +1 -0
  193. package/dist/src/cli/commands/review.js +401 -0
  194. package/dist/src/cli/commands/review.js.map +1 -0
  195. package/dist/src/cli/commands/save.d.ts +3 -0
  196. package/dist/src/cli/commands/save.d.ts.map +1 -0
  197. package/dist/src/cli/commands/save.js +111 -0
  198. package/dist/src/cli/commands/save.js.map +1 -0
  199. package/dist/src/cli/commands/search.d.ts +37 -0
  200. package/dist/src/cli/commands/search.d.ts.map +1 -0
  201. package/dist/src/cli/commands/search.js +118 -0
  202. package/dist/src/cli/commands/search.js.map +1 -0
  203. package/dist/src/cli/commands/setup.d.ts +30 -0
  204. package/dist/src/cli/commands/setup.d.ts.map +1 -0
  205. package/dist/src/cli/commands/setup.js +122 -0
  206. package/dist/src/cli/commands/setup.js.map +1 -0
  207. package/dist/src/cli/commands/stats.d.ts +3 -0
  208. package/dist/src/cli/commands/stats.d.ts.map +1 -0
  209. package/dist/src/cli/commands/stats.js +42 -0
  210. package/dist/src/cli/commands/stats.js.map +1 -0
  211. package/dist/src/cli/commands/status.d.ts +17 -0
  212. package/dist/src/cli/commands/status.d.ts.map +1 -0
  213. package/dist/src/cli/commands/status.js +206 -0
  214. package/dist/src/cli/commands/status.js.map +1 -0
  215. package/dist/src/cli/commands/token-issue.d.ts +3 -0
  216. package/dist/src/cli/commands/token-issue.d.ts.map +1 -0
  217. package/dist/src/cli/commands/token-issue.js +33 -0
  218. package/dist/src/cli/commands/token-issue.js.map +1 -0
  219. package/dist/src/cli/commands/triage.d.ts +3 -0
  220. package/dist/src/cli/commands/triage.d.ts.map +1 -0
  221. package/dist/src/cli/commands/triage.js +127 -0
  222. package/dist/src/cli/commands/triage.js.map +1 -0
  223. package/dist/src/cli/commands/uninstall.d.ts +85 -0
  224. package/dist/src/cli/commands/uninstall.d.ts.map +1 -0
  225. package/dist/src/cli/commands/uninstall.js +512 -0
  226. package/dist/src/cli/commands/uninstall.js.map +1 -0
  227. package/dist/src/cli/commands/update.d.ts +105 -0
  228. package/dist/src/cli/commands/update.d.ts.map +1 -0
  229. package/dist/src/cli/commands/update.js +556 -0
  230. package/dist/src/cli/commands/update.js.map +1 -0
  231. package/dist/src/cli/default-config-path.d.ts +15 -0
  232. package/dist/src/cli/default-config-path.d.ts.map +1 -0
  233. package/dist/src/cli/default-config-path.js +28 -0
  234. package/dist/src/cli/default-config-path.js.map +1 -0
  235. package/dist/src/cli/feedback/feedback-config.d.ts +67 -0
  236. package/dist/src/cli/feedback/feedback-config.d.ts.map +1 -0
  237. package/dist/src/cli/feedback/feedback-config.js +169 -0
  238. package/dist/src/cli/feedback/feedback-config.js.map +1 -0
  239. package/dist/src/cli/feedback/feedback-history.d.ts +11 -0
  240. package/dist/src/cli/feedback/feedback-history.d.ts.map +1 -0
  241. package/dist/src/cli/feedback/feedback-history.js +145 -0
  242. package/dist/src/cli/feedback/feedback-history.js.map +1 -0
  243. package/dist/src/cli/feedback/feedback-payload.d.ts +74 -0
  244. package/dist/src/cli/feedback/feedback-payload.d.ts.map +1 -0
  245. package/dist/src/cli/feedback/feedback-payload.js +10 -0
  246. package/dist/src/cli/feedback/feedback-payload.js.map +1 -0
  247. package/dist/src/cli/feedback/feedback-relay.d.ts +15 -0
  248. package/dist/src/cli/feedback/feedback-relay.d.ts.map +1 -0
  249. package/dist/src/cli/feedback/feedback-relay.js +47 -0
  250. package/dist/src/cli/feedback/feedback-relay.js.map +1 -0
  251. package/dist/src/cli/feedback/feedback-status.d.ts +11 -0
  252. package/dist/src/cli/feedback/feedback-status.d.ts.map +1 -0
  253. package/dist/src/cli/feedback/feedback-status.js +122 -0
  254. package/dist/src/cli/feedback/feedback-status.js.map +1 -0
  255. package/dist/src/cli/feedback/invite.d.ts +17 -0
  256. package/dist/src/cli/feedback/invite.d.ts.map +1 -0
  257. package/dist/src/cli/feedback/invite.js +73 -0
  258. package/dist/src/cli/feedback/invite.js.map +1 -0
  259. package/dist/src/cli/feedback/relay-secret-store.d.ts +32 -0
  260. package/dist/src/cli/feedback/relay-secret-store.d.ts.map +1 -0
  261. package/dist/src/cli/feedback/relay-secret-store.js +137 -0
  262. package/dist/src/cli/feedback/relay-secret-store.js.map +1 -0
  263. package/dist/src/cli/hooks-writers/claude-code-policy-script.d.ts +35 -0
  264. package/dist/src/cli/hooks-writers/claude-code-policy-script.d.ts.map +1 -0
  265. package/dist/src/cli/hooks-writers/claude-code-policy-script.js +122 -0
  266. package/dist/src/cli/hooks-writers/claude-code-policy-script.js.map +1 -0
  267. package/dist/src/cli/hooks-writers/claude-code.d.ts +63 -0
  268. package/dist/src/cli/hooks-writers/claude-code.d.ts.map +1 -0
  269. package/dist/src/cli/hooks-writers/claude-code.js +289 -0
  270. package/dist/src/cli/hooks-writers/claude-code.js.map +1 -0
  271. package/dist/src/cli/hooks-writers/codex.d.ts +16 -0
  272. package/dist/src/cli/hooks-writers/codex.d.ts.map +1 -0
  273. package/dist/src/cli/hooks-writers/codex.js +17 -0
  274. package/dist/src/cli/hooks-writers/codex.js.map +1 -0
  275. package/dist/src/cli/hooks-writers/errors.d.ts +16 -0
  276. package/dist/src/cli/hooks-writers/errors.d.ts.map +1 -0
  277. package/dist/src/cli/hooks-writers/errors.js +24 -0
  278. package/dist/src/cli/hooks-writers/errors.js.map +1 -0
  279. package/dist/src/cli/hooks-writers/index.d.ts +23 -0
  280. package/dist/src/cli/hooks-writers/index.d.ts.map +1 -0
  281. package/dist/src/cli/hooks-writers/index.js +34 -0
  282. package/dist/src/cli/hooks-writers/index.js.map +1 -0
  283. package/dist/src/cli/hooks-writers/state.d.ts +43 -0
  284. package/dist/src/cli/hooks-writers/state.d.ts.map +1 -0
  285. package/dist/src/cli/hooks-writers/state.js +225 -0
  286. package/dist/src/cli/hooks-writers/state.js.map +1 -0
  287. package/dist/src/cli/hooks-writers/types.d.ts +28 -0
  288. package/dist/src/cli/hooks-writers/types.d.ts.map +1 -0
  289. package/dist/src/cli/hooks-writers/types.js +8 -0
  290. package/dist/src/cli/hooks-writers/types.js.map +1 -0
  291. package/dist/src/cli/http-client.d.ts +128 -0
  292. package/dist/src/cli/http-client.d.ts.map +1 -0
  293. package/dist/src/cli/http-client.js +401 -0
  294. package/dist/src/cli/http-client.js.map +1 -0
  295. package/dist/src/cli/index.d.ts +4 -0
  296. package/dist/src/cli/index.d.ts.map +1 -0
  297. package/dist/src/cli/index.js +99 -0
  298. package/dist/src/cli/index.js.map +1 -0
  299. package/dist/src/cli/job-poller.d.ts +13 -0
  300. package/dist/src/cli/job-poller.d.ts.map +1 -0
  301. package/dist/src/cli/job-poller.js +29 -0
  302. package/dist/src/cli/job-poller.js.map +1 -0
  303. package/dist/src/cli/mcp-config-writers/codex-toml.d.ts +20 -0
  304. package/dist/src/cli/mcp-config-writers/codex-toml.d.ts.map +1 -0
  305. package/dist/src/cli/mcp-config-writers/codex-toml.js +918 -0
  306. package/dist/src/cli/mcp-config-writers/codex-toml.js.map +1 -0
  307. package/dist/src/cli/mcp-config-writers/earlier-name-restrictions.d.ts +11 -0
  308. package/dist/src/cli/mcp-config-writers/earlier-name-restrictions.d.ts.map +1 -0
  309. package/dist/src/cli/mcp-config-writers/earlier-name-restrictions.js +152 -0
  310. package/dist/src/cli/mcp-config-writers/earlier-name-restrictions.js.map +1 -0
  311. package/dist/src/cli/mcp-config-writers/errors.d.ts +17 -0
  312. package/dist/src/cli/mcp-config-writers/errors.d.ts.map +1 -0
  313. package/dist/src/cli/mcp-config-writers/errors.js +13 -0
  314. package/dist/src/cli/mcp-config-writers/errors.js.map +1 -0
  315. package/dist/src/cli/mcp-config-writers/index.d.ts +28 -0
  316. package/dist/src/cli/mcp-config-writers/index.d.ts.map +1 -0
  317. package/dist/src/cli/mcp-config-writers/index.js +70 -0
  318. package/dist/src/cli/mcp-config-writers/index.js.map +1 -0
  319. package/dist/src/cli/mcp-config-writers/json-config.d.ts +20 -0
  320. package/dist/src/cli/mcp-config-writers/json-config.d.ts.map +1 -0
  321. package/dist/src/cli/mcp-config-writers/json-config.js +301 -0
  322. package/dist/src/cli/mcp-config-writers/json-config.js.map +1 -0
  323. package/dist/src/cli/mcp-config-writers/left-in-folder.d.ts +18 -0
  324. package/dist/src/cli/mcp-config-writers/left-in-folder.d.ts.map +1 -0
  325. package/dist/src/cli/mcp-config-writers/left-in-folder.js +140 -0
  326. package/dist/src/cli/mcp-config-writers/left-in-folder.js.map +1 -0
  327. package/dist/src/cli/mcp-config-writers/redact.d.ts +28 -0
  328. package/dist/src/cli/mcp-config-writers/redact.d.ts.map +1 -0
  329. package/dist/src/cli/mcp-config-writers/redact.js +48 -0
  330. package/dist/src/cli/mcp-config-writers/redact.js.map +1 -0
  331. package/dist/src/cli/mcp-config-writers/types.d.ts +46 -0
  332. package/dist/src/cli/mcp-config-writers/types.d.ts.map +1 -0
  333. package/dist/src/cli/mcp-config-writers/types.js +5 -0
  334. package/dist/src/cli/mcp-config-writers/types.js.map +1 -0
  335. package/dist/src/cli/output.d.ts +8 -0
  336. package/dist/src/cli/output.d.ts.map +1 -0
  337. package/dist/src/cli/output.js +34 -0
  338. package/dist/src/cli/output.js.map +1 -0
  339. package/dist/src/cli/postinstall-menubar.d.ts +38 -0
  340. package/dist/src/cli/postinstall-menubar.d.ts.map +1 -0
  341. package/dist/src/cli/postinstall-menubar.js +139 -0
  342. package/dist/src/cli/postinstall-menubar.js.map +1 -0
  343. package/dist/src/cli/status/friend-header.d.ts +61 -0
  344. package/dist/src/cli/status/friend-header.d.ts.map +1 -0
  345. package/dist/src/cli/status/friend-header.js +708 -0
  346. package/dist/src/cli/status/friend-header.js.map +1 -0
  347. package/dist/src/cli/status/local-signals.d.ts +89 -0
  348. package/dist/src/cli/status/local-signals.d.ts.map +1 -0
  349. package/dist/src/cli/status/local-signals.js +194 -0
  350. package/dist/src/cli/status/local-signals.js.map +1 -0
  351. package/dist/src/cli/token.d.ts +37 -0
  352. package/dist/src/cli/token.d.ts.map +1 -0
  353. package/dist/src/cli/token.js +105 -0
  354. package/dist/src/cli/token.js.map +1 -0
  355. package/dist/src/cli/ui.d.ts +47 -0
  356. package/dist/src/cli/ui.d.ts.map +1 -0
  357. package/dist/src/cli/ui.js +166 -0
  358. package/dist/src/cli/ui.js.map +1 -0
  359. package/dist/src/cli/uninstall/mcp-uninstall.d.ts +33 -0
  360. package/dist/src/cli/uninstall/mcp-uninstall.d.ts.map +1 -0
  361. package/dist/src/cli/uninstall/mcp-uninstall.js +116 -0
  362. package/dist/src/cli/uninstall/mcp-uninstall.js.map +1 -0
  363. package/dist/src/config/loader.d.ts +9 -0
  364. package/dist/src/config/loader.d.ts.map +1 -0
  365. package/dist/src/config/loader.js +73 -0
  366. package/dist/src/config/loader.js.map +1 -0
  367. package/dist/src/config/schema.d.ts +956 -0
  368. package/dist/src/config/schema.d.ts.map +1 -0
  369. package/dist/src/config/schema.js +339 -0
  370. package/dist/src/config/schema.js.map +1 -0
  371. package/dist/src/diagnostics/claude-preflight.d.ts +35 -0
  372. package/dist/src/diagnostics/claude-preflight.d.ts.map +1 -0
  373. package/dist/src/diagnostics/claude-preflight.js +90 -0
  374. package/dist/src/diagnostics/claude-preflight.js.map +1 -0
  375. package/dist/src/diagnostics/codex-preflight.d.ts +33 -0
  376. package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -0
  377. package/dist/src/diagnostics/codex-preflight.js +99 -0
  378. package/dist/src/diagnostics/codex-preflight.js.map +1 -0
  379. package/dist/src/diagnostics/doctor.d.ts +125 -0
  380. package/dist/src/diagnostics/doctor.d.ts.map +1 -0
  381. package/dist/src/diagnostics/doctor.js +450 -0
  382. package/dist/src/diagnostics/doctor.js.map +1 -0
  383. package/dist/src/diagnostics/install-layout.d.ts +40 -0
  384. package/dist/src/diagnostics/install-layout.d.ts.map +1 -0
  385. package/dist/src/diagnostics/install-layout.js +55 -0
  386. package/dist/src/diagnostics/install-layout.js.map +1 -0
  387. package/dist/src/diagnostics/memory-coverage.d.ts +54 -0
  388. package/dist/src/diagnostics/memory-coverage.d.ts.map +1 -0
  389. package/dist/src/diagnostics/memory-coverage.js +272 -0
  390. package/dist/src/diagnostics/memory-coverage.js.map +1 -0
  391. package/dist/src/diagnostics/notify.d.ts +107 -0
  392. package/dist/src/diagnostics/notify.d.ts.map +1 -0
  393. package/dist/src/diagnostics/notify.js +217 -0
  394. package/dist/src/diagnostics/notify.js.map +1 -0
  395. package/dist/src/diagnostics/repair-prompt.d.ts +49 -0
  396. package/dist/src/diagnostics/repair-prompt.d.ts.map +1 -0
  397. package/dist/src/diagnostics/repair-prompt.js +223 -0
  398. package/dist/src/diagnostics/repair-prompt.js.map +1 -0
  399. package/dist/src/ingestion/bulk-ingest.d.ts +11 -0
  400. package/dist/src/ingestion/bulk-ingest.d.ts.map +1 -0
  401. package/dist/src/ingestion/bulk-ingest.js +11 -0
  402. package/dist/src/ingestion/bulk-ingest.js.map +1 -0
  403. package/dist/src/ingestion/chunk-meta.d.ts +85 -0
  404. package/dist/src/ingestion/chunk-meta.d.ts.map +1 -0
  405. package/dist/src/ingestion/chunk-meta.js +167 -0
  406. package/dist/src/ingestion/chunk-meta.js.map +1 -0
  407. package/dist/src/ingestion/chunk-text.d.ts +39 -0
  408. package/dist/src/ingestion/chunk-text.d.ts.map +1 -0
  409. package/dist/src/ingestion/chunk-text.js +114 -0
  410. package/dist/src/ingestion/chunk-text.js.map +1 -0
  411. package/dist/src/ingestion/cursor/cursor-store.d.ts +177 -0
  412. package/dist/src/ingestion/cursor/cursor-store.d.ts.map +1 -0
  413. package/dist/src/ingestion/cursor/cursor-store.js +242 -0
  414. package/dist/src/ingestion/cursor/cursor-store.js.map +1 -0
  415. package/dist/src/ingestion/cursor/enrich-roots.d.ts +16 -0
  416. package/dist/src/ingestion/cursor/enrich-roots.d.ts.map +1 -0
  417. package/dist/src/ingestion/cursor/enrich-roots.js +22 -0
  418. package/dist/src/ingestion/cursor/enrich-roots.js.map +1 -0
  419. package/dist/src/ingestion/cursor/vscdb-reader.d.ts +32 -0
  420. package/dist/src/ingestion/cursor/vscdb-reader.d.ts.map +1 -0
  421. package/dist/src/ingestion/cursor/vscdb-reader.js +113 -0
  422. package/dist/src/ingestion/cursor/vscdb-reader.js.map +1 -0
  423. package/dist/src/ingestion/cursor/workspace-root.d.ts +96 -0
  424. package/dist/src/ingestion/cursor/workspace-root.d.ts.map +1 -0
  425. package/dist/src/ingestion/cursor/workspace-root.js +187 -0
  426. package/dist/src/ingestion/cursor/workspace-root.js.map +1 -0
  427. package/dist/src/ingestion/extractor.d.ts +16 -0
  428. package/dist/src/ingestion/extractor.d.ts.map +1 -0
  429. package/dist/src/ingestion/extractor.js +85 -0
  430. package/dist/src/ingestion/extractor.js.map +1 -0
  431. package/dist/src/ingestion/extractors/docx.d.ts +3 -0
  432. package/dist/src/ingestion/extractors/docx.d.ts.map +1 -0
  433. package/dist/src/ingestion/extractors/docx.js +20 -0
  434. package/dist/src/ingestion/extractors/docx.js.map +1 -0
  435. package/dist/src/ingestion/extractors/pdf.d.ts +3 -0
  436. package/dist/src/ingestion/extractors/pdf.d.ts.map +1 -0
  437. package/dist/src/ingestion/extractors/pdf.js +32 -0
  438. package/dist/src/ingestion/extractors/pdf.js.map +1 -0
  439. package/dist/src/ingestion/historical-campaign.d.ts +340 -0
  440. package/dist/src/ingestion/historical-campaign.d.ts.map +1 -0
  441. package/dist/src/ingestion/historical-campaign.js +1010 -0
  442. package/dist/src/ingestion/historical-campaign.js.map +1 -0
  443. package/dist/src/ingestion/ignored-paths.d.ts +20 -0
  444. package/dist/src/ingestion/ignored-paths.d.ts.map +1 -0
  445. package/dist/src/ingestion/ignored-paths.js +45 -0
  446. package/dist/src/ingestion/ignored-paths.js.map +1 -0
  447. package/dist/src/ingestion/inbox-core/conversation-fingerprint.d.ts +2 -0
  448. package/dist/src/ingestion/inbox-core/conversation-fingerprint.d.ts.map +1 -0
  449. package/dist/src/ingestion/inbox-core/conversation-fingerprint.js +27 -0
  450. package/dist/src/ingestion/inbox-core/conversation-fingerprint.js.map +1 -0
  451. package/dist/src/ingestion/inbox-core/conversation-key.d.ts +2 -0
  452. package/dist/src/ingestion/inbox-core/conversation-key.d.ts.map +1 -0
  453. package/dist/src/ingestion/inbox-core/conversation-key.js +31 -0
  454. package/dist/src/ingestion/inbox-core/conversation-key.js.map +1 -0
  455. package/dist/src/ingestion/inbox-core/extensions.d.ts +3 -0
  456. package/dist/src/ingestion/inbox-core/extensions.d.ts.map +1 -0
  457. package/dist/src/ingestion/inbox-core/extensions.js +16 -0
  458. package/dist/src/ingestion/inbox-core/extensions.js.map +1 -0
  459. package/dist/src/ingestion/inbox-core/idempotency.d.ts +2 -0
  460. package/dist/src/ingestion/inbox-core/idempotency.d.ts.map +1 -0
  461. package/dist/src/ingestion/inbox-core/idempotency.js +22 -0
  462. package/dist/src/ingestion/inbox-core/idempotency.js.map +1 -0
  463. package/dist/src/ingestion/inbox-core/index.d.ts +20 -0
  464. package/dist/src/ingestion/inbox-core/index.d.ts.map +1 -0
  465. package/dist/src/ingestion/inbox-core/index.js +20 -0
  466. package/dist/src/ingestion/inbox-core/index.js.map +1 -0
  467. package/dist/src/ingestion/inbox-core/source-detection.d.ts +2 -0
  468. package/dist/src/ingestion/inbox-core/source-detection.d.ts.map +1 -0
  469. package/dist/src/ingestion/inbox-core/source-detection.js +23 -0
  470. package/dist/src/ingestion/inbox-core/source-detection.js.map +1 -0
  471. package/dist/src/ingestion/inbox-core/source-sniffer.d.ts +11 -0
  472. package/dist/src/ingestion/inbox-core/source-sniffer.d.ts.map +1 -0
  473. package/dist/src/ingestion/inbox-core/source-sniffer.js +69 -0
  474. package/dist/src/ingestion/inbox-core/source-sniffer.js.map +1 -0
  475. package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts +70 -0
  476. package/dist/src/ingestion/inbox-core/zip-sniffer.d.ts.map +1 -0
  477. package/dist/src/ingestion/inbox-core/zip-sniffer.js +161 -0
  478. package/dist/src/ingestion/inbox-core/zip-sniffer.js.map +1 -0
  479. package/dist/src/ingestion/inbox-watcher.d.ts +12 -0
  480. package/dist/src/ingestion/inbox-watcher.d.ts.map +1 -0
  481. package/dist/src/ingestion/inbox-watcher.js +83 -0
  482. package/dist/src/ingestion/inbox-watcher.js.map +1 -0
  483. package/dist/src/ingestion/indexer.d.ts +39 -0
  484. package/dist/src/ingestion/indexer.d.ts.map +1 -0
  485. package/dist/src/ingestion/indexer.js +111 -0
  486. package/dist/src/ingestion/indexer.js.map +1 -0
  487. package/dist/src/ingestion/metadata-extraction.d.ts +56 -0
  488. package/dist/src/ingestion/metadata-extraction.d.ts.map +1 -0
  489. package/dist/src/ingestion/metadata-extraction.js +151 -0
  490. package/dist/src/ingestion/metadata-extraction.js.map +1 -0
  491. package/dist/src/ingestion/parsers/chatgpt-web.d.ts +29 -0
  492. package/dist/src/ingestion/parsers/chatgpt-web.d.ts.map +1 -0
  493. package/dist/src/ingestion/parsers/chatgpt-web.js +100 -0
  494. package/dist/src/ingestion/parsers/chatgpt-web.js.map +1 -0
  495. package/dist/src/ingestion/parsers/claude-code-jsonl.d.ts +26 -0
  496. package/dist/src/ingestion/parsers/claude-code-jsonl.d.ts.map +1 -0
  497. package/dist/src/ingestion/parsers/claude-code-jsonl.js +125 -0
  498. package/dist/src/ingestion/parsers/claude-code-jsonl.js.map +1 -0
  499. package/dist/src/ingestion/parsers/claude-desktop-sessions.d.ts +17 -0
  500. package/dist/src/ingestion/parsers/claude-desktop-sessions.d.ts.map +1 -0
  501. package/dist/src/ingestion/parsers/claude-desktop-sessions.js +112 -0
  502. package/dist/src/ingestion/parsers/claude-desktop-sessions.js.map +1 -0
  503. package/dist/src/ingestion/parsers/claude-web.d.ts +24 -0
  504. package/dist/src/ingestion/parsers/claude-web.d.ts.map +1 -0
  505. package/dist/src/ingestion/parsers/claude-web.js +75 -0
  506. package/dist/src/ingestion/parsers/claude-web.js.map +1 -0
  507. package/dist/src/ingestion/parsers/codex-jsonl.d.ts +18 -0
  508. package/dist/src/ingestion/parsers/codex-jsonl.d.ts.map +1 -0
  509. package/dist/src/ingestion/parsers/codex-jsonl.js +150 -0
  510. package/dist/src/ingestion/parsers/codex-jsonl.js.map +1 -0
  511. package/dist/src/ingestion/parsers/gemini-web.d.ts +16 -0
  512. package/dist/src/ingestion/parsers/gemini-web.d.ts.map +1 -0
  513. package/dist/src/ingestion/parsers/gemini-web.js +170 -0
  514. package/dist/src/ingestion/parsers/gemini-web.js.map +1 -0
  515. package/dist/src/ingestion/parsers/grok-cli.d.ts +19 -0
  516. package/dist/src/ingestion/parsers/grok-cli.d.ts.map +1 -0
  517. package/dist/src/ingestion/parsers/grok-cli.js +126 -0
  518. package/dist/src/ingestion/parsers/grok-cli.js.map +1 -0
  519. package/dist/src/ingestion/parsers/grok-web.d.ts +40 -0
  520. package/dist/src/ingestion/parsers/grok-web.d.ts.map +1 -0
  521. package/dist/src/ingestion/parsers/grok-web.js +67 -0
  522. package/dist/src/ingestion/parsers/grok-web.js.map +1 -0
  523. package/dist/src/ingestion/parsers/turns.d.ts +36 -0
  524. package/dist/src/ingestion/parsers/turns.d.ts.map +1 -0
  525. package/dist/src/ingestion/parsers/turns.js +25 -0
  526. package/dist/src/ingestion/parsers/turns.js.map +1 -0
  527. package/dist/src/ingestion/parsers/types.d.ts +47 -0
  528. package/dist/src/ingestion/parsers/types.d.ts.map +1 -0
  529. package/dist/src/ingestion/parsers/types.js +26 -0
  530. package/dist/src/ingestion/parsers/types.js.map +1 -0
  531. package/dist/src/ingestion/report-cards.d.ts +75 -0
  532. package/dist/src/ingestion/report-cards.d.ts.map +1 -0
  533. package/dist/src/ingestion/report-cards.js +224 -0
  534. package/dist/src/ingestion/report-cards.js.map +1 -0
  535. package/dist/src/ingestion/scanner.d.ts +48 -0
  536. package/dist/src/ingestion/scanner.d.ts.map +1 -0
  537. package/dist/src/ingestion/scanner.js +131 -0
  538. package/dist/src/ingestion/scanner.js.map +1 -0
  539. package/dist/src/ingestion/skip-quarantine.d.ts +10 -0
  540. package/dist/src/ingestion/skip-quarantine.d.ts.map +1 -0
  541. package/dist/src/ingestion/skip-quarantine.js +35 -0
  542. package/dist/src/ingestion/skip-quarantine.js.map +1 -0
  543. package/dist/src/ingestion/staging.d.ts +109 -0
  544. package/dist/src/ingestion/staging.d.ts.map +1 -0
  545. package/dist/src/ingestion/staging.js +411 -0
  546. package/dist/src/ingestion/staging.js.map +1 -0
  547. package/dist/src/ingestion/watcher.d.ts +65 -0
  548. package/dist/src/ingestion/watcher.d.ts.map +1 -0
  549. package/dist/src/ingestion/watcher.js +182 -0
  550. package/dist/src/ingestion/watcher.js.map +1 -0
  551. package/dist/src/jobs/codex-override-handler.d.ts +3 -0
  552. package/dist/src/jobs/codex-override-handler.d.ts.map +1 -0
  553. package/dist/src/jobs/codex-override-handler.js +16 -0
  554. package/dist/src/jobs/codex-override-handler.js.map +1 -0
  555. package/dist/src/jobs/handlers/compact.d.ts +30 -0
  556. package/dist/src/jobs/handlers/compact.d.ts.map +1 -0
  557. package/dist/src/jobs/handlers/compact.js +360 -0
  558. package/dist/src/jobs/handlers/compact.js.map +1 -0
  559. package/dist/src/jobs/handlers/dedupe-conversations.d.ts +134 -0
  560. package/dist/src/jobs/handlers/dedupe-conversations.d.ts.map +1 -0
  561. package/dist/src/jobs/handlers/dedupe-conversations.js +371 -0
  562. package/dist/src/jobs/handlers/dedupe-conversations.js.map +1 -0
  563. package/dist/src/jobs/handlers/ingest.d.ts +13 -0
  564. package/dist/src/jobs/handlers/ingest.d.ts.map +1 -0
  565. package/dist/src/jobs/handlers/ingest.js +557 -0
  566. package/dist/src/jobs/handlers/ingest.js.map +1 -0
  567. package/dist/src/jobs/handlers/optimize.d.ts +11 -0
  568. package/dist/src/jobs/handlers/optimize.d.ts.map +1 -0
  569. package/dist/src/jobs/handlers/optimize.js +12 -0
  570. package/dist/src/jobs/handlers/optimize.js.map +1 -0
  571. package/dist/src/jobs/handlers/reconcile.d.ts +57 -0
  572. package/dist/src/jobs/handlers/reconcile.d.ts.map +1 -0
  573. package/dist/src/jobs/handlers/reconcile.js +685 -0
  574. package/dist/src/jobs/handlers/reconcile.js.map +1 -0
  575. package/dist/src/jobs/handlers/reindex.d.ts +38 -0
  576. package/dist/src/jobs/handlers/reindex.d.ts.map +1 -0
  577. package/dist/src/jobs/handlers/reindex.js +63 -0
  578. package/dist/src/jobs/handlers/reindex.js.map +1 -0
  579. package/dist/src/jobs/handlers/save.d.ts +10 -0
  580. package/dist/src/jobs/handlers/save.d.ts.map +1 -0
  581. package/dist/src/jobs/handlers/save.js +316 -0
  582. package/dist/src/jobs/handlers/save.js.map +1 -0
  583. package/dist/src/jobs/handlers/triage.d.ts +47 -0
  584. package/dist/src/jobs/handlers/triage.d.ts.map +1 -0
  585. package/dist/src/jobs/handlers/triage.js +95 -0
  586. package/dist/src/jobs/handlers/triage.js.map +1 -0
  587. package/dist/src/jobs/maintenance-scheduler.d.ts +30 -0
  588. package/dist/src/jobs/maintenance-scheduler.d.ts.map +1 -0
  589. package/dist/src/jobs/maintenance-scheduler.js +41 -0
  590. package/dist/src/jobs/maintenance-scheduler.js.map +1 -0
  591. package/dist/src/jobs/queue.d.ts +157 -0
  592. package/dist/src/jobs/queue.d.ts.map +1 -0
  593. package/dist/src/jobs/queue.js +759 -0
  594. package/dist/src/jobs/queue.js.map +1 -0
  595. package/dist/src/jobs/types.d.ts +53 -0
  596. package/dist/src/jobs/types.d.ts.map +1 -0
  597. package/dist/src/jobs/types.js +33 -0
  598. package/dist/src/jobs/types.js.map +1 -0
  599. package/dist/src/jobs/worker-entry.d.ts +10 -0
  600. package/dist/src/jobs/worker-entry.d.ts.map +1 -0
  601. package/dist/src/jobs/worker-entry.js +252 -0
  602. package/dist/src/jobs/worker-entry.js.map +1 -0
  603. package/dist/src/jobs/worker-process.d.ts +67 -0
  604. package/dist/src/jobs/worker-process.d.ts.map +1 -0
  605. package/dist/src/jobs/worker-process.js +227 -0
  606. package/dist/src/jobs/worker-process.js.map +1 -0
  607. package/dist/src/jobs/worker.d.ts +11 -0
  608. package/dist/src/jobs/worker.d.ts.map +1 -0
  609. package/dist/src/jobs/worker.js +14 -0
  610. package/dist/src/jobs/worker.js.map +1 -0
  611. package/dist/src/main.d.ts +2 -0
  612. package/dist/src/main.d.ts.map +1 -0
  613. package/dist/src/main.js +683 -0
  614. package/dist/src/main.js.map +1 -0
  615. package/dist/src/mcp/capture-diagnostics.d.ts +51 -0
  616. package/dist/src/mcp/capture-diagnostics.d.ts.map +1 -0
  617. package/dist/src/mcp/capture-diagnostics.js +127 -0
  618. package/dist/src/mcp/capture-diagnostics.js.map +1 -0
  619. package/dist/src/mcp/errors.d.ts +8 -0
  620. package/dist/src/mcp/errors.d.ts.map +1 -0
  621. package/dist/src/mcp/errors.js +69 -0
  622. package/dist/src/mcp/errors.js.map +1 -0
  623. package/dist/src/mcp/memory-diagnostics.d.ts +6 -0
  624. package/dist/src/mcp/memory-diagnostics.d.ts.map +1 -0
  625. package/dist/src/mcp/memory-diagnostics.js +51 -0
  626. package/dist/src/mcp/memory-diagnostics.js.map +1 -0
  627. package/dist/src/mcp/names.d.ts +48 -0
  628. package/dist/src/mcp/names.d.ts.map +1 -0
  629. package/dist/src/mcp/names.js +77 -0
  630. package/dist/src/mcp/names.js.map +1 -0
  631. package/dist/src/mcp/server.d.ts +19 -0
  632. package/dist/src/mcp/server.d.ts.map +1 -0
  633. package/dist/src/mcp/server.js +184 -0
  634. package/dist/src/mcp/server.js.map +1 -0
  635. package/dist/src/mcp/stdio.d.ts +2 -0
  636. package/dist/src/mcp/stdio.d.ts.map +1 -0
  637. package/dist/src/mcp/stdio.js +8 -0
  638. package/dist/src/mcp/stdio.js.map +1 -0
  639. package/dist/src/mcp/tools/context-pack.d.ts +35 -0
  640. package/dist/src/mcp/tools/context-pack.d.ts.map +1 -0
  641. package/dist/src/mcp/tools/context-pack.js +279 -0
  642. package/dist/src/mcp/tools/context-pack.js.map +1 -0
  643. package/dist/src/mcp/tools/conversations-search.d.ts +38 -0
  644. package/dist/src/mcp/tools/conversations-search.d.ts.map +1 -0
  645. package/dist/src/mcp/tools/conversations-search.js +79 -0
  646. package/dist/src/mcp/tools/conversations-search.js.map +1 -0
  647. package/dist/src/mcp/tools/evidence-feedback.d.ts +60 -0
  648. package/dist/src/mcp/tools/evidence-feedback.d.ts.map +1 -0
  649. package/dist/src/mcp/tools/evidence-feedback.js +62 -0
  650. package/dist/src/mcp/tools/evidence-feedback.js.map +1 -0
  651. package/dist/src/mcp/tools/log-outcome.d.ts +72 -0
  652. package/dist/src/mcp/tools/log-outcome.d.ts.map +1 -0
  653. package/dist/src/mcp/tools/log-outcome.js +59 -0
  654. package/dist/src/mcp/tools/log-outcome.js.map +1 -0
  655. package/dist/src/mcp/tools/open-evidence.d.ts +37 -0
  656. package/dist/src/mcp/tools/open-evidence.d.ts.map +1 -0
  657. package/dist/src/mcp/tools/open-evidence.js +72 -0
  658. package/dist/src/mcp/tools/open-evidence.js.map +1 -0
  659. package/dist/src/mcp/tools/save.d.ts +37 -0
  660. package/dist/src/mcp/tools/save.d.ts.map +1 -0
  661. package/dist/src/mcp/tools/save.js +65 -0
  662. package/dist/src/mcp/tools/save.js.map +1 -0
  663. package/dist/src/mcp/tools/search.d.ts +37 -0
  664. package/dist/src/mcp/tools/search.d.ts.map +1 -0
  665. package/dist/src/mcp/tools/search.js +95 -0
  666. package/dist/src/mcp/tools/search.js.map +1 -0
  667. package/dist/src/mcp/tools/status.d.ts +31 -0
  668. package/dist/src/mcp/tools/status.d.ts.map +1 -0
  669. package/dist/src/mcp/tools/status.js +63 -0
  670. package/dist/src/mcp/tools/status.js.map +1 -0
  671. package/dist/src/observability/coverage.d.ts +100 -0
  672. package/dist/src/observability/coverage.d.ts.map +1 -0
  673. package/dist/src/observability/coverage.js +178 -0
  674. package/dist/src/observability/coverage.js.map +1 -0
  675. package/dist/src/observability/embedding-events.d.ts +52 -0
  676. package/dist/src/observability/embedding-events.d.ts.map +1 -0
  677. package/dist/src/observability/embedding-events.js +149 -0
  678. package/dist/src/observability/embedding-events.js.map +1 -0
  679. package/dist/src/observability/index-events.d.ts +70 -0
  680. package/dist/src/observability/index-events.d.ts.map +1 -0
  681. package/dist/src/observability/index-events.js +148 -0
  682. package/dist/src/observability/index-events.js.map +1 -0
  683. package/dist/src/observability/onboarding-metric.d.ts +131 -0
  684. package/dist/src/observability/onboarding-metric.d.ts.map +1 -0
  685. package/dist/src/observability/onboarding-metric.js +352 -0
  686. package/dist/src/observability/onboarding-metric.js.map +1 -0
  687. package/dist/src/observability/retrieval-feedback.d.ts +82 -0
  688. package/dist/src/observability/retrieval-feedback.d.ts.map +1 -0
  689. package/dist/src/observability/retrieval-feedback.js +231 -0
  690. package/dist/src/observability/retrieval-feedback.js.map +1 -0
  691. package/dist/src/observability/rift-context.d.ts +53 -0
  692. package/dist/src/observability/rift-context.d.ts.map +1 -0
  693. package/dist/src/observability/rift-context.js +141 -0
  694. package/dist/src/observability/rift-context.js.map +1 -0
  695. package/dist/src/observability/staleness.d.ts +43 -0
  696. package/dist/src/observability/staleness.d.ts.map +1 -0
  697. package/dist/src/observability/staleness.js +74 -0
  698. package/dist/src/observability/staleness.js.map +1 -0
  699. package/dist/src/observability/tool-usage-stats.d.ts +139 -0
  700. package/dist/src/observability/tool-usage-stats.d.ts.map +1 -0
  701. package/dist/src/observability/tool-usage-stats.js +245 -0
  702. package/dist/src/observability/tool-usage-stats.js.map +1 -0
  703. package/dist/src/observability/tool-usage.d.ts +231 -0
  704. package/dist/src/observability/tool-usage.d.ts.map +1 -0
  705. package/dist/src/observability/tool-usage.js +489 -0
  706. package/dist/src/observability/tool-usage.js.map +1 -0
  707. package/dist/src/observability/version-check.d.ts +71 -0
  708. package/dist/src/observability/version-check.d.ts.map +1 -0
  709. package/dist/src/observability/version-check.js +198 -0
  710. package/dist/src/observability/version-check.js.map +1 -0
  711. package/dist/src/onboarding/capture-switch.d.ts +20 -0
  712. package/dist/src/onboarding/capture-switch.d.ts.map +1 -0
  713. package/dist/src/onboarding/capture-switch.js +52 -0
  714. package/dist/src/onboarding/capture-switch.js.map +1 -0
  715. package/dist/src/onboarding/daemon-control.d.ts +33 -0
  716. package/dist/src/onboarding/daemon-control.d.ts.map +1 -0
  717. package/dist/src/onboarding/daemon-control.js +92 -0
  718. package/dist/src/onboarding/daemon-control.js.map +1 -0
  719. package/dist/src/onboarding/env-file.d.ts +18 -0
  720. package/dist/src/onboarding/env-file.d.ts.map +1 -0
  721. package/dist/src/onboarding/env-file.js +89 -0
  722. package/dist/src/onboarding/env-file.js.map +1 -0
  723. package/dist/src/onboarding/search-by-meaning.d.ts +35 -0
  724. package/dist/src/onboarding/search-by-meaning.d.ts.map +1 -0
  725. package/dist/src/onboarding/search-by-meaning.js +163 -0
  726. package/dist/src/onboarding/search-by-meaning.js.map +1 -0
  727. package/dist/src/onboarding/setup-page.d.ts +7 -0
  728. package/dist/src/onboarding/setup-page.d.ts.map +1 -0
  729. package/dist/src/onboarding/setup-page.js +823 -0
  730. package/dist/src/onboarding/setup-page.js.map +1 -0
  731. package/dist/src/onboarding/setup-session.d.ts +22 -0
  732. package/dist/src/onboarding/setup-session.d.ts.map +1 -0
  733. package/dist/src/onboarding/setup-session.js +80 -0
  734. package/dist/src/onboarding/setup-session.js.map +1 -0
  735. package/dist/src/onboarding/setup-state.d.ts +117 -0
  736. package/dist/src/onboarding/setup-state.d.ts.map +1 -0
  737. package/dist/src/onboarding/setup-state.js +267 -0
  738. package/dist/src/onboarding/setup-state.js.map +1 -0
  739. package/dist/src/onboarding/voyage-validate.d.ts +22 -0
  740. package/dist/src/onboarding/voyage-validate.d.ts.map +1 -0
  741. package/dist/src/onboarding/voyage-validate.js +96 -0
  742. package/dist/src/onboarding/voyage-validate.js.map +1 -0
  743. package/dist/src/providers/anthropic-digest.d.ts +23 -0
  744. package/dist/src/providers/anthropic-digest.d.ts.map +1 -0
  745. package/dist/src/providers/anthropic-digest.js +91 -0
  746. package/dist/src/providers/anthropic-digest.js.map +1 -0
  747. package/dist/src/providers/basic-metadata-extraction.d.ts +60 -0
  748. package/dist/src/providers/basic-metadata-extraction.d.ts.map +1 -0
  749. package/dist/src/providers/basic-metadata-extraction.js +114 -0
  750. package/dist/src/providers/basic-metadata-extraction.js.map +1 -0
  751. package/dist/src/providers/claude-cli-metadata-extraction.d.ts +47 -0
  752. package/dist/src/providers/claude-cli-metadata-extraction.d.ts.map +1 -0
  753. package/dist/src/providers/claude-cli-metadata-extraction.js +130 -0
  754. package/dist/src/providers/claude-cli-metadata-extraction.js.map +1 -0
  755. package/dist/src/providers/claude-cli-runner.d.ts +92 -0
  756. package/dist/src/providers/claude-cli-runner.d.ts.map +1 -0
  757. package/dist/src/providers/claude-cli-runner.js +598 -0
  758. package/dist/src/providers/claude-cli-runner.js.map +1 -0
  759. package/dist/src/providers/claude-input-limit.d.ts +32 -0
  760. package/dist/src/providers/claude-input-limit.d.ts.map +1 -0
  761. package/dist/src/providers/claude-input-limit.js +32 -0
  762. package/dist/src/providers/claude-input-limit.js.map +1 -0
  763. package/dist/src/providers/codex-cli-digest.d.ts +12 -0
  764. package/dist/src/providers/codex-cli-digest.d.ts.map +1 -0
  765. package/dist/src/providers/codex-cli-digest.js +70 -0
  766. package/dist/src/providers/codex-cli-digest.js.map +1 -0
  767. package/dist/src/providers/codex-cli-metadata-extraction.d.ts +15 -0
  768. package/dist/src/providers/codex-cli-metadata-extraction.d.ts.map +1 -0
  769. package/dist/src/providers/codex-cli-metadata-extraction.js +78 -0
  770. package/dist/src/providers/codex-cli-metadata-extraction.js.map +1 -0
  771. package/dist/src/providers/codex-cli-model.d.ts +61 -0
  772. package/dist/src/providers/codex-cli-model.d.ts.map +1 -0
  773. package/dist/src/providers/codex-cli-model.js +194 -0
  774. package/dist/src/providers/codex-cli-model.js.map +1 -0
  775. package/dist/src/providers/codex-cli-runner.d.ts +60 -0
  776. package/dist/src/providers/codex-cli-runner.d.ts.map +1 -0
  777. package/dist/src/providers/codex-cli-runner.js +584 -0
  778. package/dist/src/providers/codex-cli-runner.js.map +1 -0
  779. package/dist/src/providers/codex-input-limit.d.ts +43 -0
  780. package/dist/src/providers/codex-input-limit.d.ts.map +1 -0
  781. package/dist/src/providers/codex-input-limit.js +70 -0
  782. package/dist/src/providers/codex-input-limit.js.map +1 -0
  783. package/dist/src/providers/conversation-generation.d.ts +21 -0
  784. package/dist/src/providers/conversation-generation.d.ts.map +1 -0
  785. package/dist/src/providers/conversation-generation.js +132 -0
  786. package/dist/src/providers/conversation-generation.js.map +1 -0
  787. package/dist/src/providers/ollama-embed.d.ts +23 -0
  788. package/dist/src/providers/ollama-embed.d.ts.map +1 -0
  789. package/dist/src/providers/ollama-embed.js +137 -0
  790. package/dist/src/providers/ollama-embed.js.map +1 -0
  791. package/dist/src/providers/ollama.d.ts +42 -0
  792. package/dist/src/providers/ollama.d.ts.map +1 -0
  793. package/dist/src/providers/ollama.js +169 -0
  794. package/dist/src/providers/ollama.js.map +1 -0
  795. package/dist/src/providers/openai-metadata-extraction.d.ts +120 -0
  796. package/dist/src/providers/openai-metadata-extraction.d.ts.map +1 -0
  797. package/dist/src/providers/openai-metadata-extraction.js +225 -0
  798. package/dist/src/providers/openai-metadata-extraction.js.map +1 -0
  799. package/dist/src/providers/operator-overrides.d.ts +24 -0
  800. package/dist/src/providers/operator-overrides.d.ts.map +1 -0
  801. package/dist/src/providers/operator-overrides.js +84 -0
  802. package/dist/src/providers/operator-overrides.js.map +1 -0
  803. package/dist/src/providers/placeholder-embed.d.ts +56 -0
  804. package/dist/src/providers/placeholder-embed.d.ts.map +1 -0
  805. package/dist/src/providers/placeholder-embed.js +64 -0
  806. package/dist/src/providers/placeholder-embed.js.map +1 -0
  807. package/dist/src/providers/shared-request.d.ts +22 -0
  808. package/dist/src/providers/shared-request.d.ts.map +1 -0
  809. package/dist/src/providers/shared-request.js +63 -0
  810. package/dist/src/providers/shared-request.js.map +1 -0
  811. package/dist/src/providers/stub.d.ts +19 -0
  812. package/dist/src/providers/stub.d.ts.map +1 -0
  813. package/dist/src/providers/stub.js +74 -0
  814. package/dist/src/providers/stub.js.map +1 -0
  815. package/dist/src/providers/types.d.ts +100 -0
  816. package/dist/src/providers/types.d.ts.map +1 -0
  817. package/dist/src/providers/types.js +63 -0
  818. package/dist/src/providers/types.js.map +1 -0
  819. package/dist/src/providers/voyage.d.ts +55 -0
  820. package/dist/src/providers/voyage.d.ts.map +1 -0
  821. package/dist/src/providers/voyage.js +179 -0
  822. package/dist/src/providers/voyage.js.map +1 -0
  823. package/dist/src/retrieval/brief.d.ts +26 -0
  824. package/dist/src/retrieval/brief.d.ts.map +1 -0
  825. package/dist/src/retrieval/brief.js +268 -0
  826. package/dist/src/retrieval/brief.js.map +1 -0
  827. package/dist/src/retrieval/canonical-files.d.ts +79 -0
  828. package/dist/src/retrieval/canonical-files.d.ts.map +1 -0
  829. package/dist/src/retrieval/canonical-files.js +432 -0
  830. package/dist/src/retrieval/canonical-files.js.map +1 -0
  831. package/dist/src/retrieval/compact.d.ts +306 -0
  832. package/dist/src/retrieval/compact.d.ts.map +1 -0
  833. package/dist/src/retrieval/compact.js +810 -0
  834. package/dist/src/retrieval/compact.js.map +1 -0
  835. package/dist/src/retrieval/context-pack.d.ts +344 -0
  836. package/dist/src/retrieval/context-pack.d.ts.map +1 -0
  837. package/dist/src/retrieval/context-pack.js +1473 -0
  838. package/dist/src/retrieval/context-pack.js.map +1 -0
  839. package/dist/src/retrieval/conversation-dedup.d.ts +54 -0
  840. package/dist/src/retrieval/conversation-dedup.d.ts.map +1 -0
  841. package/dist/src/retrieval/conversation-dedup.js +162 -0
  842. package/dist/src/retrieval/conversation-dedup.js.map +1 -0
  843. package/dist/src/retrieval/current-truth.d.ts +360 -0
  844. package/dist/src/retrieval/current-truth.d.ts.map +1 -0
  845. package/dist/src/retrieval/current-truth.js +766 -0
  846. package/dist/src/retrieval/current-truth.js.map +1 -0
  847. package/dist/src/retrieval/cwd.d.ts +25 -0
  848. package/dist/src/retrieval/cwd.d.ts.map +1 -0
  849. package/dist/src/retrieval/cwd.js +48 -0
  850. package/dist/src/retrieval/cwd.js.map +1 -0
  851. package/dist/src/retrieval/degraded.d.ts +20 -0
  852. package/dist/src/retrieval/degraded.d.ts.map +1 -0
  853. package/dist/src/retrieval/degraded.js +43 -0
  854. package/dist/src/retrieval/degraded.js.map +1 -0
  855. package/dist/src/retrieval/evidence-key.d.ts +48 -0
  856. package/dist/src/retrieval/evidence-key.d.ts.map +1 -0
  857. package/dist/src/retrieval/evidence-key.js +131 -0
  858. package/dist/src/retrieval/evidence-key.js.map +1 -0
  859. package/dist/src/retrieval/feedback-ranking.d.ts +49 -0
  860. package/dist/src/retrieval/feedback-ranking.d.ts.map +1 -0
  861. package/dist/src/retrieval/feedback-ranking.js +138 -0
  862. package/dist/src/retrieval/feedback-ranking.js.map +1 -0
  863. package/dist/src/retrieval/git-state.d.ts +62 -0
  864. package/dist/src/retrieval/git-state.d.ts.map +1 -0
  865. package/dist/src/retrieval/git-state.js +192 -0
  866. package/dist/src/retrieval/git-state.js.map +1 -0
  867. package/dist/src/retrieval/group-by-parent.d.ts +38 -0
  868. package/dist/src/retrieval/group-by-parent.d.ts.map +1 -0
  869. package/dist/src/retrieval/group-by-parent.js +40 -0
  870. package/dist/src/retrieval/group-by-parent.js.map +1 -0
  871. package/dist/src/retrieval/hybrid.d.ts +75 -0
  872. package/dist/src/retrieval/hybrid.d.ts.map +1 -0
  873. package/dist/src/retrieval/hybrid.js +151 -0
  874. package/dist/src/retrieval/hybrid.js.map +1 -0
  875. package/dist/src/retrieval/lexical.d.ts +33 -0
  876. package/dist/src/retrieval/lexical.d.ts.map +1 -0
  877. package/dist/src/retrieval/lexical.js +379 -0
  878. package/dist/src/retrieval/lexical.js.map +1 -0
  879. package/dist/src/retrieval/locator-boost.d.ts +37 -0
  880. package/dist/src/retrieval/locator-boost.d.ts.map +1 -0
  881. package/dist/src/retrieval/locator-boost.js +129 -0
  882. package/dist/src/retrieval/locator-boost.js.map +1 -0
  883. package/dist/src/retrieval/passages.d.ts +24 -0
  884. package/dist/src/retrieval/passages.d.ts.map +1 -0
  885. package/dist/src/retrieval/passages.js +160 -0
  886. package/dist/src/retrieval/passages.js.map +1 -0
  887. package/dist/src/retrieval/post-filter.d.ts +32 -0
  888. package/dist/src/retrieval/post-filter.d.ts.map +1 -0
  889. package/dist/src/retrieval/post-filter.js +57 -0
  890. package/dist/src/retrieval/post-filter.js.map +1 -0
  891. package/dist/src/retrieval/project-index.d.ts +71 -0
  892. package/dist/src/retrieval/project-index.d.ts.map +1 -0
  893. package/dist/src/retrieval/project-index.js +348 -0
  894. package/dist/src/retrieval/project-index.js.map +1 -0
  895. package/dist/src/retrieval/recall-hint.d.ts +22 -0
  896. package/dist/src/retrieval/recall-hint.d.ts.map +1 -0
  897. package/dist/src/retrieval/recall-hint.js +33 -0
  898. package/dist/src/retrieval/recall-hint.js.map +1 -0
  899. package/dist/src/retrieval/receipt.d.ts +57 -0
  900. package/dist/src/retrieval/receipt.d.ts.map +1 -0
  901. package/dist/src/retrieval/receipt.js +122 -0
  902. package/dist/src/retrieval/receipt.js.map +1 -0
  903. package/dist/src/retrieval/report-demotion.d.ts +46 -0
  904. package/dist/src/retrieval/report-demotion.d.ts.map +1 -0
  905. package/dist/src/retrieval/report-demotion.js +169 -0
  906. package/dist/src/retrieval/report-demotion.js.map +1 -0
  907. package/dist/src/retrieval/reranker.d.ts +119 -0
  908. package/dist/src/retrieval/reranker.d.ts.map +1 -0
  909. package/dist/src/retrieval/reranker.js +220 -0
  910. package/dist/src/retrieval/reranker.js.map +1 -0
  911. package/dist/src/retrieval/stitch-chunks.d.ts +76 -0
  912. package/dist/src/retrieval/stitch-chunks.d.ts.map +1 -0
  913. package/dist/src/retrieval/stitch-chunks.js +113 -0
  914. package/dist/src/retrieval/stitch-chunks.js.map +1 -0
  915. package/dist/src/retrieval/vector.d.ts +71 -0
  916. package/dist/src/retrieval/vector.d.ts.map +1 -0
  917. package/dist/src/retrieval/vector.js +147 -0
  918. package/dist/src/retrieval/vector.js.map +1 -0
  919. package/dist/src/runtime/legacy-migration.d.ts +27 -0
  920. package/dist/src/runtime/legacy-migration.d.ts.map +1 -0
  921. package/dist/src/runtime/legacy-migration.js +140 -0
  922. package/dist/src/runtime/legacy-migration.js.map +1 -0
  923. package/dist/src/runtime/legacy-name-guard.d.ts +35 -0
  924. package/dist/src/runtime/legacy-name-guard.d.ts.map +1 -0
  925. package/dist/src/runtime/legacy-name-guard.js +58 -0
  926. package/dist/src/runtime/legacy-name-guard.js.map +1 -0
  927. package/dist/src/runtime/rift-env.d.ts +14 -0
  928. package/dist/src/runtime/rift-env.d.ts.map +1 -0
  929. package/dist/src/runtime/rift-env.js +79 -0
  930. package/dist/src/runtime/rift-env.js.map +1 -0
  931. package/dist/src/runtime/voyage-key-source.d.ts +46 -0
  932. package/dist/src/runtime/voyage-key-source.d.ts.map +1 -0
  933. package/dist/src/runtime/voyage-key-source.js +97 -0
  934. package/dist/src/runtime/voyage-key-source.js.map +1 -0
  935. package/dist/src/runtime/watcher-startup.d.ts +2 -0
  936. package/dist/src/runtime/watcher-startup.d.ts.map +1 -0
  937. package/dist/src/runtime/watcher-startup.js +4 -0
  938. package/dist/src/runtime/watcher-startup.js.map +1 -0
  939. package/dist/src/security/archive.d.ts +23 -0
  940. package/dist/src/security/archive.d.ts.map +1 -0
  941. package/dist/src/security/archive.js +163 -0
  942. package/dist/src/security/archive.js.map +1 -0
  943. package/dist/src/security/paths.d.ts +21 -0
  944. package/dist/src/security/paths.d.ts.map +1 -0
  945. package/dist/src/security/paths.js +67 -0
  946. package/dist/src/security/paths.js.map +1 -0
  947. package/dist/src/server/app.d.ts +29 -0
  948. package/dist/src/server/app.d.ts.map +1 -0
  949. package/dist/src/server/app.js +356 -0
  950. package/dist/src/server/app.js.map +1 -0
  951. package/dist/src/server/build-info.d.ts +8 -0
  952. package/dist/src/server/build-info.d.ts.map +1 -0
  953. package/dist/src/server/build-info.js +61 -0
  954. package/dist/src/server/build-info.js.map +1 -0
  955. package/dist/src/server/lifecycle.d.ts +30 -0
  956. package/dist/src/server/lifecycle.d.ts.map +1 -0
  957. package/dist/src/server/lifecycle.js +59 -0
  958. package/dist/src/server/lifecycle.js.map +1 -0
  959. package/dist/src/server/middleware/multipart.d.ts +51 -0
  960. package/dist/src/server/middleware/multipart.d.ts.map +1 -0
  961. package/dist/src/server/middleware/multipart.js +86 -0
  962. package/dist/src/server/middleware/multipart.js.map +1 -0
  963. package/dist/src/server/routes/compact.d.ts +37 -0
  964. package/dist/src/server/routes/compact.d.ts.map +1 -0
  965. package/dist/src/server/routes/compact.js +80 -0
  966. package/dist/src/server/routes/compact.js.map +1 -0
  967. package/dist/src/server/routes/context.d.ts +12 -0
  968. package/dist/src/server/routes/context.d.ts.map +1 -0
  969. package/dist/src/server/routes/context.js +73 -0
  970. package/dist/src/server/routes/context.js.map +1 -0
  971. package/dist/src/server/routes/conversations-search.d.ts +4 -0
  972. package/dist/src/server/routes/conversations-search.d.ts.map +1 -0
  973. package/dist/src/server/routes/conversations-search.js +287 -0
  974. package/dist/src/server/routes/conversations-search.js.map +1 -0
  975. package/dist/src/server/routes/enqueue.d.ts +11 -0
  976. package/dist/src/server/routes/enqueue.d.ts.map +1 -0
  977. package/dist/src/server/routes/enqueue.js +17 -0
  978. package/dist/src/server/routes/enqueue.js.map +1 -0
  979. package/dist/src/server/routes/friend-status.d.ts +474 -0
  980. package/dist/src/server/routes/friend-status.d.ts.map +1 -0
  981. package/dist/src/server/routes/friend-status.js +671 -0
  982. package/dist/src/server/routes/friend-status.js.map +1 -0
  983. package/dist/src/server/routes/ingest.d.ts +15 -0
  984. package/dist/src/server/routes/ingest.d.ts.map +1 -0
  985. package/dist/src/server/routes/ingest.js +142 -0
  986. package/dist/src/server/routes/ingest.js.map +1 -0
  987. package/dist/src/server/routes/jobs.d.ts +10 -0
  988. package/dist/src/server/routes/jobs.d.ts.map +1 -0
  989. package/dist/src/server/routes/jobs.js +29 -0
  990. package/dist/src/server/routes/jobs.js.map +1 -0
  991. package/dist/src/server/routes/mcp-usage.d.ts +17 -0
  992. package/dist/src/server/routes/mcp-usage.d.ts.map +1 -0
  993. package/dist/src/server/routes/mcp-usage.js +17 -0
  994. package/dist/src/server/routes/mcp-usage.js.map +1 -0
  995. package/dist/src/server/routes/reconcile.d.ts +4 -0
  996. package/dist/src/server/routes/reconcile.d.ts.map +1 -0
  997. package/dist/src/server/routes/reconcile.js +62 -0
  998. package/dist/src/server/routes/reconcile.js.map +1 -0
  999. package/dist/src/server/routes/reindex.d.ts +4 -0
  1000. package/dist/src/server/routes/reindex.d.ts.map +1 -0
  1001. package/dist/src/server/routes/reindex.js +77 -0
  1002. package/dist/src/server/routes/reindex.js.map +1 -0
  1003. package/dist/src/server/routes/retrieval-feedback.d.ts +3 -0
  1004. package/dist/src/server/routes/retrieval-feedback.d.ts.map +1 -0
  1005. package/dist/src/server/routes/retrieval-feedback.js +290 -0
  1006. package/dist/src/server/routes/retrieval-feedback.js.map +1 -0
  1007. package/dist/src/server/routes/save.d.ts +52 -0
  1008. package/dist/src/server/routes/save.d.ts.map +1 -0
  1009. package/dist/src/server/routes/save.js +127 -0
  1010. package/dist/src/server/routes/save.js.map +1 -0
  1011. package/dist/src/server/routes/search.d.ts +5 -0
  1012. package/dist/src/server/routes/search.d.ts.map +1 -0
  1013. package/dist/src/server/routes/search.js +689 -0
  1014. package/dist/src/server/routes/search.js.map +1 -0
  1015. package/dist/src/server/routes/setup.d.ts +46 -0
  1016. package/dist/src/server/routes/setup.d.ts.map +1 -0
  1017. package/dist/src/server/routes/setup.js +322 -0
  1018. package/dist/src/server/routes/setup.js.map +1 -0
  1019. package/dist/src/server/routes/stats.d.ts +10 -0
  1020. package/dist/src/server/routes/stats.d.ts.map +1 -0
  1021. package/dist/src/server/routes/stats.js +15 -0
  1022. package/dist/src/server/routes/stats.js.map +1 -0
  1023. package/dist/src/server/routes/status.d.ts +20 -0
  1024. package/dist/src/server/routes/status.d.ts.map +1 -0
  1025. package/dist/src/server/routes/status.js +31 -0
  1026. package/dist/src/server/routes/status.js.map +1 -0
  1027. package/dist/src/server/routes/triage.d.ts +4 -0
  1028. package/dist/src/server/routes/triage.d.ts.map +1 -0
  1029. package/dist/src/server/routes/triage.js +97 -0
  1030. package/dist/src/server/routes/triage.js.map +1 -0
  1031. package/dist/src/server/save-quality.d.ts +21 -0
  1032. package/dist/src/server/save-quality.d.ts.map +1 -0
  1033. package/dist/src/server/save-quality.js +51 -0
  1034. package/dist/src/server/save-quality.js.map +1 -0
  1035. package/dist/src/server/serving-marker.d.ts +85 -0
  1036. package/dist/src/server/serving-marker.d.ts.map +1 -0
  1037. package/dist/src/server/serving-marker.js +226 -0
  1038. package/dist/src/server/serving-marker.js.map +1 -0
  1039. package/dist/src/storage/atomic.d.ts +8 -0
  1040. package/dist/src/storage/atomic.d.ts.map +1 -0
  1041. package/dist/src/storage/atomic.js +22 -0
  1042. package/dist/src/storage/atomic.js.map +1 -0
  1043. package/dist/src/storage/chunk-backfill.d.ts +39 -0
  1044. package/dist/src/storage/chunk-backfill.d.ts.map +1 -0
  1045. package/dist/src/storage/chunk-backfill.js +295 -0
  1046. package/dist/src/storage/chunk-backfill.js.map +1 -0
  1047. package/dist/src/storage/db.d.ts +15 -0
  1048. package/dist/src/storage/db.d.ts.map +1 -0
  1049. package/dist/src/storage/db.js +47 -0
  1050. package/dist/src/storage/db.js.map +1 -0
  1051. package/dist/src/storage/filter.d.ts +42 -0
  1052. package/dist/src/storage/filter.d.ts.map +1 -0
  1053. package/dist/src/storage/filter.js +70 -0
  1054. package/dist/src/storage/filter.js.map +1 -0
  1055. package/dist/src/storage/fts.d.ts +47 -0
  1056. package/dist/src/storage/fts.d.ts.map +1 -0
  1057. package/dist/src/storage/fts.js +86 -0
  1058. package/dist/src/storage/fts.js.map +1 -0
  1059. package/dist/src/storage/integrity.d.ts +11 -0
  1060. package/dist/src/storage/integrity.d.ts.map +1 -0
  1061. package/dist/src/storage/integrity.js +66 -0
  1062. package/dist/src/storage/integrity.js.map +1 -0
  1063. package/dist/src/storage/maintenance.d.ts +27 -0
  1064. package/dist/src/storage/maintenance.d.ts.map +1 -0
  1065. package/dist/src/storage/maintenance.js +66 -0
  1066. package/dist/src/storage/maintenance.js.map +1 -0
  1067. package/dist/src/storage/rebuild.d.ts +71 -0
  1068. package/dist/src/storage/rebuild.d.ts.map +1 -0
  1069. package/dist/src/storage/rebuild.js +605 -0
  1070. package/dist/src/storage/rebuild.js.map +1 -0
  1071. package/dist/src/storage/report-card-backfill.d.ts +20 -0
  1072. package/dist/src/storage/report-card-backfill.d.ts.map +1 -0
  1073. package/dist/src/storage/report-card-backfill.js +114 -0
  1074. package/dist/src/storage/report-card-backfill.js.map +1 -0
  1075. package/dist/src/storage/shadow-swap.d.ts +20 -0
  1076. package/dist/src/storage/shadow-swap.d.ts.map +1 -0
  1077. package/dist/src/storage/shadow-swap.js +163 -0
  1078. package/dist/src/storage/shadow-swap.js.map +1 -0
  1079. package/dist/src/storage/tables.d.ts +147 -0
  1080. package/dist/src/storage/tables.d.ts.map +1 -0
  1081. package/dist/src/storage/tables.js +290 -0
  1082. package/dist/src/storage/tables.js.map +1 -0
  1083. package/operator/swiftbar/render-menu.py +475 -0
  1084. package/operator/swiftbar/rift.10s.sh +201 -0
  1085. package/package.json +57 -3
@@ -0,0 +1,1873 @@
1
+ /**
2
+ * `onadit onboard` — first-run wizard.
3
+ *
4
+ * Walks a friend from "fresh install + Voyage key in hand" to "first
5
+ * useful recall against their freshly-imported data". Step ordering
6
+ * matches Slice 4 in the friend-beta plan; each step is idempotent and
7
+ * `--yes` accepts every prompt's default.
8
+ *
9
+ * Flags worth pointing out:
10
+ * --voyage-key <key> non-interactive key entry
11
+ * --voyage-label <label> operator-supplied display label (no inference)
12
+ * --enable-feedback-relay <url>
13
+ * opt into the Clem-side relay non-interactively
14
+ * --import-export <path> import an export inline; `--no-import-export`
15
+ * skips the prompt entirely
16
+ * --reconfigure-voyage Slice 6 recovery flow — skip everything
17
+ * except validate + write key + kickstart + smoke
18
+ * --yes accept all defaults (used by install scripts)
19
+ * --skip-capture suppress the post-onboarding capture pass
20
+ * (useful in tests / CI dry-runs)
21
+ */
22
+ import crypto from "node:crypto";
23
+ import fs from "node:fs";
24
+ import os from "node:os";
25
+ import path from "node:path";
26
+ import readline from "node:readline";
27
+ import { Command, Option } from "commander";
28
+ import { CliError, createHttpClient, readToken, resolveBaseUrl, } from "../http-client.js";
29
+ import { issueToken } from "../token.js";
30
+ import { loadConfig } from "../../config/loader.js";
31
+ import { defaultRiftEnvPath, loadRiftEnv, } from "../../runtime/rift-env.js";
32
+ import { resolveVoyageKeySource, readSavedVoyageKey, voyageKeySourceLines, } from "../../runtime/voyage-key-source.js";
33
+ import { runLegacyMigration } from "../../runtime/legacy-migration.js";
34
+ import { sanitizeProjectLabel } from "../../runtime/legacy-name-guard.js";
35
+ import { validateVoyageKey } from "../../onboarding/voyage-validate.js";
36
+ import { useVoyageOwnEndpoint } from "../../onboarding/search-by-meaning.js";
37
+ import { writeCaptureEnabled } from "../../onboarding/capture-switch.js";
38
+ import { writeEnvFile } from "../../onboarding/env-file.js";
39
+ import { kickstartDaemon, waitForHealth, } from "../../onboarding/daemon-control.js";
40
+ import { runAutoCapture, resolveCodexCaptureDeps, resolveCursorCaptureDeps, } from "../../capture/auto-capture.js";
41
+ import { appendAutoCaptureRunRecord, buildAutoCaptureRunRecord, } from "../../capture/observability.js";
42
+ import { DEFAULT_AUTO_CAPTURE_SOURCES, CLAUDE_DESKTOP_CAPTURE_SOURCE, CURSOR_CAPTURE_SOURCE, } from "../../capture/sources.js";
43
+ import { createTriageProvider, resolveTriageProviderName, setConfiguredTriageProviderName, triageWorkerLabel, } from "../../capture/triage-provider-factory.js";
44
+ import { discoverClaudeCodeSessions } from "../../ingestion/parsers/claude-code-jsonl.js";
45
+ import { discoverCodexSessions } from "../../ingestion/parsers/codex-jsonl.js";
46
+ import { sniffInboxSource } from "../../ingestion/inbox-core/source-sniffer.js";
47
+ import { writeHookConfig } from "../hooks-writers/index.js";
48
+ import { HooksParseFailedError } from "../hooks-writers/index.js";
49
+ import { pollJob } from "../job-poller.js";
50
+ import { isJobFailure } from "../output.js";
51
+ import * as ui from "../ui.js";
52
+ import { getBuildInfo } from "../../server/build-info.js";
53
+ import { postFeedback } from "../feedback/feedback-relay.js";
54
+ import { parseInvite } from "../feedback/invite.js";
55
+ import { macRelaySecretStore, } from "../feedback/relay-secret-store.js";
56
+ import { LockedKeychainError } from "../../auth/keychain.js";
57
+ /**
58
+ * Resolve a `--no-<flag>` to a single boolean ("yes, skip this thing").
59
+ * Commander populates the affirmative key with `false`; programmatic
60
+ * callers may pass the `no*` key with `true`. Either form wins.
61
+ */
62
+ export function isOff(opts, affirmative, negative) {
63
+ return opts[affirmative] === false || opts[negative] === true;
64
+ }
65
+ /**
66
+ * True when this `onadit onboard` invocation asks to CHANGE something — set a key,
67
+ * enable a lane, import, opt into feedback, install a hook. Absence marks a
68
+ * "passive" re-run (the user just ran the command again), which on an
69
+ * already-onboarded install should report state instead of redoing first-time
70
+ * setup or gating on the stored Voyage key. `--yes`, `--skip-capture`, and the
71
+ * `--no-*` declines are NOT mutations; `--reconfigure-voyage` has its own flow
72
+ * and is handled before this is consulted.
73
+ *
74
+ * Exported for testing — it gates the idempotent short-circuit in `runOnboard`.
75
+ */
76
+ export function hasOnboardMutationIntent(opts) {
77
+ return ((typeof opts.voyageKey === "string" && opts.voyageKey.trim().length > 0) ||
78
+ opts.voyageLabel !== undefined ||
79
+ opts.enableCapture === true ||
80
+ opts.enableCoworkCapture === true || opts.enableGrokCapture === true ||
81
+ opts.enableCodexEnrichment === true ||
82
+ opts.enableClaudeEnrichment === true ||
83
+ (typeof opts.importExport === "string" && opts.importExport.length > 0) ||
84
+ opts.invite !== undefined ||
85
+ opts.enableFeedbackRelay !== undefined ||
86
+ opts.email !== undefined ||
87
+ opts.withClaudeHook === true);
88
+ }
89
+ const SUPPORTED_INGEST_EXTENSIONS = new Set([".json", ".zip"]);
90
+ const DEFAULT_DATA_DIR = path.join(os.homedir(), "Library", "Application Support", "Rift", // rename:keep data folder name
91
+ "data");
92
+ // Inline import is intentionally narrow until Slice 3 lands the real
93
+ // `onadit import` flow with structural sniffing per source. ChatGPT exports
94
+ // are the most common friend handoff and we route them straight through.
95
+ const ONBOARD_INLINE_IMPORT_SOURCE = "chatgpt_web";
96
+ /** Only explicit feature opt-ins open the longer configuration flow. */
97
+ export function usesAdvancedOnboarding(opts) {
98
+ return opts.advanced === true || opts.reconfigureVoyage === true ||
99
+ (typeof opts.voyageKey === "string" && !!opts.voyageKey.trim()) ||
100
+ opts.voyageLabel !== undefined || opts.enableCapture === true ||
101
+ opts.enableCoworkCapture === true || opts.enableGrokCapture === true || opts.enableCodexEnrichment === true ||
102
+ opts.enableClaudeEnrichment === true || opts.invite !== undefined ||
103
+ opts.enableFeedbackRelay !== undefined || opts.email !== undefined ||
104
+ opts.withClaudeHook === true;
105
+ }
106
+ export function makeOnboardCommand() {
107
+ return new Command("onboard")
108
+ .description("Add an archive, find a memory, connect your AI tool")
109
+ .option("--query <words>", "Find a real topic after import")
110
+ .addOption(new Option("--source <name>", "Archive source (detected when possible)").choices(["chatgpt_web", "claude_web", "gemini_web", "grok_web"]))
111
+ .addOption(new Option("--client <name>", "Connect this AI tool after recall").choices(["claude-desktop", "claude-code", "codex", "cursor"]))
112
+ .option("--advanced", "Configure optional cloud search, capture, and feedback", false)
113
+ .option("--voyage-key <key>", "Voyage API key (skips paste prompt)")
114
+ .option("--no-voyage-key", "Finish without a Voyage key — keyword-only (lexical) search; add a key later")
115
+ .option("--voyage-label <label>", "Operator-supplied display label for the Voyage project")
116
+ .option("--invite <code>", "Accept a feedback invite from Clem (or omit it to paste when asked)")
117
+ .option("--enable-feedback-relay <url>", "Opt into the Onadit feedback relay non-interactively (URL required)")
118
+ .addOption(
119
+ // Hidden: back-compat operator flag. The secret never appears in
120
+ // user-facing help; friends use --invite (or the interactive paste).
121
+ new Option("--relay-secret <secret>", "Back-compat HMAC secret paired with --enable-feedback-relay (stored in the Keychain)").hideHelp())
122
+ .addOption(
123
+ // Hidden: dev/operator escape hatch for unsigned local receivers.
124
+ new Option("--allow-unsigned-feedback-relay", "Dev-only: allow --enable-feedback-relay without a secret (receiver rejects in prod)")
125
+ .hideHelp()
126
+ .default(false))
127
+ .option("--no-feedback-relay", "Decline the feedback relay (local-only)")
128
+ .option("--email <address>", "Opt into beta updates + feedback non-interactively (skips the prompt)")
129
+ .option("--import-export <path>", "Import an export inline (.json or .zip)")
130
+ .option("--no-import-export", "Skip the import-now prompt")
131
+ .option("--reconfigure-voyage", "Recovery flow: replace the Voyage key only", false)
132
+ .option("--yes", "Accept all defaults (non-interactive)", false)
133
+ .option("--skip-capture", "Skip the post-setup capture pass (test-only)", false)
134
+ .option("--no-codex-capture", "Skip the triage-worker preflight + disable the capture pass for this run")
135
+ .option("--with-claude-hook", "Install the Onadit policy hook into Claude Code without prompting", false)
136
+ .option("--no-claude-hook", "Skip the Claude Code policy-hook prompt entirely")
137
+ .option("--enable-codex-enrichment", "Opt into Codex AI metadata enrichment (default: AI-free import + keyword search)", false)
138
+ .option("--enable-claude-enrichment", "Opt into Claude Code AI metadata enrichment (digests/compaction stay off until Claude digest support ships; mutually exclusive with --enable-codex-enrichment)", false)
139
+ .option("--enable-capture", "Opt into scheduled chat capture + its triage-worker preflight (Codex by default, or Claude Code via capture.triage.provider; default: capture off, zero AI-worker calls)", false)
140
+ .option("--enable-grok-capture", "Opt into existing and future Grok CLI sessions (adds grok_cli to capture.sources and enables scheduled capture)")
141
+ .option("--enable-cowork-capture", "Opt into Claude Desktop agent/Cowork capture (adds claude_desktop_sessions to capture.sources and enables scheduled capture)", false)
142
+ .action(async (opts, cmd) => {
143
+ const globalOpts = cmd.optsWithGlobals();
144
+ try {
145
+ if (usesAdvancedOnboarding(opts))
146
+ await runOnboard(opts, globalOpts);
147
+ else {
148
+ const { runFirstRun } = await import("./onboard-first-run.js");
149
+ await runFirstRun(opts, globalOpts);
150
+ }
151
+ }
152
+ catch (err) {
153
+ const msg = err instanceof CliError
154
+ ? err.message
155
+ : err instanceof Error
156
+ ? err.message
157
+ : String(err);
158
+ process.stderr.write(`onboard failed: ${msg}\n`);
159
+ process.exitCode = 1;
160
+ }
161
+ });
162
+ }
163
+ // Exported for orchestrator-level tests (e.g. the capture-without-key gate);
164
+ // `makeOnboardCommand().action` is the only production caller.
165
+ export async function runOnboard(opts, globalOpts) {
166
+ const rl = readline.createInterface({
167
+ input: process.stdin,
168
+ output: process.stdout,
169
+ terminal: !!process.stdin.isTTY,
170
+ });
171
+ try {
172
+ // Fail fast, before any config write: the two enrichment opt-ins pick
173
+ // different metadata workers (Codex vs Claude), so passing both is an
174
+ // ambiguous request, not a mergeable one. Reject it up front rather than
175
+ // letting last-writer-wins silently decide which provider you got.
176
+ if (opts.enableCodexEnrichment === true && opts.enableClaudeEnrichment === true) {
177
+ throw new CliError("Pass only one of --enable-codex-enrichment or --enable-claude-enrichment — they select different metadata workers.", "validation");
178
+ }
179
+ if (opts.reconfigureVoyage) {
180
+ await reconfigureVoyageFlow(opts, globalOpts, rl);
181
+ return;
182
+ }
183
+ // Idempotent re-run. An already-onboarded install + a passive invocation
184
+ // (no flag asking to change anything) + a Voyage key already on disk must
185
+ // NOT redo first-time setup or GATE on that stored key. Re-validating the
186
+ // saved key as a first-time gate is exactly the beta.25 bug: a re-run on an
187
+ // expired key ended with "onboard failed". Instead, report "already set up"
188
+ // with a NON-FATAL key health check and exit clean. A keyword-only install
189
+ // (no key) falls through so the normal flow can still offer to add one.
190
+ if (!hasOnboardMutationIntent(opts)) {
191
+ const absoluteConfig = path.resolve(globalOpts.config);
192
+ const onboarded = readOnboardedState(absoluteConfig);
193
+ const keyRes = resolveOnboardVoyageKeySource(absoluteConfig);
194
+ if (onboarded && keyRes.key) {
195
+ await reportAlreadyOnboarded(keyRes);
196
+ return;
197
+ }
198
+ }
199
+ ui.banner();
200
+ // Step 1 — legacy migration (idempotent).
201
+ const dataDir = await ensureConfigAndDataDir(globalOpts.config, opts, rl);
202
+ const migration = await runLegacyMigration({ dataDir });
203
+ if (migration.migratedCount > 0) {
204
+ ui.step("ok", "Existing data", `carried over ${migration.migratedCount} item(s)`);
205
+ }
206
+ else {
207
+ ui.step("ok", "Existing data", "nothing to carry over");
208
+ }
209
+ // Privacy contract — shown BEFORE the first outbound choice (the
210
+ // Voyage key, whose snippets leave the machine for embedding). A beta
211
+ // user should understand what stays local and what leaves before they
212
+ // paste anything.
213
+ ui.step("info", "Privacy", "");
214
+ sayPrivacyContract();
215
+ // Step 2 — Voyage key + validate + persist env. The daemon kickstart +
216
+ // smoke is deferred to Step 2e (after the opt-in writes below) so the
217
+ // respawned daemon boots with the final config.json.
218
+ //
219
+ // A key this install already has stays as it is: the user's own, or the
220
+ // one Onadit provided (Search by meaning). Asking for a key again made a
221
+ // lane opt-in (`--enable-capture`) depend on pasting a second one, and a
222
+ // user on an Onadit-provided key has none to paste. Changing the key is
223
+ // `--voyage-key` or `--reconfigure-voyage`.
224
+ const savedLast4 = savedVoyageKeyToKeep(opts, path.resolve(globalOpts.config));
225
+ if (savedLast4 !== null) {
226
+ ui.step("ok", "Search index", `using the key already set up · ····${savedLast4}`);
227
+ }
228
+ const last4 = savedLast4 ?? (await collectAndPersistVoyageKey(opts, rl));
229
+ // A pasted key is the user's own Voyage key: stop pointing at the
230
+ // endpoint of a key Onadit provided earlier (Search by meaning).
231
+ if (savedLast4 === null && last4 !== null && useVoyageOwnEndpoint(path.resolve(globalOpts.config))) {
232
+ say("Search index now uses your own Voyage key instead of the one Onadit provided.");
233
+ }
234
+ // Step 2b — sanitize + persist optional --voyage-label to config.json
235
+ // (backup first). Invalid labels are dropped without echoing the raw
236
+ // value, so a key-shaped, path-shaped, or legacy-name-shaped label
237
+ // can never leak through stdout or config.json.
238
+ const safeLabel = applyVoyageLabel(opts.voyageLabel, globalOpts.config, say);
239
+ // Step 2c — optional opt-in to Codex AI metadata enrichment. Default is
240
+ // AI-free import + keyword search (zero Codex calls). Only persisted when
241
+ // the user explicitly passed --enable-codex-enrichment.
242
+ applyCodexEnrichmentOptIn(opts.enableCodexEnrichment, globalOpts.config, say);
243
+ applyClaudeEnrichmentOptIn(opts.enableClaudeEnrichment, globalOpts.config, say);
244
+ // Step 2d — optional opt-in to scheduled chat capture. Default off, so a
245
+ // fresh install makes zero Codex calls. Auto-capture embeds each saved
246
+ // conversation, so it requires a Voyage key; opting in without one would
247
+ // persist `capture.enabled = true` that the daemon can't honor (it would
248
+ // wake hourly, find no embedding provider, and save nothing). So we only
249
+ // persist the opt-in when a key was provided, and warn otherwise.
250
+ // `captureEnabled` is the single source of truth for the capture lane:
251
+ // requested AND a key is present. It gates BOTH the persistence here and
252
+ // the Codex preflight in Step 3 — refusing the opt-in must also skip the
253
+ // preflight's Codex triage call, or `--enable-capture` without a key would
254
+ // still leak a Codex call.
255
+ const captureRequested = opts.enableCapture === true || opts.enableCoworkCapture === true || opts.enableGrokCapture === true;
256
+ const captureEnabled = captureRequested && last4 !== null;
257
+ if (captureRequested && last4 === null) {
258
+ const ignoredFlag = opts.enableCoworkCapture === true && opts.enableCapture !== true
259
+ ? "--enable-cowork-capture"
260
+ : opts.enableGrokCapture === true && opts.enableCapture !== true
261
+ ? "--enable-grok-capture" : "--enable-capture";
262
+ ui.note(`${ignoredFlag} ignored: capture embeds saved conversations and needs a Voyage key. Re-run \`onadit onboard\` with a key to enable it.`);
263
+ }
264
+ else {
265
+ applyCaptureOptIn(captureRequested, globalOpts.config, say);
266
+ applyCoworkCaptureOptIn(opts.enableCoworkCapture, globalOpts.config, say);
267
+ applyGrokCaptureOptIn(opts.enableGrokCapture, globalOpts.config, say);
268
+ }
269
+ // Step 2e — (re)start the daemon AFTER all config writes so it boots with
270
+ // the final config.json. The daemon builds its capture loop and metadata
271
+ // extractor once at boot (src/main.ts), so persisting the opt-ins above
272
+ // BEFORE this kickstart is what makes --enable-capture /
273
+ // --enable-codex-enrichment take effect immediately instead of only after
274
+ // a later restart. Key path only: the smoke asserts voyage_key_present,
275
+ // and the keyword-only path has no daemon smoke to run (the daemon was
276
+ // bootstrapped by install.sh and picks up config on its next start).
277
+ // `not_configured` / `agent_not_loaded` stay recoverable — the daemon
278
+ // simply isn't running yet on a fresh-Mac install before install.sh
279
+ // bootstraps the plist.
280
+ if (last4 !== null) {
281
+ const refresh = await daemonRefreshFlow(globalOpts);
282
+ if (!refresh.ok &&
283
+ refresh.kind !== "not_configured" &&
284
+ refresh.kind !== "agent_not_loaded") {
285
+ throw new CliError(`Voyage smoke failed after daemon kickstart: ${refresh.reason}`, "server_error");
286
+ }
287
+ }
288
+ // Step 3 — triage-worker preflight (capture lane only).
289
+ //
290
+ // Capture is OFF by default (trust-first): a fresh install makes zero
291
+ // Codex calls. The preflight below performs a real Codex triage call,
292
+ // so it ONLY runs when capture is actually enabled — i.e. `--enable-capture`
293
+ // AND a Voyage key (see `captureEnabled` above). Without the flag, or with
294
+ // the flag but no key, the capture lane — and its Codex preflight — is
295
+ // skipped entirely, and import + keyword search below still work with no
296
+ // Codex dependency.
297
+ //
298
+ // When capture IS enabled, a failed preflight is a warning, not fatal —
299
+ // onboarding continues and the capture pass is skipped for this run.
300
+ // `--no-codex-capture` skips the preflight even when capture was enabled
301
+ // (e.g. enable the daemon schedule but skip the one-shot).
302
+ let captureDisabled = false;
303
+ // `codexUnavailable` is set ONLY when capture was enabled and the live
304
+ // Codex preflight actually failed — i.e. scheduled capture is configured
305
+ // on but cannot run until Codex is fixed. `--no-codex-capture` is NOT this
306
+ // case: it only skips the onboarding one-shot, leaving the daemon's
307
+ // scheduled capture to run normally. Keeping the two apart is what lets the
308
+ // import-prompt and summary copy stay honest instead of either over- or
309
+ // under-promising automatic capture.
310
+ let codexUnavailable = false;
311
+ // Resolve the configured triage worker so the preflight probes (and labels)
312
+ // the worker the daemon will actually use, and record it process-wide so
313
+ // the first-capture pass below inherits the same selection. Unreadable
314
+ // config falls back to codex_cli — byte-for-byte the prior default.
315
+ let triageWorkerName = "codex_cli";
316
+ try {
317
+ triageWorkerName = resolveTriageProviderName(loadConfig(path.resolve(globalOpts.config)));
318
+ }
319
+ catch {
320
+ triageWorkerName = "codex_cli";
321
+ }
322
+ setConfiguredTriageProviderName(triageWorkerName);
323
+ const workerLabel = triageWorkerLabel(triageWorkerName);
324
+ if (!captureEnabled) {
325
+ ui.step("skip", "Chat access", captureRequested
326
+ ? "capture needs a Voyage key — skipped"
327
+ : "capture off (default) · enable with --enable-capture");
328
+ captureDisabled = true;
329
+ }
330
+ else if (isOff(opts, "codexCapture", "noCodexCapture")) {
331
+ ui.step("skip", "Chat access", "skipped (--no-codex-capture) · auto-import off");
332
+ captureDisabled = true;
333
+ }
334
+ else {
335
+ const preflightSpin = new ui.Spinner("Chat access").start();
336
+ const preflightOk = await triagePreflight(triageWorkerName);
337
+ if (preflightOk) {
338
+ preflightSpin.succeed("Chat access", `ready · ${workerLabel}`);
339
+ }
340
+ else {
341
+ preflightSpin.fail("Chat access", `not ready · ${workerLabel} — auto-import off`);
342
+ ui.note(triageWorkerName === "claude_code"
343
+ ? "To enable later: run `claude` once and sign in, then re-run `onadit onboard`."
344
+ : "To enable later: run `codex login`, then re-run `onadit onboard`.");
345
+ captureDisabled = true;
346
+ codexUnavailable = true;
347
+ }
348
+ }
349
+ // Will the daemon's scheduled auto-capture actually run going forward?
350
+ // Configured on (requested + Voyage key) AND Codex available. This is the
351
+ // signal the import prompt and the summary line must use — NOT bare
352
+ // `captureEnabled`, which is only "configured on" and stays true even after
353
+ // a failed Codex preflight already told the user auto-import is off.
354
+ const autoCaptureWillRun = captureEnabled && !codexUnavailable;
355
+ // Step 4 — discover sessions.
356
+ const claudeSessions = safeDiscover(() => discoverClaudeCodeSessions(path.join(os.homedir(), ".claude")));
357
+ const codexSessions = safeDiscover(() => discoverCodexSessions());
358
+ ui.step("ok", "Chat history", `${claudeSessions} Claude Code · ${codexSessions} Codex CLI`);
359
+ // Set the expectation honestly up front: auto-capture covers the CLI agents,
360
+ // not every AI app on the Mac. The Claude/ChatGPT desktop + web apps keep
361
+ // their history server-side, so those chats arrive via export → onadit import.
362
+ // `ui.detail` (legible, not dimmed) because this is trust-critical copy.
363
+ //
364
+ // The CLI-agent line is gated on `autoCaptureWillRun`: "captured
365
+ // automatically" is only true once capture is enabled AND the worker
366
+ // preflight passed. On a default/off or not-ready install (we just printed
367
+ // "capture off"/"not ready" above) we describe ELIGIBILITY instead, so the
368
+ // block never contradicts the gate it sits under.
369
+ const cliAgentsLine = autoCaptureWillRun
370
+ ? " • Claude Code + Codex CLI — captured automatically\n"
371
+ : " • Claude Code + Codex CLI — eligible for auto-capture once capture is enabled and chat access is ready\n";
372
+ ui.detail("Auto-capture covers your terminal AI agents — not every AI app on your Mac:\n" +
373
+ cliAgentsLine +
374
+ " • Cursor — only if you turn it on (add cursor_composer to capture.sources)\n" +
375
+ " • Grok CLI sessions — opt in with: onadit onboard --enable-grok-capture (existing and future sessions)\n" +
376
+ " • Claude Desktop Cowork / agent sessions — opt in with: onadit onboard --enable-cowork-capture\n" +
377
+ " • Claude Desktop normal chats / ChatGPT / web chats — NOT automatic; export them, then:\n" +
378
+ " onadit import <file> --source claude_web (or chatgpt_web)");
379
+ // Step 5 — beta opt-in (stay connected: news, pricing, feedback).
380
+ const feedback = await collectFeedbackPreference(opts, dataDir, rl);
381
+ if (feedback.email) {
382
+ ui.step("ok", "Stay connected", `${feedback.email} — opted in (news + feedback)`);
383
+ }
384
+ else if (feedback.enabled) {
385
+ ui.step("ok", "Stay connected", `feedback relay on (installation_id: ${feedback.installation_id})`);
386
+ }
387
+ else {
388
+ ui.step("ok", "Stay connected", "skipped — nothing shared, feedback stays local");
389
+ }
390
+ // Step 5b — optional Claude Code policy hook.
391
+ await maybeInstallClaudeCodeHook(opts, rl);
392
+ // Step 6 + 7 — watermark current sessions + run one capture pass.
393
+ let captureSaved = 0;
394
+ let captureRan = false;
395
+ if (opts.skipCapture) {
396
+ ui.step("skip", "Chat import", "skipped (--skip-capture)");
397
+ }
398
+ else if (last4 === null) {
399
+ // Auto-capture saves embed each conversation, so it needs a real
400
+ // embedding provider. In keyword-only mode it is skipped; import +
401
+ // search below still work.
402
+ ui.step("skip", "Chat import", "skipped (no embedding key — capture needs one)");
403
+ }
404
+ else if (captureDisabled) {
405
+ // Capture lane is off — either the default (no --enable-capture) or a
406
+ // failed/declined Codex preflight. The "Chat access" step above already
407
+ // printed the specific reason.
408
+ ui.step("skip", "Chat import", "skipped (capture not enabled)");
409
+ }
410
+ else {
411
+ captureRan = true;
412
+ const captureResult = await runFirstCapturePass(globalOpts.config, dataDir);
413
+ captureSaved = captureResult.saved;
414
+ // Per A-1.1/C-1.3: a token-issuance failure during capture-pass
415
+ // is fatal. The wizard cannot meaningfully continue without auth
416
+ // (import + recall both need a token), and silently advancing
417
+ // past it was the original bug.
418
+ if (captureResult.fatal) {
419
+ rl.close();
420
+ return;
421
+ }
422
+ }
423
+ // Step 8 — optional export import.
424
+ let importSucceeded = false;
425
+ let importAttempted = false;
426
+ if (isOff(opts, "importExport", "noImportExport")) {
427
+ ui.step("skip", "File import", "skipped (--no-import-export)");
428
+ }
429
+ else {
430
+ const importPath = await collectImportPath(opts, rl, {
431
+ willRun: autoCaptureWillRun,
432
+ configured: captureEnabled,
433
+ workerLabel,
434
+ });
435
+ if (importPath) {
436
+ importAttempted = true;
437
+ const outcome = await runImport(importPath, globalOpts.config);
438
+ if (outcome.kind === "imported" || outcome.kind === "duplicate") {
439
+ importSucceeded = true;
440
+ }
441
+ }
442
+ else {
443
+ ui.step("skip", "File import", "none — run `onadit import <path> --source <name>` later");
444
+ }
445
+ }
446
+ // Step 9 — first-recall verification.
447
+ // A recall check only makes sense once this run actually landed user data.
448
+ // When nothing was imported or captured (the default, deliberate path), we
449
+ // skip the search check rather than start a spinner and FAIL it — failing a
450
+ // check the user opted out of is what made a clean setup feel broken.
451
+ const ingestedAny = captureSaved > 0 || importSucceeded;
452
+ const ingestAttempted = captureRan || importAttempted;
453
+ let recall;
454
+ if (!ingestedAny) {
455
+ ui.step("skip", "Search check", "nothing imported yet — skipped");
456
+ recall = { ok: false, reason: "nothing imported yet" };
457
+ }
458
+ else {
459
+ const recallSpin = new ui.Spinner("Search check").start();
460
+ recall = await firstRecallCheck(globalOpts.config);
461
+ if (recall.ok && recall.hits > 0) {
462
+ recallSpin.succeed("Search check", `found ${recall.hits} result(s)`);
463
+ }
464
+ else if (recall.ok) {
465
+ recallSpin.warn("Search check", "no results yet — index is fresh, try a query shortly");
466
+ }
467
+ else {
468
+ recallSpin.fail("Search check", recall.reason);
469
+ }
470
+ }
471
+ // Step 10 — next-action card.
472
+ const card = decideOnboardOutcome({ ingestedAny, recall, ingestAttempted });
473
+ card.push(ui.pc.dim(last4 !== null
474
+ ? `Voyage: key ${savedLast4 !== null ? "already set up" : "valid"} (last 4 …${last4})${safeLabel ? ` · label ${safeLabel}` : ""}`
475
+ : "Search: keyword-only (no embedding key) — add one later for semantic search"));
476
+ // One-line "what's on/off" so the friend leaves knowing whether Onadit keeps
477
+ // itself fed. Three honest states: ready (configured + worker available),
478
+ // configured-but-not-ready (preflight failed — don't claim it's running),
479
+ // and off (the default). Capture is off by default (zero-egress default).
480
+ card.push(ui.pc.dim(autoCaptureWillRun
481
+ ? "Auto-capture: on — new chats are captured on a schedule."
482
+ : captureEnabled
483
+ ? `Auto-capture: configured on, but not ready — ${workerLabel} isn't available (${triageWorkerName === "claude_code"
484
+ ? "run `claude` and sign in"
485
+ : "run `codex login`"}).`
486
+ : "Auto-capture: off — enable with: onadit onboard --enable-capture"));
487
+ ui.box(card);
488
+ ui.line("");
489
+ }
490
+ finally {
491
+ rl.close();
492
+ }
493
+ }
494
+ // ----- Idempotent re-run: "already set up" report -----
495
+ /**
496
+ * An install is "already onboarded" once its config.json exists and the data
497
+ * dir it points at is present. Returns the data dir, or null when this looks
498
+ * like a fresh install (no config, unreadable config, or a missing data dir) —
499
+ * in which case the caller runs the normal first-time flow.
500
+ */
501
+ function readOnboardedState(absoluteConfig) {
502
+ if (!fs.existsSync(absoluteConfig))
503
+ return null;
504
+ try {
505
+ const cfg = loadConfig(absoluteConfig);
506
+ const dataDir = cfg.data_paths.data_dir;
507
+ return fs.existsSync(dataDir) ? { dataDir } : null;
508
+ }
509
+ catch {
510
+ return null;
511
+ }
512
+ }
513
+ /**
514
+ * Resolve the key an installed Onadit CLI would use for an already-onboarded
515
+ * report — AND where it came from. The shell `$VOYAGE_API_KEY` wins (it
516
+ * overrides in-process checks); the saved `~/.rift.env` is read only when the
517
+ * config path is the canonical installed Onadit config under that same home, so
518
+ * custom/test `--config` runs never read the developer machine's real env file.
519
+ * When both exist and differ, the resolution flags the shadow so we can warn.
520
+ */
521
+ function resolveOnboardVoyageKeySource(absoluteConfig) {
522
+ const shellKey = (process.env["VOYAGE_API_KEY"] ?? "").trim() || null;
523
+ const homeDir = homeDirForInstalledRiftConfig(absoluteConfig);
524
+ const fileKey = homeDir ? readSavedVoyageKey(defaultRiftEnvPath(homeDir)) : null;
525
+ return resolveVoyageKeySource(shellKey, fileKey);
526
+ }
527
+ /**
528
+ * Last-4 of the Voyage key already saved for this install, when this run
529
+ * should keep using it: no key was passed to replace it, and the shell does
530
+ * not export a different one. Null otherwise, and the key step runs as usual.
531
+ * The key is not re-validated here: the engine's own health check after the
532
+ * restart says whether it loaded one.
533
+ */
534
+ function savedVoyageKeyToKeep(opts, absoluteConfig) {
535
+ if (typeof opts.voyageKey === "string" && opts.voyageKey.trim())
536
+ return null;
537
+ const homeDir = homeDirForInstalledRiftConfig(absoluteConfig);
538
+ const saved = homeDir ? readSavedVoyageKey(defaultRiftEnvPath(homeDir)) : null;
539
+ if (!saved)
540
+ return null;
541
+ const shell = (process.env["VOYAGE_API_KEY"] ?? "").trim();
542
+ if (shell && shell !== saved)
543
+ return null;
544
+ return resolveVoyageKeySource(null, saved).last4;
545
+ }
546
+ function homeDirForInstalledRiftConfig(absoluteConfig) {
547
+ const suffix = path.join("Library", "Application Support", "Rift", // rename:keep data folder name
548
+ "data", "config.json");
549
+ const marker = `${path.sep}${suffix}`;
550
+ if (!absoluteConfig.endsWith(marker))
551
+ return null;
552
+ const homeDir = absoluteConfig.slice(0, -marker.length);
553
+ return homeDir.length > 0 ? homeDir : null;
554
+ }
555
+ /**
556
+ * Passive-re-run summary for an already-onboarded install. Validates the stored
557
+ * Voyage key ONLY to report its health — never to gate. The three outcomes are
558
+ * all clean exits (this function never throws, which is the whole point):
559
+ * - valid → "you're all set"
560
+ * - rejected → "key expired/revoked, replace it" (degraded, not broken)
561
+ * - probe error (offline/timeout) → "couldn't check, run doctor if search is off"
562
+ *
563
+ * Throwing here is the beta.25 bug: a re-run on an expired key ended the whole
564
+ * command with "onboard failed" even though the install was fine.
565
+ *
566
+ * Exported for testing; `runOnboard` is the only production caller.
567
+ */
568
+ export async function reportAlreadyOnboarded(keyRes, deps = {}) {
569
+ const validate = deps.validate ?? validateVoyageKey;
570
+ ui.step("ok", "Onadit", "already set up");
571
+ // Be explicit about WHICH key this check used (shell env vs ~/.rift.env) and
572
+ // warn when a shell value shadows the saved key — so a stale shell export
573
+ // can't make a healthy install look broken without explanation.
574
+ for (const line of voyageKeySourceLines(keyRes))
575
+ ui.note(line);
576
+ const storedKey = keyRes.key ?? "";
577
+ const spin = new ui.Spinner("Search index").start();
578
+ let result;
579
+ try {
580
+ result = await validate({ apiKey: storedKey });
581
+ }
582
+ catch {
583
+ // A probe error (offline, timeout) is not a setup failure — the key may be
584
+ // fine. Don't fail the command; point at doctor for a deeper check.
585
+ spin.warn("Search index", "couldn't reach Voyage to check the key");
586
+ ui.note("Your install is set up. If semantic search seems off, run `onadit doctor`.");
587
+ return;
588
+ }
589
+ if (result.ok) {
590
+ spin.succeed("Search index", `Voyage key valid · ····${result.last4}`);
591
+ ui.note('You\'re all set. Search: `onadit search "<query>"`. Re-check anytime: `onadit doctor`.');
592
+ return;
593
+ }
594
+ // Key present but rejected (expired/revoked): semantic search is degraded, not
595
+ // broken. Point to repair; never throw.
596
+ spin.warn("Search index", "stored Voyage key was rejected");
597
+ ui.note("Your install is set up, but Voyage rejected the saved key (expired or revoked). " +
598
+ "Semantic search is degraded until you replace it:\n" +
599
+ " • Replace the key: onadit onboard --reconfigure-voyage\n" +
600
+ " • Diagnose search: onadit doctor");
601
+ }
602
+ // ----- Step 1: config.json + data dir -----
603
+ export async function ensureConfigAndDataDir(configPath, opts, rl) {
604
+ const absoluteConfig = path.resolve(configPath);
605
+ const shownConfig = absoluteConfig.replace(os.homedir(), "~");
606
+ if (fs.existsSync(absoluteConfig)) {
607
+ const config = loadConfig(absoluteConfig);
608
+ ui.step("ok", "Settings", shownConfig);
609
+ ui.note(`data dir: ${config.data_paths.data_dir}`);
610
+ return config.data_paths.data_dir;
611
+ }
612
+ const defaultDataDir = DEFAULT_DATA_DIR;
613
+ const dataDir = opts.yes
614
+ ? defaultDataDir
615
+ : (await ask(rl, `Data dir [${defaultDataDir}]: `, defaultDataDir)).trim() ||
616
+ defaultDataDir;
617
+ fs.mkdirSync(dataDir, { recursive: true });
618
+ const inboxDir = path.join(dataDir, "inbox");
619
+ fs.mkdirSync(inboxDir, { recursive: true });
620
+ const config = {
621
+ sources: [
622
+ {
623
+ path: inboxDir,
624
+ extraction: "cloud",
625
+ mode: "watch",
626
+ scope: "project",
627
+ },
628
+ ],
629
+ embedding: { provider: "voyage", model: "voyage-3-lite" },
630
+ data_paths: { data_dir: dataDir, jobs_dir: path.join(dataDir, "..", "jobs") },
631
+ rate_limit: { window_ms: 60_000, max_requests: 100 },
632
+ // Trust-first default: scheduled chat capture is OFF. The capture lane
633
+ // runs a Codex CLI triage call, so a fresh install sends no conversation
634
+ // content off-device, runs no Voyage embedding, and makes no Codex model
635
+ // call until the user opts in with `--enable-capture` (persisted below).
636
+ // (The daemon does make a metadata-only npm version check — no content, no
637
+ // key, no machine info.) The daemon gates auto-capture on `capture.enabled`.
638
+ capture: { enabled: false, interval_seconds: 3600 },
639
+ // Trust-first default: AI metadata enrichment is OFF. Import + keyword
640
+ // search run AI-free (BasicMetadataExtractor) and make no Codex calls,
641
+ // even on a machine with Codex installed. `--enable-codex-enrichment`
642
+ // (persisted below) flips this on. The `embedding` block above is a
643
+ // routing target only — without a Voyage key, search stays lexical.
644
+ enrichment: { ai_metadata: false },
645
+ };
646
+ fs.mkdirSync(path.dirname(absoluteConfig), { recursive: true });
647
+ fs.writeFileSync(absoluteConfig, JSON.stringify(config, null, 2) + "\n", {
648
+ encoding: "utf8",
649
+ mode: 0o644,
650
+ });
651
+ ui.step("ok", "Settings", `wrote default · ${shownConfig}`);
652
+ ui.note(`data dir: ${dataDir}`);
653
+ // Trigger ensureDirectories.
654
+ loadConfig(absoluteConfig);
655
+ return dataDir;
656
+ }
657
+ // ----- Step 2a: persist --voyage-label to config.json -----
658
+ /**
659
+ * Sanitize a raw `--voyage-label`, persist it when valid, and return the
660
+ * string the caller should use for display. Invalid labels are dropped
661
+ * with a generic notice that never echoes the raw value — so a
662
+ * key-shaped, path-shaped, or legacy-name-shaped label cannot leak
663
+ * through stdout or `config.json`. Returns `null` when the input was
664
+ * absent or rejected.
665
+ *
666
+ * Exported for orchestrator-level tests; `runOnboard` is the only
667
+ * production caller.
668
+ */
669
+ export function applyVoyageLabel(rawLabel, configPath, emit) {
670
+ if (rawLabel === undefined)
671
+ return null;
672
+ const sanitized = sanitizeProjectLabel(rawLabel);
673
+ if (!sanitized) {
674
+ // Generic message: never echo the raw value. Anything we say here
675
+ // also has to land in the friend's terminal, so it must not name
676
+ // the rejected token.
677
+ emit("Ignoring --voyage-label: must be 1–32 chars of letters, digits, '-' or '_' " +
678
+ "(no paths, secrets, or legacy product names).");
679
+ return null;
680
+ }
681
+ persistVoyageLabel(configPath, sanitized);
682
+ emit(`Stored Voyage label: ${sanitized}`);
683
+ return sanitized;
684
+ }
685
+ /**
686
+ * Merge `voyage.project_label` into the config file. The file is
687
+ * backed up to `<file>.bak.<iso>` first so an interrupted write or a
688
+ * future operator typo can be undone. Display only — never sent to the
689
+ * relay, never inferred from the key bytes.
690
+ *
691
+ * Defensively re-runs `sanitizeProjectLabel` even though the standard
692
+ * `applyVoyageLabel` caller has already validated: a future programmer
693
+ * who reaches for this export directly still cannot land an unsafe
694
+ * string in the file.
695
+ */
696
+ export function persistVoyageLabel(configPath, label) {
697
+ const sanitized = sanitizeProjectLabel(label);
698
+ if (!sanitized) {
699
+ throw new CliError("Refusing to persist Voyage label: not a valid label " +
700
+ "(1–32 chars of letters, digits, '-' or '_'; no paths, secrets, or legacy names).", "validation");
701
+ }
702
+ const absolute = path.resolve(configPath);
703
+ if (!fs.existsSync(absolute)) {
704
+ // ensureConfigAndDataDir always writes config.json before this runs;
705
+ // a missing file here means the caller bypassed step 1.
706
+ throw new CliError(`Cannot persist Voyage label: config not found at ${absolute}`, "validation");
707
+ }
708
+ const raw = fs.readFileSync(absolute, "utf8");
709
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
710
+ fs.writeFileSync(`${absolute}.bak.${stamp}`, raw, { encoding: "utf8", mode: 0o600 });
711
+ const parsed = JSON.parse(raw);
712
+ const voyage = parsed["voyage"] ?? {};
713
+ voyage["project_label"] = sanitized;
714
+ parsed["voyage"] = voyage;
715
+ const tmp = `${absolute}.tmp.${process.pid}`;
716
+ fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", {
717
+ encoding: "utf8",
718
+ mode: 0o644,
719
+ });
720
+ fs.renameSync(tmp, absolute);
721
+ }
722
+ /**
723
+ * Persist the Codex AI-metadata-enrichment opt-in into config.json. Default
724
+ * onboarding leaves `enrichment.ai_metadata = false` (AI-free import + keyword
725
+ * search, zero Codex calls). When the user passes `--enable-codex-enrichment`,
726
+ * this flips it to true AND pins `enrichment.metadata.provider = "codex_cli"` so
727
+ * the daemon/worker select the Codex-backed extractor — overriding any prior
728
+ * `claude_code` pin rather than silently leaving Claude selected. Backs the file
729
+ * up first, mirroring `persistVoyageLabel`.
730
+ *
731
+ * Exported for orchestrator-level tests; `runOnboard` is the only production
732
+ * caller. Returns true when the flag was set and persisted, false otherwise.
733
+ */
734
+ export function applyCodexEnrichmentOptIn(enable, configPath, emit) {
735
+ if (enable !== true)
736
+ return false;
737
+ const absolute = path.resolve(configPath);
738
+ if (!fs.existsSync(absolute)) {
739
+ throw new CliError(`Cannot persist enrichment opt-in: config not found at ${absolute}`, "validation");
740
+ }
741
+ const raw = fs.readFileSync(absolute, "utf8");
742
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
743
+ fs.writeFileSync(`${absolute}.bak.${stamp}`, raw, { encoding: "utf8", mode: 0o600 });
744
+ const parsed = JSON.parse(raw);
745
+ const enrichment = parsed["enrichment"] ?? {};
746
+ enrichment["ai_metadata"] = true;
747
+ // Pin the metadata worker to Codex explicitly. Setting only `ai_metadata`
748
+ // would leave a pre-existing `metadata.provider = "claude_code"` in place, so
749
+ // "use Codex" would silently keep routing metadata through Claude (and keep
750
+ // digests off). Codex opt-in must win the provider selection, not just the gate.
751
+ const metadata = enrichment["metadata"] ?? {};
752
+ metadata["provider"] = "codex_cli";
753
+ enrichment["metadata"] = metadata;
754
+ parsed["enrichment"] = enrichment;
755
+ const tmp = `${absolute}.tmp.${process.pid}`;
756
+ fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", {
757
+ encoding: "utf8",
758
+ mode: 0o644,
759
+ });
760
+ fs.renameSync(tmp, absolute);
761
+ emit("Codex AI metadata enrichment enabled (enrichment.ai_metadata = true, metadata.provider = codex_cli).");
762
+ return true;
763
+ }
764
+ /**
765
+ * Persist the Claude-Code AI-metadata-enrichment opt-in into config.json. Like
766
+ * `applyCodexEnrichmentOptIn` it flips `enrichment.ai_metadata = true`, but it
767
+ * ALSO pins `enrichment.metadata.provider = "claude_code"` so the daemon/worker
768
+ * route metadata through the `claude` CLI instead of Codex. Backs the file up
769
+ * first, mirroring the Codex opt-in. Callers must reject the combination of
770
+ * both enrichment flags before reaching here (see `runOnboard`).
771
+ *
772
+ * Discloses the one capability this does NOT turn on: there is no Claude digest
773
+ * worker yet and we will not silently borrow Codex for it, so digests/
774
+ * compaction stay off until a dedicated digest-provider slice ships. Saying so
775
+ * here prevents a silent capability loss for a user who switches to Claude.
776
+ *
777
+ * Exported for orchestrator-level tests; `runOnboard` is the only production
778
+ * caller. Returns true when the flag was set and persisted, false otherwise.
779
+ */
780
+ export function applyClaudeEnrichmentOptIn(enable, configPath, emit) {
781
+ if (enable !== true)
782
+ return false;
783
+ const absolute = path.resolve(configPath);
784
+ if (!fs.existsSync(absolute)) {
785
+ throw new CliError(`Cannot persist enrichment opt-in: config not found at ${absolute}`, "validation");
786
+ }
787
+ const raw = fs.readFileSync(absolute, "utf8");
788
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
789
+ fs.writeFileSync(`${absolute}.bak.${stamp}`, raw, { encoding: "utf8", mode: 0o600 });
790
+ const parsed = JSON.parse(raw);
791
+ const enrichment = parsed["enrichment"] ?? {};
792
+ enrichment["ai_metadata"] = true;
793
+ const metadata = enrichment["metadata"] ?? {};
794
+ metadata["provider"] = "claude_code";
795
+ enrichment["metadata"] = metadata;
796
+ parsed["enrichment"] = enrichment;
797
+ const tmp = `${absolute}.tmp.${process.pid}`;
798
+ fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", {
799
+ encoding: "utf8",
800
+ mode: 0o644,
801
+ });
802
+ fs.renameSync(tmp, absolute);
803
+ emit("Claude metadata enrichment enabled. Digests/compaction stay off until Claude digest support ships.");
804
+ return true;
805
+ }
806
+ /**
807
+ * Persist the scheduled-capture opt-in. Default install writes
808
+ * `capture.enabled = false` (trust-first: zero Codex calls on a fresh
809
+ * machine). When the user passes `--enable-capture`, this flips it to true
810
+ * so the daemon runs auto-capture on its interval. Backs the file up first,
811
+ * mirroring `applyCodexEnrichmentOptIn`.
812
+ *
813
+ * Exported for orchestrator-level tests; `runOnboard` is the only production
814
+ * caller. Returns true when the flag was set and persisted, false otherwise.
815
+ */
816
+ export function applyCaptureOptIn(enable, configPath, emit) {
817
+ if (enable !== true)
818
+ return false;
819
+ const absolute = path.resolve(configPath);
820
+ if (!fs.existsSync(absolute)) {
821
+ throw new CliError(`Cannot persist capture opt-in: config not found at ${absolute}`, "validation");
822
+ }
823
+ writeCaptureEnabled(absolute, true);
824
+ emit("Scheduled chat capture enabled (capture.enabled = true).");
825
+ return true;
826
+ }
827
+ /**
828
+ * Persist the Claude Desktop agent/Cowork capture opt-in into config.json.
829
+ * This adds `claude_desktop_sessions` to `capture.sources` without making it a
830
+ * default for fresh installs. Existing Cowork history is still privacy-safe:
831
+ * the first capture run bootstraps/watermarks already-present sessions instead
832
+ * of importing them as new.
833
+ *
834
+ * Exported for focused tests; `runOnboard` is the production caller.
835
+ */
836
+ export function applyCoworkCaptureOptIn(enable, configPath, emit) {
837
+ if (enable !== true)
838
+ return false;
839
+ const absolute = path.resolve(configPath);
840
+ if (!fs.existsSync(absolute)) {
841
+ throw new CliError(`Cannot persist Cowork capture opt-in: config not found at ${absolute}`, "validation");
842
+ }
843
+ const raw = fs.readFileSync(absolute, "utf8");
844
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
845
+ fs.writeFileSync(`${absolute}.bak.${stamp}`, raw, { encoding: "utf8", mode: 0o600 });
846
+ const parsed = JSON.parse(raw);
847
+ const capture = parsed["capture"] ?? {};
848
+ const currentSources = Array.isArray(capture["sources"])
849
+ ? capture["sources"].filter((s) => typeof s === "string" &&
850
+ (s === "claude_code" ||
851
+ s === "codex_cli" ||
852
+ s === CURSOR_CAPTURE_SOURCE ||
853
+ s === CLAUDE_DESKTOP_CAPTURE_SOURCE || s === "grok_cli"))
854
+ : [...DEFAULT_AUTO_CAPTURE_SOURCES];
855
+ if (!currentSources.includes(CLAUDE_DESKTOP_CAPTURE_SOURCE)) {
856
+ currentSources.push(CLAUDE_DESKTOP_CAPTURE_SOURCE);
857
+ }
858
+ capture["sources"] = currentSources;
859
+ parsed["capture"] = capture;
860
+ const tmp = `${absolute}.tmp.${process.pid}`;
861
+ fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", {
862
+ encoding: "utf8",
863
+ mode: 0o644,
864
+ });
865
+ fs.renameSync(tmp, absolute);
866
+ emit("Claude Desktop Cowork capture enabled (capture.sources includes claude_desktop_sessions). Existing Cowork sessions are baselined on first run; new sessions are captured after that.");
867
+ return true;
868
+ }
869
+ export function applyGrokCaptureOptIn(enable, configPath, emit) {
870
+ if (enable !== true)
871
+ return false;
872
+ const absolute = path.resolve(configPath);
873
+ if (!fs.existsSync(absolute)) {
874
+ throw new CliError(`Cannot persist Grok CLI capture opt-in: config not found at ${absolute}`, "validation");
875
+ }
876
+ const raw = fs.readFileSync(absolute, "utf8");
877
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
878
+ fs.writeFileSync(`${absolute}.bak.${stamp}`, raw, { encoding: "utf8", mode: 0o600 });
879
+ const parsed = JSON.parse(raw);
880
+ const capture = parsed["capture"] ?? {};
881
+ const currentSources = Array.isArray(capture["sources"])
882
+ ? capture["sources"].filter((s) => typeof s === "string" &&
883
+ (s === "claude_code" ||
884
+ s === "codex_cli" ||
885
+ s === CURSOR_CAPTURE_SOURCE ||
886
+ s === CLAUDE_DESKTOP_CAPTURE_SOURCE || s === "grok_cli"))
887
+ : [...DEFAULT_AUTO_CAPTURE_SOURCES];
888
+ if (!currentSources.includes("grok_cli")) {
889
+ currentSources.push("grok_cli");
890
+ }
891
+ capture["sources"] = currentSources;
892
+ parsed["capture"] = capture;
893
+ const tmp = `${absolute}.tmp.${process.pid}`;
894
+ fs.writeFileSync(tmp, JSON.stringify(parsed, null, 2) + "\n", {
895
+ encoding: "utf8",
896
+ mode: 0o644,
897
+ });
898
+ fs.renameSync(tmp, absolute);
899
+ emit("Grok CLI capture enabled (capture.sources includes grok_cli). Existing and future local CLI sessions are captured. Grok Bot is not captured.");
900
+ return true;
901
+ }
902
+ // ----- Step 2: Voyage key flow -----
903
+ async function collectAndPersistVoyageKey(opts, rl) {
904
+ const key = await collectVoyageKey(opts, rl);
905
+ if (!key) {
906
+ // No key → keyword-only (lexical) mode. Not a failure; import + search
907
+ // still work. Skip validation, the env write, and the Voyage smoke.
908
+ ui.step("info", "Search index", "no key — keyword search (semantic off)");
909
+ ui.note("Add semantic search later: run `onadit onboard` and paste a Voyage key.");
910
+ return null;
911
+ }
912
+ const validateSpin = new ui.Spinner("Search index").start();
913
+ const validation = await validateVoyageKey({ apiKey: key });
914
+ if (!validation.ok) {
915
+ validateSpin.fail("Search index", "validation failed");
916
+ throw new CliError(`Voyage validation failed: ${validation.reason}`, "validation");
917
+ }
918
+ validateSpin.succeed("Search index", `connected · Voyage · ····${validation.last4}`);
919
+ const envPath = defaultRiftEnvPath();
920
+ const writeResult = writeEnvFile({ filePath: envPath, key: "VOYAGE_API_KEY", value: key });
921
+ ui.note(writeResult.backedUp
922
+ ? "wrote ~/.rift.env (existing file backed up)"
923
+ : "wrote ~/.rift.env (mode 0600)");
924
+ // Refresh process.env so any subsequent in-process Voyage call sees it.
925
+ loadRiftEnv({ filePath: envPath });
926
+ // NOTE: the daemon kickstart + smoke deliberately does NOT happen here.
927
+ // It runs in `runOnboard` AFTER the opt-in writes (label/enrichment/
928
+ // capture) land in config.json, so the respawned daemon boots with the
929
+ // final config. The daemon builds its capture loop and metadata extractor
930
+ // once at boot (src/main.ts), so kickstarting before those writes would
931
+ // leave `--enable-capture` / `--enable-codex-enrichment` inert until a
932
+ // later restart.
933
+ return validation.last4;
934
+ }
935
+ /**
936
+ * Resolve the Voyage key, or `""` to mean "finish without a key" (keyword-only
937
+ * lexical mode). The key is no longer mandatory: a friend can import and search
938
+ * first, then add a key later for semantic ranking. Returns `""` on explicit
939
+ * opt-out (`--no-voyage-key`), on `--yes` with no key available, or when the
940
+ * interactive prompt is left blank.
941
+ */
942
+ export async function collectVoyageKey(opts, rl) {
943
+ if (opts.voyageKey === false || opts.noVoyageKey === true)
944
+ return "";
945
+ if (typeof opts.voyageKey === "string" && opts.voyageKey.trim()) {
946
+ return opts.voyageKey.trim();
947
+ }
948
+ if (process.env["VOYAGE_API_KEY"])
949
+ return process.env["VOYAGE_API_KEY"].trim();
950
+ // Non-interactive with no key supplied: finish in lexical mode rather than
951
+ // fail. The friend can run `onadit onboard` again with a key anytime.
952
+ if (opts.yes)
953
+ return "";
954
+ // Explain the key BEFORE asking for it — a beta user should know what
955
+ // they are pasting and why, not be confronted with a bare prompt.
956
+ ui.detail([
957
+ "Search index key (optional)",
958
+ "• What: paste the Voyage key Clem sent you (it won't echo as you type).",
959
+ "• Why: Voyage adds meaning-based (semantic) search on top of keyword search.",
960
+ "• Skip: press Enter to finish now with keyword search — add a key later anytime.",
961
+ "• Privacy: the key is stored locally and only sent to Voyage when Onadit calls Voyage; never sent to Clem.",
962
+ ].join("\n"));
963
+ const answer = (await ask(rl, "Paste your Voyage API key (or press Enter to skip): ")).trim();
964
+ return answer; // "" → finish in keyword-only mode
965
+ }
966
+ /**
967
+ * Kickstart, wait for /health, confirm the respawned daemon process has
968
+ * VOYAGE_API_KEY loaded. The smoke is fully non-indexing — `/health`
969
+ * exposes `voyage_key_present` so we never write a row to LanceDB just to
970
+ * prove the daemon read its env file. That keeps first-recall results
971
+ * free of an "onboarding probe" hit that would otherwise satisfy the
972
+ * completion check without any real user data being present.
973
+ */
974
+ async function daemonRefreshFlow(globalOpts) {
975
+ const baseUrl = safeResolveBaseUrl(globalOpts.config);
976
+ if (!baseUrl) {
977
+ ui.step("skip", "Onadit service", "not configured yet — bootstrap via install.sh, then re-run");
978
+ return { ok: false, reason: "daemon not configured", kind: "not_configured" };
979
+ }
980
+ const daemonSpin = new ui.Spinner("Onadit service").start();
981
+ const kick = await kickstartDaemon();
982
+ if (kick.status === "agent_not_loaded") {
983
+ daemonSpin.fail("Onadit service", "launchd agent not loaded");
984
+ ui.note(kick.hint);
985
+ return { ok: false, reason: kick.hint ?? "agent not loaded", kind: "agent_not_loaded" };
986
+ }
987
+ if (kick.status === "failed") {
988
+ daemonSpin.fail("Onadit service", "kickstart failed");
989
+ return {
990
+ ok: false,
991
+ reason: kick.hint ?? "kickstart failed",
992
+ kind: "kickstart_failed",
993
+ };
994
+ }
995
+ const health = await waitForHealth({ baseUrl });
996
+ if (!health.ok) {
997
+ daemonSpin.fail("Onadit service", "health check failed");
998
+ return { ok: false, reason: health.reason, kind: "health_failed" };
999
+ }
1000
+ if (!health.voyageKeyPresent) {
1001
+ daemonSpin.fail("Onadit service", "voyage_key_present=false after kickstart");
1002
+ return {
1003
+ ok: false,
1004
+ reason: "Daemon /health reports voyage_key_present=false after kickstart.",
1005
+ kind: "smoke_failed",
1006
+ };
1007
+ }
1008
+ daemonSpin.succeed("Onadit service", `healthy · daemon · uptime ${health.uptimeSeconds}s`);
1009
+ return { ok: true, kickstarted: true };
1010
+ }
1011
+ export function classifyTokenFailure(err) {
1012
+ const message = err instanceof Error ? err.message : String(err);
1013
+ const lower = message.toLowerCase();
1014
+ // A-1.2: the macOS Keychain prints the same string whether the lock
1015
+ // hits a read or a write. Catch on substring; don't try to inspect
1016
+ // SecKeychain error codes from JS.
1017
+ //
1018
+ // Two shapes can land here:
1019
+ // 1. The raw `security` error from a write path (`issueToken`),
1020
+ // whose message contains "User interaction is not allowed."
1021
+ // 2. The friendly `CliError` shape that `readToken` now throws
1022
+ // (post-beta.7) in place of the raw error. Its message starts
1023
+ // with "Login Keychain is locked" and embeds the
1024
+ // `security unlock-keychain` recovery command verbatim.
1025
+ // Both must classify as `keychain_locked` so the typed
1026
+ // recovery branch in `runFirstCapturePass` fires correctly.
1027
+ if (lower.includes("user interaction is not allowed") ||
1028
+ lower.includes("login keychain is locked") ||
1029
+ lower.includes("security unlock-keychain")) {
1030
+ return { reason: "keychain_locked", message };
1031
+ }
1032
+ return { reason: "other", message };
1033
+ }
1034
+ export async function ensureToken(configPath) {
1035
+ // A-1.2: readToken is inside the try — a locked-keychain *read* must
1036
+ // be classified the same as a locked-keychain *write*.
1037
+ try {
1038
+ const existing = await readToken();
1039
+ if (existing)
1040
+ return { ok: true, token: existing, source: "existing" };
1041
+ }
1042
+ catch (err) {
1043
+ const { reason, message } = classifyTokenFailure(err);
1044
+ return { ok: false, reason, message, hint: describeTokenFailure(message) };
1045
+ }
1046
+ try {
1047
+ const { token } = await issueToken(path.resolve(configPath));
1048
+ // Mirror to ~/.rift/token so subsequent CLI calls don't depend on Keychain.
1049
+ const tokenPath = path.join(os.homedir(), ".rift", "token");
1050
+ try {
1051
+ fs.mkdirSync(path.dirname(tokenPath), { recursive: true });
1052
+ fs.writeFileSync(tokenPath, token + "\n", {
1053
+ encoding: "utf8",
1054
+ mode: 0o600,
1055
+ });
1056
+ fs.chmodSync(tokenPath, 0o600);
1057
+ }
1058
+ catch (writeErr) {
1059
+ const reason = writeErr instanceof Error ? writeErr.message : String(writeErr);
1060
+ say(`Token issued but mirror to ${tokenPath} failed: ${reason}. Subsequent CLI calls will rely on Keychain only.`);
1061
+ }
1062
+ return { ok: true, token, source: "issued" };
1063
+ }
1064
+ catch (err) {
1065
+ const { reason, message } = classifyTokenFailure(err);
1066
+ return { ok: false, reason, message, hint: describeTokenFailure(message) };
1067
+ }
1068
+ }
1069
+ export function describeTokenFailure(reason) {
1070
+ const lower = reason.toLowerCase();
1071
+ // Two SSH-locked shapes can land here — check both before the generic
1072
+ // Keychain branch so the GUI-only "Keychain Access → File → Unlock"
1073
+ // copy never replaces the SSH-specific `security unlock-keychain`
1074
+ // command: (1) the raw `security` error from the write path, and
1075
+ // (2) the friendly CliError that readToken now emits post-beta.7,
1076
+ // whose message starts with "Login Keychain is locked" and embeds
1077
+ // the unlock command verbatim.
1078
+ if (lower.includes("user interaction is not allowed") ||
1079
+ lower.includes("login keychain is locked") ||
1080
+ lower.includes("security unlock-keychain")) {
1081
+ return "the login Keychain is locked (typical over SSH). Run `security unlock-keychain ~/Library/Keychains/login.keychain-db` (it will prompt for your Mac login password), then re-run `onadit onboard`. For local Terminal installs this should not happen.";
1082
+ }
1083
+ if (lower.includes("keychain") || lower.includes("security:")) {
1084
+ return "unlock the login Keychain (Keychain Access → File → Unlock) and re-run, or run from a Terminal session with GUI access (not over SSH).";
1085
+ }
1086
+ if (lower.includes("eacces") || lower.includes("permission denied")) {
1087
+ return "check that `~/.rift/` is writable by your user, then re-run `onadit onboard`.";
1088
+ }
1089
+ if (lower.includes("enoent") ||
1090
+ lower.includes("no such file") ||
1091
+ lower.includes("daemon") ||
1092
+ lower.includes("pid file") ||
1093
+ lower.includes("not running")) {
1094
+ return "start the daemon with `launchctl kickstart -k gui/$UID/com.getrift.daemon`, then re-run `onadit onboard`.";
1095
+ }
1096
+ return "re-run `onadit onboard`. If the failure repeats, run `onadit feedback --kind=broke --with-status` to ship a diagnostic bundle.";
1097
+ }
1098
+ // ----- Step 3: triage-worker preflight -----
1099
+ /**
1100
+ * Live triage probe for the CONFIGURED worker (Codex CLI by default, or Claude
1101
+ * Code when `capture.triage.provider = claude_code`). Routing through the
1102
+ * factory — not a hardcoded CodexCliTriageProvider — is what stops a Claude
1103
+ * Code user who deliberately picked `claude_code` from being failed by a Codex
1104
+ * probe they never asked for.
1105
+ */
1106
+ async function triagePreflight(name) {
1107
+ try {
1108
+ await createTriageProvider(name, { timeoutMs: 120_000 }).triage({
1109
+ content: "User: Onadit onboarding preflight.\n\nAssistant: Ready.",
1110
+ });
1111
+ return true;
1112
+ }
1113
+ catch {
1114
+ return false;
1115
+ }
1116
+ }
1117
+ /**
1118
+ * Conservative email check — enough to catch obvious typos at the prompt;
1119
+ * the relay endpoint can re-validate. Returns the normalized (trimmed,
1120
+ * lowercased) address, or undefined if it doesn't look like an email.
1121
+ */
1122
+ export function normalizeEmail(raw) {
1123
+ const s = raw.trim().toLowerCase();
1124
+ return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s) ? s : undefined;
1125
+ }
1126
+ /**
1127
+ * Bundled "stay connected" opt-in. One yes/no that, on yes, collects an
1128
+ * email used for product news, pricing, a leaving-beta heads-up, and a
1129
+ * feedback channel. Opt-in only: `--yes` alone never subscribes (consent
1130
+ * must be active), `--no-feedback-relay` declines, and `--email` subscribes
1131
+ * non-interactively. The relay URL stays operator-only infra; when none is
1132
+ * configured the email is captured locally (sidecar + beta-signups.jsonl)
1133
+ * and reaches the operator once an endpoint is wired.
1134
+ */
1135
+ export async function collectFeedbackPreference(opts, dataDir, rl, store = macRelaySecretStore) {
1136
+ const declined = isOff(opts, "feedbackRelay", "noFeedbackRelay");
1137
+ // Relay URL + signing secret come from EITHER an invite code (preferred:
1138
+ // nothing to paste by hand) OR the back-compat operator flags. The secret
1139
+ // never lands in the sidecar — it goes to the Keychain below.
1140
+ let url;
1141
+ let secret;
1142
+ if (!declined) {
1143
+ if (opts.invite) {
1144
+ const invite = parseInvite(opts.invite); // throws a friendly CliError if bad
1145
+ url = invite.url;
1146
+ secret = invite.secret;
1147
+ }
1148
+ else {
1149
+ url = opts.enableFeedbackRelay;
1150
+ secret = url ? opts.relaySecret : undefined;
1151
+ }
1152
+ }
1153
+ // Friend-grade interactive path: when no relay flags were passed, offer to
1154
+ // paste an invite so the bearer code never lands in shell history. Skipped
1155
+ // off a TTY and under --yes (automation). A bad paste warns and skips — it
1156
+ // never aborts onboarding.
1157
+ if (!declined &&
1158
+ !url &&
1159
+ !opts.invite &&
1160
+ !opts.enableFeedbackRelay &&
1161
+ !opts.yes &&
1162
+ process.stdin.isTTY) {
1163
+ // Most friends will NOT have an invite code — make that the obvious,
1164
+ // pressure-free default so the bare prompt doesn't read as "something is
1165
+ // missing". An invite only turns on the direct feedback relay; the email
1166
+ // ask below (and `onadit feedback`) work without it.
1167
+ ui.detail([
1168
+ "Feedback channel (optional)",
1169
+ "• Have an invite code from Clem? Paste it to turn on the direct feedback relay.",
1170
+ "• No code? Just press Enter — this is optional, and most people skip it.",
1171
+ "• Either way you can send feedback any time with `onadit feedback`.",
1172
+ ].join("\n"));
1173
+ const pasted = (await ask(rl, "Invite code from Clem (or press Enter to skip): ")).trim();
1174
+ if (pasted) {
1175
+ try {
1176
+ const invite = parseInvite(pasted);
1177
+ url = invite.url;
1178
+ secret = invite.secret;
1179
+ }
1180
+ catch {
1181
+ say(" That invite code is not valid — skipping feedback setup.");
1182
+ }
1183
+ }
1184
+ }
1185
+ // Configuring a URL without a signing secret leaves the install "looks
1186
+ // configured, silently dead" — the receiver requires a valid signature.
1187
+ // An invite always carries one; the flag path must pair a secret or
1188
+ // knowingly opt into unsigned mode (dev/local receivers only).
1189
+ if (url && !secret && !opts.allowUnsignedFeedbackRelay) {
1190
+ throw new CliError("Relay needs a signing secret. Use an invite (onadit onboard --invite <code>), " +
1191
+ "or pair --enable-feedback-relay with --relay-secret " +
1192
+ "(or --allow-unsigned-feedback-relay for a dev receiver).", "validation");
1193
+ }
1194
+ // Secure the secret BEFORE enabling relay: a write failure must not leave an
1195
+ // enabled config that can't sign. (3a's `onadit feedback setup` does the same.)
1196
+ if (secret) {
1197
+ try {
1198
+ await store.write(secret);
1199
+ }
1200
+ catch (err) {
1201
+ if (err instanceof LockedKeychainError) {
1202
+ throw new CliError("Your macOS Keychain is locked. Unlock it and retry: " +
1203
+ "security unlock-keychain ~/Library/Keychains/login.keychain-db", "validation");
1204
+ }
1205
+ throw err;
1206
+ }
1207
+ }
1208
+ let email;
1209
+ if (!declined) {
1210
+ if (opts.email) {
1211
+ email = normalizeEmail(opts.email);
1212
+ if (!email) {
1213
+ throw new CliError(`--email "${opts.email}" is not a valid email address.`, "validation");
1214
+ }
1215
+ }
1216
+ else if (!opts.yes && process.stdin.isTTY) {
1217
+ email = await promptStayConnected(rl);
1218
+ }
1219
+ // --yes / non-TTY with no --email: do not auto-subscribe.
1220
+ }
1221
+ const optedIn = email !== undefined || url !== undefined;
1222
+ const cfg = optedIn
1223
+ ? {
1224
+ enabled: true,
1225
+ installation_id: crypto.randomUUID(),
1226
+ ...(email ? { email } : {}),
1227
+ ...(url ? { url } : {}),
1228
+ // url && !secret only happens under --allow-unsigned-feedback-relay
1229
+ // (the guard above throws otherwise): mark it an intentional unsigned
1230
+ // relay so maybeRelay may POST without a secret for THIS install only.
1231
+ ...(url && !secret ? { unsigned: true } : {}),
1232
+ }
1233
+ : { enabled: false };
1234
+ // The sidecar holds only non-secret fields; the secret is already in the
1235
+ // Keychain (above).
1236
+ fs.mkdirSync(dataDir, { recursive: true });
1237
+ const sidecar = path.join(dataDir, "feedback-config.json");
1238
+ fs.writeFileSync(sidecar, JSON.stringify(cfg, null, 2) + "\n", {
1239
+ encoding: "utf8",
1240
+ mode: 0o600,
1241
+ });
1242
+ fs.chmodSync(sidecar, 0o600);
1243
+ if (cfg.email && cfg.installation_id) {
1244
+ // Sign the signup POST with the in-hand secret (no Keychain round-trip).
1245
+ await emitBetaSignup(cfg.email, cfg.installation_id, cfg.url, secret, dataDir);
1246
+ }
1247
+ return cfg;
1248
+ }
1249
+ /**
1250
+ * Interactive bundled opt-in. Returns the chosen email, or undefined if the
1251
+ * user declines or skips. Re-prompts up to 3× on a malformed address; an
1252
+ * empty line at any point means "skip".
1253
+ */
1254
+ async function promptStayConnected(rl) {
1255
+ ui.detail([
1256
+ "Stay in the loop (optional)",
1257
+ "• Get product news, pricing once we set it, and a heads-up when Onadit leaves beta.",
1258
+ "• Gives you a direct line to send feedback any time via `onadit feedback`.",
1259
+ "• Opt-in. Stored locally, shared only with Clem — never sold, never spammed.",
1260
+ ].join("\n"));
1261
+ const yn = (await ask(rl, "Share your email to stay connected? [y/N] ")).trim().toLowerCase();
1262
+ if (yn !== "y" && yn !== "yes")
1263
+ return undefined;
1264
+ for (let attempt = 0; attempt < 3; attempt++) {
1265
+ const raw = (await ask(rl, "Your email (Enter to skip): ")).trim();
1266
+ if (raw.length === 0)
1267
+ return undefined;
1268
+ const norm = normalizeEmail(raw);
1269
+ if (norm)
1270
+ return norm;
1271
+ say(" That doesn't look like an email address — try again, or press Enter to skip.");
1272
+ }
1273
+ return undefined;
1274
+ }
1275
+ /**
1276
+ * Record a one-time beta signup. The local JSONL row is canonical (never
1277
+ * lost); the relay POST is best-effort and only fires when an endpoint URL
1278
+ * is configured. Failures are swallowed — onboarding must never break on a
1279
+ * signup hiccup.
1280
+ */
1281
+ async function emitBetaSignup(email, installationId, url, hmacSecret, dataDir) {
1282
+ const build = getBuildInfo();
1283
+ const payload = {
1284
+ ts: new Date().toISOString(),
1285
+ event: "beta_signup",
1286
+ email,
1287
+ installation_id: installationId,
1288
+ version: build.version,
1289
+ commit: build.commit,
1290
+ node: build.node,
1291
+ };
1292
+ // Audit invariant: every byte that reaches Clem must exist locally first.
1293
+ // If the canonical row can't be written, we must NOT relay — otherwise a
1294
+ // signup could reach Clem with no local record to audit against.
1295
+ let wroteLocal = false;
1296
+ try {
1297
+ const dir = path.join(dataDir, "observability");
1298
+ fs.mkdirSync(dir, { recursive: true });
1299
+ const file = path.join(dir, "beta-signups.jsonl");
1300
+ fs.appendFileSync(file, `${JSON.stringify(payload)}\n`, {
1301
+ encoding: "utf8",
1302
+ mode: 0o600,
1303
+ });
1304
+ wroteLocal = true; // the canonical row is on disk; chmod below is cosmetic
1305
+ try {
1306
+ fs.chmodSync(file, 0o600);
1307
+ }
1308
+ catch {
1309
+ // best-effort permission fix — does not affect the audit invariant
1310
+ }
1311
+ }
1312
+ catch {
1313
+ // Local write failed — don't break onboarding over a signup row, and
1314
+ // (below) don't relay something we couldn't record locally.
1315
+ }
1316
+ if (url && wroteLocal) {
1317
+ try {
1318
+ await postFeedback(payload, {
1319
+ url,
1320
+ ...(hmacSecret ? { hmacSecret } : {}),
1321
+ });
1322
+ }
1323
+ catch {
1324
+ // Best-effort; the canonical row is already on disk.
1325
+ }
1326
+ }
1327
+ }
1328
+ // ----- Step 5b: Claude Code policy hook (opt-in) -----
1329
+ /**
1330
+ * Offer to install the Onadit policy hook into Claude Code's settings.
1331
+ *
1332
+ * Only runs when `~/.claude/settings.json` looks plausible (the dir
1333
+ * exists). Honors `--with-claude-hook` (force install, no prompt) and
1334
+ * `--no-claude-hook` (skip silently). Default `--yes` declines unless
1335
+ * `--with-claude-hook` is also set, so non-interactive operators never
1336
+ * silently get a global hook installed.
1337
+ *
1338
+ * Failures are non-fatal — onboarding continues. The hook is a quality
1339
+ * guardrail, not a correctness requirement.
1340
+ */
1341
+ async function maybeInstallClaudeCodeHook(opts, rl) {
1342
+ if (isOff(opts, "claudeHook", "noClaudeHook")) {
1343
+ return;
1344
+ }
1345
+ const homeDir = os.homedir();
1346
+ const claudeDir = path.join(homeDir, ".claude");
1347
+ const claudeCodeDetected = fs.existsSync(claudeDir);
1348
+ if (!claudeCodeDetected) {
1349
+ return;
1350
+ }
1351
+ let install = false;
1352
+ if (opts.withClaudeHook) {
1353
+ install = true;
1354
+ }
1355
+ else if (opts.yes) {
1356
+ // Non-interactive default: skip. Operator must opt in with --with-claude-hook.
1357
+ ui.step("skip", "Claude Code", "skipped (pass --with-claude-hook to install non-interactively)");
1358
+ return;
1359
+ }
1360
+ else {
1361
+ ui.note([
1362
+ "Claude Code detected.",
1363
+ "Optional: install a PreToolUse policy hook so Onadit retrieval starts with onadit_context_pack",
1364
+ "(prevents broad onadit_search dumps from burning context). Disable any time with RIFT_POLICY_DISABLED=1.",
1365
+ ].join("\n"));
1366
+ const answer = (await ask(rl, " Install Claude Code policy hook? [y/N]: ", "n"))
1367
+ .trim()
1368
+ .toLowerCase();
1369
+ install = answer === "y" || answer === "yes";
1370
+ }
1371
+ if (!install) {
1372
+ ui.step("skip", "Claude Code", "not installed");
1373
+ return;
1374
+ }
1375
+ try {
1376
+ const outcome = writeHookConfig({
1377
+ client: "claude-code",
1378
+ homeDir,
1379
+ dryRun: false,
1380
+ });
1381
+ if (outcome.hookEntryAdded) {
1382
+ ui.step("ok", "Claude Code", "connected · auto-recall hook added");
1383
+ }
1384
+ else if (outcome.hookEntryReplaced || outcome.scriptUpdated) {
1385
+ ui.step("ok", "Claude Code", "updated");
1386
+ }
1387
+ else {
1388
+ ui.step("ok", "Claude Code", "already up-to-date");
1389
+ }
1390
+ if (outcome.backupId) {
1391
+ ui.note(`backup ID: ${outcome.backupId}`);
1392
+ }
1393
+ ui.note("(Restart Claude Code or open /hooks once for the new entry to load.)");
1394
+ }
1395
+ catch (err) {
1396
+ if (err instanceof HooksParseFailedError) {
1397
+ ui.step("fail", "Claude Code", err.message);
1398
+ }
1399
+ else {
1400
+ ui.step("fail", "Claude Code", `install failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
1401
+ }
1402
+ }
1403
+ }
1404
+ // ----- Step 6 + 7: capture pass -----
1405
+ export async function runFirstCapturePass(configPath, dataDir) {
1406
+ const baseUrl = safeResolveBaseUrl(configPath);
1407
+ if (!baseUrl) {
1408
+ ui.step("skip", "Chat import", "daemon not reachable — skipped");
1409
+ return { saved: 0, reviewed: 0 };
1410
+ }
1411
+ // Per A-1.1/C-1.3: token failure here is fatal. The wizard cannot
1412
+ // proceed without a token (capture, import, recall all need auth).
1413
+ // The previous "skipping" path silently broke onboarding.
1414
+ const tokenResult = await ensureToken(configPath);
1415
+ if (!tokenResult.ok) {
1416
+ say("");
1417
+ if (tokenResult.reason === "keychain_locked") {
1418
+ say("Could not issue an auth token: the macOS login keychain is locked.");
1419
+ say("Run this, then re-run `onadit onboard`:");
1420
+ say(" security unlock-keychain ~/Library/Keychains/login.keychain-db");
1421
+ say("Note: the wizard will restart from the top. If your Voyage key is in");
1422
+ say(" VOYAGE_API_KEY it won't re-prompt; otherwise you'll re-paste it.");
1423
+ }
1424
+ else {
1425
+ // Per C-1.4 (round-6 fix): the "other" branch must spell out the
1426
+ // manual recovery so the user knows the exit path is `onadit token
1427
+ // issue` then re-running onboard. Generic hints alone aren't
1428
+ // enough.
1429
+ say(`Could not issue an auth token: ${tokenResult.message}`);
1430
+ say(`Recover: ${tokenResult.hint}`);
1431
+ say("If the failure persists, run `onadit token issue` manually, then re-run `onadit onboard`.");
1432
+ }
1433
+ process.exitCode = 1;
1434
+ return { saved: 0, reviewed: 0, fatal: true };
1435
+ }
1436
+ const token = tokenResult.token;
1437
+ const client = createHttpClient({ baseUrl, token });
1438
+ let codexCaptureDeps = {};
1439
+ let cursorCaptureDeps = {};
1440
+ // Onboarding is a config-driven capture path, so it must honor the Cursor
1441
+ // opt-in exactly like the daemon: if `cursor_composer` is in
1442
+ // `config.capture.sources`, this first pass authorizes Cursor discovery +
1443
+ // persistence WITHOUT the env flags (which exist only for ad-hoc dogfood
1444
+ // runs). Without this, onboarding would record cursor_composer in its ledger
1445
+ // row yet runAutoCapture would treat Cursor as disabled — capturing nothing.
1446
+ let cursorConfigEnabled = false;
1447
+ let enabledSources = DEFAULT_AUTO_CAPTURE_SOURCES;
1448
+ // Worker name for the honest preflight-failed warning below (defaults to the
1449
+ // codex_cli label until config resolves).
1450
+ let captureWorkerLabel = triageWorkerLabel("codex_cli");
1451
+ try {
1452
+ const { loadConfig } = await import("../../config/loader.js");
1453
+ const cfg = loadConfig(configPath);
1454
+ // Route this first capture pass through the configured triage worker —
1455
+ // runAutoCapture builds its provider from the process-wide configured name,
1456
+ // so without this a claude_code user's onboarding pass would silently fall
1457
+ // back to Codex. (Step 3 already set it; re-assert here so this function is
1458
+ // correct independent of call order.)
1459
+ const captureWorkerName = resolveTriageProviderName(cfg);
1460
+ setConfiguredTriageProviderName(captureWorkerName);
1461
+ captureWorkerLabel = triageWorkerLabel(captureWorkerName);
1462
+ codexCaptureDeps = resolveCodexCaptureDeps(cfg);
1463
+ cursorCaptureDeps = resolveCursorCaptureDeps(cfg);
1464
+ cursorConfigEnabled = cfg.capture.sources.includes(CURSOR_CAPTURE_SOURCE);
1465
+ enabledSources = cfg.capture.sources;
1466
+ }
1467
+ catch {
1468
+ codexCaptureDeps = {};
1469
+ cursorCaptureDeps = {};
1470
+ cursorConfigEnabled = false;
1471
+ }
1472
+ const startedAt = new Date();
1473
+ const captureSpin = new ui.Spinner("Chat import").start();
1474
+ try {
1475
+ const report = await runAutoCapture({
1476
+ dataDir,
1477
+ // Capture exactly the sources config enables — the same set the
1478
+ // scheduled daemon loop uses (buildDaemonAutoCaptureDeps passes
1479
+ // cfg.capture.sources) and the same set recorded in the ledger row
1480
+ // below. Omitting this falls back to DEFAULT_AUTO_CAPTURE_SOURCES, which
1481
+ // would let onboarding capture sources it never records — a status
1482
+ // ledger that says one thing while capture did another.
1483
+ sources: enabledSources,
1484
+ ...codexCaptureDeps,
1485
+ ...cursorCaptureDeps,
1486
+ cursorConfigEnabled,
1487
+ saveFn: async (saveOpts) => {
1488
+ const { data } = await client.post("/save", {
1489
+ source: saveOpts.source,
1490
+ summary: saveOpts.summary,
1491
+ content: saveOpts.content,
1492
+ topics: saveOpts.topics,
1493
+ ...(saveOpts.decisions?.length
1494
+ ? { decisions: saveOpts.decisions, user_statements_seal: saveOpts.user_statements_seal }
1495
+ : {}),
1496
+ domain: saveOpts.domain,
1497
+ idempotency_key: saveOpts.idempotency_key,
1498
+ ...(saveOpts.replace_idempotency_key
1499
+ ? { replace_idempotency_key: saveOpts.replace_idempotency_key }
1500
+ : {}),
1501
+ });
1502
+ const resp = data;
1503
+ if (resp.duplicate)
1504
+ return;
1505
+ const result = await pollJob({ get: client.get.bind(client), jobId: resp.job_id });
1506
+ if (isJobFailure(result.job, result.timedOut)) {
1507
+ throw new Error(`Save job failed: ${result.job.error ?? "unknown"}`);
1508
+ }
1509
+ },
1510
+ });
1511
+ // Record this onboard run in the health ledger (best-effort). Without
1512
+ // it, a friend who finishes onboarding and immediately runs `rift
1513
+ // status`/`onadit doctor` sees "no runs yet" — the exact stale-health
1514
+ // trust break this ledger exists to prevent, at the moment it matters
1515
+ // most. Tagged `onboard` so it sets freshness without ever speaking for
1516
+ // the scheduled daemon loop.
1517
+ try {
1518
+ await appendAutoCaptureRunRecord(dataDir, buildAutoCaptureRunRecord({
1519
+ timestamp: startedAt.toISOString(),
1520
+ enabledSources,
1521
+ durationMs: Date.now() - startedAt.getTime(),
1522
+ report,
1523
+ trigger: "onboard",
1524
+ }));
1525
+ }
1526
+ catch (observabilityErr) {
1527
+ process.stderr.write(`Onboard capture run-record append failed: ${observabilityErr instanceof Error
1528
+ ? observabilityErr.message
1529
+ : String(observabilityErr)}\n`);
1530
+ }
1531
+ const base = `${report.saved} added · ${report.review} to review`;
1532
+ // A preflight failure (triage-worker health probe) carries 0 per-session
1533
+ // errors, so an `errors > 0` check alone would `succeed()` on a run where
1534
+ // triage never ran — telling a friend everything's fine when it isn't.
1535
+ // Treat a failed probe as a warning too, and surface why.
1536
+ if (!report.preflight_ok) {
1537
+ captureSpin.warn("Chat import", `${base} · ${captureWorkerLabel} preflight failed${report.preflight_error ? ` (${report.preflight_error})` : ""}`);
1538
+ }
1539
+ else if (report.errors > 0) {
1540
+ captureSpin.warn("Chat import", `${base} · ${report.errors} error(s)`);
1541
+ }
1542
+ else {
1543
+ captureSpin.succeed("Chat import", base);
1544
+ }
1545
+ return { saved: report.saved, reviewed: report.review };
1546
+ }
1547
+ catch (err) {
1548
+ captureSpin.fail("Chat import", `error (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
1549
+ return { saved: 0, reviewed: 0 };
1550
+ }
1551
+ }
1552
+ // ----- Step 8: import -----
1553
+ async function collectImportPath(opts, rl, capture) {
1554
+ // opts.importExport is `string | false | undefined` — Commander writes
1555
+ // `false` when `--no-import-export` was passed, but the caller already
1556
+ // short-circuits in that case. Only a non-empty string is a real path.
1557
+ if (typeof opts.importExport === "string" && opts.importExport.length > 0) {
1558
+ return opts.importExport;
1559
+ }
1560
+ if (opts.yes)
1561
+ return null;
1562
+ // Explain what a path is, where to find the export, why it's optional,
1563
+ // and that ChatGPT is the only inline source — BEFORE the prompt. A beta
1564
+ // user who has never exported a chat archive shouldn't hit a bare
1565
+ // "Drop a path" prompt. The source-sniffer below still fail-fasts a
1566
+ // non-ChatGPT export, but the friend learns the boundary earlier here.
1567
+ //
1568
+ // The "skipping is fine" reassurance MUST match what will actually happen.
1569
+ // Auto-capture is OFF by default, AND can be configured-on-but-not-running
1570
+ // when the triage-worker preflight failed — promising "new chats get captured
1571
+ // automatically" in either case is the exact trust break this flow removes.
1572
+ // Only promise it when capture will genuinely run; otherwise point at the
1573
+ // real next step (fix the triage worker if configured, or enable it if off).
1574
+ const whySkip = capture.willRun
1575
+ ? "skipping is fine — new chats get captured automatically."
1576
+ : capture.configured
1577
+ ? `skipping is fine — import later with \`onadit import\` (auto-capture is on but won't run until ${capture.workerLabel} is ready — see above).`
1578
+ : "skipping is fine — import later with `onadit import`, or turn on auto-capture with `onadit onboard --enable-capture`.";
1579
+ ui.detail([
1580
+ "Import past chats (optional)",
1581
+ "• What: the file path to a ChatGPT data export (a .zip or .json on your Mac), e.g. ~/Downloads/chatgpt-export.zip.",
1582
+ "• Where: chatgpt.com → Settings → Data controls → Export data, then unzip nothing — just drop the downloaded file's path here.",
1583
+ `• Why: this seeds Onadit with your existing ChatGPT history so search works on day one; ${whySkip}`,
1584
+ "• Other tools: Claude/Grok/Gemini exports aren't imported here. Run them later with: onadit import <path> --source claude_web|grok_web|gemini_web",
1585
+ ].join("\n"));
1586
+ const answer = (await ask(rl, "Path to a ChatGPT export to import now (or `skip`): ", "skip")).trim();
1587
+ if (!answer || answer.toLowerCase() === "skip")
1588
+ return null;
1589
+ return answer;
1590
+ }
1591
+ /**
1592
+ * Inline import is intentionally narrow: ChatGPT exports only.
1593
+ * Friends importing Claude / Grok / Gemini exports during onboarding
1594
+ * are pointed at the standalone `onadit import <path> --source <name>`
1595
+ * command (Slice 3), which adds structural sniffing per source.
1596
+ */
1597
+ export async function runImport(filePath, configPath, source) {
1598
+ const unquoted = filePath.trim().replace(/^(["'])(.*)\1$/, "$2");
1599
+ const absolute = path.resolve(unquoted.startsWith("~/") ? path.join(os.homedir(), unquoted.slice(2)) : unquoted);
1600
+ if (!fs.existsSync(absolute)) {
1601
+ say(`Import file not found: ${absolute}`);
1602
+ return { kind: "skipped", reason: "file not found" };
1603
+ }
1604
+ const ext = path.extname(absolute).toLowerCase();
1605
+ if (!SUPPORTED_INGEST_EXTENSIONS.has(ext)) {
1606
+ say(`Unsupported file extension "${ext}". Allowed: .json, .zip.`);
1607
+ return { kind: "skipped", reason: "unsupported extension" };
1608
+ }
1609
+ const baseUrl = safeResolveBaseUrl(configPath);
1610
+ const tokenResult = await ensureToken(configPath);
1611
+ if (!baseUrl || !tokenResult.ok) {
1612
+ say("Daemon not reachable — cannot import.");
1613
+ return { kind: "skipped", reason: "daemon not reachable" };
1614
+ }
1615
+ const client = createHttpClient({ baseUrl, token: tokenResult.token });
1616
+ const buf = fs.readFileSync(absolute);
1617
+ // Fail-fast for non-ChatGPT exports: route them to `onadit import` with
1618
+ // the right `--source` flag instead of silently feeding them through
1619
+ // the ChatGPT parser. Returns null on "looks like ChatGPT or unknown,"
1620
+ // a concrete provider otherwise.
1621
+ const sniffed = sniffInboxSource(path.basename(absolute), buf);
1622
+ if (sniffed && !source) {
1623
+ say(`Detected a ${sniffed} export — the inline importer is ChatGPT-only.`);
1624
+ say(`Run: onadit import "${absolute}" --source ${sniffed}`);
1625
+ return { kind: "skipped", reason: `non-chatgpt export detected: ${sniffed}` };
1626
+ }
1627
+ const form = new FormData();
1628
+ const importSource = source === "auto" ? sniffed ?? ONBOARD_INLINE_IMPORT_SOURCE : source ?? ONBOARD_INLINE_IMPORT_SOURCE;
1629
+ form.append("source", importSource);
1630
+ form.append("file", new Blob([buf]), path.basename(absolute));
1631
+ say(`Importing ${path.basename(absolute)} as ${importSource}…`);
1632
+ const { data } = await client.postMultipart("/ingest", form);
1633
+ const resp = data;
1634
+ if (resp.duplicate) {
1635
+ say(`Import already submitted (job ${resp.job_id}).`);
1636
+ }
1637
+ const result = await pollJob({ get: client.get.bind(client), jobId: resp.job_id });
1638
+ if (result.timedOut) {
1639
+ return { kind: "failed", reason: `Import is still running. Check its status with: onadit status (job ${resp.job_id}). Do not start another import.` };
1640
+ }
1641
+ if (isJobFailure(result.job, false)) {
1642
+ const reason = result.job.error ?? "unknown";
1643
+ say(`Import failed: ${reason}`);
1644
+ return { kind: "failed", reason };
1645
+ }
1646
+ say(`Import complete (job ${resp.job_id}).`);
1647
+ return { kind: "imported", jobId: resp.job_id, ...(result.job.import_summary ? { summary: result.job.import_summary } : {}) };
1648
+ }
1649
+ /**
1650
+ * Pure outcome decision for the next-action card.
1651
+ *
1652
+ * "Complete + verified" needs both: this run ingested user data AND a recall
1653
+ * query returned a hit (smoke is non-indexing — see daemonRefreshFlow — so a
1654
+ * hit is real user data, not a leftover probe).
1655
+ *
1656
+ * But an EMPTY archive is not a failure. By default capture is OFF (zero-Codex
1657
+ * trust default) and import is optional, so a friend who simply presses Enter
1658
+ * past the import prompt has finished a valid setup — they just have nothing to
1659
+ * recall yet. That case (`ingestAttempted === false`) is reported as DONE, not
1660
+ * "incomplete". We only flag a retry when an ingest was actually attempted and
1661
+ * still added nothing.
1662
+ */
1663
+ export function decideOnboardOutcome(input) {
1664
+ const { ingestedAny, recall } = input;
1665
+ const ingestAttempted = input.ingestAttempted ?? false;
1666
+ if (ingestedAny && recall.ok && recall.hits > 0) {
1667
+ return [
1668
+ `Setup complete — recall returned ${recall.hits} result(s) from your data.`,
1669
+ "Next: onadit mcp install --client=claude-desktop",
1670
+ ];
1671
+ }
1672
+ if (!ingestedAny) {
1673
+ if (!ingestAttempted) {
1674
+ // Deliberate empty setup — a finished, valid state, not a failure.
1675
+ return [
1676
+ "Setup complete — nothing imported yet.",
1677
+ "Import later: onadit import <path> --source <name>",
1678
+ "Next: onadit mcp install --client=claude-desktop",
1679
+ ];
1680
+ }
1681
+ // An ingest ran but landed nothing — honest, calm retry guidance.
1682
+ return [
1683
+ "Setup ready — but capture/import added nothing this run.",
1684
+ "Try: onadit import <path> --source <name>",
1685
+ "If it repeats: onadit feedback --kind=broke --with-status",
1686
+ ];
1687
+ }
1688
+ if (recall.ok) {
1689
+ return [
1690
+ "Setup ready — capture+import succeeded but the generic recall query returned 0 hits.",
1691
+ "Indexing may still be in flight, or this query just didn't match your archive yet.",
1692
+ "Try: onadit search \"<a topic you remember discussing>\"",
1693
+ "If repeated tries still return nothing, run: onadit feedback --kind=broke --with-status",
1694
+ ];
1695
+ }
1696
+ return [
1697
+ `Setup partially complete — recall check failed: ${recall.reason}`,
1698
+ "Next: onadit status (then: onadit feedback --kind=broke --with-status)",
1699
+ ];
1700
+ }
1701
+ // ----- Step 9: first-recall verification -----
1702
+ async function firstRecallCheck(configPath) {
1703
+ const baseUrl = safeResolveBaseUrl(configPath);
1704
+ const tokenResult = await ensureToken(configPath);
1705
+ if (!baseUrl || !tokenResult.ok) {
1706
+ return { ok: false, reason: "daemon not reachable" };
1707
+ }
1708
+ const client = createHttpClient({ baseUrl, token: tokenResult.token });
1709
+ // Generic, content-bearing query — likely to land on captured CLI
1710
+ // sessions or imported chat exports without targeting any onboarding
1711
+ // marker. The smoke is non-indexing (see daemonRefreshFlow), so any
1712
+ // hit returned here is real user data, not a leftover probe.
1713
+ //
1714
+ // Small unusual imports (e.g. one short Claude project export) can
1715
+ // return 0 hits for this generic query even when the data was
1716
+ // indexed correctly. Retry briefly so the post-onboard nudge isn't a
1717
+ // false alarm on slow embedders / sparse archives.
1718
+ const RECALL_RETRY_DELAYS_MS = [0, 5_000];
1719
+ let lastErr = null;
1720
+ for (const delay of RECALL_RETRY_DELAYS_MS) {
1721
+ if (delay > 0)
1722
+ await new Promise((r) => setTimeout(r, delay));
1723
+ try {
1724
+ const { data } = await client.post("/search", {
1725
+ query: "recent conversation",
1726
+ scope: "all",
1727
+ top_k: 10,
1728
+ });
1729
+ const body = data;
1730
+ const hits = (body.results?.length ?? body.hits?.length ?? 0);
1731
+ if (hits > 0)
1732
+ return { ok: true, hits };
1733
+ lastErr = null;
1734
+ }
1735
+ catch (err) {
1736
+ lastErr = err instanceof Error ? err.message : String(err);
1737
+ }
1738
+ }
1739
+ if (lastErr)
1740
+ return { ok: false, reason: lastErr };
1741
+ return { ok: true, hits: 0 };
1742
+ }
1743
+ // ----- Slice 6: --reconfigure-voyage -----
1744
+ /**
1745
+ * Reconfigure the Voyage key. ALL of (kickstart succeeds, /health 200,
1746
+ * smoke `voyage_key_present=true`) must pass; any failure rolls back the
1747
+ * env file AND restores the previous in-process VOYAGE_API_KEY so a
1748
+ * caller is never left with a half-replaced credential. `agent_not_loaded`
1749
+ * counts as a failure here (unlike initial onboard) because reconfigure
1750
+ * is, by definition, called against a daemon that should already be
1751
+ * running — if the launchd label is gone, we don't trust the new key.
1752
+ */
1753
+ async function reconfigureVoyageFlow(opts, globalOpts, rl) {
1754
+ say("Reconfiguring Voyage key…");
1755
+ const key = await collectVoyageKey(opts, rl);
1756
+ await performVoyageReconfigure({
1757
+ key,
1758
+ envPath: defaultRiftEnvPath(),
1759
+ refresh: () => daemonRefreshFlow(globalOpts),
1760
+ });
1761
+ }
1762
+ /**
1763
+ * Core reconfigure logic, extracted so tests can drive every failure
1764
+ * branch (validate fail, kickstart agent_not_loaded, /health fail,
1765
+ * voyage_key_present=false) without spinning up a real daemon.
1766
+ *
1767
+ * Contract: ALL of {validate ok, daemonRefresh ok} must succeed; any
1768
+ * failure rolls back the env file AND restores the previous in-process
1769
+ * VOYAGE_API_KEY. agent_not_loaded counts as a failure here — the call
1770
+ * site only invokes this when the daemon should already be running.
1771
+ */
1772
+ export async function performVoyageReconfigure(deps) {
1773
+ const validate = deps.validate ?? validateVoyageKey;
1774
+ const write = deps.write ?? writeEnvFile;
1775
+ const loadEnv = deps.loadEnv ?? loadRiftEnv;
1776
+ const emit = deps.emit ?? say;
1777
+ const validation = await validate({ apiKey: deps.key });
1778
+ if (!validation.ok) {
1779
+ throw new CliError(`Voyage validation failed: ${validation.reason}`, "validation");
1780
+ }
1781
+ emit(`Voyage key valid (last 4 …${validation.last4}).`);
1782
+ const previousInProcessKey = process.env["VOYAGE_API_KEY"];
1783
+ const writeResult = write({
1784
+ filePath: deps.envPath,
1785
+ key: "VOYAGE_API_KEY",
1786
+ value: deps.key,
1787
+ });
1788
+ loadEnv({ filePath: deps.envPath });
1789
+ const refresh = await deps.refresh();
1790
+ if (refresh.ok) {
1791
+ emit(`Voyage reconfigured (last 4 …${validation.last4}).`);
1792
+ return;
1793
+ }
1794
+ rollbackVoyageEnv(deps.envPath, writeResult, previousInProcessKey);
1795
+ throw new CliError(`Reconfigure failed — restored previous Voyage key (reason: ${refresh.reason}).`, "server_error");
1796
+ }
1797
+ /**
1798
+ * Restore a Voyage env file + in-process VOYAGE_API_KEY after a failed
1799
+ * write. Exported for testing — `reconfigureVoyageFlow` is the only
1800
+ * production caller. When `writeResult.backedUp` is true, the prior
1801
+ * env-file contents are copied back at mode 0600; when false (no prior
1802
+ * file existed), the file we just wrote is removed so we don't leave
1803
+ * a key paired with a now-rejected daemon respawn.
1804
+ */
1805
+ export function rollbackVoyageEnv(envPath, writeResult, previousInProcessKey) {
1806
+ // 1. Env file.
1807
+ if (writeResult.backedUp && writeResult.backupPath) {
1808
+ try {
1809
+ fs.copyFileSync(writeResult.backupPath, envPath);
1810
+ fs.chmodSync(envPath, 0o600);
1811
+ }
1812
+ catch {
1813
+ say("Reconfigure rollback: env-file restore failed — ping Clem for recovery.");
1814
+ }
1815
+ }
1816
+ else {
1817
+ // No prior env file — best effort: drop the line we just wrote so we
1818
+ // don't leave a key paired with a now-rejected daemon respawn.
1819
+ try {
1820
+ fs.rmSync(envPath, { force: true });
1821
+ }
1822
+ catch {
1823
+ // Best-effort.
1824
+ }
1825
+ }
1826
+ // 2. In-process VOYAGE_API_KEY — restore prior value or delete.
1827
+ if (typeof previousInProcessKey === "string" && previousInProcessKey.length > 0) {
1828
+ process.env["VOYAGE_API_KEY"] = previousInProcessKey;
1829
+ }
1830
+ else {
1831
+ delete process.env["VOYAGE_API_KEY"];
1832
+ }
1833
+ }
1834
+ // ----- Helpers -----
1835
+ function ask(rl, question, fallback) {
1836
+ return new Promise((resolve) => {
1837
+ rl.question(question, (answer) => {
1838
+ resolve(answer || fallback || "");
1839
+ });
1840
+ });
1841
+ }
1842
+ function say(line) {
1843
+ process.stdout.write(line + "\n");
1844
+ }
1845
+ function sayPrivacyContract() {
1846
+ ui.detail([
1847
+ "• Conversation content stays local (LanceDB + raw transcripts).",
1848
+ "• Indexed conversation text — and your search queries — leave the machine",
1849
+ " for embedding only when a Voyage key is configured (Voyage AI).",
1850
+ "• The Voyage key sits in ~/.rift.env (mode 0600), is sent only to Voyage,",
1851
+ " and is never logged or sent to Clem.",
1852
+ "• Feedback is stored locally as JSONL. Relay is opt-in: explicit notes only,",
1853
+ " plus daemon health booleans — no paths, no content, no key bytes.",
1854
+ "• Full contract: https://onadit.com/privacy",
1855
+ ].join("\n"));
1856
+ }
1857
+ function safeDiscover(fn) {
1858
+ try {
1859
+ return fn().length;
1860
+ }
1861
+ catch {
1862
+ return 0;
1863
+ }
1864
+ }
1865
+ function safeResolveBaseUrl(configPath) {
1866
+ try {
1867
+ return resolveBaseUrl(configPath);
1868
+ }
1869
+ catch {
1870
+ return null;
1871
+ }
1872
+ }
1873
+ //# sourceMappingURL=onboard.js.map