@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,223 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const {
6
+ getSquadOverview,
7
+ getRecentContent,
8
+ getLearnings,
9
+ getRecentDeliveries,
10
+ getRecentEvents,
11
+ getSquadMetrics
12
+ } = require('./metrics');
13
+ const { getContextUsage } = require('./context-monitor');
14
+ const { getTokenUsage } = require('./token-tracker');
15
+ const { getActiveProcesses, stopProcess } = require('./process-monitor');
16
+ const { getHunks, updateHunk, getReviewProgress, HUNK_STATES } = require('./hunk-review');
17
+ const { generateRecovery, readRecovery } = require('../squad/recovery-context');
18
+ const { getLogsForTask, getSessionLog } = require('./execution-logs');
19
+
20
+ const SQUADS_DIR = path.join('.aioson', 'squads');
21
+
22
+ async function loadSquadList(projectDir) {
23
+ const squadsDir = path.join(projectDir, SQUADS_DIR);
24
+ let entries;
25
+ try {
26
+ entries = await fs.readdir(squadsDir, { withFileTypes: true });
27
+ } catch {
28
+ return [];
29
+ }
30
+
31
+ const squads = [];
32
+ for (const entry of entries) {
33
+ if (!entry.isDirectory()) continue;
34
+ const manifestPath = path.join(squadsDir, entry.name, 'squad.manifest.json');
35
+ try {
36
+ const raw = await fs.readFile(manifestPath, 'utf8');
37
+ const manifest = JSON.parse(raw);
38
+ squads.push({
39
+ slug: entry.name,
40
+ name: manifest.name || entry.name,
41
+ mode: manifest.mode || 'mixed',
42
+ goal: manifest.goal || '',
43
+ status: manifest.status || 'active',
44
+ executorCount: (manifest.executors || []).length,
45
+ manifest
46
+ });
47
+ } catch {
48
+ squads.push({
49
+ slug: entry.name,
50
+ name: entry.name,
51
+ mode: 'unknown',
52
+ goal: '',
53
+ status: 'unknown',
54
+ executorCount: 0,
55
+ manifest: null
56
+ });
57
+ }
58
+ }
59
+ return squads;
60
+ }
61
+
62
+ function detectPanels(manifest) {
63
+ const panels = ['overview', 'content', 'learnings', 'logs'];
64
+
65
+ if (manifest) {
66
+ if (manifest.mode === 'content') panels.push('content-preview');
67
+ if (manifest.mode === 'software') panels.push('tasks');
68
+
69
+ const hasWebhooks = manifest.outputStrategy &&
70
+ manifest.outputStrategy.delivery &&
71
+ Array.isArray(manifest.outputStrategy.delivery.webhooks) &&
72
+ manifest.outputStrategy.delivery.webhooks.length > 0;
73
+ const hasMcps = Array.isArray(manifest.mcps) && manifest.mcps.length > 0;
74
+ if (hasWebhooks || hasMcps) panels.push('integrations');
75
+
76
+ const channelMcps = (manifest.mcps || []).filter(function (m) {
77
+ return ['whatsapp', 'telegram', 'sms', 'voice'].some(function (ch) {
78
+ return (m.slug || '').includes(ch);
79
+ });
80
+ });
81
+ if (channelMcps.length > 0) panels.push('channels');
82
+ }
83
+
84
+ panels.push('metrics');
85
+ panels.push('processes');
86
+ return panels;
87
+ }
88
+
89
+ function loadSquadData(db, squadSlug) {
90
+ const overview = getSquadOverview(db, squadSlug);
91
+ const content = getRecentContent(db, squadSlug);
92
+ const learnings = getLearnings(db, squadSlug);
93
+ const deliveries = getRecentDeliveries(db, squadSlug);
94
+ const events = getRecentEvents(db, squadSlug);
95
+ const customMetrics = getSquadMetrics(db, squadSlug);
96
+
97
+ return {
98
+ overview,
99
+ content,
100
+ learnings,
101
+ deliveries,
102
+ events,
103
+ customMetrics,
104
+ pipelineInfo: overview.pipelineInfo,
105
+ metrics: {
106
+ content_items: overview.contentItems,
107
+ sessions: overview.sessions,
108
+ learnings: overview.learnings,
109
+ delivery_rate: overview.deliveryRate
110
+ }
111
+ };
112
+ }
113
+
114
+ /**
115
+ * GET /api/squads/:slug/context
116
+ * Returns context usage with warning levels for all agents in a squad.
117
+ */
118
+ async function getContextData(projectDir, squadSlug, agentSlug) {
119
+ return getContextUsage(projectDir, squadSlug, agentSlug || null);
120
+ }
121
+
122
+ /**
123
+ * GET /api/squads/:slug/tokens?breakdown=true
124
+ * Returns token usage with cost estimates and waste flags.
125
+ */
126
+ async function getTokenData(projectDir, squadSlug, breakdown) {
127
+ return getTokenUsage(projectDir, squadSlug, breakdown);
128
+ }
129
+
130
+ /**
131
+ * GET /api/processes[?squad=:slug]
132
+ * Returns active agent processes across all squads (or filtered by squad).
133
+ */
134
+ async function getProcesses(projectDir, squadSlug) {
135
+ return getActiveProcesses(projectDir, squadSlug || null);
136
+ }
137
+
138
+ /**
139
+ * POST /api/processes/:pid/stop
140
+ * Sends SIGTERM to the process and removes its process file.
141
+ */
142
+ async function stopProcessById(projectDir, pid) {
143
+ return stopProcess(projectDir, pid);
144
+ }
145
+
146
+ /**
147
+ * GET /api/tasks/:id/hunks
148
+ * Returns hunk review state for a task.
149
+ * Requires squadSlug and optionally diff (to init on first call).
150
+ */
151
+ async function getTaskHunks(projectDir, squadSlug, taskId, diff) {
152
+ return getHunks(projectDir, squadSlug, taskId, diff || null);
153
+ }
154
+
155
+ /**
156
+ * POST /api/tasks/:id/hunks/:hunkId/approve
157
+ */
158
+ async function approveHunk(projectDir, squadSlug, taskId, hunkId) {
159
+ return updateHunk(projectDir, squadSlug, taskId, hunkId, HUNK_STATES.APPROVED, null);
160
+ }
161
+
162
+ /**
163
+ * POST /api/tasks/:id/hunks/:hunkId/reject
164
+ */
165
+ async function rejectHunk(projectDir, squadSlug, taskId, hunkId, comment) {
166
+ return updateHunk(projectDir, squadSlug, taskId, hunkId, HUNK_STATES.REJECTED, comment || null);
167
+ }
168
+
169
+ /**
170
+ * POST /api/tasks/:id/hunks/:hunkId/comment
171
+ */
172
+ async function commentHunk(projectDir, squadSlug, taskId, hunkId, comment) {
173
+ return updateHunk(projectDir, squadSlug, taskId, hunkId, HUNK_STATES.REVISED, comment || null);
174
+ }
175
+
176
+ /**
177
+ * GET /api/squads/:slug/agents/:agent/recovery
178
+ * Returns the recovery-context.md for an agent (generates if missing).
179
+ */
180
+ async function getAgentRecovery(projectDir, squadSlug, agentSlug) {
181
+ // Try to read existing first
182
+ const existing = await readRecovery(projectDir, squadSlug);
183
+ if (existing) return { ok: true, content: existing, squadSlug, agentSlug };
184
+ // Generate on demand
185
+ const result = await generateRecovery(projectDir, squadSlug, agentSlug);
186
+ if (!result.ok) return result;
187
+ const content = await readRecovery(projectDir, squadSlug);
188
+ return { ok: true, content, squadSlug, agentSlug, tokens: result.tokens };
189
+ }
190
+
191
+ /**
192
+ * GET /api/squads/:slug/tasks/:taskId/logs
193
+ * Returns all session logs for a task, sorted oldest-first.
194
+ */
195
+ async function getTaskLogs(projectDir, squadSlug, taskId) {
196
+ return getLogsForTask(projectDir, squadSlug, taskId);
197
+ }
198
+
199
+ /**
200
+ * GET /api/squads/:slug/tasks/:taskId/logs/:sessionId
201
+ * Returns a single session log by sessionId.
202
+ */
203
+ async function getTaskSessionLog(projectDir, squadSlug, taskId, sessionId) {
204
+ return getSessionLog(projectDir, squadSlug, taskId, sessionId);
205
+ }
206
+
207
+ module.exports = {
208
+ loadSquadList,
209
+ detectPanels,
210
+ loadSquadData,
211
+ getContextData,
212
+ getTokenData,
213
+ getProcesses,
214
+ stopProcessById,
215
+ getTaskHunks,
216
+ approveHunk,
217
+ rejectHunk,
218
+ commentHunk,
219
+ getAgentRecovery,
220
+ getReviewProgress,
221
+ getTaskLogs,
222
+ getTaskSessionLog
223
+ };
@@ -0,0 +1,93 @@
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
+ const IMAGE_EXTS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg']);
9
+
10
+ const MIME_MAP = {
11
+ '.png': 'image/png',
12
+ '.jpg': 'image/jpeg',
13
+ '.jpeg': 'image/jpeg',
14
+ '.gif': 'image/gif',
15
+ '.webp': 'image/webp',
16
+ '.svg': 'image/svg+xml',
17
+ '.pdf': 'application/pdf',
18
+ '.txt': 'text/plain',
19
+ '.md': 'text/markdown',
20
+ '.json': 'application/json'
21
+ };
22
+
23
+ function attachmentsDir(projectDir, squadSlug) {
24
+ return path.join(projectDir, SQUADS_DIR, squadSlug, 'attachments');
25
+ }
26
+
27
+ function safeName(filename) {
28
+ return path.basename(filename).replace(/[^a-zA-Z0-9._-]/g, '_');
29
+ }
30
+
31
+ /**
32
+ * Save a Buffer or string as an attachment.
33
+ * Returns { ok, filename, filePath, isImage }.
34
+ */
35
+ async function saveAttachment(projectDir, squadSlug, filename, buffer) {
36
+ const dir = attachmentsDir(projectDir, squadSlug);
37
+ await fs.mkdir(dir, { recursive: true });
38
+ const safe = safeName(filename);
39
+ const dest = path.join(dir, safe);
40
+ await fs.writeFile(dest, buffer);
41
+ const ext = path.extname(safe).toLowerCase();
42
+ return { ok: true, filePath: dest, filename: safe, isImage: IMAGE_EXTS.has(ext) };
43
+ }
44
+
45
+ /**
46
+ * List all attachments for a squad.
47
+ * Returns array of { filename, filePath, isImage, mime, size }.
48
+ */
49
+ async function listAttachments(projectDir, squadSlug) {
50
+ const dir = attachmentsDir(projectDir, squadSlug);
51
+ let entries;
52
+ try {
53
+ entries = await fs.readdir(dir, { withFileTypes: true });
54
+ } catch {
55
+ return [];
56
+ }
57
+ const result = [];
58
+ for (const entry of entries) {
59
+ if (!entry.isFile()) continue;
60
+ const ext = path.extname(entry.name).toLowerCase();
61
+ let size = 0;
62
+ try {
63
+ const stat = await fs.stat(path.join(dir, entry.name));
64
+ size = stat.size;
65
+ } catch { /* ignore */ }
66
+ result.push({
67
+ filename: entry.name,
68
+ filePath: path.join(dir, entry.name),
69
+ isImage: IMAGE_EXTS.has(ext),
70
+ mime: MIME_MAP[ext] || 'application/octet-stream',
71
+ size
72
+ });
73
+ }
74
+ return result;
75
+ }
76
+
77
+ /**
78
+ * Read an attachment file for serving (e.g. inline image preview).
79
+ * Returns { ok, buffer, mime, filename } or { ok: false }.
80
+ */
81
+ async function readAttachment(projectDir, squadSlug, filename) {
82
+ const safe = safeName(filename);
83
+ const filePath = path.join(attachmentsDir(projectDir, squadSlug), safe);
84
+ try {
85
+ const buffer = await fs.readFile(filePath);
86
+ const ext = path.extname(safe).toLowerCase();
87
+ return { ok: true, buffer, mime: MIME_MAP[ext] || 'application/octet-stream', filename: safe };
88
+ } catch {
89
+ return { ok: false };
90
+ }
91
+ }
92
+
93
+ module.exports = { saveAttachment, listAttachments, readAttachment, IMAGE_EXTS, MIME_MAP };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { generateRecovery, shouldRefreshOnEvent } = require('../squad/recovery-context');
6
+
7
+ const SQUADS_DIR = path.join('.aioson', 'squads');
8
+
9
+ // Minimum ratio drop between consecutive measurements to be considered a compact
10
+ const COMPACT_DROP_THRESHOLD = 0.30;
11
+
12
+ // Warning level thresholds (ratio of used/windowSize)
13
+ const THRESHOLDS = { warning: 0.85, critical: 0.95 };
14
+
15
+ // Notification event types (dispatched by caller when notification system is available)
16
+ const EVENTS = {
17
+ CONTEXT_WARNING: 'context_warning',
18
+ CONTEXT_CRITICAL: 'context_critical'
19
+ };
20
+
21
+ // Context categories (6) — order determines donut segment order
22
+ const CATEGORIES = [
23
+ 'system_prompt',
24
+ 'conversation_history',
25
+ 'tool_outputs',
26
+ 'files_loaded',
27
+ 'inline_data',
28
+ 'other'
29
+ ];
30
+
31
+ function computeWarningLevel(used, windowSize) {
32
+ if (!windowSize || windowSize <= 0) return 'unknown';
33
+ const ratio = used / windowSize;
34
+ if (ratio >= 1.0) return 'overflow';
35
+ if (ratio >= THRESHOLDS.critical) return 'critical';
36
+ if (ratio >= THRESHOLDS.warning) return 'warning';
37
+ return 'normal';
38
+ }
39
+
40
+ /**
41
+ * Read context-monitor.json for a squad and compute warning levels.
42
+ * @param {string} projectDir
43
+ * @param {string} squadSlug
44
+ * @param {string|null} agentSlug — if set, return only that agent
45
+ * @returns {object|null}
46
+ */
47
+ async function getContextUsage(projectDir, squadSlug, agentSlug) {
48
+ const filePath = path.join(projectDir, SQUADS_DIR, squadSlug, 'context-monitor.json');
49
+ let data;
50
+ try {
51
+ const raw = await fs.readFile(filePath, 'utf8');
52
+ data = JSON.parse(raw);
53
+ } catch {
54
+ return null;
55
+ }
56
+
57
+ const agents = data.agents || {};
58
+
59
+ if (agentSlug) {
60
+ const agent = agents[agentSlug];
61
+ if (!agent) return null;
62
+ const warningLevel = computeWarningLevel(agent.totalUsed || 0, agent.windowSize || 0);
63
+ return { squadSlug, agentSlug, ...agent, warningLevel };
64
+ }
65
+
66
+ const enrichedAgents = {};
67
+ for (const [slug, agent] of Object.entries(agents)) {
68
+ enrichedAgents[slug] = {
69
+ ...agent,
70
+ warningLevel: computeWarningLevel(agent.totalUsed || 0, agent.windowSize || 0)
71
+ };
72
+ }
73
+ return { squadSlug, agents: enrichedAgents, updatedAt: data.updatedAt };
74
+ }
75
+
76
+ /**
77
+ * Return pending notification events for a context snapshot.
78
+ * Caller dispatches these once the notification system exists.
79
+ */
80
+ function checkNotificationEvents(squadSlug, contextData) {
81
+ if (!contextData || !contextData.agents) return [];
82
+ const events = [];
83
+ for (const [agentSlug, agent] of Object.entries(contextData.agents)) {
84
+ if (agent.warningLevel === 'critical' || agent.warningLevel === 'overflow') {
85
+ events.push({ type: EVENTS.CONTEXT_CRITICAL, squadSlug, agentSlug, warningLevel: agent.warningLevel });
86
+ } else if (agent.warningLevel === 'warning') {
87
+ events.push({ type: EVENTS.CONTEXT_WARNING, squadSlug, agentSlug, warningLevel: agent.warningLevel });
88
+ }
89
+ }
90
+ return events;
91
+ }
92
+
93
+ /**
94
+ * Detect if a context compact occurred between two consecutive measurements.
95
+ * A compact is inferred when totalUsed drops by > 30% from the previous snapshot.
96
+ * @param {number} prevUsed — previous totalUsed value
97
+ * @param {number} currUsed — current totalUsed value
98
+ * @returns {boolean}
99
+ */
100
+ function isCompactDetected(prevUsed, currUsed) {
101
+ if (!prevUsed || prevUsed <= 0) return false;
102
+ const drop = (prevUsed - currUsed) / prevUsed;
103
+ return drop > COMPACT_DROP_THRESHOLD;
104
+ }
105
+
106
+ /**
107
+ * Compare two context-monitor snapshots and trigger recovery injection if a
108
+ * compact is detected for any agent.
109
+ *
110
+ * @param {string} projectDir
111
+ * @param {string} squadSlug
112
+ * @param {object} prevData — previous result from getContextUsage (or null)
113
+ * @param {object} currData — current result from getContextUsage
114
+ * @returns {Array<{agentSlug, recovery}>} list of recovery results triggered
115
+ */
116
+ async function checkAndInjectRecovery(projectDir, squadSlug, prevData, currData) {
117
+ if (!prevData || !currData) return [];
118
+ const prevAgents = prevData.agents || {};
119
+ const currAgents = currData.agents || {};
120
+ const triggered = [];
121
+
122
+ for (const [agentSlug, curr] of Object.entries(currAgents)) {
123
+ const prev = prevAgents[agentSlug];
124
+ if (!prev) continue;
125
+ if (isCompactDetected(prev.totalUsed || 0, curr.totalUsed || 0)) {
126
+ const recovery = await generateRecovery(projectDir, squadSlug, agentSlug);
127
+ triggered.push({ agentSlug, recovery });
128
+ }
129
+ }
130
+
131
+ return triggered;
132
+ }
133
+
134
+ /**
135
+ * Optionally trigger a recovery refresh when a specific runtime event fires.
136
+ * @param {string} projectDir
137
+ * @param {string} squadSlug
138
+ * @param {string} agentSlug
139
+ * @param {string} eventType
140
+ */
141
+ async function onRuntimeEvent(projectDir, squadSlug, agentSlug, eventType) {
142
+ if (!shouldRefreshOnEvent(eventType)) return null;
143
+ return generateRecovery(projectDir, squadSlug, agentSlug);
144
+ }
145
+
146
+ module.exports = {
147
+ getContextUsage,
148
+ computeWarningLevel,
149
+ checkNotificationEvents,
150
+ isCompactDetected,
151
+ checkAndInjectRecovery,
152
+ onRuntimeEvent,
153
+ CATEGORIES,
154
+ EVENTS,
155
+ THRESHOLDS,
156
+ COMPACT_DROP_THRESHOLD
157
+ };
@@ -0,0 +1,115 @@
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
+ const ENTRY_TYPES = {
9
+ TOOL_CALL: 'tool_call',
10
+ REASONING: 'reasoning',
11
+ MILESTONE: 'milestone',
12
+ ERROR: 'error'
13
+ };
14
+
15
+ /**
16
+ * Session log file schema:
17
+ * {
18
+ * agentSlug: string,
19
+ * taskId: string,
20
+ * startedAt: ISO string,
21
+ * summary: string | null,
22
+ * entries: Array<{
23
+ * type: 'tool_call' | 'reasoning' | 'milestone' | 'error',
24
+ * timestamp: ISO string,
25
+ * // tool_call
26
+ * toolName?: string,
27
+ * input?: any,
28
+ * output?: any,
29
+ * durationMs?: number,
30
+ * // reasoning
31
+ * text?: string,
32
+ * // milestone
33
+ * label?: string,
34
+ * // error
35
+ * message?: string,
36
+ * stack?: string
37
+ * }>
38
+ * }
39
+ *
40
+ * File path: .aioson/squads/{slug}/logs/{task-id}/session-{timestamp}.json
41
+ */
42
+
43
+ function logsDir(projectDir, squadSlug, taskId) {
44
+ return path.join(projectDir, SQUADS_DIR, squadSlug, 'logs', taskId);
45
+ }
46
+
47
+ async function listSessionFiles(projectDir, squadSlug, taskId) {
48
+ const dir = logsDir(projectDir, squadSlug, taskId);
49
+ let entries;
50
+ try {
51
+ entries = await fs.readdir(dir);
52
+ } catch {
53
+ return [];
54
+ }
55
+ return entries
56
+ .filter(f => f.startsWith('session-') && f.endsWith('.json'))
57
+ .map(f => {
58
+ const ts = f.replace(/^session-/, '').replace(/\.json$/, '');
59
+ return { sessionId: f.replace('.json', ''), filename: f, timestamp: ts, filePath: path.join(dir, f) };
60
+ })
61
+ .sort((a, b) => a.timestamp.localeCompare(b.timestamp));
62
+ }
63
+
64
+ /**
65
+ * Returns all sessions (with entries) for a given task, sorted oldest-first.
66
+ */
67
+ async function getLogsForTask(projectDir, squadSlug, taskId) {
68
+ const files = await listSessionFiles(projectDir, squadSlug, taskId);
69
+ const sessions = [];
70
+ for (const file of files) {
71
+ try {
72
+ const raw = await fs.readFile(file.filePath, 'utf8');
73
+ const session = JSON.parse(raw);
74
+ sessions.push({
75
+ sessionId: file.sessionId,
76
+ timestamp: file.timestamp,
77
+ taskId,
78
+ squadSlug,
79
+ agentSlug: session.agentSlug || null,
80
+ startedAt: session.startedAt || file.timestamp,
81
+ summary: session.summary || null,
82
+ entries: session.entries || []
83
+ });
84
+ } catch {
85
+ sessions.push({
86
+ sessionId: file.sessionId,
87
+ timestamp: file.timestamp,
88
+ taskId,
89
+ squadSlug,
90
+ agentSlug: null,
91
+ startedAt: file.timestamp,
92
+ summary: null,
93
+ entries: [],
94
+ parseError: true
95
+ });
96
+ }
97
+ }
98
+ return sessions;
99
+ }
100
+
101
+ /**
102
+ * Returns a single session log by sessionId (filename without .json).
103
+ */
104
+ async function getSessionLog(projectDir, squadSlug, taskId, sessionId) {
105
+ const dir = logsDir(projectDir, squadSlug, taskId);
106
+ const filePath = path.join(dir, `${sessionId}.json`);
107
+ try {
108
+ const raw = await fs.readFile(filePath, 'utf8');
109
+ return JSON.parse(raw);
110
+ } catch {
111
+ return null;
112
+ }
113
+ }
114
+
115
+ module.exports = { ENTRY_TYPES, getLogsForTask, getSessionLog };