@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
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const fs = require('node:fs/promises');
3
4
  const path = require('node:path');
4
5
  const {
5
6
  openRuntimeDb,
@@ -9,6 +10,107 @@ const {
9
10
  getTopologicalOrder
10
11
  } = require('../runtime-store');
11
12
 
13
+ /**
14
+ * Determine node completion status by checking handoffs.
15
+ * A node is "complete" if all its outgoing edges have consumed handoffs,
16
+ * or if it has no outgoing edges and has at least one incoming consumed handoff
17
+ * (or is the first node with no incoming edges and has produced output handoffs).
18
+ */
19
+ function classifyNodes(db, pipelineSlug, order, edges) {
20
+ const handoffs = db
21
+ .prepare('SELECT * FROM squad_handoffs WHERE pipeline_slug = ? ORDER BY created_at DESC')
22
+ .all(pipelineSlug);
23
+
24
+ const outgoing = {};
25
+ const incoming = {};
26
+ for (const slug of order) {
27
+ outgoing[slug] = [];
28
+ incoming[slug] = [];
29
+ }
30
+ for (const edge of edges) {
31
+ if (outgoing[edge.source_squad]) outgoing[edge.source_squad].push(edge);
32
+ if (incoming[edge.target_squad]) incoming[edge.target_squad].push(edge);
33
+ }
34
+
35
+ const nodeStatus = {};
36
+
37
+ for (const slug of order) {
38
+ const outEdges = outgoing[slug];
39
+ const inEdges = incoming[slug];
40
+
41
+ // Check if all outgoing handoffs are consumed
42
+ if (outEdges.length > 0) {
43
+ const allProduced = outEdges.every(edge =>
44
+ handoffs.some(h =>
45
+ h.from_squad === edge.source_squad &&
46
+ h.from_port === edge.source_port &&
47
+ (h.status === 'consumed' || h.status === 'pending')
48
+ )
49
+ );
50
+ const allConsumed = outEdges.every(edge =>
51
+ handoffs.some(h =>
52
+ h.from_squad === edge.source_squad &&
53
+ h.from_port === edge.source_port &&
54
+ h.status === 'consumed'
55
+ )
56
+ );
57
+
58
+ if (allConsumed) {
59
+ nodeStatus[slug] = 'completed';
60
+ } else if (allProduced) {
61
+ nodeStatus[slug] = 'produced';
62
+ } else {
63
+ nodeStatus[slug] = 'pending';
64
+ }
65
+ } else {
66
+ // Terminal node — check if all incoming handoffs are consumed
67
+ if (inEdges.length === 0) {
68
+ // Root node with no edges — mark pending
69
+ nodeStatus[slug] = 'pending';
70
+ } else {
71
+ const allInConsumed = inEdges.every(edge =>
72
+ handoffs.some(h =>
73
+ h.to_squad === edge.target_squad &&
74
+ h.to_port === edge.target_port &&
75
+ h.status === 'consumed'
76
+ )
77
+ );
78
+ nodeStatus[slug] = allInConsumed ? 'completed' : 'pending';
79
+ }
80
+ }
81
+ }
82
+
83
+ // First node with no incoming edges: if it has produced outputs, mark completed
84
+ for (const slug of order) {
85
+ if (incoming[slug].length === 0 && outgoing[slug].length > 0) {
86
+ if (nodeStatus[slug] === 'produced' || nodeStatus[slug] === 'completed') {
87
+ nodeStatus[slug] = 'completed';
88
+ }
89
+ }
90
+ }
91
+
92
+ return { nodeStatus, handoffs };
93
+ }
94
+
95
+ function findNextPendingNode(order, nodeStatus) {
96
+ // Find first node that is pending and whose dependencies are all completed
97
+ return order.find(slug => nodeStatus[slug] === 'pending') || null;
98
+ }
99
+
100
+ function findSquadOrchestratorAgent(projectDir, squadSlug) {
101
+ // Convention: squad orchestrator is at .aioson/squads/{slug}/agents/{slug}-orchestrator.md
102
+ // or the first agent in the squad
103
+ return `@${squadSlug}-orchestrator`;
104
+ }
105
+
106
+ async function requirePipelineSlug(slugArg, logger) {
107
+ if (!slugArg) {
108
+ logger.error('Usage: aioson squad:pipeline [path] --sub=run --pipeline=<slug>');
109
+ return null;
110
+ }
111
+ return slugArg;
112
+ }
113
+
12
114
  async function runSquadPipeline({ args = [], options = {}, logger = console } = {}) {
13
115
  const projectDir = path.resolve(process.cwd(), args[0] || '.');
14
116
  const subcommand = options.sub || args[1] || 'list';
@@ -87,7 +189,151 @@ async function runSquadPipeline({ args = [], options = {}, logger = console } =
87
189
  return { ok: true, pipeline: dag.pipeline, handoffs: { pending, consumed, failed } };
88
190
  }
89
191
 
90
- logger.error(`Unknown subcommand: ${subcommand}. Available: list, show, status`);
192
+ // --- NEW: run (guided mode) ---
193
+ if (subcommand === 'run' || subcommand === 'continue') {
194
+ const slug = await requirePipelineSlug(slugArg, logger);
195
+ if (!slug) return { ok: false, error: 'missing_slug' };
196
+
197
+ const dag = getPipelineDAG(db, slug);
198
+ if (!dag) {
199
+ logger.error(`Pipeline not found: ${slug}`);
200
+ return { ok: false, error: 'not_found' };
201
+ }
202
+
203
+ const order = getTopologicalOrder(db, slug);
204
+ if (!order) {
205
+ logger.error('Cycle detected in pipeline — cannot run.');
206
+ return { ok: false, error: 'cycle_detected' };
207
+ }
208
+
209
+ const { nodeStatus, handoffs } = classifyNodes(db, slug, order, dag.edges);
210
+
211
+ // Show pipeline progress
212
+ logger.log('');
213
+ logger.log(`Pipeline: ${dag.pipeline.name || dag.pipeline.slug}`);
214
+ logger.log(`Mode: guided (the system suggests, you execute)`);
215
+ logger.log('');
216
+
217
+ logger.log('Progress:');
218
+ for (const nodeSlugg of order) {
219
+ const status = nodeStatus[nodeSlugg];
220
+ const icon = status === 'completed' ? '[v]'
221
+ : status === 'produced' ? '[~]'
222
+ : '[>]';
223
+ // Only mark the first pending as [>], rest as [ ]
224
+ const displayIcon = status === 'pending'
225
+ ? (nodeSlugg === findNextPendingNode(order, nodeStatus) ? '[>]' : '[ ]')
226
+ : icon;
227
+ logger.log(` ${displayIcon} ${nodeSlugg} (${status})`);
228
+ }
229
+ logger.log('');
230
+
231
+ // Find next node to activate
232
+ const nextNode = findNextPendingNode(order, nodeStatus);
233
+
234
+ if (!nextNode) {
235
+ // All nodes completed
236
+ const allCompleted = order.every(s => nodeStatus[s] === 'completed');
237
+ if (allCompleted) {
238
+ logger.log('Pipeline completed! All nodes have been executed.');
239
+ return { ok: true, pipeline: slug, status: 'completed', nextNode: null };
240
+ }
241
+ logger.log('No actionable node found. Check pending handoffs.');
242
+ return { ok: true, pipeline: slug, status: 'blocked', nextNode: null };
243
+ }
244
+
245
+ // Check if next node has pending incoming handoffs to consume
246
+ const pendingIncoming = handoffs.filter(h =>
247
+ h.to_squad === nextNode && h.status === 'pending'
248
+ );
249
+
250
+ // Consume pending incoming handoffs for this node
251
+ if (pendingIncoming.length > 0) {
252
+ const updateStmt = db.prepare(
253
+ 'UPDATE squad_handoffs SET status = ?, consumed_at = ? WHERE id = ?'
254
+ );
255
+ for (const h of pendingIncoming) {
256
+ updateStmt.run('consumed', new Date().toISOString(), h.id);
257
+ }
258
+ logger.log(`Consumed ${pendingIncoming.length} incoming handoff(s) for ${nextNode}.`);
259
+ }
260
+
261
+ const orchestratorAgent = findSquadOrchestratorAgent(projectDir, nextNode);
262
+ logger.log(`Next: activate squad "${nextNode}"`);
263
+ logger.log(` Agent: ${orchestratorAgent}`);
264
+ logger.log(` Command: aioson agent ${orchestratorAgent} --tool=claude`);
265
+ logger.log('');
266
+ logger.log('After the squad completes its work, run:');
267
+ logger.log(` aioson squad:pipeline . --sub=run --pipeline=${slug}`);
268
+
269
+ return {
270
+ ok: true,
271
+ pipeline: slug,
272
+ status: 'running',
273
+ nextNode,
274
+ orchestratorAgent,
275
+ nodeStatus
276
+ };
277
+ }
278
+
279
+ // --- NEW: skip ---
280
+ if (subcommand === 'skip') {
281
+ const slug = await requirePipelineSlug(slugArg, logger);
282
+ if (!slug) return { ok: false, error: 'missing_slug' };
283
+
284
+ const dag = getPipelineDAG(db, slug);
285
+ if (!dag) {
286
+ logger.error(`Pipeline not found: ${slug}`);
287
+ return { ok: false, error: 'not_found' };
288
+ }
289
+
290
+ const order = getTopologicalOrder(db, slug);
291
+ if (!order) {
292
+ logger.error('Cycle detected — cannot skip.');
293
+ return { ok: false, error: 'cycle_detected' };
294
+ }
295
+
296
+ const { nodeStatus } = classifyNodes(db, slug, order, dag.edges);
297
+ const nextNode = findNextPendingNode(order, nodeStatus);
298
+
299
+ if (!nextNode) {
300
+ logger.log('No pending node to skip.');
301
+ return { ok: true, pipeline: slug, skipped: null };
302
+ }
303
+
304
+ // Create synthetic handoffs for all outgoing edges of the skipped node
305
+ const outEdges = dag.edges.filter(e => e.source_squad === nextNode);
306
+ const insertHandoff = db.prepare(`
307
+ INSERT INTO squad_handoffs (id, pipeline_slug, from_squad, from_port, to_squad, to_port, payload_json, status, created_at)
308
+ VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?)
309
+ `);
310
+
311
+ for (const edge of outEdges) {
312
+ const id = `skip-${nextNode}-${edge.target_squad}-${Date.now()}`;
313
+ insertHandoff.run(
314
+ id,
315
+ slug,
316
+ edge.source_squad,
317
+ edge.source_port,
318
+ edge.target_squad,
319
+ edge.target_port,
320
+ JSON.stringify({ skipped: true, reason: 'Node skipped by user' }),
321
+ new Date().toISOString()
322
+ );
323
+ }
324
+
325
+ logger.log(`Skipped node: ${nextNode}`);
326
+ if (outEdges.length > 0) {
327
+ logger.log(`Created ${outEdges.length} synthetic handoff(s) for downstream nodes.`);
328
+ }
329
+ logger.log('');
330
+ logger.log('Run again to see the next node:');
331
+ logger.log(` aioson squad:pipeline . --sub=run --pipeline=${slug}`);
332
+
333
+ return { ok: true, pipeline: slug, skipped: nextNode };
334
+ }
335
+
336
+ logger.error(`Unknown subcommand: ${subcommand}. Available: list, show, status, run, continue, skip`);
91
337
  return { ok: false, error: 'unknown_subcommand' };
92
338
  } finally {
93
339
  db.close();
@@ -0,0 +1,329 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const crypto = require('node:crypto');
6
+ const {
7
+ openRuntimeDb,
8
+ upsertSquadExecutionPlan,
9
+ getSquadExecutionPlan,
10
+ getSquadExecutionPlanBySquad,
11
+ listSquadExecutionPlans,
12
+ updateSquadExecutionPlanStatus,
13
+ upsertSquadPlanRound,
14
+ updateSquadPlanRoundStatus,
15
+ getSquadPlanRounds
16
+ } = require('../runtime-store');
17
+
18
+ const SQUADS_DIR = path.join('.aioson', 'squads');
19
+
20
+ async function pathExists(targetPath) {
21
+ try {
22
+ await fs.access(targetPath);
23
+ return true;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Compute hash of squad manifest for staleness detection.
31
+ */
32
+ async function computeManifestHash(projectDir, squadSlug) {
33
+ const manifestPath = path.resolve(projectDir, SQUADS_DIR, squadSlug, 'squad.manifest.json');
34
+ const hash = crypto.createHash('sha256');
35
+ try {
36
+ const stat = await fs.stat(manifestPath);
37
+ hash.update(`manifest:${stat.mtimeMs}`);
38
+ } catch {
39
+ hash.update('manifest:missing');
40
+ }
41
+ return hash.digest('hex').slice(0, 16);
42
+ }
43
+
44
+ /**
45
+ * Parse execution plan frontmatter.
46
+ */
47
+ function parsePlanFrontmatter(content) {
48
+ const text = String(content || '');
49
+ const match = text.match(/^---\n([\s\S]*?)\n---/);
50
+ if (!match) return {};
51
+ const meta = {};
52
+ for (const line of match[1].split('\n')) {
53
+ const [key, ...rest] = line.split(':');
54
+ if (key && rest.length) {
55
+ meta[key.trim()] = rest.join(':').trim().replace(/^"(.*)"$/, '$1');
56
+ }
57
+ }
58
+ return meta;
59
+ }
60
+
61
+ /**
62
+ * Count rounds in an execution plan markdown.
63
+ */
64
+ function countRounds(content) {
65
+ const text = String(content || '');
66
+ const matches = text.match(/^### Round \d+/gm);
67
+ return matches ? matches.length : 0;
68
+ }
69
+
70
+ /**
71
+ * Resolve the execution plan path for a squad.
72
+ */
73
+ function planPath(projectDir, squadSlug) {
74
+ return path.resolve(projectDir, SQUADS_DIR, squadSlug, 'docs', 'execution-plan.md');
75
+ }
76
+
77
+ /**
78
+ * Subcommand: show <slug>
79
+ * Shows the execution plan for a squad.
80
+ */
81
+ async function handleShow(projectDir, squadSlug, { logger, t }) {
82
+ if (!squadSlug) {
83
+ logger.error(t('squad_plan.slug_required'));
84
+ return { found: false };
85
+ }
86
+
87
+ const pp = planPath(projectDir, squadSlug);
88
+ if (!(await pathExists(pp))) {
89
+ logger.error(t('squad_plan.not_found', { slug: squadSlug }));
90
+ return { found: false };
91
+ }
92
+
93
+ const content = await fs.readFile(pp, 'utf8');
94
+ const meta = parsePlanFrontmatter(content);
95
+ const rounds = countRounds(content);
96
+
97
+ logger.log(`Execution Plan: ${squadSlug}`);
98
+ logger.log(`Status: ${meta.status || 'unknown'}`);
99
+ logger.log(`Rounds: ${rounds}`);
100
+ logger.log('');
101
+ logger.log(content);
102
+
103
+ return { found: true, meta, rounds };
104
+ }
105
+
106
+ /**
107
+ * Subcommand: status <slug>
108
+ * Shows progress of the execution plan from SQLite.
109
+ */
110
+ async function handleStatus(projectDir, squadSlug, { logger, t }) {
111
+ if (!squadSlug) {
112
+ logger.error(t('squad_plan.slug_required'));
113
+ return { found: false };
114
+ }
115
+
116
+ const handle = await openRuntimeDb(projectDir, { mustExist: true });
117
+ if (!handle) {
118
+ logger.error(t('squad_plan.no_runtime'));
119
+ return { found: false };
120
+ }
121
+ const { db } = handle;
122
+ try {
123
+ const plan = getSquadExecutionPlanBySquad(db, squadSlug);
124
+ if (!plan) {
125
+ logger.error(t('squad_plan.no_plan', { slug: squadSlug }));
126
+ return { found: false };
127
+ }
128
+
129
+ const rounds = getSquadPlanRounds(db, plan.plan_slug);
130
+ logger.log(`Plan: ${plan.plan_slug}`);
131
+ logger.log(`Squad: ${plan.squad_slug}`);
132
+ logger.log(`Status: ${plan.status}`);
133
+ logger.log(`Progress: ${plan.rounds_completed}/${plan.rounds_total}`);
134
+ logger.log('');
135
+ for (const rd of rounds) {
136
+ const icon = rd.status === 'completed' ? '✓' : rd.status === 'in_progress' ? '▸' : '○';
137
+ logger.log(` ${icon} Round ${rd.round_number}: ${rd.title} (@${rd.executor_slug}) [${rd.status}]`);
138
+ }
139
+ return { found: true, plan, rounds };
140
+ } finally {
141
+ db.close();
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Subcommand: checkpoint <slug> <round-number>
147
+ * Marks a round as completed.
148
+ */
149
+ async function handleCheckpoint(projectDir, squadSlug, roundNumber, { logger, t }) {
150
+ if (!squadSlug || !roundNumber || isNaN(Number(roundNumber))) {
151
+ logger.error(t('squad_plan.checkpoint_usage'));
152
+ return { updated: false };
153
+ }
154
+
155
+ const handle = await openRuntimeDb(projectDir, { mustExist: true });
156
+ if (!handle) {
157
+ logger.error(t('squad_plan.no_runtime'));
158
+ return { updated: false };
159
+ }
160
+ const { db } = handle;
161
+ try {
162
+ const plan = getSquadExecutionPlanBySquad(db, squadSlug);
163
+ if (!plan) {
164
+ logger.error(t('squad_plan.no_plan', { slug: squadSlug }));
165
+ return { updated: false };
166
+ }
167
+
168
+ const updated = updateSquadPlanRoundStatus(db, plan.plan_slug, Number(roundNumber), 'completed');
169
+ if (updated) {
170
+ logger.log(t('squad_plan.round_completed', { round: roundNumber }));
171
+ } else {
172
+ logger.error(t('squad_plan.round_not_found', { round: roundNumber }));
173
+ }
174
+ return { updated };
175
+ } finally {
176
+ db.close();
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Subcommand: stale <slug>
182
+ * Checks if the squad manifest changed after the plan was created.
183
+ */
184
+ async function handleStale(projectDir, squadSlug, { logger, t }) {
185
+ if (!squadSlug) {
186
+ logger.error(t('squad_plan.slug_required'));
187
+ return { found: false, stale: false };
188
+ }
189
+
190
+ const pp = planPath(projectDir, squadSlug);
191
+ if (!(await pathExists(pp))) {
192
+ logger.error(t('squad_plan.not_found', { slug: squadSlug }));
193
+ return { found: false, stale: false };
194
+ }
195
+
196
+ const content = await fs.readFile(pp, 'utf8');
197
+ const meta = parsePlanFrontmatter(content);
198
+ if (!meta.created) {
199
+ logger.log(t('squad_plan.no_created_date'));
200
+ return { found: true, stale: false };
201
+ }
202
+
203
+ const planDate = new Date(meta.created);
204
+ const manifestFile = path.resolve(projectDir, SQUADS_DIR, squadSlug, 'squad.manifest.json');
205
+ let stale = false;
206
+
207
+ try {
208
+ const stat = await fs.stat(manifestFile);
209
+ if (stat.mtime > planDate) {
210
+ logger.log(' ⚠ squad.manifest.json modified after plan was created');
211
+ stale = true;
212
+ }
213
+ } catch {
214
+ // manifest missing — not stale, just broken
215
+ }
216
+
217
+ // Also check blueprint
218
+ const designsDir = path.resolve(projectDir, SQUADS_DIR, '.designs');
219
+ try {
220
+ const files = await fs.readdir(designsDir);
221
+ const bpFile = files.find(f => f.startsWith(squadSlug) && f.endsWith('.blueprint.json'));
222
+ if (bpFile) {
223
+ const bpPath = path.join(designsDir, bpFile);
224
+ const stat = await fs.stat(bpPath);
225
+ if (stat.mtime > planDate) {
226
+ logger.log(' ⚠ blueprint modified after plan was created');
227
+ stale = true;
228
+ }
229
+ }
230
+ } catch {
231
+ // designs dir may not exist
232
+ }
233
+
234
+ if (stale) {
235
+ logger.log(t('squad_plan.is_stale'));
236
+ } else {
237
+ logger.log(t('squad_plan.is_fresh'));
238
+ }
239
+
240
+ return { found: true, stale };
241
+ }
242
+
243
+ /**
244
+ * Subcommand: register <slug>
245
+ * Registers an existing execution plan file into the runtime SQLite.
246
+ */
247
+ async function handleRegister(projectDir, squadSlug, { logger, t }) {
248
+ if (!squadSlug) {
249
+ logger.error(t('squad_plan.slug_required'));
250
+ return { registered: false };
251
+ }
252
+
253
+ const pp = planPath(projectDir, squadSlug);
254
+ if (!(await pathExists(pp))) {
255
+ logger.error(t('squad_plan.not_found', { slug: squadSlug }));
256
+ return { registered: false };
257
+ }
258
+
259
+ const content = await fs.readFile(pp, 'utf8');
260
+ const meta = parsePlanFrontmatter(content);
261
+ const rounds = countRounds(content);
262
+ const hash = await computeManifestHash(projectDir, squadSlug);
263
+
264
+ const handle = await openRuntimeDb(projectDir);
265
+ const { db } = handle;
266
+ try {
267
+ const planSlug = upsertSquadExecutionPlan(db, {
268
+ squadSlug,
269
+ status: meta.status || 'draft',
270
+ roundsTotal: rounds,
271
+ roundsCompleted: 0,
272
+ basedOnBlueprint: meta.based_on_blueprint || null,
273
+ basedOnInvestigation: meta.based_on_investigation || null,
274
+ sourceHash: hash
275
+ });
276
+ logger.log(t('squad_plan.registered', { planSlug, rounds }));
277
+ return { registered: true, planSlug };
278
+ } finally {
279
+ db.close();
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Main router for squad-plan subcommands.
285
+ */
286
+ async function run(projectDir, args, context) {
287
+ const sub = args[0] || 'show';
288
+ const rest = args.slice(1);
289
+
290
+ switch (sub) {
291
+ case 'show':
292
+ return handleShow(projectDir, rest[0], context);
293
+ case 'status':
294
+ return handleStatus(projectDir, rest[0], context);
295
+ case 'checkpoint':
296
+ return handleCheckpoint(projectDir, rest[0], rest[1], context);
297
+ case 'stale':
298
+ return handleStale(projectDir, rest[0], context);
299
+ case 'register':
300
+ return handleRegister(projectDir, rest[0], context);
301
+ default:
302
+ context.logger.error(`Unknown subcommand: ${sub}. Available: show, status, checkpoint, stale, register`);
303
+ return { error: true };
304
+ }
305
+ }
306
+
307
+ /**
308
+ * Entry point for CLI integration (same signature as other commands).
309
+ */
310
+ async function runSquadPlan({ args = [], options = {}, logger = console, t = (k) => k } = {}) {
311
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
312
+ const sub = options.sub || args[1] || 'show';
313
+ const slug = options.squad || args[2] || null;
314
+ const context = { logger, t };
315
+
316
+ if (sub === 'show') return handleShow(projectDir, slug, context);
317
+ if (sub === 'status') return handleStatus(projectDir, slug, context);
318
+ if (sub === 'checkpoint') {
319
+ const round = args[3] || options.round;
320
+ return handleCheckpoint(projectDir, slug, round, context);
321
+ }
322
+ if (sub === 'stale') return handleStale(projectDir, slug, context);
323
+ if (sub === 'register') return handleRegister(projectDir, slug, context);
324
+
325
+ logger.error(`Unknown subcommand: ${sub}. Available: show, status, checkpoint, stale, register`);
326
+ return { error: true };
327
+ }
328
+
329
+ module.exports = { run, runSquadPlan, handleShow, handleStatus, handleCheckpoint, handleStale, handleRegister };
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { getActiveProcesses, stopProcess, stopSquadProcesses } = require('../squad-dashboard/process-monitor');
5
+
6
+ function formatElapsed(seconds) {
7
+ if (seconds == null) return '-';
8
+ if (seconds < 60) return `${seconds}s`;
9
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m${seconds % 60}s`;
10
+ return `${Math.floor(seconds / 3600)}h${Math.floor((seconds % 3600) / 60)}m`;
11
+ }
12
+
13
+ async function runSquadProcesses({ args, options, logger }) {
14
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
15
+ const squadFilter = options.squad || null;
16
+
17
+ // --stop <pid>
18
+ if (options.stop && options.stop !== true) {
19
+ const result = await stopProcess(projectDir, options.stop);
20
+ if (result.ok) {
21
+ logger.log(`Process ${options.stop} stopped.`);
22
+ } else {
23
+ logger.error(`Failed to stop ${options.stop}: ${result.error}`);
24
+ }
25
+ return result;
26
+ }
27
+
28
+ // --stop-squad <squad>
29
+ if (options['stop-squad']) {
30
+ const slug = options['stop-squad'];
31
+ const results = await stopSquadProcesses(projectDir, slug);
32
+ const stopped = results.filter(r => r.ok).length;
33
+ logger.log(`Stopped ${stopped}/${results.length} processes for squad "${slug}".`);
34
+ return { ok: true, results };
35
+ }
36
+
37
+ // List
38
+ const processes = await getActiveProcesses(projectDir, squadFilter);
39
+ if (processes.length === 0) {
40
+ logger.log(squadFilter ? `No active processes for squad "${squadFilter}".` : 'No active processes.');
41
+ return { ok: true, processes: [] };
42
+ }
43
+
44
+ logger.log(`Active processes (${processes.length}):`);
45
+ for (const proc of processes) {
46
+ const status = proc.alive ? '[*]' : '[ ]';
47
+ const elapsed = formatElapsed(proc.elapsedSeconds);
48
+ const ctx = proc.contextPct != null ? ` ctx:${proc.contextPct}%` : '';
49
+ const url = proc.url ? ` ${proc.url}` : '';
50
+ logger.log(` ${status} [${proc.squadSlug}] ${proc.agentSlug} pid:${proc.pid} elapsed:${elapsed}${ctx}${url}`);
51
+ }
52
+
53
+ return { ok: true, processes };
54
+ }
55
+
56
+ module.exports = { runSquadProcesses };
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { generateRecovery, readRecovery } = require('../squad/recovery-context');
5
+
6
+ /**
7
+ * aioson squad:recovery <project> --squad <squad> --agent <agent> [--show]
8
+ *
9
+ * Generates (or re-generates) the recovery-context.md for an agent.
10
+ * --show: print the generated content to stdout instead of just confirming.
11
+ */
12
+ async function runSquadRecovery({ args, options, logger }) {
13
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
14
+ const squadSlug = options.squad || args[1];
15
+ const agentSlug = options.agent || args[2];
16
+
17
+ if (!squadSlug || !agentSlug) {
18
+ logger.error('Usage: aioson squad:recovery <project> --squad <squad> --agent <agent> [--show]');
19
+ return { ok: false };
20
+ }
21
+
22
+ const result = await generateRecovery(projectDir, squadSlug, agentSlug);
23
+
24
+ if (!result.ok) {
25
+ logger.error(`Failed to generate recovery context: ${result.error}`);
26
+ return result;
27
+ }
28
+
29
+ logger.log(`Recovery context generated: ${result.path} (~${result.tokens} tokens)`);
30
+
31
+ if (options.show) {
32
+ const content = await readRecovery(projectDir, squadSlug);
33
+ if (content) {
34
+ logger.log('');
35
+ logger.log(content);
36
+ }
37
+ }
38
+
39
+ return result;
40
+ }
41
+
42
+ module.exports = { runSquadRecovery };