@ashlr/hub 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (477) hide show
  1. package/CHANGELOG.md +1158 -0
  2. package/LICENSE +21 -0
  3. package/README.md +833 -0
  4. package/bin/ashlr +8 -0
  5. package/dist/api/core.d.ts +28 -0
  6. package/dist/api/core.js +42 -0
  7. package/dist/api/core.js.map +1 -0
  8. package/dist/api/index.d.ts +9 -0
  9. package/dist/api/index.js +9 -0
  10. package/dist/api/index.js.map +1 -0
  11. package/dist/api/plugin.d.ts +12 -0
  12. package/dist/api/plugin.js +13 -0
  13. package/dist/api/plugin.js.map +1 -0
  14. package/dist/api/types.d.ts +9 -0
  15. package/dist/api/types.js +9 -0
  16. package/dist/api/types.js.map +1 -0
  17. package/dist/cli/args.d.ts +20 -0
  18. package/dist/cli/args.js +23 -0
  19. package/dist/cli/args.js.map +1 -0
  20. package/dist/cli/ask.d.ts +22 -0
  21. package/dist/cli/ask.js +240 -0
  22. package/dist/cli/ask.js.map +1 -0
  23. package/dist/cli/audit.d.ts +26 -0
  24. package/dist/cli/audit.js +199 -0
  25. package/dist/cli/audit.js.map +1 -0
  26. package/dist/cli/backlog.d.ts +26 -0
  27. package/dist/cli/backlog.js +322 -0
  28. package/dist/cli/backlog.js.map +1 -0
  29. package/dist/cli/completions.d.ts +18 -0
  30. package/dist/cli/completions.js +156 -0
  31. package/dist/cli/completions.js.map +1 -0
  32. package/dist/cli/daemon.d.ts +31 -0
  33. package/dist/cli/daemon.js +334 -0
  34. package/dist/cli/daemon.js.map +1 -0
  35. package/dist/cli/demo-sandbox.d.ts +78 -0
  36. package/dist/cli/demo-sandbox.js +227 -0
  37. package/dist/cli/demo-sandbox.js.map +1 -0
  38. package/dist/cli/demo.d.ts +76 -0
  39. package/dist/cli/demo.js +285 -0
  40. package/dist/cli/demo.js.map +1 -0
  41. package/dist/cli/digest.d.ts +46 -0
  42. package/dist/cli/digest.js +352 -0
  43. package/dist/cli/digest.js.map +1 -0
  44. package/dist/cli/doctor-init.d.ts +28 -0
  45. package/dist/cli/doctor-init.js +335 -0
  46. package/dist/cli/doctor-init.js.map +1 -0
  47. package/dist/cli/genome.d.ts +62 -0
  48. package/dist/cli/genome.js +1061 -0
  49. package/dist/cli/genome.js.map +1 -0
  50. package/dist/cli/gh.d.ts +27 -0
  51. package/dist/cli/gh.js +322 -0
  52. package/dist/cli/gh.js.map +1 -0
  53. package/dist/cli/goals.d.ts +55 -0
  54. package/dist/cli/goals.js +667 -0
  55. package/dist/cli/goals.js.map +1 -0
  56. package/dist/cli/health.d.ts +56 -0
  57. package/dist/cli/health.js +407 -0
  58. package/dist/cli/health.js.map +1 -0
  59. package/dist/cli/help.d.ts +51 -0
  60. package/dist/cli/help.js +436 -0
  61. package/dist/cli/help.js.map +1 -0
  62. package/dist/cli/inbox.d.ts +28 -0
  63. package/dist/cli/inbox.js +589 -0
  64. package/dist/cli/inbox.js.map +1 -0
  65. package/dist/cli/index.d.ts +41 -0
  66. package/dist/cli/index.js +1208 -0
  67. package/dist/cli/index.js.map +1 -0
  68. package/dist/cli/knowledge.d.ts +33 -0
  69. package/dist/cli/knowledge.js +575 -0
  70. package/dist/cli/knowledge.js.map +1 -0
  71. package/dist/cli/mcp.d.ts +26 -0
  72. package/dist/cli/mcp.js +487 -0
  73. package/dist/cli/mcp.js.map +1 -0
  74. package/dist/cli/models.d.ts +26 -0
  75. package/dist/cli/models.js +435 -0
  76. package/dist/cli/models.js.map +1 -0
  77. package/dist/cli/new.d.ts +32 -0
  78. package/dist/cli/new.js +565 -0
  79. package/dist/cli/new.js.map +1 -0
  80. package/dist/cli/notify.d.ts +20 -0
  81. package/dist/cli/notify.js +188 -0
  82. package/dist/cli/notify.js.map +1 -0
  83. package/dist/cli/onboard.d.ts +85 -0
  84. package/dist/cli/onboard.js +305 -0
  85. package/dist/cli/onboard.js.map +1 -0
  86. package/dist/cli/open.d.ts +38 -0
  87. package/dist/cli/open.js +86 -0
  88. package/dist/cli/open.js.map +1 -0
  89. package/dist/cli/orient.d.ts +14 -0
  90. package/dist/cli/orient.js +110 -0
  91. package/dist/cli/orient.js.map +1 -0
  92. package/dist/cli/picker.d.ts +21 -0
  93. package/dist/cli/picker.js +177 -0
  94. package/dist/cli/picker.js.map +1 -0
  95. package/dist/cli/plugins.d.ts +21 -0
  96. package/dist/cli/plugins.js +394 -0
  97. package/dist/cli/plugins.js.map +1 -0
  98. package/dist/cli/preflight.d.ts +29 -0
  99. package/dist/cli/preflight.js +131 -0
  100. package/dist/cli/preflight.js.map +1 -0
  101. package/dist/cli/pulse.d.ts +26 -0
  102. package/dist/cli/pulse.js +482 -0
  103. package/dist/cli/pulse.js.map +1 -0
  104. package/dist/cli/reflect.d.ts +42 -0
  105. package/dist/cli/reflect.js +381 -0
  106. package/dist/cli/reflect.js.map +1 -0
  107. package/dist/cli/run.d.ts +29 -0
  108. package/dist/cli/run.js +687 -0
  109. package/dist/cli/run.js.map +1 -0
  110. package/dist/cli/sandbox.d.ts +20 -0
  111. package/dist/cli/sandbox.js +345 -0
  112. package/dist/cli/sandbox.js.map +1 -0
  113. package/dist/cli/seams.d.ts +41 -0
  114. package/dist/cli/seams.js +167 -0
  115. package/dist/cli/seams.js.map +1 -0
  116. package/dist/cli/serve.d.ts +25 -0
  117. package/dist/cli/serve.js +249 -0
  118. package/dist/cli/serve.js.map +1 -0
  119. package/dist/cli/ship.d.ts +33 -0
  120. package/dist/cli/ship.js +433 -0
  121. package/dist/cli/ship.js.map +1 -0
  122. package/dist/cli/spec.d.ts +19 -0
  123. package/dist/cli/spec.js +478 -0
  124. package/dist/cli/spec.js.map +1 -0
  125. package/dist/cli/swarm.d.ts +42 -0
  126. package/dist/cli/swarm.js +1365 -0
  127. package/dist/cli/swarm.js.map +1 -0
  128. package/dist/cli/telemetry.d.ts +26 -0
  129. package/dist/cli/telemetry.js +364 -0
  130. package/dist/cli/telemetry.js.map +1 -0
  131. package/dist/cli/tui.d.ts +17 -0
  132. package/dist/cli/tui.js +52 -0
  133. package/dist/cli/tui.js.map +1 -0
  134. package/dist/cli/ui.d.ts +53 -0
  135. package/dist/cli/ui.js +66 -0
  136. package/dist/cli/ui.js.map +1 -0
  137. package/dist/cli/update.d.ts +38 -0
  138. package/dist/cli/update.js +682 -0
  139. package/dist/cli/update.js.map +1 -0
  140. package/dist/cli/vercel.d.ts +20 -0
  141. package/dist/cli/vercel.js +193 -0
  142. package/dist/cli/vercel.js.map +1 -0
  143. package/dist/cli/verify-safety.d.ts +96 -0
  144. package/dist/cli/verify-safety.js +509 -0
  145. package/dist/cli/verify-safety.js.map +1 -0
  146. package/dist/cli/wire.d.ts +22 -0
  147. package/dist/cli/wire.js +205 -0
  148. package/dist/cli/wire.js.map +1 -0
  149. package/dist/core/classify.d.ts +51 -0
  150. package/dist/core/classify.js +450 -0
  151. package/dist/core/classify.js.map +1 -0
  152. package/dist/core/config.d.ts +63 -0
  153. package/dist/core/config.js +474 -0
  154. package/dist/core/config.js.map +1 -0
  155. package/dist/core/daemon/loop.d.ts +74 -0
  156. package/dist/core/daemon/loop.js +618 -0
  157. package/dist/core/daemon/loop.js.map +1 -0
  158. package/dist/core/daemon/state.d.ts +66 -0
  159. package/dist/core/daemon/state.js +197 -0
  160. package/dist/core/daemon/state.js.map +1 -0
  161. package/dist/core/dashboard.d.ts +40 -0
  162. package/dist/core/dashboard.js +463 -0
  163. package/dist/core/dashboard.js.map +1 -0
  164. package/dist/core/digest/build.d.ts +51 -0
  165. package/dist/core/digest/build.js +230 -0
  166. package/dist/core/digest/build.js.map +1 -0
  167. package/dist/core/digest/deliver.d.ts +47 -0
  168. package/dist/core/digest/deliver.js +230 -0
  169. package/dist/core/digest/deliver.js.map +1 -0
  170. package/dist/core/digest/store.d.ts +57 -0
  171. package/dist/core/digest/store.js +223 -0
  172. package/dist/core/digest/store.js.map +1 -0
  173. package/dist/core/doctor-fix.d.ts +21 -0
  174. package/dist/core/doctor-fix.js +440 -0
  175. package/dist/core/doctor-fix.js.map +1 -0
  176. package/dist/core/doctor.d.ts +18 -0
  177. package/dist/core/doctor.js +806 -0
  178. package/dist/core/doctor.js.map +1 -0
  179. package/dist/core/env-bridge.d.ts +64 -0
  180. package/dist/core/env-bridge.js +103 -0
  181. package/dist/core/env-bridge.js.map +1 -0
  182. package/dist/core/genome/capture.d.ts +49 -0
  183. package/dist/core/genome/capture.js +352 -0
  184. package/dist/core/genome/capture.js.map +1 -0
  185. package/dist/core/genome/consolidate.d.ts +38 -0
  186. package/dist/core/genome/consolidate.js +426 -0
  187. package/dist/core/genome/consolidate.js.map +1 -0
  188. package/dist/core/genome/export.d.ts +29 -0
  189. package/dist/core/genome/export.js +102 -0
  190. package/dist/core/genome/export.js.map +1 -0
  191. package/dist/core/genome/playbook.d.ts +33 -0
  192. package/dist/core/genome/playbook.js +320 -0
  193. package/dist/core/genome/playbook.js.map +1 -0
  194. package/dist/core/genome/recall.d.ts +45 -0
  195. package/dist/core/genome/recall.js +293 -0
  196. package/dist/core/genome/recall.js.map +1 -0
  197. package/dist/core/genome/store.d.ts +62 -0
  198. package/dist/core/genome/store.js +711 -0
  199. package/dist/core/genome/store.js.map +1 -0
  200. package/dist/core/git.d.ts +34 -0
  201. package/dist/core/git.js +115 -0
  202. package/dist/core/git.js.map +1 -0
  203. package/dist/core/goals/advance.d.ts +82 -0
  204. package/dist/core/goals/advance.js +263 -0
  205. package/dist/core/goals/advance.js.map +1 -0
  206. package/dist/core/goals/planner.d.ts +58 -0
  207. package/dist/core/goals/planner.js +233 -0
  208. package/dist/core/goals/planner.js.map +1 -0
  209. package/dist/core/goals/store.d.ts +128 -0
  210. package/dist/core/goals/store.js +442 -0
  211. package/dist/core/goals/store.js.map +1 -0
  212. package/dist/core/inbox/apply.d.ts +36 -0
  213. package/dist/core/inbox/apply.js +407 -0
  214. package/dist/core/inbox/apply.js.map +1 -0
  215. package/dist/core/inbox/notify-proposal.d.ts +13 -0
  216. package/dist/core/inbox/notify-proposal.js +21 -0
  217. package/dist/core/inbox/notify-proposal.js.map +1 -0
  218. package/dist/core/inbox/store.d.ts +67 -0
  219. package/dist/core/inbox/store.js +258 -0
  220. package/dist/core/inbox/store.js.map +1 -0
  221. package/dist/core/index-engine.d.ts +62 -0
  222. package/dist/core/index-engine.js +486 -0
  223. package/dist/core/index-engine.js.map +1 -0
  224. package/dist/core/integrations/desktop-notify.d.ts +18 -0
  225. package/dist/core/integrations/desktop-notify.js +42 -0
  226. package/dist/core/integrations/desktop-notify.js.map +1 -0
  227. package/dist/core/integrations/editors.d.ts +50 -0
  228. package/dist/core/integrations/editors.js +216 -0
  229. package/dist/core/integrations/editors.js.map +1 -0
  230. package/dist/core/integrations/github.d.ts +66 -0
  231. package/dist/core/integrations/github.js +332 -0
  232. package/dist/core/integrations/github.js.map +1 -0
  233. package/dist/core/integrations/identity.d.ts +29 -0
  234. package/dist/core/integrations/identity.js +359 -0
  235. package/dist/core/integrations/identity.js.map +1 -0
  236. package/dist/core/integrations/notify.d.ts +23 -0
  237. package/dist/core/integrations/notify.js +96 -0
  238. package/dist/core/integrations/notify.js.map +1 -0
  239. package/dist/core/integrations/vercel.d.ts +37 -0
  240. package/dist/core/integrations/vercel.js +192 -0
  241. package/dist/core/integrations/vercel.js.map +1 -0
  242. package/dist/core/knowledge/ask.d.ts +34 -0
  243. package/dist/core/knowledge/ask.js +325 -0
  244. package/dist/core/knowledge/ask.js.map +1 -0
  245. package/dist/core/knowledge/graph.d.ts +51 -0
  246. package/dist/core/knowledge/graph.js +564 -0
  247. package/dist/core/knowledge/graph.js.map +1 -0
  248. package/dist/core/knowledge/index.d.ts +74 -0
  249. package/dist/core/knowledge/index.js +586 -0
  250. package/dist/core/knowledge/index.js.map +1 -0
  251. package/dist/core/learn/playbooks.d.ts +84 -0
  252. package/dist/core/learn/playbooks.js +241 -0
  253. package/dist/core/learn/playbooks.js.map +1 -0
  254. package/dist/core/learn/reflect.d.ts +87 -0
  255. package/dist/core/learn/reflect.js +435 -0
  256. package/dist/core/learn/reflect.js.map +1 -0
  257. package/dist/core/learn/store.d.ts +51 -0
  258. package/dist/core/learn/store.js +165 -0
  259. package/dist/core/learn/store.js.map +1 -0
  260. package/dist/core/learn/tuning.d.ts +48 -0
  261. package/dist/core/learn/tuning.js +201 -0
  262. package/dist/core/learn/tuning.js.map +1 -0
  263. package/dist/core/lifecycle/scaffold.d.ts +43 -0
  264. package/dist/core/lifecycle/scaffold.js +260 -0
  265. package/dist/core/lifecycle/scaffold.js.map +1 -0
  266. package/dist/core/lifecycle/ship.d.ts +48 -0
  267. package/dist/core/lifecycle/ship.js +513 -0
  268. package/dist/core/lifecycle/ship.js.map +1 -0
  269. package/dist/core/lifecycle/templates.d.ts +20 -0
  270. package/dist/core/lifecycle/templates.js +605 -0
  271. package/dist/core/lifecycle/templates.js.map +1 -0
  272. package/dist/core/mcp-gateway.d.ts +59 -0
  273. package/dist/core/mcp-gateway.js +385 -0
  274. package/dist/core/mcp-gateway.js.map +1 -0
  275. package/dist/core/mcp-native.d.ts +53 -0
  276. package/dist/core/mcp-native.js +507 -0
  277. package/dist/core/mcp-native.js.map +1 -0
  278. package/dist/core/mcp-registry.d.ts +36 -0
  279. package/dist/core/mcp-registry.js +180 -0
  280. package/dist/core/mcp-registry.js.map +1 -0
  281. package/dist/core/observability/budget-alert.d.ts +18 -0
  282. package/dist/core/observability/budget-alert.js +90 -0
  283. package/dist/core/observability/budget-alert.js.map +1 -0
  284. package/dist/core/observability/estimate.d.ts +27 -0
  285. package/dist/core/observability/estimate.js +188 -0
  286. package/dist/core/observability/estimate.js.map +1 -0
  287. package/dist/core/observability/forecast.d.ts +19 -0
  288. package/dist/core/observability/forecast.js +101 -0
  289. package/dist/core/observability/forecast.js.map +1 -0
  290. package/dist/core/observability/governance.d.ts +28 -0
  291. package/dist/core/observability/governance.js +101 -0
  292. package/dist/core/observability/governance.js.map +1 -0
  293. package/dist/core/observability/otlp.d.ts +88 -0
  294. package/dist/core/observability/otlp.js +217 -0
  295. package/dist/core/observability/otlp.js.map +1 -0
  296. package/dist/core/observability/rollup.d.ts +35 -0
  297. package/dist/core/observability/rollup.js +311 -0
  298. package/dist/core/observability/rollup.js.map +1 -0
  299. package/dist/core/observability/telemetry-sink.d.ts +63 -0
  300. package/dist/core/observability/telemetry-sink.js +350 -0
  301. package/dist/core/observability/telemetry-sink.js.map +1 -0
  302. package/dist/core/observability/usage-source.d.ts +60 -0
  303. package/dist/core/observability/usage-source.js +347 -0
  304. package/dist/core/observability/usage-source.js.map +1 -0
  305. package/dist/core/onboard.d.ts +27 -0
  306. package/dist/core/onboard.js +288 -0
  307. package/dist/core/onboard.js.map +1 -0
  308. package/dist/core/orient.d.ts +23 -0
  309. package/dist/core/orient.js +135 -0
  310. package/dist/core/orient.js.map +1 -0
  311. package/dist/core/phantom.d.ts +23 -0
  312. package/dist/core/phantom.js +279 -0
  313. package/dist/core/phantom.js.map +1 -0
  314. package/dist/core/plugins/host-api.d.ts +29 -0
  315. package/dist/core/plugins/host-api.js +113 -0
  316. package/dist/core/plugins/host-api.js.map +1 -0
  317. package/dist/core/plugins/integrity.d.ts +36 -0
  318. package/dist/core/plugins/integrity.js +73 -0
  319. package/dist/core/plugins/integrity.js.map +1 -0
  320. package/dist/core/plugins/manifest.d.ts +31 -0
  321. package/dist/core/plugins/manifest.js +316 -0
  322. package/dist/core/plugins/manifest.js.map +1 -0
  323. package/dist/core/plugins/registry.d.ts +87 -0
  324. package/dist/core/plugins/registry.js +415 -0
  325. package/dist/core/plugins/registry.js.map +1 -0
  326. package/dist/core/plugins/types.d.ts +182 -0
  327. package/dist/core/plugins/types.js +40 -0
  328. package/dist/core/plugins/types.js.map +1 -0
  329. package/dist/core/plugins/wrappers.d.ts +40 -0
  330. package/dist/core/plugins/wrappers.js +229 -0
  331. package/dist/core/plugins/wrappers.js.map +1 -0
  332. package/dist/core/portfolio/backlog.d.ts +40 -0
  333. package/dist/core/portfolio/backlog.js +177 -0
  334. package/dist/core/portfolio/backlog.js.map +1 -0
  335. package/dist/core/portfolio/scanners.d.ts +21 -0
  336. package/dist/core/portfolio/scanners.js +600 -0
  337. package/dist/core/portfolio/scanners.js.map +1 -0
  338. package/dist/core/providers.d.ts +34 -0
  339. package/dist/core/providers.js +250 -0
  340. package/dist/core/providers.js.map +1 -0
  341. package/dist/core/quality/conventions.d.ts +35 -0
  342. package/dist/core/quality/conventions.js +267 -0
  343. package/dist/core/quality/conventions.js.map +1 -0
  344. package/dist/core/quality/fixes.d.ts +56 -0
  345. package/dist/core/quality/fixes.js +209 -0
  346. package/dist/core/quality/fixes.js.map +1 -0
  347. package/dist/core/quality/health.d.ts +69 -0
  348. package/dist/core/quality/health.js +350 -0
  349. package/dist/core/quality/health.js.map +1 -0
  350. package/dist/core/quality/store.d.ts +56 -0
  351. package/dist/core/quality/store.js +195 -0
  352. package/dist/core/quality/store.js.map +1 -0
  353. package/dist/core/readiness.d.ts +112 -0
  354. package/dist/core/readiness.js +431 -0
  355. package/dist/core/readiness.js.map +1 -0
  356. package/dist/core/run/agent-loop.d.ts +40 -0
  357. package/dist/core/run/agent-loop.js +291 -0
  358. package/dist/core/run/agent-loop.js.map +1 -0
  359. package/dist/core/run/budget.d.ts +47 -0
  360. package/dist/core/run/budget.js +113 -0
  361. package/dist/core/run/budget.js.map +1 -0
  362. package/dist/core/run/engines.d.ts +75 -0
  363. package/dist/core/run/engines.js +199 -0
  364. package/dist/core/run/engines.js.map +1 -0
  365. package/dist/core/run/model-manager.d.ts +64 -0
  366. package/dist/core/run/model-manager.js +339 -0
  367. package/dist/core/run/model-manager.js.map +1 -0
  368. package/dist/core/run/orchestrator.d.ts +100 -0
  369. package/dist/core/run/orchestrator.js +1515 -0
  370. package/dist/core/run/orchestrator.js.map +1 -0
  371. package/dist/core/run/provider-client.d.ts +46 -0
  372. package/dist/core/run/provider-client.js +796 -0
  373. package/dist/core/run/provider-client.js.map +1 -0
  374. package/dist/core/run/retry.d.ts +19 -0
  375. package/dist/core/run/retry.js +68 -0
  376. package/dist/core/run/retry.js.map +1 -0
  377. package/dist/core/run/router.d.ts +50 -0
  378. package/dist/core/run/router.js +257 -0
  379. package/dist/core/run/router.js.map +1 -0
  380. package/dist/core/run/self-heal.d.ts +52 -0
  381. package/dist/core/run/self-heal.js +181 -0
  382. package/dist/core/run/self-heal.js.map +1 -0
  383. package/dist/core/run/streaming.d.ts +31 -0
  384. package/dist/core/run/streaming.js +122 -0
  385. package/dist/core/run/streaming.js.map +1 -0
  386. package/dist/core/run/verify.d.ts +30 -0
  387. package/dist/core/run/verify.js +204 -0
  388. package/dist/core/run/verify.js.map +1 -0
  389. package/dist/core/sandbox/audit.d.ts +31 -0
  390. package/dist/core/sandbox/audit.js +169 -0
  391. package/dist/core/sandbox/audit.js.map +1 -0
  392. package/dist/core/sandbox/policy.d.ts +61 -0
  393. package/dist/core/sandbox/policy.js +211 -0
  394. package/dist/core/sandbox/policy.js.map +1 -0
  395. package/dist/core/sandbox/worktree.d.ts +175 -0
  396. package/dist/core/sandbox/worktree.js +673 -0
  397. package/dist/core/sandbox/worktree.js.map +1 -0
  398. package/dist/core/seams/backlog.d.ts +47 -0
  399. package/dist/core/seams/backlog.js +47 -0
  400. package/dist/core/seams/backlog.js.map +1 -0
  401. package/dist/core/seams/daemon-coordinator.d.ts +72 -0
  402. package/dist/core/seams/daemon-coordinator.js +76 -0
  403. package/dist/core/seams/daemon-coordinator.js.map +1 -0
  404. package/dist/core/seams/genome.d.ts +45 -0
  405. package/dist/core/seams/genome.js +53 -0
  406. package/dist/core/seams/genome.js.map +1 -0
  407. package/dist/core/seams/identity.d.ts +40 -0
  408. package/dist/core/seams/identity.js +44 -0
  409. package/dist/core/seams/identity.js.map +1 -0
  410. package/dist/core/seams/inbox.d.ts +60 -0
  411. package/dist/core/seams/inbox.js +66 -0
  412. package/dist/core/seams/inbox.js.map +1 -0
  413. package/dist/core/seams/index.d.ts +20 -0
  414. package/dist/core/seams/index.js +21 -0
  415. package/dist/core/seams/index.js.map +1 -0
  416. package/dist/core/seams/portfolio.d.ts +50 -0
  417. package/dist/core/seams/portfolio.js +61 -0
  418. package/dist/core/seams/portfolio.js.map +1 -0
  419. package/dist/core/seams/registry.d.ts +42 -0
  420. package/dist/core/seams/registry.js +128 -0
  421. package/dist/core/seams/registry.js.map +1 -0
  422. package/dist/core/seams/run-swarm.d.ts +66 -0
  423. package/dist/core/seams/run-swarm.js +74 -0
  424. package/dist/core/seams/run-swarm.js.map +1 -0
  425. package/dist/core/seams/types.d.ts +123 -0
  426. package/dist/core/seams/types.js +35 -0
  427. package/dist/core/seams/types.js.map +1 -0
  428. package/dist/core/spec/spec-store.d.ts +62 -0
  429. package/dist/core/spec/spec-store.js +359 -0
  430. package/dist/core/spec/spec-store.js.map +1 -0
  431. package/dist/core/swarm/gate.d.ts +45 -0
  432. package/dist/core/swarm/gate.js +114 -0
  433. package/dist/core/swarm/gate.js.map +1 -0
  434. package/dist/core/swarm/planner.d.ts +32 -0
  435. package/dist/core/swarm/planner.js +293 -0
  436. package/dist/core/swarm/planner.js.map +1 -0
  437. package/dist/core/swarm/rollback.d.ts +56 -0
  438. package/dist/core/swarm/rollback.js +266 -0
  439. package/dist/core/swarm/rollback.js.map +1 -0
  440. package/dist/core/swarm/runner.d.ts +62 -0
  441. package/dist/core/swarm/runner.js +1263 -0
  442. package/dist/core/swarm/runner.js.map +1 -0
  443. package/dist/core/swarm/sign.d.ts +71 -0
  444. package/dist/core/swarm/sign.js +362 -0
  445. package/dist/core/swarm/sign.js.map +1 -0
  446. package/dist/core/swarm/store.d.ts +52 -0
  447. package/dist/core/swarm/store.js +195 -0
  448. package/dist/core/swarm/store.js.map +1 -0
  449. package/dist/core/tidy.d.ts +32 -0
  450. package/dist/core/tidy.js +354 -0
  451. package/dist/core/tidy.js.map +1 -0
  452. package/dist/core/tools-registry.d.ts +16 -0
  453. package/dist/core/tools-registry.js +308 -0
  454. package/dist/core/tools-registry.js.map +1 -0
  455. package/dist/core/types.d.ts +2545 -0
  456. package/dist/core/types.js +9 -0
  457. package/dist/core/types.js.map +1 -0
  458. package/dist/core/web/api.d.ts +53 -0
  459. package/dist/core/web/api.js +698 -0
  460. package/dist/core/web/api.js.map +1 -0
  461. package/dist/core/web/public/app.js +1906 -0
  462. package/dist/core/web/public/index.html +721 -0
  463. package/dist/core/web/public/styles.css +2007 -0
  464. package/dist/core/web/server.d.ts +18 -0
  465. package/dist/core/web/server.js +122 -0
  466. package/dist/core/web/server.js.map +1 -0
  467. package/dist/core/web/static.d.ts +18 -0
  468. package/dist/core/web/static.js +122 -0
  469. package/dist/core/web/static.js.map +1 -0
  470. package/dist/tui/app.d.ts +33 -0
  471. package/dist/tui/app.js +350 -0
  472. package/dist/tui/app.js.map +1 -0
  473. package/dist/tui/render.d.ts +20 -0
  474. package/dist/tui/render.js +558 -0
  475. package/dist/tui/render.js.map +1 -0
  476. package/package.json +80 -0
  477. package/schema/config.schema.json +223 -0
@@ -0,0 +1,347 @@
1
+ /**
2
+ * usage-source.ts — local-first UsageEvent collector (M5 observability).
3
+ *
4
+ * PRIVACY GUARDRAILS: reads ONLY token counts, model id, timestamp, and the
5
+ * project path (decoded from the encoded dir name). Never reads or retains
6
+ * message content, tool args/results, prompts, or completions.
7
+ *
8
+ * PERFORMANCE: streams line-by-line; skips files whose mtime is older than
9
+ * sinceMs; tolerates malformed lines; never throws.
10
+ */
11
+ import * as fs from "fs";
12
+ import * as path from "path";
13
+ import * as os from "os";
14
+ // ---------------------------------------------------------------------------
15
+ // Public helpers
16
+ // ---------------------------------------------------------------------------
17
+ /** Absolute path to ~/.claude/projects (honors $HOME). */
18
+ export function claudeProjectsDir() {
19
+ return path.join(os.homedir(), ".claude", "projects");
20
+ }
21
+ /**
22
+ * Decode an encoded Claude Code project dir name back to an absolute path.
23
+ *
24
+ * Claude encodes the absolute path by replacing the leading `/` with a `-`
25
+ * and then replacing every subsequent `/` with `-`. For example:
26
+ * '-Users-you-Desktop-foo' -> '/Users/you/Desktop/foo'
27
+ *
28
+ * This is lossy for path segments that naturally contain `-`, but we do
29
+ * the best-effort reconstruction by:
30
+ * 1. Stripping the leading `-`
31
+ * 2. Re-prefixing with `/`
32
+ * 3. Replacing remaining `-` with `/`
33
+ *
34
+ * The result is a plausible absolute path suitable for display/grouping.
35
+ */
36
+ export function decodeProjectPath(dirName) {
37
+ // Remove leading dash (represents the leading `/` of an absolute path)
38
+ const withoutLeadingDash = dirName.startsWith("-")
39
+ ? dirName.slice(1)
40
+ : dirName;
41
+ // Re-add leading slash and replace dashes with path separators
42
+ return "/" + withoutLeadingDash.replace(/-/g, "/");
43
+ }
44
+ /**
45
+ * Collapse a real absolute path to the dash-normalized form Claude uses to
46
+ * encode project dir names: every `/` AND every `-` becomes `-`.
47
+ *
48
+ * Both the real path '/Users/x/dev-tools/ashlr-hub' and its lossy decode
49
+ * '/Users/x/dev/tools/ashlr/hub' normalize to the SAME string
50
+ * '-Users-x-dev-tools-ashlr-hub'. That makes dashNormalize a reliable join key
51
+ * between the index's REAL paths and the transcript's MANGLED decoded paths,
52
+ * which recovers correct grouping/labels for any repo whose name has a dash.
53
+ */
54
+ export function dashNormalize(absPath) {
55
+ return absPath.replace(/[/-]/g, "-");
56
+ }
57
+ /**
58
+ * Resolve a (possibly mangled) decoded project path against known real paths
59
+ * from the index. Returns the matching real path when the dash-normalized
60
+ * forms agree, otherwise returns the input unchanged (best-effort decode).
61
+ *
62
+ * `realByNorm` maps dashNormalize(realPath) -> realPath and is built once by
63
+ * the caller so this stays O(1) per event.
64
+ */
65
+ export function reconcileProjectPath(decodedPath, realByNorm) {
66
+ const match = realByNorm.get(dashNormalize(decodedPath));
67
+ return match ?? decodedPath;
68
+ }
69
+ // ---------------------------------------------------------------------------
70
+ // Internal helpers
71
+ // ---------------------------------------------------------------------------
72
+ /** Chunk size for the streaming reader (64 KiB). */
73
+ const READ_CHUNK = 64 * 1024;
74
+ /**
75
+ * Hard cap on bytes scanned per transcript (256 MiB). Transcripts can be
76
+ * hundreds of MB; this bounds worst-case work while still covering any
77
+ * realistic session. Peak memory stays ~one chunk + one line regardless.
78
+ */
79
+ const MAX_BYTES_PER_FILE = 256 * 1024 * 1024;
80
+ /**
81
+ * Read a file line-by-line with BOUNDED memory, calling cb for each non-empty
82
+ * line. Instead of readFileSync + split (which loads the whole file as a string
83
+ * AND a full line array — pathological for 100+ MB transcripts), we pull fixed
84
+ * 64 KiB chunks via fs.readSync and split on newlines incrementally, carrying a
85
+ * partial-line buffer across chunk boundaries. Peak memory is ~one chunk plus
86
+ * one line, not the whole file. Never throws.
87
+ */
88
+ function eachLine(filePath, cb) {
89
+ let fd;
90
+ try {
91
+ fd = fs.openSync(filePath, "r");
92
+ }
93
+ catch {
94
+ return; // unreadable — skip silently
95
+ }
96
+ try {
97
+ const chunk = Buffer.allocUnsafe(READ_CHUNK);
98
+ let pending = ""; // partial line carried across chunk boundaries
99
+ let bytesRead = 0;
100
+ for (;;) {
101
+ let n;
102
+ try {
103
+ n = fs.readSync(fd, chunk, 0, READ_CHUNK, null);
104
+ }
105
+ catch {
106
+ break; // read error — stop, keep whatever we collected
107
+ }
108
+ if (n <= 0)
109
+ break; // EOF
110
+ bytesRead += n;
111
+ pending += chunk.toString("utf8", 0, n);
112
+ let nl;
113
+ while ((nl = pending.indexOf("\n")) !== -1) {
114
+ const line = pending.slice(0, nl).trim();
115
+ pending = pending.slice(nl + 1);
116
+ if (line.length > 0)
117
+ cb(line);
118
+ }
119
+ // Bound total work per file.
120
+ if (bytesRead >= MAX_BYTES_PER_FILE)
121
+ break;
122
+ }
123
+ // Flush any trailing line without a newline.
124
+ const last = pending.trim();
125
+ if (last.length > 0)
126
+ cb(last);
127
+ }
128
+ finally {
129
+ try {
130
+ fs.closeSync(fd);
131
+ }
132
+ catch {
133
+ // ignore
134
+ }
135
+ }
136
+ }
137
+ /** Extract a UsageEvent from a parsed JSONL line, or null if not applicable. */
138
+ function extractClaudeEvent(raw, project, sinceMs) {
139
+ if (typeof raw !== "object" || raw === null)
140
+ return null;
141
+ const obj = raw;
142
+ // Only process assistant-type events
143
+ if (obj["type"] !== "assistant")
144
+ return null;
145
+ // Timestamp lives at top level
146
+ const ts = typeof obj["timestamp"] === "string" ? obj["timestamp"] : null;
147
+ if (!ts)
148
+ return null;
149
+ // Filter by window early
150
+ try {
151
+ if (new Date(ts).getTime() < sinceMs)
152
+ return null;
153
+ }
154
+ catch {
155
+ return null;
156
+ }
157
+ // Model and usage are nested under `message`
158
+ const message = obj["message"];
159
+ if (typeof message !== "object" || message === null)
160
+ return null;
161
+ const msg = message;
162
+ const model = typeof msg["model"] === "string" ? msg["model"] : "";
163
+ if (!model)
164
+ return null;
165
+ const usage = msg["usage"];
166
+ if (typeof usage !== "object" || usage === null)
167
+ return null;
168
+ const u = usage;
169
+ // PRIVACY: extract ONLY the four numeric token counts — nothing else
170
+ const tokensIn = typeof u["input_tokens"] === "number" ? u["input_tokens"] : 0;
171
+ const tokensOut = typeof u["output_tokens"] === "number" ? u["output_tokens"] : 0;
172
+ const cacheRead = typeof u["cache_read_input_tokens"] === "number"
173
+ ? u["cache_read_input_tokens"]
174
+ : 0;
175
+ const cacheWrite = typeof u["cache_creation_input_tokens"] === "number"
176
+ ? u["cache_creation_input_tokens"]
177
+ : 0;
178
+ // Skip events with zero useful usage (e.g. pure-tool events)
179
+ if (tokensIn === 0 && tokensOut === 0)
180
+ return null;
181
+ return {
182
+ ts,
183
+ project,
184
+ model,
185
+ source: "claude",
186
+ tokensIn,
187
+ tokensOut,
188
+ cacheRead,
189
+ cacheWrite,
190
+ };
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // Claude Code transcript ingestion
194
+ // ---------------------------------------------------------------------------
195
+ function collectClaudeEvents(sinceMs) {
196
+ const events = [];
197
+ const projectsRoot = claudeProjectsDir();
198
+ let projectDirs;
199
+ try {
200
+ projectDirs = fs.readdirSync(projectsRoot, { withFileTypes: true })
201
+ .filter((d) => d.isDirectory())
202
+ .map((d) => d.name);
203
+ }
204
+ catch {
205
+ return events; // ~/.claude/projects doesn't exist or isn't readable
206
+ }
207
+ for (const dirName of projectDirs) {
208
+ const dirPath = path.join(projectsRoot, dirName);
209
+ const project = decodeProjectPath(dirName);
210
+ let files;
211
+ try {
212
+ files = fs.readdirSync(dirPath, { withFileTypes: true });
213
+ }
214
+ catch {
215
+ continue;
216
+ }
217
+ for (const entry of files) {
218
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
219
+ continue;
220
+ const filePath = path.join(dirPath, entry.name);
221
+ // Performance: skip files that haven't been modified since our window
222
+ try {
223
+ const stat = fs.statSync(filePath);
224
+ if (stat.mtimeMs < sinceMs)
225
+ continue;
226
+ }
227
+ catch {
228
+ continue;
229
+ }
230
+ // Stream line-by-line; PRIVACY: parse only; never retain content
231
+ eachLine(filePath, (line) => {
232
+ let parsed;
233
+ try {
234
+ parsed = JSON.parse(line);
235
+ }
236
+ catch {
237
+ return; // malformed line — skip silently
238
+ }
239
+ const event = extractClaudeEvent(parsed, project, sinceMs);
240
+ if (event)
241
+ events.push(event);
242
+ });
243
+ }
244
+ }
245
+ return events;
246
+ }
247
+ // ---------------------------------------------------------------------------
248
+ // M4 run record ingestion
249
+ // ---------------------------------------------------------------------------
250
+ function collectRunEvents(sinceMs) {
251
+ const events = [];
252
+ const runsDir = path.join(os.homedir(), ".ashlr", "runs");
253
+ let files;
254
+ try {
255
+ files = fs.readdirSync(runsDir);
256
+ }
257
+ catch {
258
+ return events; // no runs dir — fine
259
+ }
260
+ for (const name of files) {
261
+ if (!name.endsWith(".json"))
262
+ continue;
263
+ const filePath = path.join(runsDir, name);
264
+ // Performance: skip files older than window
265
+ try {
266
+ const stat = fs.statSync(filePath);
267
+ if (stat.mtimeMs < sinceMs)
268
+ continue;
269
+ }
270
+ catch {
271
+ continue;
272
+ }
273
+ let raw;
274
+ try {
275
+ raw = fs.readFileSync(filePath, "utf8");
276
+ }
277
+ catch {
278
+ continue;
279
+ }
280
+ let run;
281
+ try {
282
+ run = JSON.parse(raw);
283
+ }
284
+ catch {
285
+ continue; // malformed — skip
286
+ }
287
+ if (typeof run !== "object" || run === null)
288
+ continue;
289
+ const r = run;
290
+ // Validate createdAt is within window
291
+ const ts = typeof r["createdAt"] === "string" ? r["createdAt"] : null;
292
+ if (!ts)
293
+ continue;
294
+ try {
295
+ if (new Date(ts).getTime() < sinceMs)
296
+ continue;
297
+ }
298
+ catch {
299
+ continue;
300
+ }
301
+ const model = typeof r["provider"] === "string" ? r["provider"] : "unknown";
302
+ // Extract ONLY the numeric usage fields
303
+ const usage = r["usage"];
304
+ if (typeof usage !== "object" || usage === null)
305
+ continue;
306
+ const u = usage;
307
+ const tokensIn = typeof u["tokensIn"] === "number" ? u["tokensIn"] : 0;
308
+ const tokensOut = typeof u["tokensOut"] === "number" ? u["tokensOut"] : 0;
309
+ if (tokensIn === 0 && tokensOut === 0)
310
+ continue;
311
+ events.push({
312
+ ts,
313
+ project: null,
314
+ model,
315
+ source: "run",
316
+ tokensIn,
317
+ tokensOut,
318
+ cacheRead: 0,
319
+ cacheWrite: 0,
320
+ });
321
+ }
322
+ return events;
323
+ }
324
+ // ---------------------------------------------------------------------------
325
+ // Public API
326
+ // ---------------------------------------------------------------------------
327
+ /**
328
+ * Collect normalized UsageEvents from all local sources with ts >= sinceMs.
329
+ *
330
+ * Sources:
331
+ * (a) ~/.claude/projects/<encoded-dir>/*.jsonl — METADATA ONLY
332
+ * (b) ~/.ashlr/runs/*.json — M4 RunState records
333
+ *
334
+ * Streams line-by-line; skips files older than sinceMs by mtime; tolerates
335
+ * malformed lines; never reads message content. Never throws.
336
+ */
337
+ export function collectUsageEvents(sinceMs) {
338
+ try {
339
+ const claude = collectClaudeEvents(sinceMs);
340
+ const runs = collectRunEvents(sinceMs);
341
+ return [...claude, ...runs];
342
+ }
343
+ catch {
344
+ return []; // belt-and-suspenders: top-level guard
345
+ }
346
+ }
347
+ //# sourceMappingURL=usage-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-source.js","sourceRoot":"","sources":["../../../src/core/observability/usage-source.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * core/onboard.ts — one-command idempotent onboarding (M20).
3
+ *
4
+ * onboard(cfg, opts): detect + report + safe ensures in a single, NON-TTY-safe
5
+ * call. Never hangs on a prompt. Mutating steps are gated:
6
+ * - editor wiring: only when opts.wire
7
+ * - model downloads: NEVER (pull stays explicit)
8
+ * - shell-profile edits: NEVER
9
+ *
10
+ * Returns an OnboardResult with one OnboardStep per step, a ready flag, and
11
+ * crisp nextSteps guidance.
12
+ */
13
+ import type { AshlrConfig, OnboardResult } from './types.js';
14
+ /**
15
+ * Run the complete idempotent onboarding sequence.
16
+ *
17
+ * Guaranteed to:
18
+ * - Never throw (degrades to 'manual' steps on any error).
19
+ * - Never hang (no interactive prompts; safe in non-TTY environments).
20
+ * - Never auto-download models.
21
+ * - Never touch secrets, shell profiles, or anything outward/network.
22
+ * - Be idempotent (safe to re-run).
23
+ */
24
+ export declare function onboard(cfg: AshlrConfig, opts: {
25
+ wire: boolean;
26
+ yes: boolean;
27
+ }): Promise<OnboardResult>;
@@ -0,0 +1,288 @@
1
+ /**
2
+ * core/onboard.ts — one-command idempotent onboarding (M20).
3
+ *
4
+ * onboard(cfg, opts): detect + report + safe ensures in a single, NON-TTY-safe
5
+ * call. Never hangs on a prompt. Mutating steps are gated:
6
+ * - editor wiring: only when opts.wire
7
+ * - model downloads: NEVER (pull stays explicit)
8
+ * - shell-profile edits: NEVER
9
+ *
10
+ * Returns an OnboardResult with one OnboardStep per step, a ready flag, and
11
+ * crisp nextSteps guidance.
12
+ */
13
+ import { existsSync, mkdirSync, symlinkSync, readlinkSync } from 'node:fs';
14
+ import { homedir } from 'node:os';
15
+ import { join, resolve, dirname } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { saveConfig, defaultConfig } from './config.js';
18
+ import { listLocalModels, ollamaInstalled } from './run/model-manager.js';
19
+ import { detectEditors, wireEditor } from './integrations/editors.js';
20
+ import { getPhantomStatus } from './phantom.js';
21
+ import { runDoctor } from './doctor.js';
22
+ // ---------------------------------------------------------------------------
23
+ // Helpers
24
+ // ---------------------------------------------------------------------------
25
+ /** Produce a passing step — never throws. */
26
+ function step(name, status, detail) {
27
+ return { name, status, detail };
28
+ }
29
+ // ---------------------------------------------------------------------------
30
+ // Step implementations — each is async, catches all errors, never throws
31
+ // ---------------------------------------------------------------------------
32
+ /** Step 1: ensure ~/.ashlr/config.json exists. */
33
+ async function stepConfig() {
34
+ try {
35
+ // Resolve the config path from homedir() at call time so a moving HOME is
36
+ // honored and matches the path saveConfig()/runDoctor() actually use. The
37
+ // exported CONFIG_PATH constant is resolved once at module load and would
38
+ // point at a stale home (breaking onboarding under a relocated/test HOME).
39
+ const configPath = join(homedir(), '.ashlr', 'config.json');
40
+ if (existsSync(configPath)) {
41
+ return step('config', 'ok', `Config present at ${configPath}`);
42
+ }
43
+ // Create from defaults via saveConfig (loadConfig already does this, but we
44
+ // want explicit ensure-only semantics here — never overwrite existing).
45
+ const defaults = defaultConfig();
46
+ saveConfig(defaults);
47
+ return step('config', 'ok', `Created default config at ${configPath}`);
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ return step('config', 'manual', `Could not ensure config: ${msg}. Run: ashlr doctor --fix`);
52
+ }
53
+ }
54
+ /** Step 2: detect local models — report only, NEVER auto-download. */
55
+ async function stepModels(cfg) {
56
+ try {
57
+ const models = await listLocalModels(cfg);
58
+ if (models.length > 0) {
59
+ const names = models.map((m) => `${m.provider}/${m.name}`).join(', ');
60
+ return step('models', 'detected', `Local models found: ${names}`);
61
+ }
62
+ const ollamaPresent = ollamaInstalled();
63
+ if (ollamaPresent) {
64
+ return step('models', 'manual', 'Ollama is installed but no models are loaded. Run: ashlr models pull <model> (e.g. llama3:8b)');
65
+ }
66
+ return step('models', 'manual', 'No local models detected (Ollama/LM Studio not running or not installed). Run: ashlr models pull <model>');
67
+ }
68
+ catch (err) {
69
+ const msg = err instanceof Error ? err.message : String(err);
70
+ return step('models', 'manual', `Could not probe local models: ${msg}. Run: ashlr models pull <model>`);
71
+ }
72
+ }
73
+ /** Step 3: detect editors; wire them when opts.wire. */
74
+ async function stepEditors(opts) {
75
+ try {
76
+ const editors = detectEditors();
77
+ if (editors.length === 0) {
78
+ return step('editors', 'skipped', 'No supported editors detected (claude / codex / cursor)');
79
+ }
80
+ if (!opts.wire) {
81
+ return step('editors', 'detected', `Detected: ${editors.join(', ')}. Re-run with --wire to register the ashlr MCP gateway.`);
82
+ }
83
+ // Wire each detected editor — backup-first + idempotent (M18).
84
+ const results = [];
85
+ for (const editor of editors) {
86
+ const target = editor;
87
+ const r = await wireEditor(target, {});
88
+ results.push(`${editor}: ${r.detail}`);
89
+ }
90
+ return step('editors', 'wired', results.join('; '));
91
+ }
92
+ catch (err) {
93
+ const msg = err instanceof Error ? err.message : String(err);
94
+ return step('editors', 'manual', `Editor detection/wiring failed: ${msg}. Run: ashlr wire`);
95
+ }
96
+ }
97
+ /**
98
+ * Step 4: ensure the ashlr → ~/.local/bin/ashlr symlink.
99
+ *
100
+ * Safe ensure: create only when (a) the symlink is missing AND (b) the source
101
+ * bin/ashlr file can be resolved from this module's location. Never modifies
102
+ * shell profiles. If source cannot be resolved → manual guidance.
103
+ */
104
+ async function stepSymlink() {
105
+ const localBin = join(homedir(), '.local', 'bin');
106
+ const symlinkDest = join(localBin, 'ashlr');
107
+ try {
108
+ // Check if already present and correct.
109
+ if (existsSync(symlinkDest)) {
110
+ let target;
111
+ try {
112
+ target = readlinkSync(symlinkDest);
113
+ }
114
+ catch {
115
+ // Not a symlink (could be a real file installed by npm) — that's fine.
116
+ return step('symlink', 'ok', `ashlr present at ${symlinkDest}`);
117
+ }
118
+ return step('symlink', 'ok', `Symlink present: ${symlinkDest} → ${target}`);
119
+ }
120
+ // Attempt to resolve the bin/ashlr source from this module's directory tree.
121
+ // __dirname equivalent for ESM: walk up from src/core → project root → bin/ashlr.
122
+ const thisFile = fileURLToPath(import.meta.url);
123
+ // src/core/onboard.ts → src/core → src → project root
124
+ const projectRoot = resolve(dirname(thisFile), '..', '..');
125
+ const binSrc = join(projectRoot, 'bin', 'ashlr');
126
+ if (!existsSync(binSrc)) {
127
+ return step('symlink', 'manual', `ashlr not yet in ~/.local/bin. Run: ./install.sh (from the ashlr-hub repo)`);
128
+ }
129
+ // Create ~/.local/bin if absent, then create the symlink.
130
+ mkdirSync(localBin, { recursive: true });
131
+ symlinkSync(binSrc, symlinkDest);
132
+ return step('symlink', 'ok', `Created symlink: ${symlinkDest} → ${binSrc}`);
133
+ }
134
+ catch (err) {
135
+ const msg = err instanceof Error ? err.message : String(err);
136
+ return step('symlink', 'manual', `Could not ensure symlink: ${msg}. Run: ./install.sh (from the ashlr-hub repo)`);
137
+ }
138
+ }
139
+ /**
140
+ * Step 5: ensure the genome directory exists (~/.ashlr/genome).
141
+ * mkdir-only, never seeds/edits entries.
142
+ */
143
+ async function stepGenome() {
144
+ const genomeDir = join(homedir(), '.ashlr', 'genome');
145
+ try {
146
+ if (existsSync(genomeDir)) {
147
+ return step('genome', 'ok', `Genome dir present at ${genomeDir}`);
148
+ }
149
+ mkdirSync(genomeDir, { recursive: true });
150
+ return step('genome', 'ok', `Created genome dir at ${genomeDir}`);
151
+ }
152
+ catch (err) {
153
+ const msg = err instanceof Error ? err.message : String(err);
154
+ return step('genome', 'manual', `Could not create genome dir: ${msg}. Run: ashlr doctor --fix`);
155
+ }
156
+ }
157
+ /** Step 6: phantom status — report only, never touches secrets. */
158
+ async function stepPhantom() {
159
+ try {
160
+ const status = getPhantomStatus();
161
+ if (!status.installed) {
162
+ return step('phantom', 'manual', 'Phantom not installed. Install from https://phantom.sh to enable secrets management.');
163
+ }
164
+ if (!status.initialized) {
165
+ return step('phantom', 'detected', `Phantom v${status.version ?? 'unknown'} installed but vault not initialized. Run: phantom init`);
166
+ }
167
+ const count = status.secretNames.length;
168
+ return step('phantom', 'ok', `Phantom v${status.version ?? 'unknown'} — vault initialized (${count} secret${count !== 1 ? 's' : ''})`);
169
+ }
170
+ catch (err) {
171
+ const msg = err instanceof Error ? err.message : String(err);
172
+ return step('phantom', 'manual', `Phantom status unavailable: ${msg}`);
173
+ }
174
+ }
175
+ /**
176
+ * Doctor checks that genuinely block the hub from running. A `fail` on one of
177
+ * these means setup is NOT ready.
178
+ *
179
+ * This set is intentionally EMPTY: config presence — the one true readiness
180
+ * prerequisite — is gated authoritatively by onboard's own `configStep` (which
181
+ * resolves the config path at call time), not by doctor's `config` check (which
182
+ * compares a module-load-time CONFIG_PATH constant and can therefore disagree
183
+ * under a relocated/test HOME). Every other doctor `fail` (git/ashlr-on-PATH,
184
+ * provider reachability, MCP wiring, etc.) is environmental/advisory: you can
185
+ * still `ashlr run` with cloud fallback, install a model later, or fix PATH
186
+ * later. Those are surfaced as guidance in nextSteps, never a hard readiness
187
+ * blocker. This matches the contract's `ready` = "config present + doctor has
188
+ * no fail that blocks running".
189
+ */
190
+ const BLOCKING_FAIL_IDS = new Set();
191
+ /** Step 7: run doctor and fold roll-up into final OnboardStep. */
192
+ async function stepDoctor(cfg) {
193
+ try {
194
+ const report = await runDoctor(cfg);
195
+ const { pass, warn, fail } = report.summary;
196
+ const failChecks = report.checks.filter((c) => c.status === 'fail');
197
+ const blockingFails = failChecks.filter((c) => BLOCKING_FAIL_IDS.has(c.id));
198
+ const hasBlockingFail = blockingFails.length > 0;
199
+ const detail = `doctor: ${pass} pass, ${warn} warn, ${fail} fail`;
200
+ if (hasBlockingFail) {
201
+ const failLabels = blockingFails.map((c) => c.label).join(', ');
202
+ return {
203
+ doctorStep: step('doctor', 'manual', `${detail}. Blocking: ${failLabels}. Run: ashlr doctor --fix`),
204
+ hasBlockingFail: true,
205
+ };
206
+ }
207
+ // Non-blocking fails are advisory — report them but don't gate readiness.
208
+ if (failChecks.length > 0) {
209
+ const failLabels = failChecks.map((c) => c.label).join(', ');
210
+ return {
211
+ doctorStep: step('doctor', 'detected', `${detail}. Needs attention: ${failLabels}. Run: ashlr doctor --fix`),
212
+ hasBlockingFail: false,
213
+ };
214
+ }
215
+ return {
216
+ doctorStep: step('doctor', warn > 0 ? 'detected' : 'ok', detail),
217
+ hasBlockingFail: false,
218
+ };
219
+ }
220
+ catch (err) {
221
+ const msg = err instanceof Error ? err.message : String(err);
222
+ return {
223
+ doctorStep: step('doctor', 'manual', `Doctor check failed: ${msg}. Run: ashlr doctor`),
224
+ hasBlockingFail: false, // unknown state — don't block if doctor itself errors
225
+ };
226
+ }
227
+ }
228
+ // ---------------------------------------------------------------------------
229
+ // Public API
230
+ // ---------------------------------------------------------------------------
231
+ /**
232
+ * Run the complete idempotent onboarding sequence.
233
+ *
234
+ * Guaranteed to:
235
+ * - Never throw (degrades to 'manual' steps on any error).
236
+ * - Never hang (no interactive prompts; safe in non-TTY environments).
237
+ * - Never auto-download models.
238
+ * - Never touch secrets, shell profiles, or anything outward/network.
239
+ * - Be idempotent (safe to re-run).
240
+ */
241
+ export async function onboard(cfg, opts) {
242
+ // Run all steps sequentially so each can feed into ready computation.
243
+ // Steps that are independent in principle are still sequential here to avoid
244
+ // interleaved output and to keep the order deterministic and predictable.
245
+ const configStep = await stepConfig();
246
+ const modelsStep = await stepModels(cfg);
247
+ const editorsStep = await stepEditors(opts);
248
+ const symlinkStep = await stepSymlink();
249
+ const genomeStep = await stepGenome();
250
+ const phantomStep = await stepPhantom();
251
+ const { doctorStep, hasBlockingFail } = await stepDoctor(cfg);
252
+ const steps = [
253
+ configStep,
254
+ modelsStep,
255
+ editorsStep,
256
+ symlinkStep,
257
+ genomeStep,
258
+ phantomStep,
259
+ doctorStep,
260
+ ];
261
+ // ready = config is ok AND no doctor blocking failures.
262
+ const configOk = configStep.status === 'ok';
263
+ const ready = configOk && !hasBlockingFail;
264
+ // Build nextSteps guidance.
265
+ const nextSteps = [];
266
+ if (!configOk) {
267
+ nextSteps.push('Fix config first: ashlr doctor --fix');
268
+ }
269
+ if (modelsStep.status === 'manual') {
270
+ nextSteps.push('Pull a local model: ashlr models pull llama3:8b');
271
+ }
272
+ if (editorsStep.status === 'detected' && !opts.wire) {
273
+ nextSteps.push('Wire your editor: ashlr init --wire');
274
+ }
275
+ if (symlinkStep.status === 'manual') {
276
+ nextSteps.push('Install the CLI symlink: ./install.sh (from the ashlr-hub repo)');
277
+ }
278
+ // Surface doctor guidance for any remaining issues (blocking or advisory) —
279
+ // doctorStep is 'manual' on a blocking fail and 'detected' when there are
280
+ // non-blocking fails/warns that still warrant a `doctor --fix` pass.
281
+ if (doctorStep.status === 'manual' || hasBlockingFail) {
282
+ nextSteps.push('Fix doctor issues: ashlr doctor --fix');
283
+ }
284
+ // Always end with the crisp "you're set up" guidance.
285
+ nextSteps.push('try: ashlr run / ashlr swarm / ashlr tui');
286
+ return { steps, ready, nextSteps };
287
+ }
288
+ //# sourceMappingURL=onboard.js.map