@jaimevalasek/aioson 1.3.0 → 1.5.1

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 (330) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/LICENSE +661 -21
  3. package/README.md +22 -3
  4. package/docs/en/squad-dashboard.md +372 -0
  5. package/docs/openclaw-bridge.md +308 -0
  6. package/docs/pt/README.md +62 -2
  7. package/docs/pt/advisor-spec.md +5 -5
  8. package/docs/pt/agentes-customizados.md +670 -0
  9. package/docs/pt/agentes.md +235 -23
  10. package/docs/pt/automacao-squads.md +407 -0
  11. package/docs/pt/cenarios.md +49 -5
  12. package/docs/pt/clientes-ai.md +62 -0
  13. package/docs/pt/comandos-cli.md +226 -17
  14. package/docs/pt/deyvin.md +115 -0
  15. package/docs/pt/genome-3.0-spec.md +11 -11
  16. package/docs/pt/inicio-rapido.md +63 -2
  17. package/docs/pt/memoria-contexto.md +255 -0
  18. package/docs/pt/output-strategy-delivery.md +655 -0
  19. package/docs/pt/profiler-system.md +17 -17
  20. package/docs/pt/runtime-observability.md +5 -1
  21. package/docs/pt/skills.md +175 -0
  22. package/docs/pt/squad-dashboard.md +373 -0
  23. package/docs/pt/{squad-genoma.md → squad-genome.md} +81 -75
  24. package/docs/testing/genome-2.0-matrix.md +5 -5
  25. package/docs/testing/genome-2.0-rollout.md +10 -10
  26. package/package.json +4 -4
  27. package/src/agents.js +21 -5
  28. package/src/backup-local.js +74 -0
  29. package/src/backup-provider.js +303 -0
  30. package/src/cli.js +276 -2
  31. package/src/commands/agents.js +22 -4
  32. package/src/commands/backup-local-cmd.js +25 -0
  33. package/src/commands/backup.js +533 -0
  34. package/src/commands/cloud.js +17 -17
  35. package/src/commands/context-pack.js +45 -0
  36. package/src/commands/implementation-plan.js +340 -0
  37. package/src/commands/learning.js +134 -0
  38. package/src/commands/live.js +1583 -0
  39. package/src/commands/runtime.js +1075 -2
  40. package/src/commands/scan-project.js +288 -24
  41. package/src/commands/setup-context.js +30 -2
  42. package/src/commands/skill.js +558 -0
  43. package/src/commands/squad-agent-create.js +788 -0
  44. package/src/commands/squad-daemon.js +209 -0
  45. package/src/commands/squad-dashboard.js +39 -0
  46. package/src/commands/squad-deploy.js +64 -0
  47. package/src/commands/squad-doctor.js +103 -1
  48. package/src/commands/squad-investigate.js +261 -0
  49. package/src/commands/squad-learning.js +209 -0
  50. package/src/commands/squad-mcp.js +270 -0
  51. package/src/commands/squad-pipeline.js +247 -1
  52. package/src/commands/squad-plan.js +329 -0
  53. package/src/commands/squad-processes.js +56 -0
  54. package/src/commands/squad-recovery.js +42 -0
  55. package/src/commands/squad-roi.js +291 -0
  56. package/src/commands/squad-score.js +250 -0
  57. package/src/commands/squad-status.js +38 -2
  58. package/src/commands/squad-validate.js +118 -1
  59. package/src/commands/squad-webhook.js +160 -0
  60. package/src/commands/squad-worker.js +191 -0
  61. package/src/commands/squad-worktrees.js +75 -0
  62. package/src/commands/test-agents.js +6 -1
  63. package/src/commands/web-map.js +70 -0
  64. package/src/commands/web-scrape.js +71 -0
  65. package/src/commands/workflow-next.js +8 -1
  66. package/src/commands/workflow-status.js +250 -0
  67. package/src/constants.js +88 -16
  68. package/src/context-memory.js +837 -0
  69. package/src/context-writer.js +47 -1
  70. package/src/delivery-runner.js +319 -0
  71. package/src/genome-files.js +1 -1
  72. package/src/genome-format.js +1 -1
  73. package/src/i18n/messages/en.js +333 -8
  74. package/src/i18n/messages/es.js +240 -6
  75. package/src/i18n/messages/fr.js +239 -5
  76. package/src/i18n/messages/pt-BR.js +330 -12
  77. package/src/installer.js +30 -2
  78. package/src/lib/genomes/compat.js +1 -1
  79. package/src/lib/webhook-server.js +328 -0
  80. package/src/mcp-connectors/registry.js +602 -0
  81. package/src/runtime-store.js +1037 -42
  82. package/src/session-handoff.js +77 -0
  83. package/src/squad/external-session.js +180 -0
  84. package/src/squad/inter-squad.js +74 -0
  85. package/src/squad/recovery-context.js +201 -0
  86. package/src/squad/worktree-manager.js +114 -0
  87. package/src/squad-daemon.js +490 -0
  88. package/src/squad-dashboard/api.js +223 -0
  89. package/src/squad-dashboard/attachment-handler.js +93 -0
  90. package/src/squad-dashboard/context-monitor.js +157 -0
  91. package/src/squad-dashboard/execution-logs.js +115 -0
  92. package/src/squad-dashboard/hunk-review.js +209 -0
  93. package/src/squad-dashboard/metrics.js +133 -0
  94. package/src/squad-dashboard/process-monitor.js +125 -0
  95. package/src/squad-dashboard/renderer.js +858 -0
  96. package/src/squad-dashboard/server.js +232 -0
  97. package/src/squad-dashboard/styles.js +525 -0
  98. package/src/squad-dashboard/token-tracker.js +99 -0
  99. package/src/web.js +284 -0
  100. package/src/worker-runner.js +339 -0
  101. package/template/.aioson/agents/analyst.md +40 -9
  102. package/template/.aioson/agents/architect.md +24 -5
  103. package/template/.aioson/agents/dev.md +254 -25
  104. package/template/.aioson/agents/deyvin.md +174 -0
  105. package/template/.aioson/agents/discovery-design-doc.md +25 -1
  106. package/template/.aioson/agents/{genoma.md → genome.md} +20 -20
  107. package/template/.aioson/agents/neo.md +152 -0
  108. package/template/.aioson/agents/orache.md +388 -0
  109. package/template/.aioson/agents/orchestrator.md +63 -2
  110. package/template/.aioson/agents/pair.md +5 -0
  111. package/template/.aioson/agents/pm.md +17 -5
  112. package/template/.aioson/agents/product.md +113 -29
  113. package/template/.aioson/agents/profiler-enricher.md +1 -1
  114. package/template/.aioson/agents/profiler-forge.md +9 -9
  115. package/template/.aioson/agents/profiler-researcher.md +1 -1
  116. package/template/.aioson/agents/qa.md +18 -5
  117. package/template/.aioson/agents/setup.md +138 -18
  118. package/template/.aioson/agents/sheldon.md +603 -0
  119. package/template/.aioson/agents/squad.md +866 -28
  120. package/template/.aioson/agents/tester.md +254 -0
  121. package/template/.aioson/agents/ux-ui.md +289 -34
  122. package/template/.aioson/config.md +181 -0
  123. package/template/.aioson/context/spec.md.template +17 -0
  124. package/template/.aioson/genomes/.gitkeep +0 -0
  125. package/template/.aioson/installed-skills/.gitkeep +0 -0
  126. package/template/.aioson/locales/en/agents/analyst.md +34 -4
  127. package/template/.aioson/locales/en/agents/architect.md +18 -0
  128. package/template/.aioson/locales/en/agents/dev.md +155 -11
  129. package/template/.aioson/locales/en/agents/deyvin.md +137 -0
  130. package/template/.aioson/locales/en/agents/{genoma.md → genome.md} +14 -14
  131. package/template/.aioson/locales/en/agents/neo.md +8 -0
  132. package/template/.aioson/locales/en/agents/orchestrator.md +62 -2
  133. package/template/.aioson/locales/en/agents/pair.md +5 -0
  134. package/template/.aioson/locales/en/agents/pm.md +7 -0
  135. package/template/.aioson/locales/en/agents/product.md +35 -17
  136. package/template/.aioson/locales/en/agents/qa.md +56 -0
  137. package/template/.aioson/locales/en/agents/setup.md +53 -6
  138. package/template/.aioson/locales/en/agents/sheldon.md +340 -0
  139. package/template/.aioson/locales/en/agents/squad.md +203 -15
  140. package/template/.aioson/locales/en/agents/ux-ui.md +383 -35
  141. package/template/.aioson/locales/es/agents/analyst.md +24 -4
  142. package/template/.aioson/locales/es/agents/architect.md +18 -0
  143. package/template/.aioson/locales/es/agents/dev.md +136 -9
  144. package/template/.aioson/locales/es/agents/deyvin.md +97 -0
  145. package/template/.aioson/locales/es/agents/{genoma.md → genome.md} +13 -13
  146. package/template/.aioson/locales/es/agents/neo.md +48 -0
  147. package/template/.aioson/locales/es/agents/orache.md +103 -0
  148. package/template/.aioson/locales/es/agents/orchestrator.md +62 -2
  149. package/template/.aioson/locales/es/agents/pair.md +5 -0
  150. package/template/.aioson/locales/es/agents/pm.md +7 -0
  151. package/template/.aioson/locales/es/agents/product.md +13 -3
  152. package/template/.aioson/locales/es/agents/qa.md +33 -0
  153. package/template/.aioson/locales/es/agents/setup.md +30 -6
  154. package/template/.aioson/locales/es/agents/sheldon.md +192 -0
  155. package/template/.aioson/locales/es/agents/squad.md +284 -15
  156. package/template/.aioson/locales/es/agents/ux-ui.md +34 -25
  157. package/template/.aioson/locales/fr/agents/analyst.md +24 -4
  158. package/template/.aioson/locales/fr/agents/architect.md +18 -0
  159. package/template/.aioson/locales/fr/agents/dev.md +136 -9
  160. package/template/.aioson/locales/fr/agents/deyvin.md +97 -0
  161. package/template/.aioson/locales/fr/agents/{genoma.md → genome.md} +7 -7
  162. package/template/.aioson/locales/fr/agents/neo.md +48 -0
  163. package/template/.aioson/locales/fr/agents/orache.md +104 -0
  164. package/template/.aioson/locales/fr/agents/orchestrator.md +62 -2
  165. package/template/.aioson/locales/fr/agents/pair.md +5 -0
  166. package/template/.aioson/locales/fr/agents/pm.md +7 -0
  167. package/template/.aioson/locales/fr/agents/product.md +13 -3
  168. package/template/.aioson/locales/fr/agents/qa.md +33 -0
  169. package/template/.aioson/locales/fr/agents/setup.md +30 -6
  170. package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
  171. package/template/.aioson/locales/fr/agents/squad.md +279 -10
  172. package/template/.aioson/locales/fr/agents/ux-ui.md +34 -25
  173. package/template/.aioson/locales/pt-BR/agents/analyst.md +45 -4
  174. package/template/.aioson/locales/pt-BR/agents/architect.md +29 -0
  175. package/template/.aioson/locales/pt-BR/agents/dev.md +167 -15
  176. package/template/.aioson/locales/pt-BR/agents/deyvin.md +137 -0
  177. package/template/.aioson/locales/pt-BR/agents/{genoma.md → genome.md} +49 -49
  178. package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
  179. package/template/.aioson/locales/pt-BR/agents/orache.md +137 -0
  180. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +62 -2
  181. package/template/.aioson/locales/pt-BR/agents/pair.md +5 -0
  182. package/template/.aioson/locales/pt-BR/agents/pm.md +7 -0
  183. package/template/.aioson/locales/pt-BR/agents/product.md +43 -20
  184. package/template/.aioson/locales/pt-BR/agents/qa.md +67 -0
  185. package/template/.aioson/locales/pt-BR/agents/setup.md +53 -6
  186. package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
  187. package/template/.aioson/locales/pt-BR/agents/squad.md +591 -47
  188. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +369 -22
  189. package/template/.aioson/my-agents/.gitkeep +0 -0
  190. package/template/.aioson/rules/.gitkeep +0 -0
  191. package/template/.aioson/rules/squad/.gitkeep +0 -0
  192. package/template/.aioson/rules/squad/README.md +50 -0
  193. package/template/.aioson/schemas/genome-meta.schema.json +1 -1
  194. package/template/.aioson/schemas/genome.schema.json +1 -1
  195. package/template/.aioson/schemas/squad-blueprint.schema.json +32 -0
  196. package/template/.aioson/schemas/squad-manifest.schema.json +434 -1
  197. package/template/.aioson/skills/design/bold-editorial-ui/SKILL.md +205 -0
  198. package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
  199. package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
  200. package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
  201. package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
  202. package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
  203. package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
  204. package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
  205. package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
  206. package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
  207. package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
  208. package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
  209. package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
  210. package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
  211. package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
  212. package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
  213. package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +203 -0
  214. package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
  215. package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +407 -0
  216. package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +272 -0
  217. package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +524 -0
  218. package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +277 -0
  219. package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +289 -0
  220. package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +437 -0
  221. package/template/.aioson/skills/design/interface-design/SKILL.md +47 -0
  222. package/template/.aioson/skills/design/interface-design/references/components-and-states.md +105 -0
  223. package/template/.aioson/skills/design/interface-design/references/design-directions.md +101 -0
  224. package/template/.aioson/skills/design/interface-design/references/handoff-and-quality.md +71 -0
  225. package/template/.aioson/skills/design/interface-design/references/intent-and-domain.md +74 -0
  226. package/template/.aioson/skills/design/interface-design/references/tokens-and-depth.md +173 -0
  227. package/template/.aioson/skills/design/premium-command-center-ui/SKILL.md +62 -0
  228. package/template/.aioson/skills/design/premium-command-center-ui/references/operations.md +74 -0
  229. package/template/.aioson/skills/design/premium-command-center-ui/references/patterns.md +116 -0
  230. package/template/.aioson/skills/design/premium-command-center-ui/references/validation.md +47 -0
  231. package/template/.aioson/skills/design/premium-command-center-ui/references/visual-system.md +215 -0
  232. package/template/.aioson/skills/design/warm-craft-ui/SKILL.md +209 -0
  233. package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
  234. package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
  235. package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
  236. package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
  237. package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
  238. package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
  239. package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
  240. package/template/.aioson/skills/design-system/SKILL.md +92 -0
  241. package/template/.aioson/skills/design-system/cognitive-core-ui.skill +0 -0
  242. package/template/.aioson/skills/design-system/components/SKILL.md +274 -0
  243. package/template/.aioson/skills/design-system/components/SKILL.md:Zone.Identifier +0 -0
  244. package/template/.aioson/skills/design-system/dashboards/SKILL.md +184 -0
  245. package/template/.aioson/skills/design-system/dashboards/SKILL.md:Zone.Identifier +0 -0
  246. package/template/.aioson/skills/design-system/foundations/SKILL.md +250 -0
  247. package/template/.aioson/skills/design-system/foundations/SKILL.md:Zone.Identifier +0 -0
  248. package/template/.aioson/skills/design-system/motion/SKILL.md +197 -0
  249. package/template/.aioson/skills/design-system/motion/SKILL.md:Zone.Identifier +0 -0
  250. package/template/.aioson/skills/design-system/patterns/SKILL.md +231 -0
  251. package/template/.aioson/skills/design-system/patterns/SKILL.md:Zone.Identifier +0 -0
  252. package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
  253. package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
  254. package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
  255. package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
  256. package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
  257. package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
  258. package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
  259. package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
  260. package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
  261. package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
  262. package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
  263. package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -0
  264. package/template/.aioson/skills/squad/SKILL.md +58 -0
  265. package/template/.aioson/skills/squad/domains/.gitkeep +0 -0
  266. package/template/.aioson/skills/squad/formats/.gitkeep +0 -0
  267. package/template/.aioson/skills/squad/formats/catalog.json +15 -0
  268. package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
  269. package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
  270. package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
  271. package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
  272. package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
  273. package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
  274. package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
  275. package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
  276. package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
  277. package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
  278. package/template/.aioson/skills/squad/patterns/.gitkeep +0 -0
  279. package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
  280. package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
  281. package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
  282. package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -0
  283. package/template/.aioson/skills/squad/references/.gitkeep +0 -0
  284. package/template/.aioson/skills/squad/references/checklist-templates.md +122 -0
  285. package/template/.aioson/skills/squad/references/executor-archetypes.md +123 -0
  286. package/template/.aioson/skills/squad/references/workflow-templates.md +169 -0
  287. package/template/.aioson/skills/static/debugging-protocol.md +42 -0
  288. package/template/.aioson/skills/static/git-worktrees.md +36 -0
  289. package/template/.aioson/tasks/implementation-plan.md +307 -0
  290. package/template/.aioson/tasks/squad-create.md +1 -1
  291. package/template/.aioson/tasks/squad-design.md +28 -0
  292. package/template/.aioson/tasks/squad-execution-plan.md +279 -0
  293. package/template/.aioson/tasks/squad-export.md +1 -1
  294. package/template/.aioson/tasks/squad-investigate.md +44 -0
  295. package/template/.aioson/tasks/squad-learning-review.md +44 -0
  296. package/template/.aioson/tasks/squad-output-config.md +177 -0
  297. package/template/.aioson/tasks/squad-profile.md +48 -0
  298. package/template/.aioson/tasks/squad-review.md +61 -0
  299. package/template/.aioson/tasks/squad-task-decompose.md +66 -0
  300. package/template/.aioson/tasks/squad-validate.md +1 -1
  301. package/template/.claude/commands/aioson/agent/deyvin.md +5 -0
  302. package/template/.claude/commands/aioson/agent/discovery-design-doc.md +5 -0
  303. package/template/.claude/commands/aioson/agent/genome.md +5 -0
  304. package/template/.claude/commands/aioson/agent/neo.md +5 -0
  305. package/template/.claude/commands/aioson/agent/product.md +5 -0
  306. package/template/.claude/commands/aioson/agent/profiler-enricher.md +5 -0
  307. package/template/.claude/commands/aioson/agent/profiler-forge.md +5 -0
  308. package/template/.claude/commands/aioson/agent/profiler-researcher.md +5 -0
  309. package/template/.claude/commands/aioson/agent/squad.md +5 -0
  310. package/template/.claude/commands/aioson/agent/tester.md +5 -0
  311. package/template/.gemini/GEMINI.md +3 -0
  312. package/template/.gemini/commands/aios-deyvin.toml +6 -0
  313. package/template/.gemini/commands/aios-neo.toml +4 -0
  314. package/template/.gemini/commands/aios-pair.toml +6 -0
  315. package/template/.gemini/commands/aios-tester.toml +6 -0
  316. package/template/AGENTS.md +37 -6
  317. package/template/CLAUDE.md +34 -4
  318. package/template/OPENCODE.md +8 -2
  319. package/template/squad-searches/.gitkeep +0 -0
  320. package/template/.aioson/skills/static/interface-design.md +0 -372
  321. package/template/.aioson/skills/static/premium-command-center-ui.md +0 -190
  322. /package/template/.aioson/{genomas → docs}/.gitkeep +0 -0
  323. /package/template/.claude/commands/aioson/{analyst.md → agent/analyst.md} +0 -0
  324. /package/template/.claude/commands/aioson/{architect.md → agent/architect.md} +0 -0
  325. /package/template/.claude/commands/aioson/{dev.md → agent/dev.md} +0 -0
  326. /package/template/.claude/commands/aioson/{orchestrator.md → agent/orchestrator.md} +0 -0
  327. /package/template/.claude/commands/aioson/{pm.md → agent/pm.md} +0 -0
  328. /package/template/.claude/commands/aioson/{qa.md → agent/qa.md} +0 -0
  329. /package/template/.claude/commands/aioson/{setup.md → agent/setup.md} +0 -0
  330. /package/template/.claude/commands/aioson/{ux-ui.md → agent/ux-ui.md} +0 -0
@@ -12,6 +12,7 @@ const {
12
12
 
13
13
  const RUNTIME_DIR = path.join('.aioson', 'runtime');
14
14
  const DB_FILE = 'aios.sqlite';
15
+ const LOGS_DIR = 'aioson-logs';
15
16
  const SESSIONS_DIR = '.sessions';
16
17
  const VALID_STATUSES = new Set(['queued', 'running', 'completed', 'failed']);
17
18
  const VALID_TASK_STATUSES = new Set(['queued', 'running', 'completed', 'failed']);
@@ -32,7 +33,8 @@ function resolveRuntimePaths(targetDir) {
32
33
  const runtimeDir = path.join(targetDir, RUNTIME_DIR);
33
34
  return {
34
35
  runtimeDir,
35
- dbPath: path.join(runtimeDir, DB_FILE)
36
+ dbPath: path.join(runtimeDir, DB_FILE),
37
+ logsDir: path.join(targetDir, LOGS_DIR)
36
38
  };
37
39
  }
38
40
 
@@ -42,7 +44,7 @@ async function runtimeStoreExists(targetDir) {
42
44
  }
43
45
 
44
46
  async function openRuntimeDb(targetDir, options = {}) {
45
- const { runtimeDir, dbPath } = resolveRuntimePaths(targetDir);
47
+ const { runtimeDir, dbPath, logsDir } = resolveRuntimePaths(targetDir);
46
48
  const mustExist = Boolean(options.mustExist);
47
49
 
48
50
  if (mustExist && !(await exists(dbPath))) {
@@ -50,6 +52,7 @@ async function openRuntimeDb(targetDir, options = {}) {
50
52
  }
51
53
 
52
54
  await ensureDir(runtimeDir);
55
+ await ensureDir(logsDir);
53
56
 
54
57
  const db = new Database(dbPath);
55
58
  db.pragma('journal_mode = WAL');
@@ -125,8 +128,11 @@ async function openRuntimeDb(targetDir, options = {}) {
125
128
  task_key TEXT PRIMARY KEY,
126
129
  squad_slug TEXT,
127
130
  session_key TEXT,
131
+ task_kind TEXT,
132
+ parent_task_key TEXT,
128
133
  title TEXT NOT NULL,
129
134
  goal TEXT,
135
+ meta_json TEXT,
130
136
  status TEXT NOT NULL,
131
137
  created_by TEXT,
132
138
  created_at TEXT NOT NULL,
@@ -351,6 +357,239 @@ async function openRuntimeDb(targetDir, options = {}) {
351
357
 
352
358
  CREATE INDEX IF NOT EXISTS idx_artisan_squads_status ON artisan_squads(status, updated_at DESC);
353
359
  CREATE INDEX IF NOT EXISTS idx_artisan_messages_artisan ON artisan_messages(artisan_id, created_at ASC);
360
+
361
+ CREATE TABLE IF NOT EXISTS delivery_log (
362
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
363
+ squad_slug TEXT NOT NULL,
364
+ content_key TEXT,
365
+ webhook_slug TEXT,
366
+ trigger_type TEXT NOT NULL,
367
+ url TEXT NOT NULL,
368
+ status_code INTEGER,
369
+ response_body TEXT,
370
+ error_message TEXT,
371
+ attempt INTEGER DEFAULT 1,
372
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
373
+ );
374
+
375
+ CREATE INDEX IF NOT EXISTS idx_delivery_log_squad ON delivery_log(squad_slug);
376
+ CREATE INDEX IF NOT EXISTS idx_delivery_log_content ON delivery_log(content_key);
377
+
378
+ CREATE TABLE IF NOT EXISTS backup_manifest (
379
+ record_key TEXT PRIMARY KEY,
380
+ record_type TEXT NOT NULL,
381
+ content_hash TEXT NOT NULL,
382
+ backed_up_at TEXT NOT NULL,
383
+ remote_key TEXT NOT NULL
384
+ );
385
+ CREATE INDEX IF NOT EXISTS idx_backup_manifest_type ON backup_manifest(record_type, backed_up_at DESC);
386
+
387
+ CREATE TABLE IF NOT EXISTS squad_investigations (
388
+ investigation_slug TEXT PRIMARY KEY,
389
+ domain TEXT NOT NULL,
390
+ mode TEXT DEFAULT 'full',
391
+ dimensions_covered INTEGER DEFAULT 0,
392
+ total_dimensions INTEGER DEFAULT 7,
393
+ confidence REAL DEFAULT 0,
394
+ report_path TEXT,
395
+ linked_squad_slug TEXT,
396
+ created_at TEXT DEFAULT (datetime('now')),
397
+ updated_at TEXT DEFAULT (datetime('now'))
398
+ );
399
+
400
+ CREATE INDEX IF NOT EXISTS idx_squad_investigations_domain ON squad_investigations(domain);
401
+ CREATE INDEX IF NOT EXISTS idx_squad_investigations_squad ON squad_investigations(linked_squad_slug);
402
+
403
+ CREATE TABLE IF NOT EXISTS implementation_plans (
404
+ plan_id TEXT PRIMARY KEY,
405
+ project_name TEXT,
406
+ scope TEXT DEFAULT 'project',
407
+ feature_slug TEXT,
408
+ status TEXT DEFAULT 'draft',
409
+ classification TEXT,
410
+ phases_total INTEGER DEFAULT 0,
411
+ phases_completed INTEGER DEFAULT 0,
412
+ source_artifacts TEXT,
413
+ source_hash TEXT,
414
+ created_at TEXT DEFAULT (datetime('now')),
415
+ updated_at TEXT DEFAULT (datetime('now'))
416
+ );
417
+
418
+ CREATE TABLE IF NOT EXISTS plan_phases (
419
+ plan_id TEXT NOT NULL,
420
+ phase_number INTEGER NOT NULL,
421
+ title TEXT NOT NULL,
422
+ status TEXT DEFAULT 'pending',
423
+ completed_at TEXT,
424
+ notes TEXT,
425
+ PRIMARY KEY (plan_id, phase_number),
426
+ FOREIGN KEY (plan_id) REFERENCES implementation_plans(plan_id)
427
+ );
428
+
429
+ CREATE TABLE IF NOT EXISTS squad_execution_plans (
430
+ plan_slug TEXT PRIMARY KEY,
431
+ squad_slug TEXT NOT NULL,
432
+ status TEXT DEFAULT 'draft',
433
+ rounds_total INTEGER DEFAULT 0,
434
+ rounds_completed INTEGER DEFAULT 0,
435
+ based_on_blueprint TEXT,
436
+ based_on_investigation TEXT,
437
+ source_hash TEXT,
438
+ created_at TEXT DEFAULT (datetime('now')),
439
+ updated_at TEXT DEFAULT (datetime('now'))
440
+ );
441
+
442
+ CREATE TABLE IF NOT EXISTS squad_plan_rounds (
443
+ plan_slug TEXT NOT NULL,
444
+ round_number INTEGER NOT NULL,
445
+ executor_slug TEXT NOT NULL,
446
+ title TEXT NOT NULL,
447
+ status TEXT DEFAULT 'pending',
448
+ completed_at TEXT,
449
+ notes TEXT,
450
+ PRIMARY KEY (plan_slug, round_number),
451
+ FOREIGN KEY (plan_slug) REFERENCES squad_execution_plans(plan_slug)
452
+ );
453
+
454
+ CREATE TABLE IF NOT EXISTS squad_learnings (
455
+ learning_id TEXT PRIMARY KEY,
456
+ squad_slug TEXT NOT NULL,
457
+ type TEXT NOT NULL CHECK (type IN ('preference', 'process', 'domain', 'quality')),
458
+ title TEXT NOT NULL,
459
+ signal TEXT DEFAULT 'explicit' CHECK (signal IN ('explicit', 'implicit')),
460
+ confidence TEXT DEFAULT 'medium' CHECK (confidence IN ('high', 'medium', 'low')),
461
+ frequency INTEGER DEFAULT 1,
462
+ last_reinforced TEXT,
463
+ applies_to TEXT DEFAULT 'squad',
464
+ file_path TEXT,
465
+ promoted_to TEXT,
466
+ status TEXT DEFAULT 'active' CHECK (status IN ('active', 'stale', 'archived', 'promoted')),
467
+ source_session TEXT,
468
+ evidence TEXT,
469
+ created_at TEXT DEFAULT (datetime('now')),
470
+ updated_at TEXT DEFAULT (datetime('now'))
471
+ );
472
+
473
+ CREATE TABLE IF NOT EXISTS project_learnings (
474
+ learning_id TEXT PRIMARY KEY,
475
+ project_name TEXT,
476
+ feature_slug TEXT,
477
+ type TEXT NOT NULL CHECK (type IN ('preference', 'process', 'domain', 'quality')),
478
+ title TEXT NOT NULL,
479
+ confidence TEXT DEFAULT 'medium',
480
+ frequency INTEGER DEFAULT 1,
481
+ last_reinforced TEXT,
482
+ applies_to TEXT DEFAULT 'project',
483
+ promoted_to TEXT,
484
+ status TEXT DEFAULT 'active' CHECK (status IN ('active', 'stale', 'archived', 'promoted')),
485
+ source_session TEXT,
486
+ evidence TEXT,
487
+ created_at TEXT DEFAULT (datetime('now')),
488
+ updated_at TEXT DEFAULT (datetime('now'))
489
+ );
490
+
491
+ CREATE INDEX IF NOT EXISTS idx_impl_plans_status ON implementation_plans(status);
492
+ CREATE INDEX IF NOT EXISTS idx_squad_exec_plans_squad ON squad_execution_plans(squad_slug);
493
+ CREATE INDEX IF NOT EXISTS idx_squad_exec_plans_status ON squad_execution_plans(status);
494
+ CREATE INDEX IF NOT EXISTS idx_squad_learnings_squad ON squad_learnings(squad_slug);
495
+ CREATE INDEX IF NOT EXISTS idx_squad_learnings_type ON squad_learnings(type);
496
+ CREATE INDEX IF NOT EXISTS idx_squad_learnings_status ON squad_learnings(status);
497
+ CREATE INDEX IF NOT EXISTS idx_project_learnings_type ON project_learnings(type);
498
+ CREATE INDEX IF NOT EXISTS idx_project_learnings_status ON project_learnings(status);
499
+
500
+ CREATE TABLE IF NOT EXISTS squad_metrics (
501
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
502
+ squad_slug TEXT NOT NULL,
503
+ metric_key TEXT NOT NULL,
504
+ metric_value REAL NOT NULL,
505
+ metric_unit TEXT,
506
+ period TEXT,
507
+ baseline REAL,
508
+ target REAL,
509
+ source TEXT DEFAULT 'manual',
510
+ notes TEXT,
511
+ created_at TEXT DEFAULT (datetime('now')),
512
+ UNIQUE(squad_slug, metric_key, period)
513
+ );
514
+ CREATE INDEX IF NOT EXISTS idx_squad_metrics_squad ON squad_metrics(squad_slug, period DESC);
515
+
516
+ CREATE TABLE IF NOT EXISTS worker_runs (
517
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
518
+ squad_slug TEXT NOT NULL,
519
+ worker_slug TEXT NOT NULL,
520
+ trigger_type TEXT NOT NULL DEFAULT 'manual',
521
+ input_json TEXT,
522
+ output_json TEXT,
523
+ status TEXT DEFAULT 'running',
524
+ error_message TEXT,
525
+ duration_ms INTEGER,
526
+ attempt INTEGER DEFAULT 1,
527
+ created_at TEXT DEFAULT (datetime('now')),
528
+ completed_at TEXT
529
+ );
530
+ CREATE INDEX IF NOT EXISTS idx_worker_runs_squad ON worker_runs(squad_slug, created_at DESC);
531
+
532
+ CREATE TABLE IF NOT EXISTS squad_daemons (
533
+ squad_slug TEXT PRIMARY KEY,
534
+ status TEXT DEFAULT 'stopped',
535
+ pid INTEGER,
536
+ port INTEGER,
537
+ started_at TEXT,
538
+ last_heartbeat TEXT,
539
+ config_json TEXT,
540
+ error_message TEXT
541
+ );
542
+
543
+ CREATE TABLE IF NOT EXISTS mcp_status (
544
+ squad_slug TEXT NOT NULL,
545
+ mcp_slug TEXT NOT NULL,
546
+ connector TEXT NOT NULL,
547
+ status TEXT DEFAULT 'unconfigured',
548
+ last_check TEXT,
549
+ last_error TEXT,
550
+ calls_total INTEGER DEFAULT 0,
551
+ calls_failed INTEGER DEFAULT 0,
552
+ PRIMARY KEY (squad_slug, mcp_slug)
553
+ );
554
+
555
+ CREATE TABLE IF NOT EXISTS workflow_reviews (
556
+ review_id TEXT PRIMARY KEY,
557
+ squad_slug TEXT NOT NULL,
558
+ workflow_slug TEXT NOT NULL,
559
+ phase_id TEXT NOT NULL,
560
+ attempt_number INTEGER DEFAULT 1,
561
+ reviewer_slug TEXT NOT NULL,
562
+ verdict TEXT NOT NULL,
563
+ score REAL,
564
+ feedback TEXT,
565
+ veto_triggered TEXT,
566
+ created_at TEXT DEFAULT (datetime('now'))
567
+ );
568
+ CREATE INDEX IF NOT EXISTS idx_workflow_reviews_squad ON workflow_reviews(squad_slug, workflow_slug);
569
+
570
+ CREATE TABLE IF NOT EXISTS squad_scores (
571
+ squad_slug TEXT NOT NULL,
572
+ dimension TEXT NOT NULL,
573
+ score INTEGER NOT NULL,
574
+ max_score INTEGER NOT NULL,
575
+ details_json TEXT,
576
+ scored_at TEXT DEFAULT (datetime('now')),
577
+ PRIMARY KEY (squad_slug, dimension, scored_at)
578
+ );
579
+ CREATE INDEX IF NOT EXISTS idx_squad_scores_squad ON squad_scores(squad_slug);
580
+
581
+ CREATE TABLE IF NOT EXISTS squad_roi_config (
582
+ squad_slug TEXT PRIMARY KEY,
583
+ pricing_model TEXT DEFAULT 'fixed',
584
+ setup_fee REAL,
585
+ monthly_fee REAL,
586
+ percentage_fee REAL,
587
+ percentage_base TEXT,
588
+ currency TEXT DEFAULT 'BRL',
589
+ contract_months INTEGER DEFAULT 12,
590
+ created_at TEXT DEFAULT (datetime('now')),
591
+ updated_at TEXT DEFAULT (datetime('now'))
592
+ );
354
593
  `);
355
594
 
356
595
  ensureLegacyColumns(db);
@@ -381,6 +620,25 @@ function normalizeTaskStatus(value, fallback) {
381
620
  }
382
621
 
383
622
  function ensureLegacyColumns(db) {
623
+ const taskColumns = db.prepare('PRAGMA table_info(tasks)').all();
624
+ const taskColumnNames = new Set(taskColumns.map((column) => column.name));
625
+
626
+ if (!taskColumnNames.has('task_kind')) {
627
+ db.exec('ALTER TABLE tasks ADD COLUMN task_kind TEXT');
628
+ }
629
+
630
+ if (!taskColumnNames.has('parent_task_key')) {
631
+ db.exec('ALTER TABLE tasks ADD COLUMN parent_task_key TEXT');
632
+ }
633
+
634
+ if (!taskColumnNames.has('meta_json')) {
635
+ db.exec('ALTER TABLE tasks ADD COLUMN meta_json TEXT');
636
+ }
637
+
638
+ db.exec('CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_key, updated_at DESC)');
639
+ db.exec('CREATE INDEX IF NOT EXISTS idx_tasks_parent ON tasks(parent_task_key, updated_at DESC)');
640
+ db.exec('CREATE INDEX IF NOT EXISTS idx_tasks_kind ON tasks(task_kind, updated_at DESC)');
641
+
384
642
  const agentRunColumns = db.prepare('PRAGMA table_info(agent_runs)').all();
385
643
  const agentRunColumnNames = new Set(agentRunColumns.map((column) => column.name));
386
644
 
@@ -433,6 +691,8 @@ function ensureLegacyColumns(db) {
433
691
  if (!contentItemColumnNames.has('used_skills_json')) {
434
692
  db.exec('ALTER TABLE content_items ADD COLUMN used_skills_json TEXT');
435
693
  }
694
+
695
+ try { db.exec('ALTER TABLE worker_runs ADD COLUMN conversation_id TEXT'); } catch { /* já existe */ }
436
696
  }
437
697
 
438
698
  function insertEvent(db, record) {
@@ -498,56 +758,66 @@ function appendRunEvent(db, options) {
498
758
  const now = options.createdAt || nowIso();
499
759
  const payloadJson = options.payload ? JSON.stringify(options.payload) : null;
500
760
 
501
- insertEvent(db, {
502
- run_key: run.run_key,
503
- event_type: String(options.eventType || 'update'),
504
- message: String(options.message || ''),
505
- payload_json: payloadJson,
506
- created_at: now
507
- });
761
+ const doInsert = db.transaction(() => {
762
+ insertEvent(db, {
763
+ run_key: run.run_key,
764
+ event_type: String(options.eventType || 'update'),
765
+ message: String(options.message || ''),
766
+ payload_json: payloadJson,
767
+ created_at: now
768
+ });
508
769
 
509
- insertExecutionEvent(db, {
510
- task_key: run.task_key,
511
- run_key: run.run_key,
512
- agent_name: run.agent_name,
513
- agent_kind: run.agent_kind,
514
- squad_slug: run.squad_slug,
515
- session_key: run.session_key,
516
- source: run.source,
517
- workflow_id: run.workflow_id,
518
- workflow_stage: run.workflow_stage,
519
- parent_run_key: run.parent_run_key,
520
- event_type: String(options.eventType || 'update'),
521
- phase: options.phase ? String(options.phase).trim() : null,
522
- status: options.status ? String(options.status).trim() : run.status || null,
523
- tool_name: options.toolName ? String(options.toolName).trim() : null,
524
- message: String(options.message || ''),
525
- payload_json: payloadJson,
526
- sequence_no: nextExecutionSequence(db, run.run_key),
527
- parent_event_id: options.parentEventId || null,
528
- created_at: now
770
+ insertExecutionEvent(db, {
771
+ task_key: run.task_key,
772
+ run_key: run.run_key,
773
+ agent_name: run.agent_name,
774
+ agent_kind: run.agent_kind,
775
+ squad_slug: run.squad_slug,
776
+ session_key: run.session_key,
777
+ source: run.source,
778
+ workflow_id: run.workflow_id,
779
+ workflow_stage: run.workflow_stage,
780
+ parent_run_key: run.parent_run_key,
781
+ event_type: String(options.eventType || 'update'),
782
+ phase: options.phase ? String(options.phase).trim() : null,
783
+ status: options.status ? String(options.status).trim() : run.status || null,
784
+ tool_name: options.toolName ? String(options.toolName).trim() : null,
785
+ message: String(options.message || ''),
786
+ payload_json: payloadJson,
787
+ sequence_no: nextExecutionSequence(db, run.run_key),
788
+ parent_event_id: options.parentEventId || null,
789
+ created_at: now
790
+ });
529
791
  });
792
+
793
+ doInsert();
530
794
  }
531
795
 
532
796
  function startTask(db, options) {
533
797
  const now = nowIso();
534
798
  const taskKey = String(options.taskKey || createTaskKey(options.title));
535
799
  const status = normalizeTaskStatus(options.status, 'running');
800
+ const metaJson = options.metaJson && typeof options.metaJson === 'object'
801
+ ? JSON.stringify(options.metaJson)
802
+ : (typeof options.metaJson === 'string' && options.metaJson.trim() ? options.metaJson.trim() : null);
536
803
 
537
804
  db.prepare(`
538
805
  INSERT INTO tasks (
539
- task_key, squad_slug, session_key, title, goal, status, created_by,
540
- created_at, updated_at, finished_at
806
+ task_key, squad_slug, session_key, task_kind, parent_task_key,
807
+ title, goal, meta_json, status, created_by, created_at, updated_at, finished_at
541
808
  ) VALUES (
542
- @task_key, @squad_slug, @session_key, @title, @goal, @status, @created_by,
543
- @created_at, @updated_at, @finished_at
809
+ @task_key, @squad_slug, @session_key, @task_kind, @parent_task_key,
810
+ @title, @goal, @meta_json, @status, @created_by, @created_at, @updated_at, @finished_at
544
811
  )
545
812
  `).run({
546
813
  task_key: taskKey,
547
814
  squad_slug: options.squadSlug ? String(options.squadSlug).trim() : null,
548
815
  session_key: options.sessionKey ? String(options.sessionKey).trim() : null,
816
+ task_kind: options.taskKind ? String(options.taskKind).trim() : null,
817
+ parent_task_key: options.parentTaskKey ? String(options.parentTaskKey).trim() : null,
549
818
  title: String(options.title).trim(),
550
819
  goal: options.goal ? String(options.goal).trim() : null,
820
+ meta_json: metaJson,
551
821
  status,
552
822
  created_by: options.createdBy ? String(options.createdBy).trim() : null,
553
823
  created_at: now,
@@ -566,12 +836,18 @@ function updateTask(db, options) {
566
836
 
567
837
  const now = nowIso();
568
838
  const nextStatus = normalizeTaskStatus(options.status, existing.status || 'running');
839
+ const metaJson = options.metaJson && typeof options.metaJson === 'object'
840
+ ? JSON.stringify(options.metaJson)
841
+ : (typeof options.metaJson === 'string' && options.metaJson.trim() ? options.metaJson.trim() : null);
569
842
 
570
843
  db.prepare(`
571
844
  UPDATE tasks
572
845
  SET
573
846
  status = @status,
574
847
  goal = COALESCE(@goal, goal),
848
+ task_kind = COALESCE(@task_kind, task_kind),
849
+ parent_task_key = COALESCE(@parent_task_key, parent_task_key),
850
+ meta_json = COALESCE(@meta_json, meta_json),
575
851
  updated_at = @updated_at,
576
852
  finished_at = CASE
577
853
  WHEN @status IN ('completed', 'failed') THEN @updated_at
@@ -582,6 +858,9 @@ function updateTask(db, options) {
582
858
  task_key: String(options.taskKey),
583
859
  status: nextStatus,
584
860
  goal: options.goal ? String(options.goal).trim() : null,
861
+ task_kind: options.taskKind ? String(options.taskKind).trim() : null,
862
+ parent_task_key: options.parentTaskKey ? String(options.parentTaskKey).trim() : null,
863
+ meta_json: metaJson,
585
864
  updated_at: now
586
865
  });
587
866
 
@@ -696,6 +975,52 @@ function parseJsonArray(value) {
696
975
  }
697
976
  }
698
977
 
978
+
979
+ function parseJsonObject(value) {
980
+ if (!value) return null;
981
+ try {
982
+ const parsed = JSON.parse(value);
983
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
984
+ } catch {
985
+ return null;
986
+ }
987
+ }
988
+
989
+ function getTaskPlanProgress(meta) {
990
+ const steps = Array.isArray(meta?.plan_steps) ? meta.plan_steps : [];
991
+ return {
992
+ plan_steps_done: steps.filter((step) => step && step.done).length,
993
+ plan_steps_total: steps.length
994
+ };
995
+ }
996
+
997
+ function decorateTaskSnapshotRow(row) {
998
+ const meta = parseJsonObject(row.meta_json);
999
+ const progress = getTaskPlanProgress(meta);
1000
+ row.meta = meta;
1001
+ row.plan_steps_done = progress.plan_steps_done;
1002
+ row.plan_steps_total = progress.plan_steps_total;
1003
+ row.is_live_session = row.task_kind === 'live_session';
1004
+ row.is_micro_task = row.task_kind === 'micro_task';
1005
+ return row;
1006
+ }
1007
+
1008
+ function decorateRunSnapshotRow(row) {
1009
+ row.used_skills = parseJsonArray(row.used_skills_json);
1010
+ row.is_live = row.source === 'live';
1011
+ row.is_handoff_child = Boolean(row.parent_run_key);
1012
+ return row;
1013
+ }
1014
+
1015
+ function decorateExecutionEventSnapshotRow(row) {
1016
+ const payload = parseJsonObject(row.payload_json);
1017
+ row.payload = payload;
1018
+ row.is_handoff = row.event_type === 'handoff';
1019
+ row.handoff_from = payload?.from || row.agent_name || null;
1020
+ row.handoff_to = payload?.to || null;
1021
+ return row;
1022
+ }
1023
+
699
1024
  function upsertSquadManifest(db, options) {
700
1025
  const now = nowIso();
701
1026
  const slug = String(options.slug).trim();
@@ -1110,7 +1435,7 @@ function startRun(db, options) {
1110
1435
 
1111
1436
  appendRunEvent(db, {
1112
1437
  runKey,
1113
- eventType: 'start',
1438
+ eventType: String(options.eventType || 'start'),
1114
1439
  phase: options.phase || 'run',
1115
1440
  status,
1116
1441
  message: String(options.message || options.title || 'Agent started'),
@@ -1242,7 +1567,7 @@ function getStatusSnapshot(db) {
1242
1567
 
1243
1568
  const activeTasks = db.prepare(`
1244
1569
  SELECT
1245
- task_key, squad_slug, session_key, title, goal, status, created_by, created_at, updated_at,
1570
+ task_key, squad_slug, session_key, task_kind, parent_task_key, title, goal, meta_json, status, created_by, created_at, updated_at,
1246
1571
  (
1247
1572
  SELECT COUNT(*)
1248
1573
  FROM agent_runs
@@ -1252,7 +1577,29 @@ function getStatusSnapshot(db) {
1252
1577
  SELECT COUNT(*)
1253
1578
  FROM artifacts
1254
1579
  WHERE artifacts.task_key = tasks.task_key
1255
- ) AS artifact_count
1580
+ ) AS artifact_count,
1581
+ (
1582
+ SELECT agent_name
1583
+ FROM agent_runs
1584
+ WHERE agent_runs.task_key = tasks.task_key
1585
+ ORDER BY CASE WHEN agent_runs.status IN ('queued', 'running') THEN 0 ELSE 1 END, updated_at DESC, started_at DESC
1586
+ LIMIT 1
1587
+ ) AS latest_agent_name,
1588
+ (
1589
+ SELECT COUNT(*)
1590
+ FROM tasks AS child_tasks
1591
+ WHERE child_tasks.parent_task_key = tasks.task_key
1592
+ ) AS child_task_count,
1593
+ (
1594
+ SELECT COUNT(*)
1595
+ FROM tasks AS child_tasks
1596
+ WHERE child_tasks.parent_task_key = tasks.task_key AND child_tasks.status = 'completed'
1597
+ ) AS completed_child_task_count,
1598
+ (
1599
+ SELECT COUNT(*)
1600
+ FROM agent_runs AS handoff_runs
1601
+ WHERE handoff_runs.task_key = tasks.task_key AND handoff_runs.parent_run_key IS NOT NULL
1602
+ ) AS handoff_count
1256
1603
  FROM tasks
1257
1604
  WHERE status IN ('queued', 'running')
1258
1605
  ORDER BY updated_at DESC, created_at DESC
@@ -1260,7 +1607,7 @@ function getStatusSnapshot(db) {
1260
1607
 
1261
1608
  const recentTasks = db.prepare(`
1262
1609
  SELECT
1263
- task_key, squad_slug, session_key, title, goal, status, created_by, created_at, updated_at, finished_at,
1610
+ task_key, squad_slug, session_key, task_kind, parent_task_key, title, goal, meta_json, status, created_by, created_at, updated_at, finished_at,
1264
1611
  (
1265
1612
  SELECT COUNT(*)
1266
1613
  FROM agent_runs
@@ -1270,7 +1617,29 @@ function getStatusSnapshot(db) {
1270
1617
  SELECT COUNT(*)
1271
1618
  FROM artifacts
1272
1619
  WHERE artifacts.task_key = tasks.task_key
1273
- ) AS artifact_count
1620
+ ) AS artifact_count,
1621
+ (
1622
+ SELECT agent_name
1623
+ FROM agent_runs
1624
+ WHERE agent_runs.task_key = tasks.task_key
1625
+ ORDER BY CASE WHEN agent_runs.status IN ('queued', 'running') THEN 0 ELSE 1 END, updated_at DESC, started_at DESC
1626
+ LIMIT 1
1627
+ ) AS latest_agent_name,
1628
+ (
1629
+ SELECT COUNT(*)
1630
+ FROM tasks AS child_tasks
1631
+ WHERE child_tasks.parent_task_key = tasks.task_key
1632
+ ) AS child_task_count,
1633
+ (
1634
+ SELECT COUNT(*)
1635
+ FROM tasks AS child_tasks
1636
+ WHERE child_tasks.parent_task_key = tasks.task_key AND child_tasks.status = 'completed'
1637
+ ) AS completed_child_task_count,
1638
+ (
1639
+ SELECT COUNT(*)
1640
+ FROM agent_runs AS handoff_runs
1641
+ WHERE handoff_runs.task_key = tasks.task_key AND handoff_runs.parent_run_key IS NOT NULL
1642
+ ) AS handoff_count
1274
1643
  FROM tasks
1275
1644
  ORDER BY updated_at DESC, created_at DESC
1276
1645
  LIMIT 20
@@ -1303,17 +1672,35 @@ function getStatusSnapshot(db) {
1303
1672
  `).all();
1304
1673
 
1305
1674
  for (const row of activeRuns) {
1306
- row.used_skills = parseJsonArray(row.used_skills_json);
1675
+ decorateRunSnapshotRow(row);
1307
1676
  }
1308
1677
 
1309
1678
  for (const row of recentRuns) {
1310
- row.used_skills = parseJsonArray(row.used_skills_json);
1679
+ decorateRunSnapshotRow(row);
1680
+ }
1681
+
1682
+ for (const row of activeTasks) {
1683
+ decorateTaskSnapshotRow(row);
1684
+ }
1685
+
1686
+ for (const row of recentTasks) {
1687
+ decorateTaskSnapshotRow(row);
1311
1688
  }
1312
1689
 
1313
1690
  for (const row of recentContentItems) {
1314
1691
  row.used_skills = parseJsonArray(row.used_skills_json);
1315
1692
  }
1316
1693
 
1694
+ for (const row of recentExecutionEvents) {
1695
+ decorateExecutionEventSnapshotRow(row);
1696
+ }
1697
+
1698
+ const activeLiveSessions = activeTasks.filter((task) => task.task_kind === 'live_session');
1699
+ const activeMicroTasks = activeTasks.filter((task) => task.task_kind === 'micro_task');
1700
+ const recentLiveSessions = recentTasks.filter((task) => task.task_kind === 'live_session');
1701
+ const recentMicroTasks = recentTasks.filter((task) => task.task_kind === 'micro_task');
1702
+ const recentHandoffs = recentExecutionEvents.filter((event) => event.event_type === 'handoff');
1703
+
1317
1704
  return {
1318
1705
  taskCounts,
1319
1706
  counts,
@@ -1321,6 +1708,11 @@ function getStatusSnapshot(db) {
1321
1708
  recentTasks,
1322
1709
  activeRuns,
1323
1710
  recentRuns,
1711
+ activeLiveSessions,
1712
+ activeMicroTasks,
1713
+ recentLiveSessions,
1714
+ recentMicroTasks,
1715
+ recentHandoffs,
1324
1716
  recentArtifacts,
1325
1717
  recentContentItems,
1326
1718
  recentExecutionEvents
@@ -1374,6 +1766,7 @@ async function clearAgentSession(runtimeDir, agentName) {
1374
1766
  async function logAgentEvent(db, runtimeDir, options) {
1375
1767
  const agentName = String(options.agentName || 'unknown').trim();
1376
1768
  const squadSlug = options.squadSlug ? String(options.squadSlug).trim() : null;
1769
+ const sessionKey = options.sessionKey ? String(options.sessionKey).trim() : null;
1377
1770
  const isFinish = Boolean(options.finish);
1378
1771
  const now = nowIso();
1379
1772
 
@@ -1442,6 +1835,7 @@ async function logAgentEvent(db, runtimeDir, options) {
1442
1835
  taskKey = startTask(db, {
1443
1836
  title: taskTitle,
1444
1837
  squadSlug: null,
1838
+ sessionKey,
1445
1839
  status: 'running',
1446
1840
  createdBy: agentName
1447
1841
  });
@@ -1450,10 +1844,11 @@ async function logAgentEvent(db, runtimeDir, options) {
1450
1844
  agentName,
1451
1845
  agentKind: 'official',
1452
1846
  squadSlug: null,
1847
+ sessionKey,
1453
1848
  title: taskTitle,
1454
1849
  message: options.message || 'Iniciando'
1455
1850
  });
1456
- await writeAgentSession(runtimeDir, agentName, { runKey, taskKey, startedAt: now, finished: false });
1851
+ await writeAgentSession(runtimeDir, agentName, { runKey, taskKey, sessionKey, startedAt: now, finished: false });
1457
1852
  } else {
1458
1853
  appendRunEvent(db, {
1459
1854
  runKey,
@@ -1487,6 +1882,549 @@ async function logAgentEvent(db, runtimeDir, options) {
1487
1882
  return { runKey, taskKey };
1488
1883
  }
1489
1884
 
1885
+ // --- Squad Investigations CRUD ---
1886
+
1887
+ function insertInvestigation(db, options = {}) {
1888
+ const slug = options.investigationSlug || `inv-${slugify(options.domain || 'unknown')}-${Date.now()}`;
1889
+ const now = nowIso();
1890
+ db.prepare(`
1891
+ INSERT OR REPLACE INTO squad_investigations
1892
+ (investigation_slug, domain, mode, dimensions_covered, total_dimensions,
1893
+ confidence, report_path, linked_squad_slug, created_at, updated_at)
1894
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1895
+ `).run(
1896
+ slug,
1897
+ String(options.domain || ''),
1898
+ String(options.mode || 'full'),
1899
+ Number(options.dimensionsCovered) || 0,
1900
+ Number(options.totalDimensions) || 7,
1901
+ Number(options.confidence) || 0,
1902
+ options.reportPath || null,
1903
+ options.linkedSquadSlug || null,
1904
+ now,
1905
+ now
1906
+ );
1907
+ return slug;
1908
+ }
1909
+
1910
+ function listInvestigations(db) {
1911
+ return db.prepare(`
1912
+ SELECT * FROM squad_investigations ORDER BY created_at DESC
1913
+ `).all();
1914
+ }
1915
+
1916
+ function getInvestigation(db, slug) {
1917
+ return db.prepare(`
1918
+ SELECT * FROM squad_investigations WHERE investigation_slug = ?
1919
+ `).get(slug) || null;
1920
+ }
1921
+
1922
+ function linkInvestigation(db, investigationSlug, squadSlug) {
1923
+ const now = nowIso();
1924
+ const result = db.prepare(`
1925
+ UPDATE squad_investigations
1926
+ SET linked_squad_slug = ?, updated_at = ?
1927
+ WHERE investigation_slug = ?
1928
+ `).run(squadSlug, now, investigationSlug);
1929
+ return result.changes > 0;
1930
+ }
1931
+
1932
+ // --- Implementation Plans CRUD ---
1933
+
1934
+ function upsertImplementationPlan(db, options = {}) {
1935
+ const planId = options.planId || `plan-${slugify(options.projectName || 'proj')}-${Date.now()}`;
1936
+ const now = nowIso();
1937
+ db.prepare(`
1938
+ INSERT OR REPLACE INTO implementation_plans
1939
+ (plan_id, project_name, scope, feature_slug, status, classification,
1940
+ phases_total, phases_completed, source_artifacts, source_hash, created_at, updated_at)
1941
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
1942
+ `).run(
1943
+ planId,
1944
+ options.projectName || null,
1945
+ options.scope || 'project',
1946
+ options.featureSlug || null,
1947
+ options.status || 'draft',
1948
+ options.classification || null,
1949
+ Number(options.phasesTotal) || 0,
1950
+ Number(options.phasesCompleted) || 0,
1951
+ options.sourceArtifacts ? JSON.stringify(options.sourceArtifacts) : null,
1952
+ options.sourceHash || null,
1953
+ now,
1954
+ now
1955
+ );
1956
+ return planId;
1957
+ }
1958
+
1959
+ function getImplementationPlan(db, planId) {
1960
+ return db.prepare(`
1961
+ SELECT * FROM implementation_plans WHERE plan_id = ?
1962
+ `).get(planId) || null;
1963
+ }
1964
+
1965
+ function listImplementationPlans(db) {
1966
+ return db.prepare(`
1967
+ SELECT * FROM implementation_plans ORDER BY created_at DESC
1968
+ `).all();
1969
+ }
1970
+
1971
+ function updateImplementationPlanStatus(db, planId, status) {
1972
+ const now = nowIso();
1973
+ const result = db.prepare(`
1974
+ UPDATE implementation_plans SET status = ?, updated_at = ? WHERE plan_id = ?
1975
+ `).run(status, now, planId);
1976
+ return result.changes > 0;
1977
+ }
1978
+
1979
+ function upsertPlanPhase(db, planId, phaseNumber, title, status) {
1980
+ db.prepare(`
1981
+ INSERT OR REPLACE INTO plan_phases (plan_id, phase_number, title, status, completed_at)
1982
+ VALUES (?, ?, ?, ?, ?)
1983
+ `).run(
1984
+ planId,
1985
+ phaseNumber,
1986
+ title,
1987
+ status || 'pending',
1988
+ status === 'completed' ? nowIso() : null
1989
+ );
1990
+ }
1991
+
1992
+ function updatePlanPhaseStatus(db, planId, phaseNumber, status, notes) {
1993
+ const now = nowIso();
1994
+ const result = db.prepare(`
1995
+ UPDATE plan_phases SET status = ?, completed_at = ?, notes = ?
1996
+ WHERE plan_id = ? AND phase_number = ?
1997
+ `).run(
1998
+ status,
1999
+ status === 'completed' ? now : null,
2000
+ notes || null,
2001
+ planId,
2002
+ phaseNumber
2003
+ );
2004
+ if (result.changes > 0 && status === 'completed') {
2005
+ db.prepare(`
2006
+ UPDATE implementation_plans
2007
+ SET phases_completed = (SELECT COUNT(*) FROM plan_phases WHERE plan_id = ? AND status = 'completed'),
2008
+ updated_at = ?
2009
+ WHERE plan_id = ?
2010
+ `).run(planId, now, planId);
2011
+ }
2012
+ return result.changes > 0;
2013
+ }
2014
+
2015
+ function getPlanPhases(db, planId) {
2016
+ return db.prepare(`
2017
+ SELECT * FROM plan_phases WHERE plan_id = ? ORDER BY phase_number
2018
+ `).all(planId);
2019
+ }
2020
+
2021
+ // --- Squad Execution Plans CRUD ---
2022
+
2023
+ function upsertSquadExecutionPlan(db, options = {}) {
2024
+ const planSlug = options.planSlug || `sqplan-${slugify(options.squadSlug || 'squad')}-${Date.now()}`;
2025
+ const now = nowIso();
2026
+ db.prepare(`
2027
+ INSERT OR REPLACE INTO squad_execution_plans
2028
+ (plan_slug, squad_slug, status, rounds_total, rounds_completed,
2029
+ based_on_blueprint, based_on_investigation, source_hash, created_at, updated_at)
2030
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2031
+ `).run(
2032
+ planSlug,
2033
+ options.squadSlug || '',
2034
+ options.status || 'draft',
2035
+ Number(options.roundsTotal) || 0,
2036
+ Number(options.roundsCompleted) || 0,
2037
+ options.basedOnBlueprint || null,
2038
+ options.basedOnInvestigation || null,
2039
+ options.sourceHash || null,
2040
+ now,
2041
+ now
2042
+ );
2043
+ return planSlug;
2044
+ }
2045
+
2046
+ function getSquadExecutionPlan(db, planSlug) {
2047
+ return db.prepare(`
2048
+ SELECT * FROM squad_execution_plans WHERE plan_slug = ?
2049
+ `).get(planSlug) || null;
2050
+ }
2051
+
2052
+ function getSquadExecutionPlanBySquad(db, squadSlug) {
2053
+ return db.prepare(`
2054
+ SELECT * FROM squad_execution_plans WHERE squad_slug = ? ORDER BY created_at DESC LIMIT 1
2055
+ `).get(squadSlug) || null;
2056
+ }
2057
+
2058
+ function listSquadExecutionPlans(db) {
2059
+ return db.prepare(`
2060
+ SELECT * FROM squad_execution_plans ORDER BY created_at DESC
2061
+ `).all();
2062
+ }
2063
+
2064
+ function updateSquadExecutionPlanStatus(db, planSlug, status) {
2065
+ const now = nowIso();
2066
+ const result = db.prepare(`
2067
+ UPDATE squad_execution_plans SET status = ?, updated_at = ? WHERE plan_slug = ?
2068
+ `).run(status, now, planSlug);
2069
+ return result.changes > 0;
2070
+ }
2071
+
2072
+ function upsertSquadPlanRound(db, planSlug, roundNumber, executorSlug, title, status) {
2073
+ db.prepare(`
2074
+ INSERT OR REPLACE INTO squad_plan_rounds (plan_slug, round_number, executor_slug, title, status, completed_at)
2075
+ VALUES (?, ?, ?, ?, ?, ?)
2076
+ `).run(
2077
+ planSlug,
2078
+ roundNumber,
2079
+ executorSlug,
2080
+ title,
2081
+ status || 'pending',
2082
+ status === 'completed' ? nowIso() : null
2083
+ );
2084
+ }
2085
+
2086
+ function updateSquadPlanRoundStatus(db, planSlug, roundNumber, status, notes) {
2087
+ const now = nowIso();
2088
+ const result = db.prepare(`
2089
+ UPDATE squad_plan_rounds SET status = ?, completed_at = ?, notes = ?
2090
+ WHERE plan_slug = ? AND round_number = ?
2091
+ `).run(
2092
+ status,
2093
+ status === 'completed' ? now : null,
2094
+ notes || null,
2095
+ planSlug,
2096
+ roundNumber
2097
+ );
2098
+ if (result.changes > 0 && status === 'completed') {
2099
+ db.prepare(`
2100
+ UPDATE squad_execution_plans
2101
+ SET rounds_completed = (SELECT COUNT(*) FROM squad_plan_rounds WHERE plan_slug = ? AND status = 'completed'),
2102
+ updated_at = ?
2103
+ WHERE plan_slug = ?
2104
+ `).run(planSlug, now, planSlug);
2105
+ }
2106
+ return result.changes > 0;
2107
+ }
2108
+
2109
+ function getSquadPlanRounds(db, planSlug) {
2110
+ return db.prepare(`
2111
+ SELECT * FROM squad_plan_rounds WHERE plan_slug = ? ORDER BY round_number
2112
+ `).all(planSlug);
2113
+ }
2114
+
2115
+ // --- Squad Learnings CRUD ---
2116
+
2117
+ function insertSquadLearning(db, options = {}) {
2118
+ const learningId = options.learningId || `sl-${slugify(options.squadSlug || 'squad')}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
2119
+ const now = nowIso();
2120
+ db.prepare(`
2121
+ INSERT OR REPLACE INTO squad_learnings
2122
+ (learning_id, squad_slug, type, title, signal, confidence, frequency,
2123
+ last_reinforced, applies_to, file_path, promoted_to, status,
2124
+ source_session, evidence, created_at, updated_at)
2125
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2126
+ `).run(
2127
+ learningId,
2128
+ options.squadSlug || '',
2129
+ options.type || 'preference',
2130
+ options.title || '',
2131
+ options.signal || 'explicit',
2132
+ options.confidence || 'medium',
2133
+ Number(options.frequency) || 1,
2134
+ options.lastReinforced || now,
2135
+ options.appliesTo || 'squad',
2136
+ options.filePath || null,
2137
+ options.promotedTo || null,
2138
+ options.status || 'active',
2139
+ options.sourceSession || null,
2140
+ options.evidence || null,
2141
+ now,
2142
+ now
2143
+ );
2144
+ return learningId;
2145
+ }
2146
+
2147
+ function listSquadLearnings(db, squadSlug, statusFilter) {
2148
+ if (statusFilter) {
2149
+ return db.prepare(`
2150
+ SELECT * FROM squad_learnings WHERE squad_slug = ? AND status = ? ORDER BY created_at DESC
2151
+ `).all(squadSlug, statusFilter);
2152
+ }
2153
+ return db.prepare(`
2154
+ SELECT * FROM squad_learnings WHERE squad_slug = ? ORDER BY created_at DESC
2155
+ `).all(squadSlug);
2156
+ }
2157
+
2158
+ function getSquadLearning(db, learningId) {
2159
+ return db.prepare(`
2160
+ SELECT * FROM squad_learnings WHERE learning_id = ?
2161
+ `).get(learningId) || null;
2162
+ }
2163
+
2164
+ function updateSquadLearningStatus(db, learningId, status) {
2165
+ const now = nowIso();
2166
+ const result = db.prepare(`
2167
+ UPDATE squad_learnings SET status = ?, updated_at = ? WHERE learning_id = ?
2168
+ `).run(status, now, learningId);
2169
+ return result.changes > 0;
2170
+ }
2171
+
2172
+ function reinforceSquadLearning(db, learningId) {
2173
+ const now = nowIso();
2174
+ const result = db.prepare(`
2175
+ UPDATE squad_learnings SET frequency = frequency + 1, last_reinforced = ?, updated_at = ? WHERE learning_id = ?
2176
+ `).run(now, now, learningId);
2177
+ return result.changes > 0;
2178
+ }
2179
+
2180
+ function promoteSquadLearning(db, learningId, promotedTo) {
2181
+ const now = nowIso();
2182
+ const result = db.prepare(`
2183
+ UPDATE squad_learnings SET status = 'promoted', promoted_to = ?, updated_at = ? WHERE learning_id = ?
2184
+ `).run(promotedTo, now, learningId);
2185
+ return result.changes > 0;
2186
+ }
2187
+
2188
+ function archiveStaleSquadLearnings(db, squadSlug, staleDays) {
2189
+ const days = Number(staleDays) || 90;
2190
+ const cutoff = new Date(Date.now() - days * 86400000).toISOString();
2191
+ const result = db.prepare(`
2192
+ UPDATE squad_learnings SET status = 'stale', updated_at = datetime('now')
2193
+ WHERE squad_slug = ? AND status = 'active' AND last_reinforced < ?
2194
+ `).run(squadSlug, cutoff);
2195
+ return result.changes;
2196
+ }
2197
+
2198
+ function getSquadLearningStats(db, squadSlug) {
2199
+ return db.prepare(`
2200
+ SELECT type, status, COUNT(*) as count FROM squad_learnings
2201
+ WHERE squad_slug = ? GROUP BY type, status ORDER BY type, status
2202
+ `).all(squadSlug);
2203
+ }
2204
+
2205
+ // --- Project Learnings CRUD ---
2206
+
2207
+ function insertProjectLearning(db, options = {}) {
2208
+ const learningId = options.learningId || `pl-${slugify(options.projectName || 'proj')}-${Date.now()}`;
2209
+ const now = nowIso();
2210
+ db.prepare(`
2211
+ INSERT OR REPLACE INTO project_learnings
2212
+ (learning_id, project_name, feature_slug, type, title, confidence, frequency,
2213
+ last_reinforced, applies_to, promoted_to, status,
2214
+ source_session, evidence, created_at, updated_at)
2215
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2216
+ `).run(
2217
+ learningId,
2218
+ options.projectName || null,
2219
+ options.featureSlug || null,
2220
+ options.type || 'preference',
2221
+ options.title || '',
2222
+ options.confidence || 'medium',
2223
+ Number(options.frequency) || 1,
2224
+ options.lastReinforced || now,
2225
+ options.appliesTo || 'project',
2226
+ options.promotedTo || null,
2227
+ options.status || 'active',
2228
+ options.sourceSession || null,
2229
+ options.evidence || null,
2230
+ now,
2231
+ now
2232
+ );
2233
+ return learningId;
2234
+ }
2235
+
2236
+ function listProjectLearnings(db, statusFilter) {
2237
+ if (statusFilter) {
2238
+ return db.prepare(`
2239
+ SELECT * FROM project_learnings WHERE status = ? ORDER BY created_at DESC
2240
+ `).all(statusFilter);
2241
+ }
2242
+ return db.prepare(`
2243
+ SELECT * FROM project_learnings ORDER BY created_at DESC
2244
+ `).all();
2245
+ }
2246
+
2247
+ function getProjectLearning(db, learningId) {
2248
+ return db.prepare(`
2249
+ SELECT * FROM project_learnings WHERE learning_id = ?
2250
+ `).get(learningId) || null;
2251
+ }
2252
+
2253
+ function updateProjectLearningStatus(db, learningId, status) {
2254
+ const now = nowIso();
2255
+ const result = db.prepare(`
2256
+ UPDATE project_learnings SET status = ?, updated_at = ? WHERE learning_id = ?
2257
+ `).run(status, now, learningId);
2258
+ return result.changes > 0;
2259
+ }
2260
+
2261
+ function reinforceProjectLearning(db, learningId) {
2262
+ const now = nowIso();
2263
+ const result = db.prepare(`
2264
+ UPDATE project_learnings SET frequency = frequency + 1, last_reinforced = ?, updated_at = ? WHERE learning_id = ?
2265
+ `).run(now, now, learningId);
2266
+ return result.changes > 0;
2267
+ }
2268
+
2269
+ function promoteProjectLearning(db, learningId, promotedTo) {
2270
+ const now = nowIso();
2271
+ const result = db.prepare(`
2272
+ UPDATE project_learnings SET status = 'promoted', promoted_to = ?, updated_at = ? WHERE learning_id = ?
2273
+ `).run(promotedTo, now, learningId);
2274
+ return result.changes > 0;
2275
+ }
2276
+
2277
+ function getProjectLearningStats(db) {
2278
+ return db.prepare(`
2279
+ SELECT type, status, COUNT(*) as count FROM project_learnings
2280
+ GROUP BY type, status ORDER BY type, status
2281
+ `).all();
2282
+ }
2283
+
2284
+ // --- Squad Metrics CRUD ---
2285
+
2286
+ function upsertSquadMetric(db, { squadSlug, metricKey, value, unit, period, baseline, target, source, notes }) {
2287
+ db.prepare(`
2288
+ INSERT INTO squad_metrics (squad_slug, metric_key, metric_value, metric_unit, period, baseline, target, source, notes)
2289
+ VALUES (@squad_slug, @metric_key, @metric_value, @metric_unit, @period, @baseline, @target, @source, @notes)
2290
+ ON CONFLICT(squad_slug, metric_key, period) DO UPDATE SET
2291
+ metric_value = excluded.metric_value,
2292
+ metric_unit = excluded.metric_unit,
2293
+ baseline = COALESCE(excluded.baseline, squad_metrics.baseline),
2294
+ target = COALESCE(excluded.target, squad_metrics.target),
2295
+ source = excluded.source,
2296
+ notes = COALESCE(excluded.notes, squad_metrics.notes)
2297
+ `).run({
2298
+ squad_slug: String(squadSlug).trim(),
2299
+ metric_key: String(metricKey).trim(),
2300
+ metric_value: Number(value),
2301
+ metric_unit: unit ? String(unit).trim() : null,
2302
+ period: period ? String(period).trim() : null,
2303
+ baseline: baseline != null ? Number(baseline) : null,
2304
+ target: target != null ? Number(target) : null,
2305
+ source: source ? String(source).trim() : 'manual',
2306
+ notes: notes ? String(notes).trim() : null
2307
+ });
2308
+ }
2309
+
2310
+ function listSquadMetrics(db, squadSlug, period) {
2311
+ if (period) {
2312
+ return db.prepare(
2313
+ 'SELECT * FROM squad_metrics WHERE squad_slug = ? AND period = ? ORDER BY metric_key ASC'
2314
+ ).all(squadSlug, period);
2315
+ }
2316
+ return db.prepare(
2317
+ 'SELECT * FROM squad_metrics WHERE squad_slug = ? ORDER BY period DESC, metric_key ASC'
2318
+ ).all(squadSlug);
2319
+ }
2320
+
2321
+ function deleteSquadMetric(db, squadSlug, metricKey, period) {
2322
+ db.prepare(
2323
+ 'DELETE FROM squad_metrics WHERE squad_slug = ? AND metric_key = ? AND period = ?'
2324
+ ).run(squadSlug, metricKey, period);
2325
+ }
2326
+
2327
+ // --- Worker Runs CRUD ---
2328
+
2329
+ function insertWorkerRun(db, { squadSlug, workerSlug, triggerType, inputJson, outputJson, status, errorMessage, durationMs, attempt, conversationId }) {
2330
+ const now = nowIso();
2331
+ return db.prepare(`
2332
+ INSERT INTO worker_runs (squad_slug, worker_slug, trigger_type, input_json, output_json, status, error_message, duration_ms, attempt, conversation_id, created_at, completed_at)
2333
+ VALUES (@squad_slug, @worker_slug, @trigger_type, @input_json, @output_json, @status, @error_message, @duration_ms, @attempt, @conversation_id, @created_at, @completed_at)
2334
+ `).run({
2335
+ squad_slug: String(squadSlug).trim(),
2336
+ worker_slug: String(workerSlug).trim(),
2337
+ trigger_type: String(triggerType || 'manual').trim(),
2338
+ input_json: inputJson || null,
2339
+ output_json: outputJson || null,
2340
+ status: String(status || 'running').trim(),
2341
+ error_message: errorMessage || null,
2342
+ duration_ms: durationMs != null ? Number(durationMs) : null,
2343
+ attempt: Number(attempt || 1),
2344
+ conversation_id: conversationId || null,
2345
+ created_at: now,
2346
+ completed_at: (status === 'completed' || status === 'failed') ? now : null
2347
+ });
2348
+ }
2349
+
2350
+ function listWorkerRuns(db, squadSlug, limit = 50) {
2351
+ return db.prepare(
2352
+ 'SELECT * FROM worker_runs WHERE squad_slug = ? ORDER BY created_at DESC, id DESC LIMIT ?'
2353
+ ).all(squadSlug, limit);
2354
+ }
2355
+
2356
+ function getWorkerRunStats(db, squadSlug) {
2357
+ return db.prepare(`
2358
+ SELECT worker_slug, status, COUNT(*) as count,
2359
+ AVG(duration_ms) as avg_duration_ms
2360
+ FROM worker_runs WHERE squad_slug = ?
2361
+ GROUP BY worker_slug, status
2362
+ ORDER BY worker_slug, status
2363
+ `).all(squadSlug);
2364
+ }
2365
+
2366
+ // --- MCP Status CRUD ---
2367
+
2368
+ function upsertMcpStatus(db, { squadSlug, mcpSlug, connector, status, lastError }) {
2369
+ db.prepare(`
2370
+ INSERT INTO mcp_status (squad_slug, mcp_slug, connector, status, last_check, last_error)
2371
+ VALUES (?, ?, ?, ?, datetime('now'), ?)
2372
+ ON CONFLICT(squad_slug, mcp_slug) DO UPDATE SET
2373
+ connector = excluded.connector,
2374
+ status = excluded.status,
2375
+ last_check = excluded.last_check,
2376
+ last_error = excluded.last_error
2377
+ `).run(squadSlug, mcpSlug, connector, status || 'unconfigured', lastError || null);
2378
+ }
2379
+
2380
+ function incrementMcpCalls(db, squadSlug, mcpSlug, failed) {
2381
+ if (failed) {
2382
+ db.prepare(`
2383
+ UPDATE mcp_status SET calls_total = calls_total + 1, calls_failed = calls_failed + 1
2384
+ WHERE squad_slug = ? AND mcp_slug = ?
2385
+ `).run(squadSlug, mcpSlug);
2386
+ } else {
2387
+ db.prepare(`
2388
+ UPDATE mcp_status SET calls_total = calls_total + 1
2389
+ WHERE squad_slug = ? AND mcp_slug = ?
2390
+ `).run(squadSlug, mcpSlug);
2391
+ }
2392
+ }
2393
+
2394
+ function listMcpStatus(db, squadSlug) {
2395
+ return db.prepare('SELECT * FROM mcp_status WHERE squad_slug = ? ORDER BY mcp_slug').all(squadSlug);
2396
+ }
2397
+
2398
+ function getMcpStatus(db, squadSlug, mcpSlug) {
2399
+ return db.prepare('SELECT * FROM mcp_status WHERE squad_slug = ? AND mcp_slug = ?').get(squadSlug, mcpSlug);
2400
+ }
2401
+
2402
+ // --- ROI Config CRUD ---
2403
+
2404
+ function upsertROIConfig(db, { squadSlug, pricingModel, setupFee, monthlyFee, percentageFee, percentageBase, currency, contractMonths }) {
2405
+ db.prepare(`
2406
+ INSERT INTO squad_roi_config (squad_slug, pricing_model, setup_fee, monthly_fee, percentage_fee, percentage_base, currency, contract_months)
2407
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
2408
+ ON CONFLICT(squad_slug) DO UPDATE SET
2409
+ pricing_model = excluded.pricing_model,
2410
+ setup_fee = excluded.setup_fee,
2411
+ monthly_fee = excluded.monthly_fee,
2412
+ percentage_fee = excluded.percentage_fee,
2413
+ percentage_base = excluded.percentage_base,
2414
+ currency = excluded.currency,
2415
+ contract_months = excluded.contract_months,
2416
+ updated_at = datetime('now')
2417
+ `).run(squadSlug, pricingModel || 'fixed', setupFee || null, monthlyFee || null, percentageFee || null, percentageBase || null, currency || 'BRL', contractMonths || 12);
2418
+ }
2419
+
2420
+ function getROIConfig(db, squadSlug) {
2421
+ return db.prepare('SELECT * FROM squad_roi_config WHERE squad_slug = ?').get(squadSlug);
2422
+ }
2423
+
2424
+ function deleteROIConfig(db, squadSlug) {
2425
+ return db.prepare('DELETE FROM squad_roi_config WHERE squad_slug = ?').run(squadSlug);
2426
+ }
2427
+
1490
2428
  module.exports = {
1491
2429
  resolveRuntimePaths,
1492
2430
  runtimeStoreExists,
@@ -1505,6 +2443,7 @@ module.exports = {
1505
2443
  appendRunEvent,
1506
2444
  logAgentEvent,
1507
2445
  readAgentSession,
2446
+ writeAgentSession,
1508
2447
  clearAgentSession,
1509
2448
  // Pipeline CRUD
1510
2449
  upsertPipeline,
@@ -1523,5 +2462,61 @@ module.exports = {
1523
2462
  listArtisanSquads,
1524
2463
  deleteArtisanSquad,
1525
2464
  addArtisanMessage,
1526
- getArtisanMessages
2465
+ getArtisanMessages,
2466
+ // Investigation CRUD
2467
+ insertInvestigation,
2468
+ listInvestigations,
2469
+ getInvestigation,
2470
+ linkInvestigation,
2471
+ // Implementation Plans CRUD
2472
+ upsertImplementationPlan,
2473
+ getImplementationPlan,
2474
+ listImplementationPlans,
2475
+ updateImplementationPlanStatus,
2476
+ upsertPlanPhase,
2477
+ updatePlanPhaseStatus,
2478
+ getPlanPhases,
2479
+ // Squad Execution Plans CRUD
2480
+ upsertSquadExecutionPlan,
2481
+ getSquadExecutionPlan,
2482
+ getSquadExecutionPlanBySquad,
2483
+ listSquadExecutionPlans,
2484
+ updateSquadExecutionPlanStatus,
2485
+ upsertSquadPlanRound,
2486
+ updateSquadPlanRoundStatus,
2487
+ getSquadPlanRounds,
2488
+ // Squad Learnings CRUD
2489
+ insertSquadLearning,
2490
+ listSquadLearnings,
2491
+ getSquadLearning,
2492
+ updateSquadLearningStatus,
2493
+ reinforceSquadLearning,
2494
+ promoteSquadLearning,
2495
+ archiveStaleSquadLearnings,
2496
+ getSquadLearningStats,
2497
+ // Project Learnings CRUD
2498
+ insertProjectLearning,
2499
+ listProjectLearnings,
2500
+ getProjectLearning,
2501
+ updateProjectLearningStatus,
2502
+ reinforceProjectLearning,
2503
+ promoteProjectLearning,
2504
+ getProjectLearningStats,
2505
+ // Squad Metrics CRUD
2506
+ upsertSquadMetric,
2507
+ listSquadMetrics,
2508
+ deleteSquadMetric,
2509
+ // Worker Runs CRUD
2510
+ insertWorkerRun,
2511
+ listWorkerRuns,
2512
+ getWorkerRunStats,
2513
+ // MCP Status CRUD
2514
+ upsertMcpStatus,
2515
+ incrementMcpCalls,
2516
+ listMcpStatus,
2517
+ getMcpStatus,
2518
+ // ROI Config CRUD
2519
+ upsertROIConfig,
2520
+ getROIConfig,
2521
+ deleteROIConfig
1527
2522
  };