@jaimevalasek/aioson 1.5.1 → 1.7.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 (341) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +729 -226
  3. package/docs/design-previews/aurora-command-ui-website.html +884 -0
  4. package/docs/design-previews/aurora-command-ui.html +682 -0
  5. package/docs/design-previews/bold-editorial-ui-website.html +658 -0
  6. package/docs/design-previews/bold-editorial-ui.html +717 -0
  7. package/docs/design-previews/clean-saas-ui-website.html +1202 -0
  8. package/docs/design-previews/clean-saas-ui.html +549 -0
  9. package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
  10. package/docs/design-previews/cognitive-core-ui.html +463 -0
  11. package/docs/design-previews/glassmorphism-ui-website.html +572 -0
  12. package/docs/design-previews/glassmorphism-ui.html +886 -0
  13. package/docs/design-previews/index.html +699 -0
  14. package/docs/design-previews/interface-design-website.html +1187 -0
  15. package/docs/design-previews/interface-design.html +513 -0
  16. package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
  17. package/docs/design-previews/neo-brutalist-ui.html +797 -0
  18. package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
  19. package/docs/design-previews/premium-command-center-ui.html +552 -0
  20. package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
  21. package/docs/design-previews/warm-craft-ui-website.html +684 -0
  22. package/docs/design-previews/warm-craft-ui.html +739 -0
  23. package/docs/en/cli-reference.md +20 -9
  24. package/docs/integrations/sdlc-genius-boundary.md +76 -0
  25. package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
  26. package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
  27. package/docs/integrations/sdlc-genius-review-samples.md +86 -0
  28. package/docs/pt/README.md +10 -0
  29. package/docs/pt/agent-sharding.md +132 -0
  30. package/docs/pt/agentes.md +9 -2
  31. package/docs/pt/busca-de-contexto.md +129 -0
  32. package/docs/pt/cache-de-contexto.md +156 -0
  33. package/docs/pt/comandos-cli.md +915 -1
  34. package/docs/pt/design-hybrid-forge.md +356 -0
  35. package/docs/pt/devlog-pipeline.md +270 -0
  36. package/docs/pt/fluxo-artefatos.md +178 -0
  37. package/docs/pt/hooks-session-guard.md +454 -0
  38. package/docs/pt/inicio-rapido.md +54 -3
  39. package/docs/pt/inteligencia-adaptativa.md +324 -0
  40. package/docs/pt/monitor-de-contexto.md +158 -0
  41. package/docs/pt/recuperacao-de-sessao.md +125 -0
  42. package/docs/pt/sandbox.md +125 -0
  43. package/docs/pt/sdd-automation-scripts.md +557 -0
  44. package/docs/pt/site-forge.md +309 -0
  45. package/docs/pt/skills.md +98 -6
  46. package/docs/pt/spec-learnings-pipeline.md +265 -0
  47. package/package.json +1 -1
  48. package/src/a2a/client.js +165 -0
  49. package/src/a2a/server.js +223 -0
  50. package/src/agent-loader.js +280 -0
  51. package/src/cli.js +329 -1
  52. package/src/commands/agent-audit.js +397 -0
  53. package/src/commands/agent-export-skill.js +229 -0
  54. package/src/commands/agent-loader.js +85 -0
  55. package/src/commands/artifact-validate.js +189 -0
  56. package/src/commands/brief-gen.js +405 -0
  57. package/src/commands/brief-validate.js +65 -0
  58. package/src/commands/classify.js +256 -0
  59. package/src/commands/context-cache.js +90 -0
  60. package/src/commands/context-compact.js +49 -0
  61. package/src/commands/context-health.js +175 -0
  62. package/src/commands/context-monitor.js +163 -0
  63. package/src/commands/context-search.js +66 -0
  64. package/src/commands/context-trim.js +177 -0
  65. package/src/commands/design-hybrid-options.js +385 -0
  66. package/src/commands/detect-test-runner.js +55 -0
  67. package/src/commands/devlog-export-brains.js +27 -0
  68. package/src/commands/devlog-process.js +292 -0
  69. package/src/commands/devlog-watch.js +131 -0
  70. package/src/commands/feature-close.js +165 -0
  71. package/src/commands/gate-check.js +228 -0
  72. package/src/commands/health.js +214 -0
  73. package/src/commands/hooks-emit.js +253 -0
  74. package/src/commands/hooks-install.js +347 -0
  75. package/src/commands/init.js +54 -13
  76. package/src/commands/install.js +52 -13
  77. package/src/commands/learning-auto-promote.js +195 -0
  78. package/src/commands/learning-evolve.js +364 -0
  79. package/src/commands/learning-export.js +103 -0
  80. package/src/commands/learning-rollback.js +164 -0
  81. package/src/commands/live.js +59 -1
  82. package/src/commands/pattern-detect.js +33 -0
  83. package/src/commands/preflight-context.js +30 -0
  84. package/src/commands/preflight.js +208 -0
  85. package/src/commands/pulse-update.js +130 -0
  86. package/src/commands/recovery.js +43 -0
  87. package/src/commands/runner-daemon.js +274 -0
  88. package/src/commands/runner-plan.js +70 -0
  89. package/src/commands/runner-queue-from-plan.js +166 -0
  90. package/src/commands/runner-queue.js +189 -0
  91. package/src/commands/runner-run.js +129 -0
  92. package/src/commands/runtime.js +47 -1
  93. package/src/commands/sandbox.js +37 -0
  94. package/src/commands/self-implement-loop.js +256 -0
  95. package/src/commands/session-guard.js +218 -0
  96. package/src/commands/setup-context.js +22 -2
  97. package/src/commands/setup.js +178 -0
  98. package/src/commands/sizing.js +165 -0
  99. package/src/commands/skill.js +144 -32
  100. package/src/commands/spec-checkpoint.js +177 -0
  101. package/src/commands/spec-status.js +79 -0
  102. package/src/commands/spec-sync.js +190 -0
  103. package/src/commands/spec-tasks.js +288 -0
  104. package/src/commands/squad-autorun.js +1220 -0
  105. package/src/commands/squad-bus.js +217 -0
  106. package/src/commands/squad-card.js +149 -0
  107. package/src/commands/squad-daemon.js +134 -0
  108. package/src/commands/squad-dependency-graph.js +164 -0
  109. package/src/commands/squad-review.js +106 -0
  110. package/src/commands/squad-scaffold.js +55 -0
  111. package/src/commands/squad-tool-register.js +157 -0
  112. package/src/commands/state-save.js +122 -0
  113. package/src/commands/tool-registry-cmd.js +232 -0
  114. package/src/commands/update.js +9 -0
  115. package/src/commands/verify-gate.js +572 -0
  116. package/src/commands/workflow-execute.js +241 -0
  117. package/src/constants.js +18 -0
  118. package/src/context-cache.js +159 -0
  119. package/src/context-search.js +326 -0
  120. package/src/design-variation-catalog.js +503 -0
  121. package/src/i18n/messages/en.js +32 -2
  122. package/src/i18n/messages/es.js +30 -2
  123. package/src/i18n/messages/fr.js +30 -2
  124. package/src/i18n/messages/pt-BR.js +32 -2
  125. package/src/install-animation.js +260 -0
  126. package/src/install-profile.js +143 -0
  127. package/src/install-wizard.js +475 -0
  128. package/src/installer.js +44 -10
  129. package/src/lib/health-check.js +158 -0
  130. package/src/lib/hook-protocol.js +76 -0
  131. package/src/mcp/apps/squad-dashboard/app.js +163 -0
  132. package/src/mcp/apps/squad-dashboard/index.html +261 -0
  133. package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
  134. package/src/mcp/resources/squad-state.js +130 -0
  135. package/src/parser.js +7 -1
  136. package/src/preflight-engine.js +443 -0
  137. package/src/recovery-context-session.js +154 -0
  138. package/src/runner/cascade.js +97 -0
  139. package/src/runner/cli-launcher.js +109 -0
  140. package/src/runner/plan-importer.js +63 -0
  141. package/src/runner/queue-store.js +159 -0
  142. package/src/runtime-store.js +158 -4
  143. package/src/sandbox.js +177 -0
  144. package/src/squad/agent-teams-adapter.js +264 -0
  145. package/src/squad/brief-validator.js +350 -0
  146. package/src/squad/bus-bridge.js +140 -0
  147. package/src/squad/context-compactor.js +265 -0
  148. package/src/squad/cross-ai-synthesizer.js +250 -0
  149. package/src/squad/hooks-generator.js +196 -0
  150. package/src/squad/inter-squad-events.js +175 -0
  151. package/src/squad/intra-bus.js +345 -0
  152. package/src/squad/learning-extractor.js +213 -0
  153. package/src/squad/pattern-detector.js +365 -0
  154. package/src/squad/preflight-context.js +296 -0
  155. package/src/squad/recovery-context.js +242 -71
  156. package/src/squad/reflection.js +365 -0
  157. package/src/squad/squad-scaffold.js +177 -0
  158. package/src/squad/state-manager.js +310 -0
  159. package/src/squad/task-decomposer.js +652 -0
  160. package/src/squad/verify-gate.js +303 -0
  161. package/src/tool-executor.js +94 -0
  162. package/src/updater.js +10 -3
  163. package/src/worker-runner.js +186 -1
  164. package/template/.aioson/agents/analyst.md +119 -3
  165. package/template/.aioson/agents/architect.md +98 -0
  166. package/template/.aioson/agents/design-hybrid-forge.md +141 -0
  167. package/template/.aioson/agents/dev.md +335 -14
  168. package/template/.aioson/agents/deyvin.md +117 -2
  169. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  170. package/template/.aioson/agents/genome.md +14 -0
  171. package/template/.aioson/agents/neo.md +78 -1
  172. package/template/.aioson/agents/orache.md +50 -4
  173. package/template/.aioson/agents/orchestrator.md +197 -1
  174. package/template/.aioson/agents/pm.md +93 -0
  175. package/template/.aioson/agents/product.md +77 -4
  176. package/template/.aioson/agents/profiler-enricher.md +14 -0
  177. package/template/.aioson/agents/profiler-forge.md +14 -0
  178. package/template/.aioson/agents/profiler-researcher.md +14 -0
  179. package/template/.aioson/agents/qa.md +249 -19
  180. package/template/.aioson/agents/setup.md +144 -12
  181. package/template/.aioson/agents/sheldon.md +237 -11
  182. package/template/.aioson/agents/site-forge.md +1753 -0
  183. package/template/.aioson/agents/squad.md +162 -0
  184. package/template/.aioson/agents/tester.md +209 -0
  185. package/template/.aioson/agents/ux-ui.md +34 -1
  186. package/template/.aioson/brains/README.md +128 -0
  187. package/template/.aioson/brains/_index.json +16 -0
  188. package/template/.aioson/brains/scripts/query.js +103 -0
  189. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  190. package/template/.aioson/config.md +158 -13
  191. package/template/.aioson/constitution.md +33 -0
  192. package/template/.aioson/context/forensics/.gitkeep +0 -0
  193. package/template/.aioson/context/project-pulse.md +34 -0
  194. package/template/.aioson/context/seeds/seed-example.md +27 -0
  195. package/template/.aioson/context/user-profile.md +42 -0
  196. package/template/.aioson/docs/LAYERS.md +79 -0
  197. package/template/.aioson/docs/README.md +76 -0
  198. package/template/.aioson/docs/example-external-api-context.md +72 -0
  199. package/template/.aioson/locales/en/agents/architect.md +17 -0
  200. package/template/.aioson/locales/en/agents/dev.md +79 -13
  201. package/template/.aioson/locales/en/agents/orache.md +6 -0
  202. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  203. package/template/.aioson/locales/en/agents/product.md +50 -0
  204. package/template/.aioson/locales/en/agents/setup.md +33 -1
  205. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  206. package/template/.aioson/locales/en/agents/squad.md +14 -0
  207. package/template/.aioson/locales/en/agents/tester.md +6 -0
  208. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  209. package/template/.aioson/locales/es/agents/architect.md +19 -0
  210. package/template/.aioson/locales/es/agents/dev.md +64 -4
  211. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  212. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  213. package/template/.aioson/locales/es/agents/genome.md +2 -0
  214. package/template/.aioson/locales/es/agents/neo.md +2 -0
  215. package/template/.aioson/locales/es/agents/orache.md +2 -0
  216. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  217. package/template/.aioson/locales/es/agents/pair.md +2 -0
  218. package/template/.aioson/locales/es/agents/pm.md +2 -0
  219. package/template/.aioson/locales/es/agents/product.md +52 -0
  220. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  221. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  222. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  223. package/template/.aioson/locales/es/agents/qa.md +2 -0
  224. package/template/.aioson/locales/es/agents/setup.md +35 -1
  225. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  226. package/template/.aioson/locales/es/agents/squad.md +16 -0
  227. package/template/.aioson/locales/es/agents/tester.md +9 -0
  228. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  229. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  230. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  231. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  232. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  233. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  234. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  235. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  236. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  237. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  238. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  239. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  240. package/template/.aioson/locales/fr/agents/product.md +52 -0
  241. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  242. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  243. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  244. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  245. package/template/.aioson/locales/fr/agents/setup.md +35 -1
  246. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  247. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  248. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  249. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  250. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  251. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  252. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  253. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  254. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  255. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  256. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  257. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  258. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  259. package/template/.aioson/locales/pt-BR/agents/setup.md +134 -19
  260. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  261. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  262. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  263. package/template/.aioson/rules/README.md +69 -0
  264. package/template/.aioson/rules/data-format-convention.md +136 -0
  265. package/template/.aioson/rules/example-monetary-values.md +30 -0
  266. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  267. package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
  268. package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
  269. package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
  270. package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
  271. package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
  272. package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
  273. package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
  274. package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
  275. package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
  276. package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
  277. package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
  278. package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
  279. package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
  280. package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
  281. package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
  282. package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
  283. package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
  284. package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
  285. package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
  286. package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
  287. package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
  288. package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
  289. package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
  290. package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
  291. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  292. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  293. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  294. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  295. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  296. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  297. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  298. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +46 -0
  299. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  300. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
  301. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  302. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
  303. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
  304. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  305. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  306. package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
  307. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +101 -0
  308. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  309. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  310. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  311. package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
  312. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +147 -0
  313. package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
  314. package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
  315. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +306 -0
  316. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +149 -0
  317. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +208 -0
  318. package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
  319. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  320. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  321. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  322. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  323. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  324. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  325. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  326. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  327. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  328. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  329. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  330. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  331. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  332. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  333. package/template/.aioson/tasks/implementation-plan.md +21 -1
  334. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  335. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  336. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  337. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  338. package/template/AGENTS.md +75 -1
  339. package/template/CLAUDE.md +31 -0
  340. package/template/OPENCODE.md +4 -0
  341. package/template/researchs/.gitkeep +0 -0
@@ -0,0 +1,164 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson learning:rollback [projectDir] --evolution=<uuid> [--squad=<slug>]
5
+ *
6
+ * Reverts a specific evolution delta from evolution-log.jsonl.
7
+ *
8
+ * Steps:
9
+ * 1. Find the evolution entry by UUID in .aioson/evolution/evolution-log.jsonl
10
+ * 2. Revert the appended content from the target file
11
+ * 3. Mark the entry as rolled_back in the log
12
+ * 4. Mark source learnings as stale in SQLite
13
+ *
14
+ * Usage:
15
+ * aioson learning:rollback . --evolution=<uuid>
16
+ * aioson learning:rollback . --evolution=<uuid> --dry-run
17
+ * aioson learning:rollback . --list (show applied evolutions)
18
+ */
19
+
20
+ const fs = require('node:fs/promises');
21
+ const path = require('node:path');
22
+ const { openRuntimeDb } = require('../runtime-store');
23
+
24
+ const EVOLUTION_LOG = path.join('.aioson', 'evolution', 'evolution-log.jsonl');
25
+
26
+ async function readEvolutionLog(projectDir) {
27
+ const logPath = path.resolve(projectDir, EVOLUTION_LOG);
28
+ try {
29
+ const content = await fs.readFile(logPath, 'utf8');
30
+ return content.trim().split('\n')
31
+ .filter(Boolean)
32
+ .map((line) => {
33
+ try { return JSON.parse(line); } catch { return null; }
34
+ })
35
+ .filter(Boolean);
36
+ } catch {
37
+ return [];
38
+ }
39
+ }
40
+
41
+ async function writeEvolutionLog(projectDir, entries) {
42
+ const logPath = path.resolve(projectDir, EVOLUTION_LOG);
43
+ await fs.mkdir(path.dirname(logPath), { recursive: true });
44
+ await fs.writeFile(logPath, entries.map((e) => JSON.stringify(e)).join('\n') + '\n', 'utf8');
45
+ }
46
+
47
+ async function runLearningRollback({ args = [], options = {}, logger = console } = {}) {
48
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
49
+ const dryRun = Boolean(options['dry-run'] || options.dry);
50
+
51
+ // ── List mode ──────────────────────────────────────────────────────────────
52
+ if (options.list) {
53
+ const entries = await readEvolutionLog(projectDir);
54
+ const applied = entries.filter((e) => e.status === 'applied');
55
+
56
+ if (applied.length === 0) {
57
+ logger.log('No applied evolutions found in evolution-log.jsonl');
58
+ return { ok: true, entries: [] };
59
+ }
60
+
61
+ logger.log(`Applied evolutions (${applied.length}):`);
62
+ for (const e of applied) {
63
+ logger.log(` ${e.id.slice(0, 8)}... ${e.ts.slice(0, 16)} → ${e.file}`);
64
+ logger.log(` ${e.learning_ids?.length || 0} learning(s) applied`);
65
+ if (e.squad) logger.log(` Squad: ${e.squad}`);
66
+ }
67
+ logger.log('');
68
+ logger.log('Rollback: aioson learning:rollback . --evolution=<id>');
69
+
70
+ return { ok: true, entries: applied };
71
+ }
72
+
73
+ // ── Rollback mode ──────────────────────────────────────────────────────────
74
+ const evolutionId = String(options.evolution || '').trim();
75
+ if (!evolutionId) {
76
+ logger.error('Error: --evolution <uuid> is required (or --list to see applied evolutions)');
77
+ return { ok: false, error: 'missing_evolution_id' };
78
+ }
79
+
80
+ const entries = await readEvolutionLog(projectDir);
81
+ const entryIndex = entries.findIndex(
82
+ (e) => e.id === evolutionId || e.id.startsWith(evolutionId)
83
+ );
84
+
85
+ if (entryIndex === -1) {
86
+ logger.error(`Evolution "${evolutionId}" not found in evolution-log.jsonl`);
87
+ logger.log('Run: aioson learning:rollback . --list');
88
+ return { ok: false, error: 'evolution_not_found' };
89
+ }
90
+
91
+ const entry = entries[entryIndex];
92
+
93
+ if (entry.status === 'rolled_back') {
94
+ logger.log(`Evolution "${entry.id.slice(0, 8)}..." is already rolled back.`);
95
+ return { ok: true, alreadyRolledBack: true };
96
+ }
97
+
98
+ if (entry.status !== 'applied') {
99
+ logger.error(`Evolution "${entry.id.slice(0, 8)}..." has unexpected status: ${entry.status}`);
100
+ return { ok: false, error: 'unexpected_status' };
101
+ }
102
+
103
+ logger.log(`Rolling back evolution: ${entry.id}`);
104
+ logger.log(` File: ${entry.file}`);
105
+ logger.log(` Content to remove (${entry.content?.length || 0} chars)`);
106
+
107
+ if (dryRun) {
108
+ logger.log('[dry-run] No changes applied.');
109
+ return { ok: true, dryRun: true, entry };
110
+ }
111
+
112
+ // ── Revert file content ────────────────────────────────────────────────────
113
+ if (entry.content && entry.file) {
114
+ const filePath = path.isAbsolute(entry.file)
115
+ ? entry.file
116
+ : path.resolve(projectDir, entry.file);
117
+
118
+ try {
119
+ const current = await fs.readFile(filePath, 'utf8');
120
+ // Remove the exact content that was appended
121
+ const reverted = current.replace(entry.content, '').replace(/\n{3,}/g, '\n\n');
122
+ await fs.writeFile(filePath, reverted, 'utf8');
123
+ logger.log(` ✓ Reverted: ${entry.file}`);
124
+ } catch (err) {
125
+ logger.error(` ✗ Failed to revert ${entry.file}: ${err.message}`);
126
+ return { ok: false, error: 'file_revert_failed', detail: err.message };
127
+ }
128
+ }
129
+
130
+ // ── Mark entry as rolled_back ──────────────────────────────────────────────
131
+ entries[entryIndex] = {
132
+ ...entry,
133
+ status: 'rolled_back',
134
+ rollback_ts: new Date().toISOString(),
135
+ rollback_reason: options.reason || 'user request'
136
+ };
137
+ await writeEvolutionLog(projectDir, entries);
138
+
139
+ // ── Mark learnings as stale in SQLite ─────────────────────────────────────
140
+ const learningIds = entry.learning_ids || [];
141
+ if (learningIds.length > 0) {
142
+ const handle = await openRuntimeDb(projectDir, { mustExist: true });
143
+ if (handle) {
144
+ const { db } = handle;
145
+ try {
146
+ for (const id of learningIds) {
147
+ db.prepare(
148
+ `UPDATE squad_learnings SET status = 'stale', updated_at = datetime('now') WHERE learning_id = ?`
149
+ ).run(id);
150
+ }
151
+ logger.log(` ✓ ${learningIds.length} learning(s) marked as stale`);
152
+ } finally {
153
+ db.close();
154
+ }
155
+ }
156
+ }
157
+
158
+ logger.log('');
159
+ logger.log(`✓ Evolution rolled back: ${entry.id}`);
160
+
161
+ return { ok: true, entry: entries[entryIndex] };
162
+ }
163
+
164
+ module.exports = { runLearningRollback };
@@ -860,6 +860,20 @@ async function runLiveStart({ args, options = {}, logger, t }) {
860
860
  throw new Error(t('live.json_requires_no_launch'));
861
861
  }
862
862
 
863
+ // ── 5.3 Ambient Intelligence health check alert ────────────────────────────
864
+ if (!options.json && !options['no-health-check']) {
865
+ try {
866
+ const { runHealthCheck, formatHealthAlert } = require('../lib/health-check');
867
+ const health = await runHealthCheck(targetDir);
868
+ const alert = formatHealthAlert(health.items);
869
+ if (alert) {
870
+ logger.log('');
871
+ logger.log(alert);
872
+ logger.log('');
873
+ }
874
+ } catch { /* health check is non-fatal */ }
875
+ }
876
+
863
877
  const toolBinary = String(options['tool-bin'] || tool).trim();
864
878
  const binaryPath = await resolveExecutablePath(toolBinary);
865
879
  if (!binaryPath) {
@@ -1062,6 +1076,23 @@ async function runLiveStart({ args, options = {}, logger, t }) {
1062
1076
  logger.log(t('live.session_started', { agent: agentName, tool, session: sessionKey, dbPath }));
1063
1077
  }
1064
1078
 
1079
+ // Ambient Intelligence: exibe digest de saúde ao iniciar sessão
1080
+ if (!options.json && !options['no-health']) {
1081
+ try {
1082
+ const { getHealthDigest } = require('./health');
1083
+ const items = await getHealthDigest(targetDir);
1084
+ if (items && items.length > 0) {
1085
+ logger.log('');
1086
+ logger.log('AIOSON Health — itens pendentes:');
1087
+ for (const item of items) {
1088
+ logger.log(` ● ${item}`);
1089
+ }
1090
+ logger.log(' → aioson health . para detalhes');
1091
+ logger.log('');
1092
+ }
1093
+ } catch { /* não bloqueia o start */ }
1094
+ }
1095
+
1065
1096
  if (child) {
1066
1097
  childResult = await waitForChild(child);
1067
1098
  }
@@ -1190,6 +1221,11 @@ async function runRuntimeEmit({ args, options = {}, logger, t }) {
1190
1221
  }
1191
1222
  }
1192
1223
 
1224
+ const workerStatus = options['worker-status'] ? String(options['worker-status']).trim() : null;
1225
+ const verdict = options.verdict ? String(options.verdict).trim().toUpperCase() : null;
1226
+ const tokenCount = options['token-count'] != null ? Number(options['token-count']) || null : null;
1227
+ const progressPct = options['progress-pct'] != null ? Number(options['progress-pct']) || null : null;
1228
+
1193
1229
  appendRunEvent(db, {
1194
1230
  runKey: context.run.run_key,
1195
1231
  eventType,
@@ -1197,7 +1233,12 @@ async function runRuntimeEmit({ args, options = {}, logger, t }) {
1197
1233
  status: context.run.status || 'running',
1198
1234
  message: summary,
1199
1235
  payload: Object.keys(payload).length > 0 ? payload : null,
1200
- createdAt: now
1236
+ createdAt: now,
1237
+ planStepId: planStep || null,
1238
+ workerStatus,
1239
+ verdict,
1240
+ tokenCount,
1241
+ progressPct
1201
1242
  });
1202
1243
 
1203
1244
  const eventRecord = createLiveEventRecord(context, {
@@ -1508,6 +1549,23 @@ async function runLiveClose({ args, options = {}, logger, t }) {
1508
1549
  logger.log(t('live.session_closed', { agent: context.agentName, session: context.sessionKey, dbPath }));
1509
1550
  }
1510
1551
 
1552
+ // Ambient Intelligence: sugere evolução se há learnings acumulados
1553
+ if (!options.json && !options['no-health']) {
1554
+ try {
1555
+ const { getHealthDigest } = require('./health');
1556
+ const items = await getHealthDigest(targetDir);
1557
+ if (items && items.length > 0) {
1558
+ logger.log('');
1559
+ logger.log('AIOSON Health — itens após sessão:');
1560
+ for (const item of items) {
1561
+ logger.log(` ● ${item}`);
1562
+ }
1563
+ logger.log(' → aioson health . para detalhes e ações');
1564
+ logger.log('');
1565
+ }
1566
+ } catch { /* não bloqueia o close */ }
1567
+ }
1568
+
1511
1569
  return {
1512
1570
  ok: true,
1513
1571
  targetDir,
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson pattern:detect — Detect automation candidates from squad learnings
5
+ *
6
+ * Usage:
7
+ * aioson pattern:detect . --squad=content-team
8
+ * aioson pattern:detect . --squad=content-team --min-occurrences=2
9
+ * aioson pattern:detect . --squad=content-team --json
10
+ */
11
+
12
+ const path = require('node:path');
13
+ const { detectPatterns, formatPatternReport } = require('../squad/pattern-detector');
14
+
15
+ async function runPatternDetect({ args, options = {}, logger }) {
16
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
17
+ const squadSlug = String(options.squad || options.s || '').trim();
18
+
19
+ if (!squadSlug) {
20
+ logger.error('Error: --squad is required');
21
+ return { ok: false, error: 'missing_squad' };
22
+ }
23
+
24
+ const minOccurrences = Number(options['min-occurrences'] || options.min || 3);
25
+ const result = await detectPatterns(targetDir, squadSlug, { minOccurrences });
26
+
27
+ if (options.json) return result;
28
+
29
+ logger.log(formatPatternReport(result));
30
+ return { ok: true, ...result };
31
+ }
32
+
33
+ module.exports = { runPatternDetect };
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson preflight:context — Estimate context budget before a session
5
+ *
6
+ * Usage:
7
+ * aioson preflight:context . --agent=dev
8
+ * aioson preflight:context . --agent=orchestrator --squad=content-team
9
+ * aioson preflight:context . --agent=dev --verbose
10
+ * aioson preflight:context . --agent=dev --json
11
+ */
12
+
13
+ const path = require('node:path');
14
+ const { estimateContext, formatReport } = require('../squad/preflight-context');
15
+
16
+ async function runPreflightContext({ args, options = {}, logger }) {
17
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
18
+ const agent = String(options.agent || options.a || 'dev').trim();
19
+ const squad = options.squad ? String(options.squad).trim() : undefined;
20
+ const verbose = Boolean(options.verbose || options.v);
21
+
22
+ const result = await estimateContext(targetDir, { agent, squad, verbose });
23
+
24
+ if (options.json) return result;
25
+
26
+ logger.log(formatReport(result));
27
+ return { ok: result.exitCode === 0, ...result };
28
+ }
29
+
30
+ module.exports = { runPreflightContext };
@@ -0,0 +1,208 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson preflight — consolidated pre-flight analysis for any agent session.
5
+ *
6
+ * Replaces 10+ manual file checks with one command. Returns mode, context package,
7
+ * readiness, phase gates, and next step — deterministically, with no LLM calls.
8
+ *
9
+ * Usage:
10
+ * aioson preflight . --agent=dev --feature=checkout
11
+ * aioson preflight . --agent=qa --feature=checkout --json
12
+ * aioson preflight . (project-level, no feature)
13
+ */
14
+
15
+ const path = require('node:path');
16
+ const {
17
+ loadProjectContext,
18
+ scanArtifacts,
19
+ readPhaseGates,
20
+ readDevState,
21
+ readProjectPulse,
22
+ detectClassification,
23
+ detectFramework,
24
+ detectTestRunner,
25
+ discoverRules,
26
+ buildContextPackage,
27
+ evaluateReadiness,
28
+ extractSpecVersion,
29
+ extractLastCheckpoint,
30
+ GATE_NAMES
31
+ } = require('../preflight-engine');
32
+
33
+ const BAR = '━'.repeat(55);
34
+
35
+ function gateIcon(status) {
36
+ if (!status) return '○';
37
+ if (status === 'approved') return '✓';
38
+ if (status === 'pending') return '○';
39
+ return '✗';
40
+ }
41
+
42
+ async function runPreflight({ args, options = {}, logger }) {
43
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
44
+ const agent = options.agent ? String(options.agent) : null;
45
+ const slug = options.feature ? String(options.feature) : null;
46
+
47
+ // --- Gather all data ---
48
+ const ctx = await loadProjectContext(targetDir);
49
+ const artifacts = await scanArtifacts(targetDir, slug);
50
+ const phaseGates = await readPhaseGates(targetDir, slug);
51
+ const devState = await readDevState(targetDir);
52
+ const pulse = await readProjectPulse(targetDir);
53
+
54
+ let classification = await detectClassification(targetDir, slug);
55
+ const framework = ctx.data.framework || ctx.data.stack || await detectFramework(targetDir);
56
+ const testRunnerInfo = await detectTestRunner(targetDir);
57
+ const testRunner = testRunnerInfo ? testRunnerInfo.name : (ctx.data.test_runner || null);
58
+ const rules = agent ? await discoverRules(targetDir, agent) : [];
59
+ const contextPackage = buildContextPackage(agent || 'dev', slug, classification, artifacts, devState);
60
+ const readiness = evaluateReadiness(artifacts, phaseGates, classification, agent);
61
+
62
+ // Determine mode
63
+ const mode = slug
64
+ ? (artifacts.prd.exists ? 'feature' : 'continuation')
65
+ : (artifacts.project_context.exists ? 'project' : 'greenfield');
66
+
67
+ // Spec version + checkpoint
68
+ const specVersion = extractSpecVersion(artifacts.spec);
69
+ const lastCheckpoint = extractLastCheckpoint(artifacts.spec);
70
+
71
+ const result = {
72
+ ok: true,
73
+ mode,
74
+ feature_slug: slug,
75
+ agent,
76
+ classification,
77
+ framework: framework || null,
78
+ test_runner: testRunner,
79
+ artifacts: {
80
+ project_context: { exists: artifacts.project_context.exists, path: artifacts.project_context.path || null },
81
+ prd: { exists: artifacts.prd.exists, path: artifacts.prd.path || null },
82
+ sheldon_enrichment: { exists: artifacts.sheldon_enrichment.exists },
83
+ requirements: { exists: artifacts.requirements.exists, path: artifacts.requirements.path || null },
84
+ spec: {
85
+ exists: artifacts.spec.exists,
86
+ path: artifacts.spec.path || null,
87
+ version: specVersion,
88
+ last_checkpoint: lastCheckpoint
89
+ },
90
+ architecture: { exists: artifacts.architecture.exists },
91
+ implementation_plan: {
92
+ exists: artifacts.implementation_plan.exists,
93
+ path: artifacts.implementation_plan.path || null,
94
+ status: artifacts.implementation_plan.exists ? (artifacts.implementation_plan.frontmatter.status || null) : null
95
+ },
96
+ conformance: { exists: artifacts.conformance.exists },
97
+ dev_state: {
98
+ exists: devState.exists,
99
+ next_step: devState.next_step || null
100
+ }
101
+ },
102
+ phase_gates: {
103
+ requirements: phaseGates.requirements || 'pending',
104
+ design: phaseGates.design || 'pending',
105
+ plan: phaseGates.plan || 'pending',
106
+ execution: phaseGates.execution || 'pending'
107
+ },
108
+ context_package: contextPackage,
109
+ rules,
110
+ readiness: readiness.status,
111
+ readiness_blockers: readiness.blockers,
112
+ pulse: {
113
+ last_agent: pulse.last_agent || null,
114
+ last_gate: pulse.last_gate || null,
115
+ blockers: pulse.blockers || 'none'
116
+ },
117
+ dev_state: {
118
+ active_feature: devState.active_feature || null,
119
+ active_phase: devState.active_phase || null,
120
+ next_step: devState.next_step || null,
121
+ last_spec_version: devState.last_spec_version || null
122
+ }
123
+ };
124
+
125
+ if (options.json) return result;
126
+
127
+ // --- Human output ---
128
+ const header = agent && slug
129
+ ? `AIOSON Pre-flight — @${agent} / ${slug}`
130
+ : agent
131
+ ? `AIOSON Pre-flight — @${agent}`
132
+ : 'AIOSON Pre-flight';
133
+
134
+ logger.log('');
135
+ logger.log(header);
136
+ logger.log(BAR);
137
+ logger.log('');
138
+ logger.log(`Mode: ${mode}${classification ? ' | Classification: ' + classification : ''}${framework ? ' | Framework: ' + framework : ''}${testRunner ? ' | Test runner: ' + testRunner : ''}`);
139
+ logger.log('');
140
+
141
+ logger.log('Artifacts:');
142
+ const checks = [
143
+ ['project.context.md', artifacts.project_context.exists, null],
144
+ slug ? [`prd-${slug}.md`, artifacts.prd.exists, null] : null,
145
+ slug ? [`sheldon-enrichment-${slug}.md`, artifacts.sheldon_enrichment.exists, 'optional'] : null,
146
+ slug ? [`requirements-${slug}.md`, artifacts.requirements.exists, null] : null,
147
+ slug
148
+ ? [`spec-${slug}.md`, artifacts.spec.exists, specVersion ? `version: ${specVersion}${lastCheckpoint ? ', last: "' + lastCheckpoint + '"' : ''}` : null]
149
+ : null,
150
+ ['architecture.md', artifacts.architecture.exists, null],
151
+ slug ? [`implementation-plan-${slug}.md`, artifacts.implementation_plan.exists, artifacts.implementation_plan.exists ? `status: ${artifacts.implementation_plan.frontmatter.status || 'unknown'}` : null] : null,
152
+ slug ? [`conformance-${slug}.yaml`, artifacts.conformance.exists, classification === 'SMALL' || classification === 'MICRO' ? 'MEDIUM only — not required' : null] : null
153
+ ].filter(Boolean);
154
+
155
+ for (const [name, exists, note] of checks) {
156
+ const icon = exists ? ' ✓' : ' ✗';
157
+ const suffix = note ? ` (${note})` : '';
158
+ logger.log(`${icon} ${name}${suffix}`);
159
+ }
160
+
161
+ logger.log('');
162
+ logger.log('Phase gates:');
163
+ for (const [letter, name] of Object.entries(GATE_NAMES)) {
164
+ const status = phaseGates[name] || 'pending';
165
+ logger.log(` ${gateIcon(status)} Gate ${letter} (${name}): ${status}`);
166
+ }
167
+
168
+ if (devState.exists && devState.next_step) {
169
+ logger.log('');
170
+ logger.log('Dev state:');
171
+ if (devState.active_feature) logger.log(` active_feature: ${devState.active_feature}`);
172
+ if (devState.active_phase) logger.log(` active_phase: ${devState.active_phase}`);
173
+ logger.log(` next_step: "${devState.next_step}"`);
174
+ if (devState.last_spec_version) logger.log(` last_spec_version: ${devState.last_spec_version}`);
175
+ }
176
+
177
+ if (contextPackage.length > 0) {
178
+ logger.log('');
179
+ logger.log('Context package (load these):');
180
+ contextPackage.forEach((p, i) => logger.log(` ${i + 1}. ${p}`));
181
+ }
182
+
183
+ if (rules.length > 0) {
184
+ logger.log('');
185
+ logger.log(`Rules loaded: ${rules.join(', ')}`);
186
+ }
187
+
188
+ if (pulse.last_agent) {
189
+ logger.log('');
190
+ logger.log('Project pulse:');
191
+ if (pulse.last_agent) logger.log(` last_agent: @${pulse.last_agent}`);
192
+ if (pulse.last_gate) logger.log(` last_gate: ${pulse.last_gate}`);
193
+ logger.log(` blockers: ${pulse.blockers || 'none'}`);
194
+ }
195
+
196
+ logger.log('');
197
+ if (readiness.status === 'READY') {
198
+ logger.log(`Readiness: READY — proceed`);
199
+ } else {
200
+ logger.log(`Readiness: BLOCKED`);
201
+ for (const b of readiness.blockers) logger.log(` ✗ ${b}`);
202
+ }
203
+ logger.log('');
204
+
205
+ return result;
206
+ }
207
+
208
+ module.exports = { runPreflight };
@@ -0,0 +1,130 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson pulse:update — update project-pulse.md at session end.
5
+ *
6
+ * Replaces the manual project-pulse.md editing block in 7+ agents.
7
+ * Keeps last 3 recent activity entries.
8
+ *
9
+ * Usage:
10
+ * aioson pulse:update . --agent=dev --feature=checkout --gate="Gate C: approved" \
11
+ * --action="Implemented payment webhook handler" --next="Continue with phase 4"
12
+ * aioson pulse:update . --agent=qa --verdict=PASS --feature=checkout
13
+ */
14
+
15
+ const fs = require('node:fs/promises');
16
+ const path = require('node:path');
17
+ const { contextDir, readFileSafe, parseFrontmatter } = require('../preflight-engine');
18
+
19
+ function nowDate() {
20
+ return new Date().toISOString().slice(0, 10);
21
+ }
22
+
23
+ async function runPulseUpdate({ args, options = {}, logger }) {
24
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
25
+ const agent = options.agent ? String(options.agent) : null;
26
+ const slug = options.feature ? String(options.feature) : null;
27
+ const gate = options.gate ? String(options.gate) : null;
28
+ const action = options.action ? String(options.action) : null;
29
+ const next = options.next ? String(options.next) : null;
30
+ const phase = options.phase ? String(options.phase) : null;
31
+ const verdict = options.verdict ? String(options.verdict).toUpperCase() : null;
32
+
33
+ if (!agent) {
34
+ if (options.json) return { ok: false, reason: 'missing_agent' };
35
+ logger.log('--agent is required. Example: aioson pulse:update . --agent=dev --feature=checkout');
36
+ return { ok: false };
37
+ }
38
+
39
+ const pulsePath = path.join(contextDir(targetDir), 'project-pulse.md');
40
+ const existing = await readFileSafe(pulsePath);
41
+
42
+ // Parse existing frontmatter
43
+ const fm = existing ? parseFrontmatter(existing) : {};
44
+
45
+ // Extract existing recent_activity lines (keep last 2 to add 1 new = 3 total)
46
+ const existingActivities = [];
47
+ if (existing) {
48
+ const activityMatch = existing.match(/## Recent Activity\n([\s\S]*?)(?=\n##|\s*$)/);
49
+ if (activityMatch) {
50
+ const lines = activityMatch[1].split('\n').filter((l) => l.trim().startsWith('-'));
51
+ existingActivities.push(...lines.slice(-2));
52
+ }
53
+ }
54
+
55
+ // Build new activity line
56
+ const today = nowDate();
57
+ let activityLine = `- ${today} @${agent}`;
58
+ if (slug) activityLine += ` → ${slug}`;
59
+ if (phase) activityLine += ` phase ${phase}`;
60
+ if (gate) activityLine += ` (${gate})`;
61
+ if (verdict) activityLine += ` VERDICT: ${verdict}`;
62
+ if (action) activityLine += `: ${action}`;
63
+
64
+ const recentActivities = [...existingActivities, activityLine];
65
+
66
+ // Build active work entry
67
+ let activeWork = fm.active_work || '';
68
+ if (slug) {
69
+ const phaseStr = phase ? ` → phase ${phase}` : '';
70
+ const statusStr = verdict ? (verdict === 'PASS' ? 'done' : 'in_progress') : 'in_progress';
71
+ activeWork = `${slug}${phaseStr} → @${agent} → ${statusStr}`;
72
+ }
73
+
74
+ // Build next recommendation
75
+ const nextRec = next || fm.next_recommendation || '';
76
+
77
+ // Write pulse file
78
+ const lines = [
79
+ '---',
80
+ `last_updated: ${today}`,
81
+ `last_agent: ${agent}`,
82
+ gate ? `last_gate: ${gate}` : (fm.last_gate ? `last_gate: ${fm.last_gate}` : null),
83
+ slug ? `active_feature: ${slug}` : (fm.active_feature ? `active_feature: ${fm.active_feature}` : null),
84
+ activeWork ? `active_work: "${activeWork}"` : null,
85
+ 'blockers: none',
86
+ nextRec ? `next_recommendation: "${nextRec}"` : null,
87
+ '---',
88
+ '',
89
+ '# Project Pulse',
90
+ '',
91
+ '## Status',
92
+ '',
93
+ `- **Last agent:** @${agent}`,
94
+ gate ? `- **Last gate:** ${gate}` : null,
95
+ slug ? `- **Active feature:** ${slug}` : null,
96
+ activeWork ? `- **Active work:** ${activeWork}` : null,
97
+ nextRec ? `- **Next:** ${nextRec}` : null,
98
+ '',
99
+ '## Recent Activity',
100
+ '',
101
+ ...recentActivities,
102
+ ''
103
+ ].filter((l) => l !== null);
104
+
105
+ await fs.mkdir(path.dirname(pulsePath), { recursive: true });
106
+ await fs.writeFile(pulsePath, lines.join('\n'), 'utf8');
107
+
108
+ const result = {
109
+ ok: true,
110
+ path: path.relative(targetDir, pulsePath),
111
+ last_agent: agent,
112
+ last_gate: gate,
113
+ active_feature: slug,
114
+ active_work: activeWork,
115
+ next_recommendation: nextRec
116
+ };
117
+
118
+ if (options.json) return result;
119
+
120
+ logger.log('Project pulse updated:');
121
+ logger.log(` last_agent: ${agent}`);
122
+ if (gate) logger.log(` last_gate: ${gate}`);
123
+ if (slug) logger.log(` active_work: ${activeWork}`);
124
+ logger.log(` Recent activity: +1 entry (kept last 3)`);
125
+ if (next) logger.log(` Next: ${next}`);
126
+
127
+ return result;
128
+ }
129
+
130
+ module.exports = { runPulseUpdate };