@jaimevalasek/aioson 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/LICENSE +661 -21
  3. package/README.md +9 -1
  4. package/docs/design-previews/aurora-command-ui-website.html +884 -0
  5. package/docs/design-previews/aurora-command-ui.html +682 -0
  6. package/docs/design-previews/bold-editorial-ui-website.html +658 -0
  7. package/docs/design-previews/bold-editorial-ui.html +717 -0
  8. package/docs/design-previews/clean-saas-ui-website.html +1202 -0
  9. package/docs/design-previews/clean-saas-ui.html +549 -0
  10. package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
  11. package/docs/design-previews/cognitive-core-ui.html +463 -0
  12. package/docs/design-previews/glassmorphism-ui-website.html +572 -0
  13. package/docs/design-previews/glassmorphism-ui.html +886 -0
  14. package/docs/design-previews/index.html +699 -0
  15. package/docs/design-previews/interface-design-website.html +1187 -0
  16. package/docs/design-previews/interface-design.html +513 -0
  17. package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
  18. package/docs/design-previews/neo-brutalist-ui.html +797 -0
  19. package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
  20. package/docs/design-previews/premium-command-center-ui.html +552 -0
  21. package/docs/design-previews/warm-craft-ui-website.html +684 -0
  22. package/docs/design-previews/warm-craft-ui.html +739 -0
  23. package/docs/en/cli-reference.md +20 -9
  24. package/docs/en/squad-dashboard.md +372 -0
  25. package/docs/openclaw-bridge.md +308 -0
  26. package/docs/pt/README.md +7 -0
  27. package/docs/pt/agent-sharding.md +132 -0
  28. package/docs/pt/agentes.md +131 -11
  29. package/docs/pt/busca-de-contexto.md +129 -0
  30. package/docs/pt/cache-de-contexto.md +156 -0
  31. package/docs/pt/cenarios.md +46 -2
  32. package/docs/pt/comandos-cli.md +88 -1
  33. package/docs/pt/design-hybrid-forge.md +107 -0
  34. package/docs/pt/inicio-rapido.md +72 -5
  35. package/docs/pt/inteligencia-adaptativa.md +324 -0
  36. package/docs/pt/monitor-de-contexto.md +104 -0
  37. package/docs/pt/recuperacao-de-sessao.md +125 -0
  38. package/docs/pt/sandbox.md +125 -0
  39. package/docs/pt/skills.md +98 -6
  40. package/docs/pt/squad-dashboard.md +373 -0
  41. package/docs/testing/genome-2.0-matrix.md +5 -5
  42. package/docs/testing/genome-2.0-rollout.md +9 -9
  43. package/package.json +2 -2
  44. package/src/agent-loader.js +280 -0
  45. package/src/backup-local.js +74 -0
  46. package/src/cli.js +192 -0
  47. package/src/commands/agent-loader.js +85 -0
  48. package/src/commands/backup-local-cmd.js +25 -0
  49. package/src/commands/context-cache.js +90 -0
  50. package/src/commands/context-monitor.js +92 -0
  51. package/src/commands/context-search.js +66 -0
  52. package/src/commands/design-hybrid-options.js +385 -0
  53. package/src/commands/health.js +214 -0
  54. package/src/commands/init.js +54 -13
  55. package/src/commands/install.js +52 -13
  56. package/src/commands/learning-evolve.js +355 -0
  57. package/src/commands/live.js +34 -0
  58. package/src/commands/recovery.js +43 -0
  59. package/src/commands/runtime.js +242 -0
  60. package/src/commands/sandbox.js +37 -0
  61. package/src/commands/setup-context.js +29 -4
  62. package/src/commands/setup.js +178 -0
  63. package/src/commands/skill.js +79 -32
  64. package/src/commands/squad-daemon.js +209 -0
  65. package/src/commands/squad-dashboard.js +39 -0
  66. package/src/commands/squad-deploy.js +64 -0
  67. package/src/commands/squad-doctor.js +52 -0
  68. package/src/commands/squad-mcp.js +270 -0
  69. package/src/commands/squad-processes.js +56 -0
  70. package/src/commands/squad-recovery.js +42 -0
  71. package/src/commands/squad-roi.js +291 -0
  72. package/src/commands/squad-score.js +250 -0
  73. package/src/commands/squad-status.js +37 -1
  74. package/src/commands/squad-validate.js +62 -1
  75. package/src/commands/squad-webhook.js +160 -0
  76. package/src/commands/squad-worker.js +191 -0
  77. package/src/commands/squad-worktrees.js +75 -0
  78. package/src/commands/tool-registry-cmd.js +232 -0
  79. package/src/commands/update.js +7 -0
  80. package/src/commands/web-map.js +70 -0
  81. package/src/commands/web-scrape.js +71 -0
  82. package/src/constants.js +17 -0
  83. package/src/context-cache.js +159 -0
  84. package/src/context-search.js +326 -0
  85. package/src/context-writer.js +45 -1
  86. package/src/design-variation-catalog.js +503 -0
  87. package/src/i18n/messages/en.js +159 -3
  88. package/src/i18n/messages/es.js +147 -2
  89. package/src/i18n/messages/fr.js +147 -2
  90. package/src/i18n/messages/pt-BR.js +158 -3
  91. package/src/install-animation.js +260 -0
  92. package/src/install-profile.js +143 -0
  93. package/src/install-wizard.js +474 -0
  94. package/src/installer.js +38 -10
  95. package/src/lib/webhook-server.js +328 -0
  96. package/src/mcp-connectors/registry.js +602 -0
  97. package/src/parser.js +7 -1
  98. package/src/recovery-context-session.js +154 -0
  99. package/src/runtime-store.js +355 -2
  100. package/src/sandbox.js +177 -0
  101. package/src/squad/external-session.js +180 -0
  102. package/src/squad/inter-squad.js +74 -0
  103. package/src/squad/recovery-context.js +201 -0
  104. package/src/squad/worktree-manager.js +114 -0
  105. package/src/squad-daemon.js +490 -0
  106. package/src/squad-dashboard/api.js +223 -0
  107. package/src/squad-dashboard/attachment-handler.js +93 -0
  108. package/src/squad-dashboard/context-monitor.js +157 -0
  109. package/src/squad-dashboard/execution-logs.js +115 -0
  110. package/src/squad-dashboard/hunk-review.js +209 -0
  111. package/src/squad-dashboard/metrics.js +133 -0
  112. package/src/squad-dashboard/process-monitor.js +125 -0
  113. package/src/squad-dashboard/renderer.js +858 -0
  114. package/src/squad-dashboard/server.js +232 -0
  115. package/src/squad-dashboard/styles.js +525 -0
  116. package/src/squad-dashboard/token-tracker.js +99 -0
  117. package/src/tool-executor.js +94 -0
  118. package/src/updater.js +11 -3
  119. package/src/web.js +284 -0
  120. package/src/worker-runner.js +339 -0
  121. package/template/.aioson/agents/analyst.md +62 -3
  122. package/template/.aioson/agents/architect.md +42 -0
  123. package/template/.aioson/agents/design-hybrid-forge.md +127 -0
  124. package/template/.aioson/agents/dev.md +223 -11
  125. package/template/.aioson/agents/deyvin.md +65 -0
  126. package/template/.aioson/agents/neo.md +152 -0
  127. package/template/.aioson/agents/orache.md +17 -0
  128. package/template/.aioson/agents/orchestrator.md +26 -0
  129. package/template/.aioson/agents/pm.md +58 -0
  130. package/template/.aioson/agents/product.md +88 -12
  131. package/template/.aioson/agents/qa.md +80 -0
  132. package/template/.aioson/agents/setup.md +128 -22
  133. package/template/.aioson/agents/sheldon.md +704 -0
  134. package/template/.aioson/agents/squad.md +191 -0
  135. package/template/.aioson/agents/tester.md +410 -0
  136. package/template/.aioson/agents/ux-ui.md +12 -0
  137. package/template/.aioson/config.md +21 -0
  138. package/template/.aioson/context/forensics/.gitkeep +0 -0
  139. package/template/.aioson/context/seeds/seed-example.md +27 -0
  140. package/template/.aioson/context/user-profile.md +42 -0
  141. package/template/.aioson/locales/en/agents/analyst.md +8 -0
  142. package/template/.aioson/locales/en/agents/architect.md +8 -0
  143. package/template/.aioson/locales/en/agents/dev.md +66 -7
  144. package/template/.aioson/locales/en/agents/deyvin.md +8 -0
  145. package/template/.aioson/locales/en/agents/neo.md +8 -0
  146. package/template/.aioson/locales/en/agents/orchestrator.md +26 -0
  147. package/template/.aioson/locales/en/agents/qa.md +49 -0
  148. package/template/.aioson/locales/en/agents/setup.md +35 -2
  149. package/template/.aioson/locales/en/agents/sheldon.md +340 -0
  150. package/template/.aioson/locales/en/agents/ux-ui.md +8 -0
  151. package/template/.aioson/locales/es/agents/analyst.md +8 -0
  152. package/template/.aioson/locales/es/agents/architect.md +8 -0
  153. package/template/.aioson/locales/es/agents/dev.md +66 -7
  154. package/template/.aioson/locales/es/agents/deyvin.md +8 -0
  155. package/template/.aioson/locales/es/agents/neo.md +48 -0
  156. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  157. package/template/.aioson/locales/es/agents/qa.md +26 -0
  158. package/template/.aioson/locales/es/agents/setup.md +35 -2
  159. package/template/.aioson/locales/es/agents/sheldon.md +192 -0
  160. package/template/.aioson/locales/es/agents/squad.md +63 -0
  161. package/template/.aioson/locales/es/agents/ux-ui.md +8 -0
  162. package/template/.aioson/locales/fr/agents/analyst.md +8 -0
  163. package/template/.aioson/locales/fr/agents/architect.md +8 -0
  164. package/template/.aioson/locales/fr/agents/dev.md +66 -7
  165. package/template/.aioson/locales/fr/agents/deyvin.md +8 -0
  166. package/template/.aioson/locales/fr/agents/neo.md +48 -0
  167. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  168. package/template/.aioson/locales/fr/agents/qa.md +26 -0
  169. package/template/.aioson/locales/fr/agents/setup.md +35 -2
  170. package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
  171. package/template/.aioson/locales/fr/agents/squad.md +63 -0
  172. package/template/.aioson/locales/fr/agents/ux-ui.md +8 -0
  173. package/template/.aioson/locales/pt-BR/agents/analyst.md +19 -0
  174. package/template/.aioson/locales/pt-BR/agents/architect.md +19 -0
  175. package/template/.aioson/locales/pt-BR/agents/dev.md +75 -12
  176. package/template/.aioson/locales/pt-BR/agents/deyvin.md +8 -0
  177. package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
  178. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +26 -0
  179. package/template/.aioson/locales/pt-BR/agents/product.md +8 -3
  180. package/template/.aioson/locales/pt-BR/agents/qa.md +60 -0
  181. package/template/.aioson/locales/pt-BR/agents/setup.md +35 -2
  182. package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
  183. package/template/.aioson/locales/pt-BR/agents/squad.md +105 -0
  184. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +8 -0
  185. package/template/.aioson/schemas/squad-blueprint.schema.json +21 -0
  186. package/template/.aioson/schemas/squad-manifest.schema.json +178 -1
  187. package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
  188. package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
  189. package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
  190. package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
  191. package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
  192. package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
  193. package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
  194. package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
  195. package/template/.aioson/skills/design/bold-editorial-ui/SKILL.md +205 -0
  196. package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
  197. package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
  198. package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
  199. package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
  200. package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
  201. package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
  202. package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
  203. package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
  204. package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
  205. package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
  206. package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
  207. package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
  208. package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
  209. package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
  210. package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
  211. package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +55 -9
  212. package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
  213. package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +1 -1
  214. package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +100 -0
  215. package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +43 -9
  216. package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +40 -0
  217. package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +1 -1
  218. package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +99 -12
  219. package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
  220. package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
  221. package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
  222. package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
  223. package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
  224. package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
  225. package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
  226. package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
  227. package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
  228. package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
  229. package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
  230. package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
  231. package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
  232. package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
  233. package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
  234. package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
  235. package/template/.aioson/skills/design/warm-craft-ui/SKILL.md +209 -0
  236. package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
  237. package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
  238. package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
  239. package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
  240. package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
  241. package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
  242. package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
  243. package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
  244. package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
  245. package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
  246. package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
  247. package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
  248. package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
  249. package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
  250. package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
  251. package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
  252. package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
  253. package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
  254. package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -0
  255. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +45 -0
  256. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
  257. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
  258. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
  259. package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
  260. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +66 -0
  261. package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
  262. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +144 -0
  263. package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
  264. package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
  265. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +291 -0
  266. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +117 -0
  267. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +188 -0
  268. package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
  269. package/template/.aioson/skills/squad/formats/catalog.json +15 -0
  270. package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
  271. package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
  272. package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
  273. package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
  274. package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
  275. package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
  276. package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
  277. package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
  278. package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
  279. package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
  280. package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
  281. package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
  282. package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
  283. package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -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 +19 -0
  290. package/template/.aioson/tasks/squad-design.md +28 -0
  291. package/template/.aioson/tasks/squad-profile.md +48 -0
  292. package/template/.aioson/tasks/squad-review.md +61 -0
  293. package/template/.aioson/tasks/squad-task-decompose.md +66 -0
  294. package/template/.claude/commands/aioson/agent/neo.md +5 -0
  295. package/template/.claude/commands/aioson/agent/tester.md +5 -0
  296. package/template/.gemini/GEMINI.md +1 -0
  297. package/template/.gemini/commands/aios-neo.toml +4 -0
  298. package/template/.gemini/commands/aios-tester.toml +6 -0
  299. package/template/AGENTS.md +26 -1
  300. package/template/CLAUDE.md +6 -2
  301. package/template/OPENCODE.md +2 -0
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const SQUADS_DIR = path.join('.aioson', 'squads');
7
+
8
+ // Valid hunk states
9
+ const HUNK_STATES = { PENDING: 'pending', APPROVED: 'approved', REJECTED: 'rejected', REVISED: 'revised' };
10
+
11
+ /**
12
+ * Parse a unified diff string into individual hunks.
13
+ * Each hunk includes its header, lines, and a stable id.
14
+ *
15
+ * @param {string} diff — full unified diff text
16
+ * @returns {Array<{id, fileHeader, header, lines, additions, deletions}>}
17
+ */
18
+ function parseDiffHunks(diff) {
19
+ if (!diff || typeof diff !== 'string') return [];
20
+
21
+ const hunks = [];
22
+ let currentFile = '';
23
+ let currentHunk = null;
24
+ let hunkIndex = 0;
25
+
26
+ for (const rawLine of diff.split('\n')) {
27
+ // File header lines
28
+ if (rawLine.startsWith('--- ') || rawLine.startsWith('+++ ')) {
29
+ if (rawLine.startsWith('+++ ')) {
30
+ // Strip b/ prefix from git diffs
31
+ currentFile = rawLine.slice(4).replace(/^b\//, '').trim();
32
+ }
33
+ if (currentHunk) {
34
+ hunks.push(finalizeHunk(currentHunk));
35
+ currentHunk = null;
36
+ }
37
+ continue;
38
+ }
39
+
40
+ // Hunk header: @@ -a,b +c,d @@
41
+ if (rawLine.startsWith('@@ ')) {
42
+ if (currentHunk) {
43
+ hunks.push(finalizeHunk(currentHunk));
44
+ }
45
+ currentHunk = {
46
+ id: `hunk-${hunkIndex++}`,
47
+ fileHeader: currentFile,
48
+ header: rawLine,
49
+ lines: [],
50
+ additions: 0,
51
+ deletions: 0
52
+ };
53
+ continue;
54
+ }
55
+
56
+ if (currentHunk) {
57
+ currentHunk.lines.push(rawLine);
58
+ if (rawLine.startsWith('+') && !rawLine.startsWith('+++')) currentHunk.additions++;
59
+ if (rawLine.startsWith('-') && !rawLine.startsWith('---')) currentHunk.deletions++;
60
+ }
61
+ }
62
+
63
+ if (currentHunk) hunks.push(finalizeHunk(currentHunk));
64
+ return hunks;
65
+ }
66
+
67
+ function finalizeHunk(hunk) {
68
+ return {
69
+ id: hunk.id,
70
+ fileHeader: hunk.fileHeader,
71
+ header: hunk.header,
72
+ lines: hunk.lines,
73
+ additions: hunk.additions,
74
+ deletions: hunk.deletions
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Resolve the hunk-review state file path for a task.
80
+ */
81
+ function hunkStatePath(projectDir, squadSlug, taskId) {
82
+ return path.join(projectDir, SQUADS_DIR, squadSlug, 'tasks', taskId, 'hunk-review.json');
83
+ }
84
+
85
+ /**
86
+ * Load hunk review state for a task. Returns null if not found.
87
+ */
88
+ async function loadHunkState(projectDir, squadSlug, taskId) {
89
+ try {
90
+ const raw = await fs.readFile(hunkStatePath(projectDir, squadSlug, taskId), 'utf8');
91
+ return JSON.parse(raw);
92
+ } catch {
93
+ return null;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Save hunk review state for a task.
99
+ */
100
+ async function saveHunkState(projectDir, squadSlug, taskId, state) {
101
+ const p = hunkStatePath(projectDir, squadSlug, taskId);
102
+ await fs.mkdir(path.dirname(p), { recursive: true });
103
+ await fs.writeFile(p, JSON.stringify(state, null, 2), 'utf8');
104
+ }
105
+
106
+ /**
107
+ * Initialize hunk review state from a diff string.
108
+ * Returns the initial state object (persisted to disk).
109
+ */
110
+ async function initHunkReview(projectDir, squadSlug, taskId, diff) {
111
+ const hunks = parseDiffHunks(diff);
112
+ const state = {
113
+ taskId,
114
+ squadSlug,
115
+ diff,
116
+ hunks: hunks.map(h => ({
117
+ id: h.id,
118
+ fileHeader: h.fileHeader,
119
+ header: h.header,
120
+ lines: h.lines,
121
+ additions: h.additions,
122
+ deletions: h.deletions,
123
+ status: HUNK_STATES.PENDING,
124
+ comment: null,
125
+ reviewedAt: null
126
+ })),
127
+ createdAt: new Date().toISOString(),
128
+ updatedAt: new Date().toISOString()
129
+ };
130
+ await saveHunkState(projectDir, squadSlug, taskId, state);
131
+ return state;
132
+ }
133
+
134
+ /**
135
+ * Get current hunk review state (or init from diff if missing).
136
+ */
137
+ async function getHunks(projectDir, squadSlug, taskId, diff) {
138
+ let state = await loadHunkState(projectDir, squadSlug, taskId);
139
+ if (!state && diff) {
140
+ state = await initHunkReview(projectDir, squadSlug, taskId, diff);
141
+ }
142
+ return state;
143
+ }
144
+
145
+ /**
146
+ * Update the status of a single hunk.
147
+ * @param {string} newStatus — one of HUNK_STATES values
148
+ * @param {string|null} comment
149
+ * @returns {{ state, dispatch: string|null }}
150
+ * dispatch is 'task_done' | 'task_needs_revision' | null based on overall state after update
151
+ */
152
+ async function updateHunk(projectDir, squadSlug, taskId, hunkId, newStatus, comment) {
153
+ const state = await loadHunkState(projectDir, squadSlug, taskId);
154
+ if (!state) return { ok: false, error: 'No hunk review state found' };
155
+
156
+ const hunk = state.hunks.find(h => h.id === hunkId);
157
+ if (!hunk) return { ok: false, error: `Hunk "${hunkId}" not found` };
158
+
159
+ hunk.status = newStatus;
160
+ if (comment !== undefined && comment !== null) hunk.comment = comment;
161
+ hunk.reviewedAt = new Date().toISOString();
162
+ state.updatedAt = new Date().toISOString();
163
+
164
+ await saveHunkState(projectDir, squadSlug, taskId, state);
165
+
166
+ const dispatch = computeDispatch(state.hunks);
167
+ return { ok: true, hunk, dispatch, state };
168
+ }
169
+
170
+ /**
171
+ * Compute the dispatch event based on all hunk statuses.
172
+ * Returns: 'task_done' if all approved, 'task_needs_revision' if any rejected,
173
+ * null if still pending.
174
+ */
175
+ function computeDispatch(hunks) {
176
+ const allReviewed = hunks.every(h => h.status !== HUNK_STATES.PENDING);
177
+ if (!allReviewed) return null;
178
+
179
+ const rejectedHunks = hunks.filter(h => h.status === HUNK_STATES.REJECTED);
180
+ if (rejectedHunks.length > 0) {
181
+ return { event: 'task_needs_revision', rejectedHunks: rejectedHunks.map(h => h.id) };
182
+ }
183
+
184
+ return { event: 'task_done' };
185
+ }
186
+
187
+ /**
188
+ * Get a summary of review progress: total, approved, rejected, pending.
189
+ */
190
+ function getReviewProgress(hunks) {
191
+ return {
192
+ total: hunks.length,
193
+ approved: hunks.filter(h => h.status === HUNK_STATES.APPROVED).length,
194
+ rejected: hunks.filter(h => h.status === HUNK_STATES.REJECTED).length,
195
+ revised: hunks.filter(h => h.status === HUNK_STATES.REVISED).length,
196
+ pending: hunks.filter(h => h.status === HUNK_STATES.PENDING).length
197
+ };
198
+ }
199
+
200
+ module.exports = {
201
+ parseDiffHunks,
202
+ initHunkReview,
203
+ getHunks,
204
+ updateHunk,
205
+ loadHunkState,
206
+ computeDispatch,
207
+ getReviewProgress,
208
+ HUNK_STATES
209
+ };
@@ -0,0 +1,133 @@
1
+ 'use strict';
2
+
3
+ function countContentItems(db, squadSlug) {
4
+ const row = db.prepare('SELECT COUNT(*) AS cnt FROM content_items WHERE squad_slug = ?').get(squadSlug);
5
+ return row ? row.cnt : 0;
6
+ }
7
+
8
+ function countSessions(db, squadSlug) {
9
+ const row = db.prepare(
10
+ "SELECT COUNT(*) AS cnt FROM tasks WHERE meta_json LIKE ? AND task_kind = 'live_session'"
11
+ ).get(`%${squadSlug}%`);
12
+ return row ? row.cnt : 0;
13
+ }
14
+
15
+ function countLearnings(db, squadSlug) {
16
+ const row = db.prepare('SELECT COUNT(*) AS cnt FROM squad_learnings WHERE squad_slug = ?').get(squadSlug);
17
+ return row ? row.cnt : 0;
18
+ }
19
+
20
+ function calcDeliveryRate(db, squadSlug) {
21
+ const total = db.prepare('SELECT COUNT(*) AS cnt FROM delivery_log WHERE squad_slug = ?').get(squadSlug);
22
+ if (!total || total.cnt === 0) return null;
23
+ const success = db.prepare(
24
+ 'SELECT COUNT(*) AS cnt FROM delivery_log WHERE squad_slug = ? AND status_code >= 200 AND status_code < 300'
25
+ ).get(squadSlug);
26
+ return Math.round(((success ? success.cnt : 0) / total.cnt) * 100);
27
+ }
28
+
29
+ function getRecentDeliveries(db, squadSlug, limit = 20) {
30
+ return db.prepare(
31
+ 'SELECT * FROM delivery_log WHERE squad_slug = ? ORDER BY created_at DESC LIMIT ?'
32
+ ).all(squadSlug, limit);
33
+ }
34
+
35
+ function getRecentContent(db, squadSlug, limit = 20) {
36
+ return db.prepare(
37
+ 'SELECT content_key, title, content_type, layout_type, status, created_at, updated_at FROM content_items WHERE squad_slug = ? ORDER BY updated_at DESC LIMIT ?'
38
+ ).all(squadSlug, limit);
39
+ }
40
+
41
+ function getLearnings(db, squadSlug, statusFilter = null) {
42
+ if (statusFilter) {
43
+ return db.prepare(
44
+ 'SELECT * FROM squad_learnings WHERE squad_slug = ? AND status = ? ORDER BY updated_at DESC'
45
+ ).all(squadSlug, statusFilter);
46
+ }
47
+ return db.prepare(
48
+ 'SELECT * FROM squad_learnings WHERE squad_slug = ? ORDER BY updated_at DESC'
49
+ ).all(squadSlug);
50
+ }
51
+
52
+ function getLearningStats(db, squadSlug) {
53
+ const rows = db.prepare(
54
+ 'SELECT status, COUNT(*) AS cnt FROM squad_learnings WHERE squad_slug = ? GROUP BY status'
55
+ ).all(squadSlug);
56
+ const stats = { active: 0, stale: 0, archived: 0, promoted: 0 };
57
+ for (const row of rows) {
58
+ if (Object.prototype.hasOwnProperty.call(stats, row.status)) {
59
+ stats[row.status] = row.cnt;
60
+ }
61
+ }
62
+ return stats;
63
+ }
64
+
65
+ function getExecutionPlan(db, squadSlug) {
66
+ const plan = db.prepare(
67
+ 'SELECT * FROM squad_execution_plans WHERE squad_slug = ? ORDER BY updated_at DESC LIMIT 1'
68
+ ).get(squadSlug);
69
+ if (!plan) return null;
70
+ const rounds = db.prepare(
71
+ 'SELECT * FROM squad_plan_rounds WHERE plan_slug = ? ORDER BY round_number ASC'
72
+ ).all(plan.plan_slug);
73
+ return { ...plan, rounds };
74
+ }
75
+
76
+ function getPipelineInfo(db, squadSlug) {
77
+ const node = db.prepare(
78
+ 'SELECT * FROM pipeline_nodes WHERE squad_slug = ?'
79
+ ).get(squadSlug);
80
+ if (!node) return null;
81
+ const pipeline = db.prepare(
82
+ 'SELECT * FROM squad_pipelines WHERE pipeline_slug = ?'
83
+ ).get(node.pipeline_slug);
84
+ const handoffs = db.prepare(
85
+ 'SELECT * FROM squad_handoffs WHERE (from_squad = ? OR to_squad = ?) ORDER BY created_at DESC LIMIT 20'
86
+ ).all(squadSlug, squadSlug);
87
+ return { pipeline, node, handoffs };
88
+ }
89
+
90
+ function getSquadMetrics(db, squadSlug) {
91
+ try {
92
+ return db.prepare(
93
+ 'SELECT * FROM squad_metrics WHERE squad_slug = ? ORDER BY period DESC, metric_key ASC'
94
+ ).all(squadSlug);
95
+ } catch {
96
+ return [];
97
+ }
98
+ }
99
+
100
+ function getRecentEvents(db, squadSlug, limit = 30) {
101
+ return db.prepare(
102
+ "SELECT * FROM execution_events WHERE run_key LIKE ? ORDER BY created_at DESC LIMIT ?"
103
+ ).all(`%${squadSlug}%`, limit);
104
+ }
105
+
106
+ function getSquadOverview(db, squadSlug) {
107
+ return {
108
+ contentItems: countContentItems(db, squadSlug),
109
+ sessions: countSessions(db, squadSlug),
110
+ learnings: countLearnings(db, squadSlug),
111
+ deliveryRate: calcDeliveryRate(db, squadSlug),
112
+ learningStats: getLearningStats(db, squadSlug),
113
+ executionPlan: getExecutionPlan(db, squadSlug),
114
+ pipelineInfo: getPipelineInfo(db, squadSlug),
115
+ customMetrics: getSquadMetrics(db, squadSlug)
116
+ };
117
+ }
118
+
119
+ module.exports = {
120
+ countContentItems,
121
+ countSessions,
122
+ countLearnings,
123
+ calcDeliveryRate,
124
+ getRecentDeliveries,
125
+ getRecentContent,
126
+ getLearnings,
127
+ getLearningStats,
128
+ getExecutionPlan,
129
+ getPipelineInfo,
130
+ getSquadMetrics,
131
+ getRecentEvents,
132
+ getSquadOverview
133
+ };
@@ -0,0 +1,125 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const SQUADS_DIR = path.join('.aioson', 'squads');
7
+
8
+ async function readProcessFile(filePath) {
9
+ try {
10
+ const raw = await fs.readFile(filePath, 'utf8');
11
+ return JSON.parse(raw);
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ function isProcessAlive(pid) {
18
+ if (!pid) return false;
19
+ try {
20
+ process.kill(Number(pid), 0);
21
+ return true;
22
+ } catch {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Get all active processes across all squads (or for a specific squad).
29
+ * Reads from .aioson/squads/{slug}/processes/*.json
30
+ * Each file: { pid, squadSlug, agentSlug, startedAt, url, lastActivity, contextPct }
31
+ */
32
+ async function getActiveProcesses(projectDir, squadSlug) {
33
+ const squadsDir = path.join(projectDir, SQUADS_DIR);
34
+ const processes = [];
35
+
36
+ let squadNames;
37
+ try {
38
+ const entries = await fs.readdir(squadsDir, { withFileTypes: true });
39
+ squadNames = entries
40
+ .filter(e => e.isDirectory() && (!squadSlug || e.name === squadSlug))
41
+ .map(e => e.name);
42
+ } catch {
43
+ return [];
44
+ }
45
+
46
+ for (const slug of squadNames) {
47
+ const processesDir = path.join(squadsDir, slug, 'processes');
48
+ let files;
49
+ try {
50
+ files = await fs.readdir(processesDir);
51
+ } catch {
52
+ continue;
53
+ }
54
+
55
+ for (const file of files) {
56
+ if (!file.endsWith('.json')) continue;
57
+ const proc = await readProcessFile(path.join(processesDir, file));
58
+ if (!proc) continue;
59
+
60
+ const alive = isProcessAlive(proc.pid);
61
+ const startedAt = proc.startedAt ? new Date(proc.startedAt) : null;
62
+ const elapsedSeconds = startedAt ? Math.floor((Date.now() - startedAt.getTime()) / 1000) : null;
63
+
64
+ processes.push({
65
+ pid: proc.pid,
66
+ squadSlug: proc.squadSlug || slug,
67
+ agentSlug: proc.agentSlug || file.replace('.json', ''),
68
+ startedAt: proc.startedAt || null,
69
+ elapsedSeconds,
70
+ url: proc.url || null,
71
+ lastActivity: proc.lastActivity || null,
72
+ contextPct: proc.contextPct != null ? proc.contextPct : null,
73
+ alive,
74
+ _file: path.join(processesDir, file)
75
+ });
76
+ }
77
+ }
78
+
79
+ processes.sort((a, b) => {
80
+ if (!a.startedAt) return 1;
81
+ if (!b.startedAt) return -1;
82
+ return b.startedAt.localeCompare(a.startedAt);
83
+ });
84
+
85
+ return processes;
86
+ }
87
+
88
+ /**
89
+ * Stop a process by PID (SIGTERM) and remove its process file.
90
+ */
91
+ async function stopProcess(projectDir, pid) {
92
+ const processes = await getActiveProcesses(projectDir, null);
93
+ const proc = processes.find(p => String(p.pid) === String(pid));
94
+
95
+ if (!proc) {
96
+ return { ok: false, error: 'Process not found' };
97
+ }
98
+ if (!proc.alive) {
99
+ // Clean up stale file anyway
100
+ try { await fs.unlink(proc._file); } catch { /* ignore */ }
101
+ return { ok: false, error: 'Process is not running' };
102
+ }
103
+
104
+ try {
105
+ process.kill(Number(proc.pid), 'SIGTERM');
106
+ try { await fs.unlink(proc._file); } catch { /* ignore */ }
107
+ return { ok: true, pid: proc.pid };
108
+ } catch (err) {
109
+ return { ok: false, error: err.message };
110
+ }
111
+ }
112
+
113
+ /**
114
+ * Stop all processes for a squad.
115
+ */
116
+ async function stopSquadProcesses(projectDir, squadSlug) {
117
+ const processes = await getActiveProcesses(projectDir, squadSlug);
118
+ const results = [];
119
+ for (const proc of processes) {
120
+ results.push(await stopProcess(projectDir, proc.pid));
121
+ }
122
+ return results;
123
+ }
124
+
125
+ module.exports = { getActiveProcesses, stopProcess, stopSquadProcesses, isProcessAlive };