@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,1061 @@
1
+ /**
2
+ * `ashlr recall`, `ashlr learn`, and `ashlr genome` CLI commands (M7 + M16).
3
+ *
4
+ * Commands:
5
+ * ashlr recall "<query>" [--limit N] [--no-embeddings] [--json]
6
+ * Search the aggregated genome and print ranked hits.
7
+ *
8
+ * ashlr learn "<text>" [--title <t>] [--project <p>] [--tags a,b] [--json]
9
+ * Append a memory entry to ~/.ashlr/genome/hub.jsonl.
10
+ *
11
+ * ashlr genome [--json]
12
+ * Print genome health panel (entry counts, projects, size, staleness,
13
+ * embeddings availability).
14
+ *
15
+ * ashlr genome --teach "<note>" [--title <t>] [--project <p>] [--json]
16
+ * Append a high-value explicit memory tagged 'teach'.
17
+ *
18
+ * ashlr genome consolidate [--json]
19
+ * Merge near-duplicate genome entries (backup-first, no data loss).
20
+ *
21
+ * ashlr genome export <file> [--format json|md] [--json]
22
+ * Export the full genome to a portable JSON or Markdown file.
23
+ *
24
+ * ashlr genome playbook "<goal>" [--limit N] [--json]
25
+ * Synthesize a playbook from past genome entries for a goal.
26
+ *
27
+ * Exit codes:
28
+ * 0 success
29
+ * 1 error (missing module, I/O failure)
30
+ * 2 bad usage
31
+ */
32
+ async function importGenomeStore() {
33
+ return import('../core/genome/store.js');
34
+ }
35
+ async function importGenomeRecall() {
36
+ return import('../core/genome/recall.js');
37
+ }
38
+ async function importConfig() {
39
+ return import('../core/config.js');
40
+ }
41
+ async function importConsolidate() {
42
+ return import('../core/genome/consolidate.js');
43
+ }
44
+ async function importExport() {
45
+ return import('../core/genome/export.js');
46
+ }
47
+ async function importPlaybook() {
48
+ return import('../core/genome/playbook.js');
49
+ }
50
+ // ---------------------------------------------------------------------------
51
+ // ANSI helpers — non-TTY safe (same pattern as run.ts / ship.ts)
52
+ // ---------------------------------------------------------------------------
53
+ import { pad, makeColors, isTty } from './ui.js';
54
+ import { parsePositiveInt } from './args.js';
55
+ const { bold, dim, red, green, yellow, cyan, gray, magenta } = makeColors(isTty());
56
+ /**
57
+ * Write a line to stdout. Routes through process.stdout.write (not console.log)
58
+ * so output is reliably captured by callers/tests that intercept the stream and
59
+ * so it is unaffected by any console wiring. Appends a trailing newline.
60
+ */
61
+ function out(line = '') {
62
+ process.stdout.write(line + '\n');
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Shared helpers
66
+ // ---------------------------------------------------------------------------
67
+ /** Format bytes into a human-readable string (B / KB / MB). */
68
+ function fmtBytes(n) {
69
+ if (n < 1024)
70
+ return `${n} B`;
71
+ if (n < 1024 * 1024)
72
+ return `${(n / 1024).toFixed(1)} KB`;
73
+ return `${(n / (1024 * 1024)).toFixed(2)} MB`;
74
+ }
75
+ /** Relative time from an ISO string. Returns 'never' for null. */
76
+ function relativeTime(iso) {
77
+ if (!iso)
78
+ return gray('never');
79
+ const ms = Date.now() - new Date(iso).getTime();
80
+ const s = Math.floor(ms / 1000);
81
+ const m = Math.floor(s / 60);
82
+ const h = Math.floor(m / 60);
83
+ const d = Math.floor(h / 24);
84
+ if (d > 0)
85
+ return `${d}d ago`;
86
+ if (h > 0)
87
+ return `${h}h ago`;
88
+ if (m > 0)
89
+ return `${m}m ago`;
90
+ if (s >= 0)
91
+ return `${s}s ago`;
92
+ return 'just now';
93
+ }
94
+ /**
95
+ * Produce a short snippet of the entry text (first non-empty line up to
96
+ * `maxChars`), suitable for display in a hit list.
97
+ */
98
+ function snippet(text, maxChars = 120) {
99
+ const first = text.split('\n').map(l => l.trim()).find(l => l.length > 0) ?? '';
100
+ if (first.length <= maxChars)
101
+ return first;
102
+ return first.slice(0, maxChars - 1) + '…';
103
+ }
104
+ function parseRecallArgs(args) {
105
+ const result = {
106
+ query: '',
107
+ noEmbeddings: false,
108
+ json: false,
109
+ };
110
+ let i = 0;
111
+ while (i < args.length) {
112
+ const arg = args[i];
113
+ if (arg === '--json') {
114
+ result.json = true;
115
+ i++;
116
+ }
117
+ else if (arg === '--no-embeddings') {
118
+ result.noEmbeddings = true;
119
+ i++;
120
+ }
121
+ else if (arg === '--limit') {
122
+ const parsed = parsePositiveInt('limit', args[++i]);
123
+ if ('error' in parsed) {
124
+ result.usageError = parsed.error;
125
+ return result;
126
+ }
127
+ result.limit = parsed.n;
128
+ i++;
129
+ }
130
+ else if (!arg.startsWith('--')) {
131
+ if (result.query) {
132
+ result.usageError = `unexpected extra argument: ${arg}`;
133
+ return result;
134
+ }
135
+ result.query = arg;
136
+ i++;
137
+ }
138
+ else {
139
+ result.usageError = `unknown flag: ${arg}`;
140
+ return result;
141
+ }
142
+ }
143
+ if (!result.query.trim()) {
144
+ result.usageError =
145
+ 'Usage: ashlr recall "<query>" [--limit N] [--no-embeddings] [--json]';
146
+ }
147
+ return result;
148
+ }
149
+ function printRecallHuman(hits, query) {
150
+ if (hits.length === 0) {
151
+ out('');
152
+ out(` ${dim(`No genome entries matched "${query}".`)}`);
153
+ out(` ${dim('Add entries with: ashlr learn "<text>"')}`);
154
+ out('');
155
+ return;
156
+ }
157
+ const scoreW = 6;
158
+ const methodW = 9;
159
+ const titleW = 32;
160
+ const projectW = 18;
161
+ out('');
162
+ out(bold(' ashlr recall') + gray(` — ${hits.length} hit(s) for "${query}"`));
163
+ out('');
164
+ out(` ${bold(pad('#', 3))} ` +
165
+ `${bold(pad('Score', scoreW, 'right'))} ` +
166
+ `${bold(pad('Method', methodW))} ` +
167
+ `${bold(pad('Project', projectW))} ` +
168
+ `${bold(pad('Title', titleW))}`);
169
+ out(` ${'─'.repeat(3)} ${'─'.repeat(scoreW)} ${'─'.repeat(methodW)} ` +
170
+ `${'─'.repeat(projectW)} ${'─'.repeat(titleW)}`);
171
+ hits.forEach((hit, idx) => {
172
+ const { entry, score, method } = hit;
173
+ const num = String(idx + 1);
174
+ const scoreStr = score.toFixed(3);
175
+ const methodColor = method === 'embedding' ? magenta(method) : cyan(method);
176
+ const projectStr = entry.project
177
+ ? cyan(entry.project.length > projectW ? entry.project.slice(0, projectW - 1) + '…' : entry.project)
178
+ : gray('(hub)');
179
+ const titleStr = entry.title.length > titleW
180
+ ? entry.title.slice(0, titleW - 1) + '…'
181
+ : entry.title;
182
+ out(` ${pad(dim(num), 3)} ` +
183
+ `${pad(yellow(scoreStr), scoreW, 'right')} ` +
184
+ `${pad(methodColor, methodW)} ` +
185
+ `${pad(projectStr, projectW)} ` +
186
+ titleStr);
187
+ // Snippet on the next line, indented
188
+ const snip = snippet(entry.text);
189
+ if (snip) {
190
+ out(` ${''.padStart(3 + 2 + scoreW + 2 + methodW + 2 + projectW + 2)}${gray(snip)}`);
191
+ }
192
+ // Tags line (if any)
193
+ if (entry.tags.length > 0) {
194
+ const tagStr = entry.tags.map(t => dim(`#${t}`)).join(' ');
195
+ out(` ${''.padStart(3 + 2 + scoreW + 2 + methodW + 2 + projectW + 2)}${tagStr}`);
196
+ }
197
+ // Separator between hits
198
+ if (idx < hits.length - 1)
199
+ out('');
200
+ });
201
+ out('');
202
+ out(dim(` ${hits.length} result(s) · source: local genome · `) +
203
+ dim('ashlr learn "<text>" to add more'));
204
+ out('');
205
+ }
206
+ /**
207
+ * `ashlr recall "<query>" [--limit N] [--no-embeddings] [--json]`
208
+ *
209
+ * Exit codes: 0 success, 1 module/runtime error, 2 bad usage.
210
+ */
211
+ export async function cmdRecall(args) {
212
+ if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
213
+ printRecallHelp();
214
+ return 0;
215
+ }
216
+ const parsed = parseRecallArgs(args);
217
+ if (parsed.usageError) {
218
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
219
+ return 2;
220
+ }
221
+ // Load config
222
+ let cfg;
223
+ try {
224
+ const { loadConfig } = await importConfig();
225
+ cfg = loadConfig();
226
+ }
227
+ catch (err) {
228
+ process.stderr.write(red('error: ') + 'Failed to load config: ' +
229
+ (err instanceof Error ? err.message : String(err)) + '\n');
230
+ return 1;
231
+ }
232
+ // Load recall function
233
+ let recallFn;
234
+ try {
235
+ const mod = await importGenomeRecall();
236
+ recallFn = mod.recall;
237
+ }
238
+ catch (err) {
239
+ process.stderr.write(red('error: ') + 'Failed to load genome/recall module (M7 not yet built): ' +
240
+ (err instanceof Error ? err.message : String(err)) + '\n');
241
+ return 1;
242
+ }
243
+ // Execute recall
244
+ let hits;
245
+ try {
246
+ hits = await recallFn(parsed.query, cfg, {
247
+ limit: parsed.limit,
248
+ // Default CLI behavior opts INTO embedding rerank (best-effort, local-only).
249
+ // recall() falls back to keyword automatically when no local model is
250
+ // present or any embedding call fails. --no-embeddings forces keyword-only.
251
+ embeddings: !parsed.noEmbeddings,
252
+ });
253
+ }
254
+ catch (err) {
255
+ process.stderr.write(red('error: ') + 'Recall failed: ' +
256
+ (err instanceof Error ? err.message : String(err)) + '\n');
257
+ return 1;
258
+ }
259
+ if (parsed.json) {
260
+ process.stdout.write(JSON.stringify(hits, null, 2) + '\n');
261
+ return 0;
262
+ }
263
+ printRecallHuman(hits.filter(h => h.score > 0), parsed.query);
264
+ return 0;
265
+ }
266
+ function parseLearnArgs(args) {
267
+ const result = {
268
+ text: '',
269
+ tags: [],
270
+ json: false,
271
+ };
272
+ let i = 0;
273
+ while (i < args.length) {
274
+ const arg = args[i];
275
+ if (arg === '--json') {
276
+ result.json = true;
277
+ i++;
278
+ }
279
+ else if (arg === '--title') {
280
+ const val = args[++i];
281
+ if (!val || val.startsWith('--')) {
282
+ result.usageError = `--title requires a value, got: ${val ?? '(missing)'}`;
283
+ return result;
284
+ }
285
+ result.title = val;
286
+ i++;
287
+ }
288
+ else if (arg === '--project') {
289
+ const val = args[++i];
290
+ if (!val || val.startsWith('--')) {
291
+ result.usageError = `--project requires a value, got: ${val ?? '(missing)'}`;
292
+ return result;
293
+ }
294
+ result.project = val;
295
+ i++;
296
+ }
297
+ else if (arg === '--tags') {
298
+ const val = args[++i];
299
+ if (!val || val.startsWith('--')) {
300
+ result.usageError = `--tags requires a comma-separated list, got: ${val ?? '(missing)'}`;
301
+ return result;
302
+ }
303
+ result.tags = val.split(',').map(t => t.trim()).filter(t => t.length > 0);
304
+ i++;
305
+ }
306
+ else if (!arg.startsWith('--')) {
307
+ if (result.text) {
308
+ result.usageError = `unexpected extra argument: ${arg}`;
309
+ return result;
310
+ }
311
+ result.text = arg;
312
+ i++;
313
+ }
314
+ else {
315
+ result.usageError = `unknown flag: ${arg}`;
316
+ return result;
317
+ }
318
+ }
319
+ if (!result.text.trim()) {
320
+ result.usageError =
321
+ 'Usage: ashlr learn "<text>" [--title <title>] [--project <name>] [--tags a,b] [--json]';
322
+ }
323
+ return result;
324
+ }
325
+ /**
326
+ * `ashlr learn "<text>" [--title <t>] [--project <p>] [--tags a,b] [--json]`
327
+ *
328
+ * Appends a GenomeEntry to ~/.ashlr/genome/hub.jsonl. Never overwrites.
329
+ * Confirms what was stored — does NOT print secrets or full text verbatim
330
+ * (only the title, id, and store path are echoed).
331
+ *
332
+ * Exit codes: 0 success, 1 module/I-O error, 2 bad usage.
333
+ */
334
+ export async function cmdLearn(args) {
335
+ if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
336
+ printLearnHelp();
337
+ return 0;
338
+ }
339
+ const parsed = parseLearnArgs(args);
340
+ if (parsed.usageError) {
341
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
342
+ return 2;
343
+ }
344
+ // Load store module
345
+ let appendHubEntry;
346
+ let hubStorePath;
347
+ try {
348
+ const mod = await importGenomeStore();
349
+ appendHubEntry = mod.appendHubEntry;
350
+ hubStorePath = mod.hubStorePath;
351
+ }
352
+ catch (err) {
353
+ process.stderr.write(red('error: ') + 'Failed to load genome/store module (M7 not yet built): ' +
354
+ (err instanceof Error ? err.message : String(err)) + '\n');
355
+ return 1;
356
+ }
357
+ // Build input
358
+ const input = {
359
+ text: parsed.text,
360
+ title: parsed.title,
361
+ project: parsed.project,
362
+ tags: parsed.tags.length > 0 ? parsed.tags : undefined,
363
+ };
364
+ // Append entry
365
+ let entry;
366
+ try {
367
+ entry = appendHubEntry(input);
368
+ }
369
+ catch (err) {
370
+ process.stderr.write(red('error: ') + 'Failed to write genome entry: ' +
371
+ (err instanceof Error ? err.message : String(err)) + '\n');
372
+ return 1;
373
+ }
374
+ const storePath = hubStorePath();
375
+ if (parsed.json) {
376
+ // Return the full entry as JSON — text is the user's own note, safe to echo.
377
+ process.stdout.write(JSON.stringify(entry, null, 2) + '\n');
378
+ return 0;
379
+ }
380
+ // Human output: confirm title + id + path; do NOT echo text back (avoids
381
+ // accidental secret exposure if text was pasted from a sensitive context).
382
+ out('');
383
+ out(bold(' ashlr learn') + gray(' — entry stored'));
384
+ out('');
385
+ out(` ${bold('Title:')} ${cyan(entry.title)}`);
386
+ out(` ${bold('ID:')} ${dim(entry.id)}`);
387
+ if (entry.project) {
388
+ out(` ${bold('Project:')} ${cyan(entry.project)}`);
389
+ }
390
+ if (entry.tags.length > 0) {
391
+ out(` ${bold('Tags:')} ${entry.tags.map(t => dim(`#${t}`)).join(' ')}`);
392
+ }
393
+ out(` ${bold('Store:')} ${gray(storePath)}`);
394
+ out(` ${bold('Source:')} ${entry.source}`);
395
+ out(` ${bold('At:')} ${relativeTime(entry.ts)}`);
396
+ out('');
397
+ out(dim(' Use `ashlr recall "') + dim(entry.title.slice(0, 40)) + dim('"` to find it later.'));
398
+ out('');
399
+ return 0;
400
+ }
401
+ // ---------------------------------------------------------------------------
402
+ // `ashlr genome [subcommand] [options]`
403
+ //
404
+ // M16 subcommands routed from cmdGenome:
405
+ // --teach "<note>" — genome --teach
406
+ // consolidate — genome consolidate
407
+ // export <file> — genome export
408
+ // playbook "<goal>" — genome playbook
409
+ //
410
+ // Default (no subcommand): original M7 health panel.
411
+ // ---------------------------------------------------------------------------
412
+ // ---- subcommand detection ----
413
+ /**
414
+ * Scan args for a known M16 subcommand keyword or flag.
415
+ * Returns the subcommand name, or null to fall through to the health panel.
416
+ */
417
+ function detectSubcommand(args) {
418
+ for (const arg of args) {
419
+ if (arg === '--teach')
420
+ return 'teach';
421
+ if (arg === 'consolidate')
422
+ return 'consolidate';
423
+ if (arg === 'export')
424
+ return 'export';
425
+ if (arg === 'playbook')
426
+ return 'playbook';
427
+ }
428
+ return null;
429
+ }
430
+ function parseTeachArgs(args) {
431
+ const result = { note: '', json: false };
432
+ let i = 0;
433
+ while (i < args.length) {
434
+ const arg = args[i];
435
+ if (arg === '--teach') {
436
+ const val = args[++i];
437
+ if (!val || val.startsWith('--')) {
438
+ result.usageError = `--teach requires a value, got: ${val ?? '(missing)'}`;
439
+ return result;
440
+ }
441
+ result.note = val;
442
+ i++;
443
+ }
444
+ else if (arg === '--json') {
445
+ result.json = true;
446
+ i++;
447
+ }
448
+ else if (arg === '--title') {
449
+ const val = args[++i];
450
+ if (!val || val.startsWith('--')) {
451
+ result.usageError = `--title requires a value, got: ${val ?? '(missing)'}`;
452
+ return result;
453
+ }
454
+ result.title = val;
455
+ i++;
456
+ }
457
+ else if (arg === '--project') {
458
+ const val = args[++i];
459
+ if (!val || val.startsWith('--')) {
460
+ result.usageError = `--project requires a value, got: ${val ?? '(missing)'}`;
461
+ return result;
462
+ }
463
+ result.project = val;
464
+ i++;
465
+ }
466
+ else if (!arg.startsWith('--')) {
467
+ // positional tokens (e.g. 'genome' itself) — skip silently
468
+ i++;
469
+ }
470
+ else {
471
+ result.usageError = `unknown flag: ${arg}`;
472
+ return result;
473
+ }
474
+ }
475
+ if (!result.note.trim()) {
476
+ result.usageError =
477
+ 'Usage: ashlr genome --teach "<note>" [--title <title>] [--project <name>] [--json]';
478
+ }
479
+ return result;
480
+ }
481
+ async function runTeach(args, _cfg) {
482
+ const parsed = parseTeachArgs(args);
483
+ if (parsed.usageError) {
484
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
485
+ return 2;
486
+ }
487
+ let appendHubEntry;
488
+ let hubStorePath;
489
+ try {
490
+ const mod = await importGenomeStore();
491
+ appendHubEntry = mod.appendHubEntry;
492
+ hubStorePath = mod.hubStorePath;
493
+ }
494
+ catch (err) {
495
+ process.stderr.write(red('error: ') + 'Failed to load genome/store module: ' +
496
+ (err instanceof Error ? err.message : String(err)) + '\n');
497
+ return 1;
498
+ }
499
+ // Always tag 'teach'; preserve any project scoping.
500
+ // Note: 'source' is a GenomeEntry field set by appendHubEntry, not a LearnInput field.
501
+ const input = {
502
+ text: parsed.note,
503
+ title: parsed.title,
504
+ project: parsed.project,
505
+ tags: ['teach'],
506
+ };
507
+ let entry;
508
+ try {
509
+ entry = appendHubEntry(input);
510
+ }
511
+ catch (err) {
512
+ process.stderr.write(red('error: ') + 'Failed to write teach entry: ' +
513
+ (err instanceof Error ? err.message : String(err)) + '\n');
514
+ return 1;
515
+ }
516
+ const storePath = hubStorePath();
517
+ if (parsed.json) {
518
+ process.stdout.write(JSON.stringify(entry, null, 2) + '\n');
519
+ return 0;
520
+ }
521
+ out('');
522
+ out(bold(' ashlr genome --teach') + gray(' — high-value memory stored'));
523
+ out('');
524
+ out(` ${bold('Title:')} ${cyan(entry.title)}`);
525
+ out(` ${bold('ID:')} ${dim(entry.id)}`);
526
+ if (entry.project) {
527
+ out(` ${bold('Project:')} ${cyan(entry.project)}`);
528
+ }
529
+ out(` ${bold('Tags:')} ${entry.tags.map(t => dim(`#${t}`)).join(' ')}`);
530
+ out(` ${bold('Store:')} ${gray(storePath)}`);
531
+ out(` ${bold('At:')} ${relativeTime(entry.ts)}`);
532
+ out('');
533
+ out(dim(' Tagged #teach — surfaces in playbook synthesis and recall.'));
534
+ out('');
535
+ return 0;
536
+ }
537
+ function parseConsolidateArgs(args) {
538
+ const result = { json: false };
539
+ for (const arg of args) {
540
+ if (arg === '--json') {
541
+ result.json = true;
542
+ }
543
+ else if (arg === 'consolidate' || arg === '--help' ||
544
+ arg === '-h' || arg === 'help') {
545
+ // subcommand token or help — no-op here
546
+ }
547
+ else if (arg.startsWith('--')) {
548
+ result.usageError = `unknown flag: ${arg}`;
549
+ return result;
550
+ }
551
+ }
552
+ return result;
553
+ }
554
+ async function runConsolidate(args, cfg) {
555
+ const parsed = parseConsolidateArgs(args);
556
+ if (parsed.usageError) {
557
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
558
+ return 2;
559
+ }
560
+ let consolidateGenomeFn;
561
+ try {
562
+ const mod = await importConsolidate();
563
+ consolidateGenomeFn = mod.consolidateGenome;
564
+ }
565
+ catch (err) {
566
+ process.stderr.write(red('error: ') + 'Failed to load genome/consolidate module (M16 not yet built): ' +
567
+ (err instanceof Error ? err.message : String(err)) + '\n');
568
+ return 1;
569
+ }
570
+ let result;
571
+ try {
572
+ result = await consolidateGenomeFn(cfg);
573
+ }
574
+ catch (err) {
575
+ process.stderr.write(red('error: ') + 'Consolidation failed: ' +
576
+ (err instanceof Error ? err.message : String(err)) + '\n');
577
+ return 1;
578
+ }
579
+ if (parsed.json) {
580
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
581
+ return 0;
582
+ }
583
+ const { before, after, merged, backupPath } = result;
584
+ const savedCount = before - after;
585
+ out('');
586
+ out(bold(' ashlr genome consolidate') + gray(' — deduplication complete'));
587
+ out('');
588
+ const labelW = 22;
589
+ function row(label, value) {
590
+ out(` ${bold(pad(label, labelW))} ${value}`);
591
+ }
592
+ row('Entries before', cyan(String(before)));
593
+ row('Entries after', cyan(String(after)));
594
+ row('Merged (removed)', merged > 0 ? yellow(String(merged)) : dim(String(merged)));
595
+ row('Net reduction', savedCount > 0 ? green(`-${savedCount}`) : dim('0'));
596
+ row('Backup written', gray(backupPath));
597
+ out('');
598
+ if (merged === 0) {
599
+ out(` ${dim('No near-duplicate entries found — genome is already clean.')}`);
600
+ }
601
+ else {
602
+ out(` ${dim(`Merged ${merged} near-duplicate group(s). No data lost — backup at:`)}`);
603
+ out(` ${gray(backupPath)}`);
604
+ }
605
+ out('');
606
+ return 0;
607
+ }
608
+ function parseExportArgs(args) {
609
+ const result = {
610
+ dest: '',
611
+ format: 'json',
612
+ formatExplicit: false,
613
+ json: false,
614
+ };
615
+ let i = 0;
616
+ while (i < args.length) {
617
+ const arg = args[i];
618
+ if (arg === '--json') {
619
+ result.json = true;
620
+ i++;
621
+ }
622
+ else if (arg === '--format') {
623
+ const val = args[++i];
624
+ if (val !== 'json' && val !== 'md') {
625
+ result.usageError = `--format must be 'json' or 'md', got: ${val ?? '(missing)'}`;
626
+ return result;
627
+ }
628
+ result.format = val;
629
+ result.formatExplicit = true;
630
+ i++;
631
+ }
632
+ else if (arg === 'export') {
633
+ // subcommand token — skip
634
+ i++;
635
+ }
636
+ else if (!arg.startsWith('--')) {
637
+ if (result.dest) {
638
+ result.usageError = `unexpected extra argument: ${arg}`;
639
+ return result;
640
+ }
641
+ result.dest = arg;
642
+ i++;
643
+ }
644
+ else {
645
+ result.usageError = `unknown flag: ${arg}`;
646
+ return result;
647
+ }
648
+ }
649
+ if (!result.dest.trim()) {
650
+ result.usageError =
651
+ 'Usage: ashlr genome export <file> [--format json|md] [--json]';
652
+ return result;
653
+ }
654
+ // Infer format from extension when --format was not explicit
655
+ if (!result.formatExplicit) {
656
+ result.format = result.dest.endsWith('.md') ? 'md' : 'json';
657
+ }
658
+ return result;
659
+ }
660
+ async function runExport(args, cfg) {
661
+ const parsed = parseExportArgs(args);
662
+ if (parsed.usageError) {
663
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
664
+ return 2;
665
+ }
666
+ let exportGenomeFn;
667
+ try {
668
+ const mod = await importExport();
669
+ exportGenomeFn = mod.exportGenome;
670
+ }
671
+ catch (err) {
672
+ process.stderr.write(red('error: ') + 'Failed to load genome/export module (M16 not yet built): ' +
673
+ (err instanceof Error ? err.message : String(err)) + '\n');
674
+ return 1;
675
+ }
676
+ const result = exportGenomeFn(cfg, parsed.dest, parsed.format);
677
+ if (parsed.json) {
678
+ process.stdout.write(JSON.stringify(result, null, 2) + '\n');
679
+ return result.ok ? 0 : 1;
680
+ }
681
+ out('');
682
+ if (result.ok) {
683
+ out(bold(' ashlr genome export') + gray(' — genome exported'));
684
+ out('');
685
+ const labelW = 14;
686
+ function row(label, value) {
687
+ out(` ${bold(pad(label, labelW))} ${value}`);
688
+ }
689
+ row('Entries', cyan(String(result.count)));
690
+ row('Format', parsed.format === 'md' ? 'markdown' : 'json');
691
+ row('Path', gray(result.path));
692
+ out('');
693
+ out(dim(` Portable export — no lock-in. ${result.count} entries written.`));
694
+ }
695
+ else {
696
+ out(bold(' ashlr genome export') + red(' — export failed'));
697
+ out('');
698
+ out(` ${red('Failed to write to:')} ${gray(parsed.dest)}`);
699
+ process.stderr.write(red('error: ') + `export failed (path: ${result.path})\n`);
700
+ return 1;
701
+ }
702
+ out('');
703
+ return 0;
704
+ }
705
+ // ---- genome playbook ----
706
+ /** Hard cap on the playbook text printed/injected by the CLI. */
707
+ const PLAYBOOK_CLI_MAX_CHARS = 4000;
708
+ function parsePlaybookArgs(args) {
709
+ const result = { goal: '', json: false };
710
+ let i = 0;
711
+ while (i < args.length) {
712
+ const arg = args[i];
713
+ if (arg === '--json') {
714
+ result.json = true;
715
+ i++;
716
+ }
717
+ else if (arg === '--limit') {
718
+ const parsed = parsePositiveInt('limit', args[++i]);
719
+ if ('error' in parsed) {
720
+ result.usageError = parsed.error;
721
+ return result;
722
+ }
723
+ result.limit = parsed.n;
724
+ i++;
725
+ }
726
+ else if (arg === 'playbook') {
727
+ // subcommand token — skip
728
+ i++;
729
+ }
730
+ else if (!arg.startsWith('--')) {
731
+ if (result.goal) {
732
+ result.usageError = `unexpected extra argument: ${arg}`;
733
+ return result;
734
+ }
735
+ result.goal = arg;
736
+ i++;
737
+ }
738
+ else {
739
+ result.usageError = `unknown flag: ${arg}`;
740
+ return result;
741
+ }
742
+ }
743
+ if (!result.goal.trim()) {
744
+ result.usageError =
745
+ 'Usage: ashlr genome playbook "<goal>" [--limit N] [--json]';
746
+ }
747
+ return result;
748
+ }
749
+ function printPlaybookHuman(p, text) {
750
+ out('');
751
+ out(bold(' ashlr genome playbook') + gray(` — "${p.goal}"`));
752
+ out('');
753
+ if (p.entries.length === 0) {
754
+ out(` ${dim('No past entries found for this goal.')}`);
755
+ out(` ${dim('Run more goals or use `ashlr learn` to build the genome.')}`);
756
+ out('');
757
+ return;
758
+ }
759
+ out(` ${bold('Sources:')} ${dim(`${p.entries.length} past entry/entries recalled`)}`);
760
+ out('');
761
+ // Indent the synthesized playbook text 2 spaces for readability
762
+ for (const line of text.split('\n')) {
763
+ out(` ${line}`);
764
+ }
765
+ out('');
766
+ out(dim(` ${p.entries.length} source(s) · local genome · `) +
767
+ dim('`ashlr recall` to search manually'));
768
+ out('');
769
+ }
770
+ async function runPlaybook(args, cfg) {
771
+ const parsed = parsePlaybookArgs(args);
772
+ if (parsed.usageError) {
773
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
774
+ return 2;
775
+ }
776
+ let buildPlaybookFn;
777
+ let playbookTextFn;
778
+ try {
779
+ const mod = await importPlaybook();
780
+ buildPlaybookFn = mod.buildPlaybook;
781
+ playbookTextFn = mod.playbookText;
782
+ }
783
+ catch (err) {
784
+ process.stderr.write(red('error: ') + 'Failed to load genome/playbook module (M16 not yet built): ' +
785
+ (err instanceof Error ? err.message : String(err)) + '\n');
786
+ return 1;
787
+ }
788
+ let playbook;
789
+ try {
790
+ playbook = await buildPlaybookFn(parsed.goal, cfg, { limit: parsed.limit });
791
+ }
792
+ catch (err) {
793
+ process.stderr.write(red('error: ') + 'buildPlaybook failed: ' +
794
+ (err instanceof Error ? err.message : String(err)) + '\n');
795
+ return 1;
796
+ }
797
+ if (parsed.json) {
798
+ process.stdout.write(JSON.stringify(playbook, null, 2) + '\n');
799
+ return 0;
800
+ }
801
+ const text = playbookTextFn(playbook, PLAYBOOK_CLI_MAX_CHARS);
802
+ printPlaybookHuman(playbook, text);
803
+ return 0;
804
+ }
805
+ function parseGenomeArgs(args) {
806
+ const result = { json: false };
807
+ for (const arg of args) {
808
+ if (arg === '--json') {
809
+ result.json = true;
810
+ }
811
+ else if (arg === '--help' || arg === '-h' || arg === 'help') {
812
+ // handled upstream
813
+ }
814
+ else if (!arg.startsWith('--')) {
815
+ // ignore subcommand tokens like 'status' (the command is implicit)
816
+ }
817
+ else {
818
+ result.usageError = `unknown flag: ${arg}`;
819
+ return result;
820
+ }
821
+ }
822
+ return result;
823
+ }
824
+ function printGenomeHuman(health) {
825
+ const { totalEntries, projects, hubEntries, sizeBytes, lastLearnedAt, embeddingsAvailable, } = health;
826
+ const projectEntries = Math.max(0, totalEntries - hubEntries);
827
+ // Status badge
828
+ const statusBadge = totalEntries === 0
829
+ ? yellow('empty')
830
+ : green('ok');
831
+ out('');
832
+ out(bold(' ashlr genome') + gray(' — shared memory health'));
833
+ out('');
834
+ const labelW = 22;
835
+ function row(label, value) {
836
+ out(` ${bold(pad(label, labelW))} ${value}`);
837
+ }
838
+ row('Status', statusBadge);
839
+ row('Total entries', cyan(String(totalEntries)));
840
+ row(' hub entries', String(hubEntries));
841
+ row(' project entries', String(projectEntries));
842
+ row('Projects covered', projects > 0 ? cyan(String(projects)) : dim('0'));
843
+ row('Store size', fmtBytes(sizeBytes));
844
+ row('Last learned', lastLearnedAt ? relativeTime(lastLearnedAt) : dim('never'));
845
+ row('Embeddings (local)', embeddingsAvailable
846
+ ? green('available ') + dim('(Ollama reranking active)')
847
+ : dim('unavailable') + gray(' (keyword-only; start Ollama + bge-m3 to enable)'));
848
+ out('');
849
+ if (totalEntries === 0) {
850
+ out(` ${dim('Genome is empty. Add entries with:')}`);
851
+ out(` ${cyan('ashlr learn "<text>"')}`);
852
+ }
853
+ else {
854
+ out(` ${dim('Search:')} ${cyan('ashlr recall "<query>"')}`);
855
+ out(` ${dim('Add:')} ${cyan('ashlr learn "<text>" [--project <name>] [--tags a,b]')}`);
856
+ out(` ${dim('Teach:')} ${cyan('ashlr genome --teach "<note>"')}`);
857
+ out(` ${dim('Playbook:')} ${cyan('ashlr genome playbook "<goal>"')}`);
858
+ out(` ${dim('Export:')} ${cyan('ashlr genome export <file.json|file.md>')}`);
859
+ }
860
+ out('');
861
+ }
862
+ /**
863
+ * `ashlr genome [subcommand] [options]`
864
+ *
865
+ * M16 subcommands:
866
+ * --teach "<note>" — store a high-value explicit memory tagged 'teach'
867
+ * consolidate — merge near-duplicate entries (backup-first, no data loss)
868
+ * export <file> — export full genome to portable JSON or Markdown
869
+ * playbook "<goal>" — synthesize a playbook from past genome entries
870
+ *
871
+ * Default (no subcommand): prints genome health panel.
872
+ * --json is honored on all subcommands and the health panel.
873
+ *
874
+ * Exit codes: 0 success, 1 module/runtime error, 2 bad usage.
875
+ */
876
+ export async function cmdGenome(args) {
877
+ if (args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
878
+ printGenomeHelp();
879
+ return 0;
880
+ }
881
+ // Load config — required by all paths
882
+ let cfg;
883
+ try {
884
+ const { loadConfig } = await importConfig();
885
+ cfg = loadConfig();
886
+ }
887
+ catch (err) {
888
+ process.stderr.write(red('error: ') + 'Failed to load config: ' +
889
+ (err instanceof Error ? err.message : String(err)) + '\n');
890
+ return 1;
891
+ }
892
+ // Route M16 subcommands
893
+ const sub = detectSubcommand(args);
894
+ if (sub === 'teach')
895
+ return runTeach(args, cfg);
896
+ if (sub === 'consolidate')
897
+ return runConsolidate(args, cfg);
898
+ if (sub === 'export')
899
+ return runExport(args, cfg);
900
+ if (sub === 'playbook')
901
+ return runPlaybook(args, cfg);
902
+ // Default: original M7 health panel
903
+ const parsed = parseGenomeArgs(args);
904
+ if (parsed.usageError) {
905
+ process.stderr.write(red('error: ') + parsed.usageError + '\n');
906
+ return 2;
907
+ }
908
+ // Load store module
909
+ let genomeHealthFn;
910
+ try {
911
+ const mod = await importGenomeStore();
912
+ genomeHealthFn = mod.genomeHealth;
913
+ }
914
+ catch (err) {
915
+ process.stderr.write(red('error: ') + 'Failed to load genome/store module (M7 not yet built): ' +
916
+ (err instanceof Error ? err.message : String(err)) + '\n');
917
+ return 1;
918
+ }
919
+ // Compute health
920
+ let health;
921
+ try {
922
+ health = genomeHealthFn(cfg);
923
+ }
924
+ catch (err) {
925
+ process.stderr.write(red('error: ') + 'genomeHealth failed: ' +
926
+ (err instanceof Error ? err.message : String(err)) + '\n');
927
+ return 1;
928
+ }
929
+ if (parsed.json) {
930
+ process.stdout.write(JSON.stringify(health, null, 2) + '\n');
931
+ return 0;
932
+ }
933
+ printGenomeHuman(health);
934
+ return 0;
935
+ }
936
+ // ---------------------------------------------------------------------------
937
+ // Help printers
938
+ // ---------------------------------------------------------------------------
939
+ function printRecallHelp() {
940
+ out('');
941
+ out(bold(' ashlr recall') + dim(' — search the shared genome'));
942
+ out('');
943
+ out(' ' + bold('Usage:'));
944
+ out('');
945
+ out(` ashlr recall ${cyan('"<query>"')} [options]`);
946
+ out('');
947
+ out(' ' + bold('Options:'));
948
+ out('');
949
+ const opts = [
950
+ ['--limit N', 'Max hits to return (default: cfg.genome.maxRecall, typically 5).'],
951
+ ['--no-embeddings', 'Skip embedding rerank; use keyword/TF-IDF scoring only.'],
952
+ ['--json', 'Emit RecallHit[] JSON on stdout.'],
953
+ ];
954
+ const optW = Math.max(...opts.map(([o]) => o.length));
955
+ for (const [opt, desc] of opts) {
956
+ out(` ${cyan(pad(opt, optW))} ${desc}`);
957
+ }
958
+ out('');
959
+ out(' ' + bold('Examples:'));
960
+ out('');
961
+ out(` ${cyan('ashlr recall "typescript module resolution"')}`);
962
+ out(` ${cyan('ashlr recall "ollama embeddings" --limit 10')}`);
963
+ out(` ${cyan('ashlr recall "scaffold" --no-embeddings')}`);
964
+ out(` ${cyan('ashlr recall "genome" --json')}`);
965
+ out('');
966
+ out(' ' + bold('Notes:'));
967
+ out('');
968
+ out(` ${dim('• Local-first: ranking uses keyword/TF-IDF by default.')}`);
969
+ out(` ${dim('• If Ollama is up and has an embedding model (e.g. bge-m3), hits are')}`);
970
+ out(` ${dim(' reranked with embeddings automatically (best-effort, no cloud).')}`);
971
+ out(` ${dim('• Sources: per-project .ashlrcode/genome/ dirs + ~/.ashlr/genome/hub.jsonl.')}`);
972
+ out('');
973
+ }
974
+ function printLearnHelp() {
975
+ out('');
976
+ out(bold(' ashlr learn') + dim(' — store a memory in the genome'));
977
+ out('');
978
+ out(' ' + bold('Usage:'));
979
+ out('');
980
+ out(` ashlr learn ${cyan('"<text>"')} [options]`);
981
+ out('');
982
+ out(' ' + bold('Options:'));
983
+ out('');
984
+ const opts = [
985
+ ['--title <title>', 'Short heading for the entry (derived from text when omitted).'],
986
+ ['--project <name>', 'Scope the entry to a project (must match an indexed repo name).'],
987
+ ['--tags a,b,c', 'Comma-separated tags for filtering/grouping.'],
988
+ ['--json', 'Emit the stored GenomeEntry as JSON on stdout.'],
989
+ ];
990
+ const optW = Math.max(...opts.map(([o]) => o.length));
991
+ for (const [opt, desc] of opts) {
992
+ out(` ${cyan(pad(opt, optW))} ${desc}`);
993
+ }
994
+ out('');
995
+ out(' ' + bold('Examples:'));
996
+ out('');
997
+ out(` ${cyan('ashlr learn "Use NodeNext module resolution with .js import extensions"')}`);
998
+ out(` ${cyan('ashlr learn "Ollama runs on :11434; /api/embeddings for vectors" --project ashlr-hub')}`);
999
+ out(` ${cyan('ashlr learn "deploy to Vercel via CLI" --tags vercel,deploy,cli')}`);
1000
+ out(` ${cyan('ashlr learn "M7 genome contract" --title "Genome types" --json')}`);
1001
+ out('');
1002
+ out(' ' + bold('Notes:'));
1003
+ out('');
1004
+ out(` ${dim('• APPEND-ONLY: never overwrites or deletes existing entries.')}`);
1005
+ out(` ${dim('• Writes to ~/.ashlr/genome/hub.jsonl.')}`);
1006
+ out(` ${dim('• With --project, may also drop a note under the project\'s .ashlrcode/genome/.')}`);
1007
+ out(` ${dim('• Never stores secrets — treat this like a commit message.')}`);
1008
+ out('');
1009
+ }
1010
+ function printGenomeHelp() {
1011
+ out('');
1012
+ out(bold(' ashlr genome') + dim(' — shared memory health + compounding genome (M16)'));
1013
+ out('');
1014
+ out(' ' + bold('Usage:'));
1015
+ out('');
1016
+ out(` ashlr genome [subcommand] [options]`);
1017
+ out('');
1018
+ out(' ' + bold('Subcommands:'));
1019
+ out('');
1020
+ const subs = [
1021
+ ['(none)', 'Print genome health panel (entry counts, size, staleness, embeddings).'],
1022
+ ['--teach "<note>"', 'Store a high-value explicit memory tagged #teach.'],
1023
+ ['consolidate', 'Merge near-duplicate entries (backup-first, no data loss).'],
1024
+ ['export <file>', 'Export full genome to portable JSON or Markdown (read-only).'],
1025
+ ['playbook "<goal>"', 'Synthesize a playbook from past genome entries for a goal.'],
1026
+ ];
1027
+ const subW = Math.max(...subs.map(([s]) => s.length));
1028
+ for (const [sub, desc] of subs) {
1029
+ out(` ${cyan(pad(sub, subW))} ${desc}`);
1030
+ }
1031
+ out('');
1032
+ out(' ' + bold('Common options:'));
1033
+ out('');
1034
+ out(` ${cyan('--json')} Emit machine-readable JSON on stdout (honored by all subcommands).`);
1035
+ out('');
1036
+ out(' ' + bold('Examples:'));
1037
+ out('');
1038
+ out(` ${cyan('ashlr genome')}`);
1039
+ out(` ${cyan('ashlr genome --teach "Always use --no-capture on dry-run flows"')}`);
1040
+ out(` ${cyan('ashlr genome --teach "..." --title "Dry-run tip" --project ashlr-hub')}`);
1041
+ out(` ${cyan('ashlr genome consolidate')}`);
1042
+ out(` ${cyan('ashlr genome consolidate --json')}`);
1043
+ out(` ${cyan('ashlr genome export ~/genome-backup.json')}`);
1044
+ out(` ${cyan('ashlr genome export ~/genome-backup.md --format md')}`);
1045
+ out(` ${cyan('ashlr genome playbook "scaffold a new CLI command"')}`);
1046
+ out(` ${cyan('ashlr genome playbook "deploy to vercel" --limit 8 --json')}`);
1047
+ out('');
1048
+ out(' ' + bold('Notes:'));
1049
+ out('');
1050
+ out(` ${dim('• consolidate: writes a timestamped backup of hub.jsonl first — no data loss.')}`);
1051
+ out(` ${dim('• export: read-only, portable; no lock-in. Extension (.json/.md) infers format.')}`);
1052
+ out(` ${dim('• playbook: local-only synthesis; falls back to concatenated recall on failure.')}`);
1053
+ out(` ${dim('• teach: tagged #teach for elevated weight in playbook synthesis.')}`);
1054
+ out('');
1055
+ out(' ' + bold('Related commands:'));
1056
+ out('');
1057
+ out(` ${cyan('ashlr recall "<query>"')} ${dim('— search the genome')}`);
1058
+ out(` ${cyan('ashlr learn "<text>"')} ${dim('— add an entry')}`);
1059
+ out('');
1060
+ }
1061
+ //# sourceMappingURL=genome.js.map