@jaimevalasek/aioson 1.6.0 → 1.7.2

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 (275) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/README.md +729 -232
  3. package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
  4. package/docs/integrations/sdlc-genius-boundary.md +76 -0
  5. package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
  6. package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
  7. package/docs/integrations/sdlc-genius-review-samples.md +86 -0
  8. package/docs/pt/README.md +3 -0
  9. package/docs/pt/agentes.md +1 -0
  10. package/docs/pt/comandos-cli.md +888 -2
  11. package/docs/pt/design-hybrid-forge.md +255 -6
  12. package/docs/pt/devlog-pipeline.md +270 -0
  13. package/docs/pt/fluxo-artefatos.md +178 -0
  14. package/docs/pt/hooks-session-guard.md +454 -0
  15. package/docs/pt/monitor-de-contexto.md +59 -5
  16. package/docs/pt/sdd-automation-scripts.md +557 -0
  17. package/docs/pt/site-forge.md +309 -0
  18. package/docs/pt/spec-learnings-pipeline.md +265 -0
  19. package/package.json +1 -1
  20. package/src/a2a/client.js +165 -0
  21. package/src/a2a/server.js +223 -0
  22. package/src/cli.js +235 -1
  23. package/src/commands/agent-audit.js +397 -0
  24. package/src/commands/agent-export-skill.js +229 -0
  25. package/src/commands/artifact-validate.js +189 -0
  26. package/src/commands/brief-gen.js +405 -0
  27. package/src/commands/brief-validate.js +65 -0
  28. package/src/commands/classify.js +256 -0
  29. package/src/commands/context-compact.js +49 -0
  30. package/src/commands/context-health.js +175 -0
  31. package/src/commands/context-monitor.js +71 -0
  32. package/src/commands/context-trim.js +177 -0
  33. package/src/commands/detect-test-runner.js +55 -0
  34. package/src/commands/devlog-export-brains.js +27 -0
  35. package/src/commands/devlog-process.js +292 -0
  36. package/src/commands/devlog-watch.js +131 -0
  37. package/src/commands/feature-close.js +165 -0
  38. package/src/commands/gate-check.js +228 -0
  39. package/src/commands/hooks-emit.js +253 -0
  40. package/src/commands/hooks-install.js +347 -0
  41. package/src/commands/learning-auto-promote.js +195 -0
  42. package/src/commands/learning-evolve.js +18 -9
  43. package/src/commands/learning-export.js +103 -0
  44. package/src/commands/learning-rollback.js +164 -0
  45. package/src/commands/live.js +25 -1
  46. package/src/commands/pattern-detect.js +33 -0
  47. package/src/commands/preflight-context.js +30 -0
  48. package/src/commands/preflight.js +208 -0
  49. package/src/commands/pulse-update.js +130 -0
  50. package/src/commands/runner-daemon.js +274 -0
  51. package/src/commands/runner-plan.js +70 -0
  52. package/src/commands/runner-queue-from-plan.js +166 -0
  53. package/src/commands/runner-queue.js +189 -0
  54. package/src/commands/runner-run.js +129 -0
  55. package/src/commands/runtime.js +47 -1
  56. package/src/commands/self-implement-loop.js +256 -0
  57. package/src/commands/session-guard.js +218 -0
  58. package/src/commands/sizing.js +165 -0
  59. package/src/commands/skill.js +65 -0
  60. package/src/commands/spec-checkpoint.js +177 -0
  61. package/src/commands/spec-status.js +79 -0
  62. package/src/commands/spec-sync.js +190 -0
  63. package/src/commands/spec-tasks.js +288 -0
  64. package/src/commands/squad-autorun.js +1220 -0
  65. package/src/commands/squad-bus.js +217 -0
  66. package/src/commands/squad-card.js +149 -0
  67. package/src/commands/squad-daemon.js +134 -0
  68. package/src/commands/squad-dependency-graph.js +164 -0
  69. package/src/commands/squad-review.js +106 -0
  70. package/src/commands/squad-scaffold.js +55 -0
  71. package/src/commands/squad-tool-register.js +157 -0
  72. package/src/commands/state-save.js +122 -0
  73. package/src/commands/update.js +2 -0
  74. package/src/commands/verify-gate.js +572 -0
  75. package/src/commands/workflow-execute.js +241 -0
  76. package/src/constants.js +22 -0
  77. package/src/install-profile.js +2 -2
  78. package/src/install-wizard.js +3 -2
  79. package/src/installer.js +6 -0
  80. package/src/lib/health-check.js +158 -0
  81. package/src/lib/hook-protocol.js +76 -0
  82. package/src/mcp/apps/squad-dashboard/app.js +163 -0
  83. package/src/mcp/apps/squad-dashboard/index.html +261 -0
  84. package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
  85. package/src/mcp/resources/squad-state.js +130 -0
  86. package/src/preflight-engine.js +443 -0
  87. package/src/runner/cascade.js +97 -0
  88. package/src/runner/cli-launcher.js +109 -0
  89. package/src/runner/plan-importer.js +63 -0
  90. package/src/runner/queue-store.js +159 -0
  91. package/src/runtime-store.js +61 -3
  92. package/src/squad/agent-teams-adapter.js +264 -0
  93. package/src/squad/brief-validator.js +350 -0
  94. package/src/squad/bus-bridge.js +140 -0
  95. package/src/squad/context-compactor.js +265 -0
  96. package/src/squad/cross-ai-synthesizer.js +250 -0
  97. package/src/squad/hooks-generator.js +196 -0
  98. package/src/squad/inter-squad-events.js +175 -0
  99. package/src/squad/intra-bus.js +345 -0
  100. package/src/squad/learning-extractor.js +213 -0
  101. package/src/squad/pattern-detector.js +365 -0
  102. package/src/squad/preflight-context.js +296 -0
  103. package/src/squad/recovery-context.js +242 -71
  104. package/src/squad/reflection.js +365 -0
  105. package/src/squad/squad-scaffold.js +177 -0
  106. package/src/squad/state-manager.js +310 -0
  107. package/src/squad/task-decomposer.js +652 -0
  108. package/src/squad/verify-gate.js +303 -0
  109. package/src/updater.js +4 -5
  110. package/src/worker-runner.js +186 -1
  111. package/template/.aioson/agents/analyst.md +62 -1
  112. package/template/.aioson/agents/architect.md +61 -1
  113. package/template/.aioson/agents/copywriter.md +463 -0
  114. package/template/.aioson/agents/design-hybrid-forge.md +14 -0
  115. package/template/.aioson/agents/dev.md +271 -25
  116. package/template/.aioson/agents/deyvin.md +67 -8
  117. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  118. package/template/.aioson/agents/genome.md +14 -0
  119. package/template/.aioson/agents/neo.md +83 -2
  120. package/template/.aioson/agents/orache.md +50 -4
  121. package/template/.aioson/agents/orchestrator.md +197 -1
  122. package/template/.aioson/agents/pm.md +35 -0
  123. package/template/.aioson/agents/product.md +50 -5
  124. package/template/.aioson/agents/profiler-enricher.md +14 -0
  125. package/template/.aioson/agents/profiler-forge.md +14 -0
  126. package/template/.aioson/agents/profiler-researcher.md +14 -0
  127. package/template/.aioson/agents/qa.md +273 -21
  128. package/template/.aioson/agents/setup.md +96 -10
  129. package/template/.aioson/agents/sheldon.md +131 -6
  130. package/template/.aioson/agents/site-forge.md +1753 -0
  131. package/template/.aioson/agents/squad.md +352 -0
  132. package/template/.aioson/agents/tester.md +53 -0
  133. package/template/.aioson/agents/ux-ui.md +203 -4
  134. package/template/.aioson/brains/README.md +128 -0
  135. package/template/.aioson/brains/_index.json +16 -0
  136. package/template/.aioson/brains/scripts/query.js +103 -0
  137. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  138. package/template/.aioson/config.md +143 -13
  139. package/template/.aioson/constitution.md +33 -0
  140. package/template/.aioson/context/project-pulse.md +34 -0
  141. package/template/.aioson/docs/LAYERS.md +79 -0
  142. package/template/.aioson/docs/README.md +76 -0
  143. package/template/.aioson/docs/example-external-api-context.md +72 -0
  144. package/template/.aioson/genomes/copywriting.md +204 -0
  145. package/template/.aioson/locales/en/agents/architect.md +17 -0
  146. package/template/.aioson/locales/en/agents/dev.md +79 -13
  147. package/template/.aioson/locales/en/agents/orache.md +6 -0
  148. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  149. package/template/.aioson/locales/en/agents/product.md +50 -0
  150. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  151. package/template/.aioson/locales/en/agents/squad.md +14 -0
  152. package/template/.aioson/locales/en/agents/tester.md +6 -0
  153. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  154. package/template/.aioson/locales/es/agents/architect.md +19 -0
  155. package/template/.aioson/locales/es/agents/dev.md +64 -4
  156. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  157. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  158. package/template/.aioson/locales/es/agents/genome.md +2 -0
  159. package/template/.aioson/locales/es/agents/neo.md +2 -0
  160. package/template/.aioson/locales/es/agents/orache.md +2 -0
  161. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  162. package/template/.aioson/locales/es/agents/pair.md +2 -0
  163. package/template/.aioson/locales/es/agents/pm.md +2 -0
  164. package/template/.aioson/locales/es/agents/product.md +52 -0
  165. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  166. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  167. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  168. package/template/.aioson/locales/es/agents/qa.md +2 -0
  169. package/template/.aioson/locales/es/agents/setup.md +2 -0
  170. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  171. package/template/.aioson/locales/es/agents/squad.md +16 -0
  172. package/template/.aioson/locales/es/agents/tester.md +9 -0
  173. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  174. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  175. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  176. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  177. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  178. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  179. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  180. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  181. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  182. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  183. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  184. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  185. package/template/.aioson/locales/fr/agents/product.md +52 -0
  186. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  187. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  188. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  189. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  190. package/template/.aioson/locales/fr/agents/setup.md +2 -0
  191. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  192. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  193. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  194. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  195. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  196. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  197. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  198. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  199. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  200. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  201. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  202. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  203. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  204. package/template/.aioson/locales/pt-BR/agents/setup.md +101 -18
  205. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  206. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  207. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  208. package/template/.aioson/rules/README.md +69 -0
  209. package/template/.aioson/rules/data-format-convention.md +136 -0
  210. package/template/.aioson/rules/example-monetary-values.md +30 -0
  211. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  212. package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +2 -0
  213. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  214. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  215. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  216. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  217. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  218. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  219. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  220. package/template/.aioson/skills/marketing/references/anti-patterns.md +254 -0
  221. package/template/.aioson/skills/marketing/references/fascinations.md +192 -0
  222. package/template/.aioson/skills/marketing/references/five-acts.md +248 -0
  223. package/template/.aioson/skills/marketing/references/market-intelligence.md +198 -0
  224. package/template/.aioson/skills/marketing/references/offer-structure.md +203 -0
  225. package/template/.aioson/skills/marketing/references/one-belief.md +149 -0
  226. package/template/.aioson/skills/marketing/references/patterns.md +218 -0
  227. package/template/.aioson/skills/marketing/references/pms-research.md +193 -0
  228. package/template/.aioson/skills/marketing/vsl-craft.md +385 -0
  229. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +1 -0
  230. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  231. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  232. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  233. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  234. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +35 -0
  235. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  236. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  237. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  238. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +4 -1
  239. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +15 -0
  240. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +32 -0
  241. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +20 -0
  242. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  243. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  244. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  245. package/template/.aioson/skills/static/landing-page-deploy.md +192 -0
  246. package/template/.aioson/skills/static/landing-page-forge.md +730 -0
  247. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  248. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  249. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  250. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  251. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  252. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  253. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  254. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  255. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  256. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  257. package/template/.aioson/skills/static/ui-ux-modern.md +1 -0
  258. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  259. package/template/.aioson/tasks/implementation-plan.md +21 -1
  260. package/template/.aioson/tasks/squad-create.md +22 -0
  261. package/template/.aioson/tasks/squad-design.md +30 -0
  262. package/template/.aioson/templates/squads/digital-marketing-agency/template.json +96 -0
  263. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  264. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  265. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  266. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  267. package/template/AGENTS.md +55 -3
  268. package/template/CLAUDE.md +31 -0
  269. package/template/OPENCODE.md +4 -0
  270. package/template/researchs/.gitkeep +0 -0
  271. package/template/.aioson/skills/design-system/components/SKILL.md:Zone.Identifier +0 -0
  272. package/template/.aioson/skills/design-system/dashboards/SKILL.md:Zone.Identifier +0 -0
  273. package/template/.aioson/skills/design-system/foundations/SKILL.md:Zone.Identifier +0 -0
  274. package/template/.aioson/skills/design-system/motion/SKILL.md:Zone.Identifier +0 -0
  275. package/template/.aioson/skills/design-system/patterns/SKILL.md:Zone.Identifier +0 -0
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Squad Dashboard App Logic — Plan 81, Phase 4.1
5
+ *
6
+ * Provides data fetching and rendering logic for the MCP App dashboard.
7
+ * Can run standalone (via HTTP API) or embedded in MCP App context.
8
+ */
9
+
10
+ const fs = require('node:fs/promises');
11
+ const path = require('node:path');
12
+
13
+ const SQUADS_DIR = path.join('.aioson', 'squads');
14
+
15
+ // ─── State readers ───────────────────────────────────────────────────────────
16
+
17
+ async function readSquadState(projectDir, squadSlug) {
18
+ const statePath = path.join(projectDir, SQUADS_DIR, squadSlug, 'STATE.md');
19
+ try {
20
+ const content = await fs.readFile(statePath, 'utf8');
21
+ // Parse frontmatter
22
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
23
+ if (!match) return { raw: content };
24
+
25
+ const meta = {};
26
+ for (const line of match[1].split('\n')) {
27
+ const kv = line.match(/^(\w[\w_]*):\s*(.+)$/);
28
+ if (kv) {
29
+ const val = kv[2].trim();
30
+ if (/^\d+(\.\d+)?$/.test(val)) meta[kv[1]] = Number(val);
31
+ else meta[kv[1]] = val.replace(/^["']|["']$/g, '');
32
+ }
33
+ }
34
+
35
+ return { ...meta, raw: content };
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ async function readBusState(projectDir, squadSlug) {
42
+ // Find the most recent session
43
+ const sessionsDir = path.join(projectDir, SQUADS_DIR, squadSlug, 'sessions');
44
+ try {
45
+ const entries = await fs.readdir(sessionsDir, { withFileTypes: true });
46
+ const sessions = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
47
+
48
+ if (sessions.length === 0) return { messages: [], total: 0 };
49
+
50
+ const latestSession = sessions[0];
51
+ const busPath = path.join(sessionsDir, latestSession, 'bus.jsonl');
52
+ const raw = await fs.readFile(busPath, 'utf8');
53
+ const messages = raw.split('\n')
54
+ .filter(Boolean)
55
+ .map((line) => { try { return JSON.parse(line); } catch { return null; } })
56
+ .filter(Boolean);
57
+
58
+ // Classify
59
+ const blocks = messages.filter((m) => m.type === 'block');
60
+ const results = messages.filter((m) => m.type === 'result');
61
+ const byType = {};
62
+ const byExecutor = {};
63
+ for (const m of messages) {
64
+ byType[m.type] = (byType[m.type] || 0) + 1;
65
+ byExecutor[m.from] = (byExecutor[m.from] || 0) + 1;
66
+ }
67
+
68
+ return {
69
+ sessionId: latestSession,
70
+ total: messages.length,
71
+ blocks: blocks.length,
72
+ results: results.length,
73
+ byType,
74
+ byExecutor,
75
+ lastMessages: messages.slice(-20)
76
+ };
77
+ } catch {
78
+ return { messages: [], total: 0 };
79
+ }
80
+ }
81
+
82
+ async function readBudgetState(projectDir, squadSlug) {
83
+ const manifestPath = path.join(projectDir, SQUADS_DIR, squadSlug, 'squad.manifest.json');
84
+ try {
85
+ const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));
86
+ return manifest.budget || { max_tokens_per_session: null, max_tokens_per_task: null };
87
+ } catch {
88
+ return {};
89
+ }
90
+ }
91
+
92
+ async function readWavesState(projectDir, squadSlug) {
93
+ const sessionsDir = path.join(projectDir, SQUADS_DIR, squadSlug, 'sessions');
94
+ try {
95
+ const entries = await fs.readdir(sessionsDir, { withFileTypes: true });
96
+ const sessions = entries.filter((e) => e.isDirectory()).map((e) => e.name).sort().reverse();
97
+
98
+ if (sessions.length === 0) return { waves: [] };
99
+
100
+ const planPath = path.join(sessionsDir, sessions[0], 'plan.json');
101
+ const plan = JSON.parse(await fs.readFile(planPath, 'utf8'));
102
+
103
+ const waves = [];
104
+ const groups = plan.parallel_groups || {};
105
+
106
+ for (const [groupNum, taskIds] of Object.entries(groups)) {
107
+ const waveTasks = taskIds.map((id) => {
108
+ const task = plan.tasks.find((t) => t.id === id);
109
+ return task ? {
110
+ id: task.id,
111
+ title: task.title,
112
+ executor: task.executor,
113
+ status: task.status || 'pending'
114
+ } : { id, status: 'unknown' };
115
+ });
116
+
117
+ const allDone = waveTasks.every((t) => t.status === 'completed');
118
+ const anyRunning = waveTasks.some((t) => t.status === 'in_progress');
119
+ const anyBlocked = waveTasks.some((t) => t.status === 'escalated' || t.status === 'failed');
120
+
121
+ waves.push({
122
+ wave: Number(groupNum),
123
+ status: allDone ? 'DONE' : anyRunning ? 'RUNNING' : anyBlocked ? 'BLOCKED' : 'PENDING',
124
+ tasks: waveTasks
125
+ });
126
+ }
127
+
128
+ return { sessionId: sessions[0], waves, goal: plan.goal };
129
+ } catch {
130
+ return { waves: [] };
131
+ }
132
+ }
133
+
134
+ // ─── Composite dashboard data ────────────────────────────────────────────────
135
+
136
+ /**
137
+ * Get complete dashboard data for a squad.
138
+ */
139
+ async function getDashboardData(projectDir, squadSlug) {
140
+ const [state, busState, budget, wavesState] = await Promise.all([
141
+ readSquadState(projectDir, squadSlug),
142
+ readBusState(projectDir, squadSlug),
143
+ readBudgetState(projectDir, squadSlug),
144
+ readWavesState(projectDir, squadSlug)
145
+ ]);
146
+
147
+ return {
148
+ squad: squadSlug,
149
+ timestamp: new Date().toISOString(),
150
+ state,
151
+ bus: busState,
152
+ budget,
153
+ waves: wavesState
154
+ };
155
+ }
156
+
157
+ module.exports = {
158
+ getDashboardData,
159
+ readSquadState,
160
+ readBusState,
161
+ readBudgetState,
162
+ readWavesState
163
+ };
@@ -0,0 +1,261 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Squad Dashboard — AIOSON</title>
7
+ <style>
8
+ :root {
9
+ --bg: #1a1a2e;
10
+ --surface: #16213e;
11
+ --border: #0f3460;
12
+ --text: #e0e0e0;
13
+ --muted: #888;
14
+ --green: #4ade80;
15
+ --yellow: #fbbf24;
16
+ --red: #f87171;
17
+ --blue: #60a5fa;
18
+ }
19
+ * { margin: 0; padding: 0; box-sizing: border-box; }
20
+ body {
21
+ font-family: 'SF Mono', 'Fira Code', monospace;
22
+ background: var(--bg);
23
+ color: var(--text);
24
+ font-size: 13px;
25
+ padding: 12px;
26
+ }
27
+ .header {
28
+ display: flex;
29
+ justify-content: space-between;
30
+ align-items: center;
31
+ padding: 8px 12px;
32
+ background: var(--surface);
33
+ border: 1px solid var(--border);
34
+ border-radius: 6px;
35
+ margin-bottom: 12px;
36
+ }
37
+ .header .squad-name { font-size: 15px; font-weight: 600; }
38
+ .header .session { color: var(--muted); font-size: 11px; }
39
+ .status-dot {
40
+ display: inline-block;
41
+ width: 8px; height: 8px;
42
+ border-radius: 50%;
43
+ margin-right: 6px;
44
+ }
45
+ .status-dot.active { background: var(--green); }
46
+ .status-dot.warning { background: var(--yellow); }
47
+ .status-dot.error { background: var(--red); }
48
+ .waves-container {
49
+ display: flex;
50
+ gap: 8px;
51
+ margin-bottom: 12px;
52
+ overflow-x: auto;
53
+ }
54
+ .wave {
55
+ flex: 1;
56
+ min-width: 120px;
57
+ background: var(--surface);
58
+ border: 1px solid var(--border);
59
+ border-radius: 6px;
60
+ padding: 8px;
61
+ }
62
+ .wave-header {
63
+ font-size: 11px;
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.5px;
66
+ margin-bottom: 6px;
67
+ padding-bottom: 4px;
68
+ border-bottom: 1px solid var(--border);
69
+ }
70
+ .wave-header.done { color: var(--green); }
71
+ .wave-header.running { color: var(--blue); }
72
+ .wave-header.blocked { color: var(--red); }
73
+ .wave-header.pending { color: var(--muted); }
74
+ .task {
75
+ font-size: 12px;
76
+ padding: 2px 0;
77
+ display: flex;
78
+ align-items: center;
79
+ gap: 4px;
80
+ }
81
+ .task-icon { font-size: 10px; }
82
+ .task-icon.completed { color: var(--green); }
83
+ .task-icon.in_progress { color: var(--blue); }
84
+ .task-icon.failed { color: var(--red); }
85
+ .task-icon.pending { color: var(--muted); }
86
+ .stats-bar {
87
+ display: flex;
88
+ gap: 8px;
89
+ background: var(--surface);
90
+ border: 1px solid var(--border);
91
+ border-radius: 6px;
92
+ padding: 8px 12px;
93
+ margin-bottom: 12px;
94
+ }
95
+ .stat {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 4px;
99
+ }
100
+ .stat-label { color: var(--muted); font-size: 11px; }
101
+ .stat-value { font-weight: 600; }
102
+ .stat-divider {
103
+ width: 1px;
104
+ background: var(--border);
105
+ align-self: stretch;
106
+ }
107
+ .bus-feed {
108
+ background: var(--surface);
109
+ border: 1px solid var(--border);
110
+ border-radius: 6px;
111
+ padding: 8px;
112
+ max-height: 120px;
113
+ overflow-y: auto;
114
+ }
115
+ .bus-msg {
116
+ font-size: 11px;
117
+ padding: 2px 0;
118
+ border-bottom: 1px solid rgba(255,255,255,0.05);
119
+ }
120
+ .bus-msg .from { color: var(--blue); }
121
+ .bus-msg .type { color: var(--muted); }
122
+ .bus-msg .type.block { color: var(--red); }
123
+ .bus-msg .type.result { color: var(--green); }
124
+ #loading { text-align: center; padding: 40px; color: var(--muted); }
125
+ </style>
126
+ </head>
127
+ <body>
128
+ <div id="loading">Loading dashboard data...</div>
129
+ <div id="dashboard" style="display:none">
130
+ <div class="header">
131
+ <div>
132
+ <span class="status-dot active" id="status-dot"></span>
133
+ <span class="squad-name" id="squad-name">—</span>
134
+ </div>
135
+ <div class="session" id="session-info">—</div>
136
+ </div>
137
+
138
+ <div class="waves-container" id="waves"></div>
139
+
140
+ <div class="stats-bar">
141
+ <div class="stat">
142
+ <span class="stat-label">Bus:</span>
143
+ <span class="stat-value" id="bus-total">0</span>
144
+ <span class="stat-label">msgs</span>
145
+ </div>
146
+ <div class="stat-divider"></div>
147
+ <div class="stat">
148
+ <span class="stat-label">Blocks:</span>
149
+ <span class="stat-value" id="bus-blocks">0</span>
150
+ </div>
151
+ <div class="stat-divider"></div>
152
+ <div class="stat">
153
+ <span class="stat-label">Budget:</span>
154
+ <span class="stat-value" id="budget-info">—</span>
155
+ </div>
156
+ <div class="stat-divider"></div>
157
+ <div class="stat">
158
+ <span class="stat-label">Sessions:</span>
159
+ <span class="stat-value" id="sessions-count">0</span>
160
+ </div>
161
+ </div>
162
+
163
+ <div class="bus-feed" id="bus-feed"></div>
164
+ </div>
165
+
166
+ <script>
167
+ const TASK_ICONS = {
168
+ completed: '\u2713',
169
+ in_progress: '\u25B6',
170
+ failed: '\u2717',
171
+ escalated: '\u26A0',
172
+ pending: '\u25CB',
173
+ skipped: '\u2013'
174
+ };
175
+
176
+ function renderWaves(wavesData) {
177
+ const container = document.getElementById('waves');
178
+ container.innerHTML = '';
179
+
180
+ for (const wave of (wavesData.waves || [])) {
181
+ const el = document.createElement('div');
182
+ el.className = 'wave';
183
+ const statusClass = wave.status.toLowerCase();
184
+
185
+ el.innerHTML = `
186
+ <div class="wave-header ${statusClass}">Wave ${wave.wave} [${wave.status}]</div>
187
+ ${wave.tasks.map(t => `
188
+ <div class="task">
189
+ <span class="task-icon ${t.status}">${TASK_ICONS[t.status] || '?'}</span>
190
+ <span>${t.executor || t.title || t.id}</span>
191
+ </div>
192
+ `).join('')}
193
+ `;
194
+ container.appendChild(el);
195
+ }
196
+ }
197
+
198
+ function renderBusFeed(busData) {
199
+ const feed = document.getElementById('bus-feed');
200
+ const messages = busData.lastMessages || [];
201
+ feed.innerHTML = messages.slice(-10).reverse().map(m => `
202
+ <div class="bus-msg">
203
+ <span class="from">${m.from}</span>
204
+ <span class="type ${m.type}">[${m.type}]</span>
205
+ ${m.content ? m.content.slice(0, 80) : ''}
206
+ </div>
207
+ `).join('');
208
+ }
209
+
210
+ function renderDashboard(data) {
211
+ document.getElementById('loading').style.display = 'none';
212
+ document.getElementById('dashboard').style.display = 'block';
213
+
214
+ document.getElementById('squad-name').textContent = `Squad: ${data.squad}`;
215
+ document.getElementById('session-info').textContent =
216
+ data.waves.sessionId ? `Session: ${data.waves.sessionId.slice(0, 8)}` : '';
217
+
218
+ if (data.state) {
219
+ document.getElementById('sessions-count').textContent =
220
+ data.state.sessions_completed || 0;
221
+ }
222
+
223
+ document.getElementById('bus-total').textContent = data.bus.total || 0;
224
+ document.getElementById('bus-blocks').textContent = data.bus.blocks || 0;
225
+
226
+ if (data.budget && data.budget.max_tokens_per_session) {
227
+ document.getElementById('budget-info').textContent =
228
+ `${(data.budget.max_tokens_per_session / 1000).toFixed(0)}k`;
229
+ }
230
+
231
+ const dot = document.getElementById('status-dot');
232
+ if (data.bus.blocks > 0) {
233
+ dot.className = 'status-dot warning';
234
+ } else {
235
+ dot.className = 'status-dot active';
236
+ }
237
+
238
+ renderWaves(data.waves);
239
+ renderBusFeed(data.bus);
240
+ }
241
+
242
+ // MCP App data injection point
243
+ if (window.__MCP_DATA__) {
244
+ renderDashboard(window.__MCP_DATA__);
245
+ }
246
+
247
+ // Polling fallback for standalone mode
248
+ if (window.__DASHBOARD_API__) {
249
+ async function poll() {
250
+ try {
251
+ const res = await fetch(window.__DASHBOARD_API__);
252
+ const data = await res.json();
253
+ renderDashboard(data);
254
+ } catch { /* retry */ }
255
+ setTimeout(poll, 3000);
256
+ }
257
+ poll();
258
+ }
259
+ </script>
260
+ </body>
261
+ </html>
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "aioson-squad-dashboard",
3
+ "version": "1.0.0",
4
+ "description": "Real-time squad execution dashboard for AIOSON",
5
+ "type": "mcp-app",
6
+ "display": {
7
+ "title": "Squad Dashboard",
8
+ "icon": "grid",
9
+ "width": 600,
10
+ "height": 400
11
+ },
12
+ "entry": "index.html",
13
+ "resources": [
14
+ "aioson://squad/{slug}/state",
15
+ "aioson://squad/{slug}/bus",
16
+ "aioson://squad/{slug}/budget",
17
+ "aioson://squad/{slug}/waves"
18
+ ],
19
+ "permissions": [
20
+ "read:squad-state",
21
+ "read:squad-bus"
22
+ ]
23
+ }
@@ -0,0 +1,130 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * MCP Resources: Squad State — Plan 81, Phase 4.2
5
+ *
6
+ * Exposes squad execution state as MCP resources that can be consumed
7
+ * by MCP Apps (dashboard) and MCP clients.
8
+ *
9
+ * Resources:
10
+ * aioson://squad/{slug}/state → STATE.md parsed as JSON
11
+ * aioson://squad/{slug}/bus → last 20 bus messages
12
+ * aioson://squad/{slug}/budget → token budget status
13
+ * aioson://squad/{slug}/waves → execution wave status
14
+ */
15
+
16
+ const { readState } = require('../../squad/state-manager');
17
+ const {
18
+ getDashboardData,
19
+ readBusState,
20
+ readBudgetState,
21
+ readWavesState
22
+ } = require('../apps/squad-dashboard/app');
23
+
24
+ /**
25
+ * MCP resource URI pattern.
26
+ */
27
+ const RESOURCE_PATTERNS = [
28
+ { pattern: /^aioson:\/\/squad\/([a-z0-9-]+)\/state$/, handler: 'state' },
29
+ { pattern: /^aioson:\/\/squad\/([a-z0-9-]+)\/bus$/, handler: 'bus' },
30
+ { pattern: /^aioson:\/\/squad\/([a-z0-9-]+)\/budget$/, handler: 'budget' },
31
+ { pattern: /^aioson:\/\/squad\/([a-z0-9-]+)\/waves$/, handler: 'waves' },
32
+ { pattern: /^aioson:\/\/squad\/([a-z0-9-]+)\/dashboard$/, handler: 'dashboard' }
33
+ ];
34
+
35
+ /**
36
+ * Resolve an MCP resource URI to its data.
37
+ *
38
+ * @param {string} uri — MCP resource URI
39
+ * @param {string} projectDir — Project root
40
+ * @returns {Promise<object|null>} — Resource data or null if not found
41
+ */
42
+ async function resolveResource(uri, projectDir) {
43
+ for (const { pattern, handler } of RESOURCE_PATTERNS) {
44
+ const match = uri.match(pattern);
45
+ if (!match) continue;
46
+
47
+ const squadSlug = match[1];
48
+
49
+ switch (handler) {
50
+ case 'state':
51
+ return readState(projectDir, squadSlug);
52
+
53
+ case 'bus':
54
+ return readBusState(projectDir, squadSlug);
55
+
56
+ case 'budget':
57
+ return readBudgetState(projectDir, squadSlug);
58
+
59
+ case 'waves':
60
+ return readWavesState(projectDir, squadSlug);
61
+
62
+ case 'dashboard':
63
+ return getDashboardData(projectDir, squadSlug);
64
+ }
65
+ }
66
+
67
+ return null;
68
+ }
69
+
70
+ /**
71
+ * List available MCP resources for a project.
72
+ *
73
+ * @param {string} projectDir
74
+ * @returns {Promise<object[]>} — Array of { uri, name, description, mimeType }
75
+ */
76
+ async function listResources(projectDir) {
77
+ const fs = require('node:fs/promises');
78
+ const path = require('node:path');
79
+ const squadsDir = path.join(projectDir, '.aioson', 'squads');
80
+ const resources = [];
81
+
82
+ try {
83
+ const entries = await fs.readdir(squadsDir, { withFileTypes: true });
84
+ for (const entry of entries) {
85
+ if (!entry.isDirectory()) continue;
86
+ const slug = entry.name;
87
+
88
+ resources.push(
89
+ {
90
+ uri: `aioson://squad/${slug}/state`,
91
+ name: `Squad ${slug} — State`,
92
+ description: `Cross-session state for squad "${slug}"`,
93
+ mimeType: 'application/json'
94
+ },
95
+ {
96
+ uri: `aioson://squad/${slug}/bus`,
97
+ name: `Squad ${slug} — Bus`,
98
+ description: `Recent intra-squad bus messages for "${slug}"`,
99
+ mimeType: 'application/json'
100
+ },
101
+ {
102
+ uri: `aioson://squad/${slug}/budget`,
103
+ name: `Squad ${slug} — Budget`,
104
+ description: `Token budget status for "${slug}"`,
105
+ mimeType: 'application/json'
106
+ },
107
+ {
108
+ uri: `aioson://squad/${slug}/waves`,
109
+ name: `Squad ${slug} — Waves`,
110
+ description: `Execution wave status for "${slug}"`,
111
+ mimeType: 'application/json'
112
+ },
113
+ {
114
+ uri: `aioson://squad/${slug}/dashboard`,
115
+ name: `Squad ${slug} — Dashboard`,
116
+ description: `Complete dashboard data for "${slug}"`,
117
+ mimeType: 'application/json'
118
+ }
119
+ );
120
+ }
121
+ } catch { /* no squads dir */ }
122
+
123
+ return resources;
124
+ }
125
+
126
+ module.exports = {
127
+ resolveResource,
128
+ listResources,
129
+ RESOURCE_PATTERNS
130
+ };