@jaimevalasek/aioson 1.6.0 → 1.7.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 (252) hide show
  1. package/CHANGELOG.md +49 -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 +9 -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/design-hybrid-forge.md +14 -0
  114. package/template/.aioson/agents/dev.md +242 -24
  115. package/template/.aioson/agents/deyvin.md +66 -8
  116. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  117. package/template/.aioson/agents/genome.md +14 -0
  118. package/template/.aioson/agents/neo.md +78 -1
  119. package/template/.aioson/agents/orache.md +50 -4
  120. package/template/.aioson/agents/orchestrator.md +197 -1
  121. package/template/.aioson/agents/pm.md +35 -0
  122. package/template/.aioson/agents/product.md +50 -5
  123. package/template/.aioson/agents/profiler-enricher.md +14 -0
  124. package/template/.aioson/agents/profiler-forge.md +14 -0
  125. package/template/.aioson/agents/profiler-researcher.md +14 -0
  126. package/template/.aioson/agents/qa.md +172 -21
  127. package/template/.aioson/agents/setup.md +79 -9
  128. package/template/.aioson/agents/sheldon.md +131 -6
  129. package/template/.aioson/agents/site-forge.md +1753 -0
  130. package/template/.aioson/agents/squad.md +162 -0
  131. package/template/.aioson/agents/tester.md +53 -0
  132. package/template/.aioson/agents/ux-ui.md +34 -1
  133. package/template/.aioson/brains/README.md +128 -0
  134. package/template/.aioson/brains/_index.json +16 -0
  135. package/template/.aioson/brains/scripts/query.js +103 -0
  136. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  137. package/template/.aioson/config.md +143 -13
  138. package/template/.aioson/constitution.md +33 -0
  139. package/template/.aioson/context/project-pulse.md +34 -0
  140. package/template/.aioson/docs/LAYERS.md +79 -0
  141. package/template/.aioson/docs/README.md +76 -0
  142. package/template/.aioson/docs/example-external-api-context.md +72 -0
  143. package/template/.aioson/locales/en/agents/architect.md +17 -0
  144. package/template/.aioson/locales/en/agents/dev.md +79 -13
  145. package/template/.aioson/locales/en/agents/orache.md +6 -0
  146. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  147. package/template/.aioson/locales/en/agents/product.md +50 -0
  148. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  149. package/template/.aioson/locales/en/agents/squad.md +14 -0
  150. package/template/.aioson/locales/en/agents/tester.md +6 -0
  151. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  152. package/template/.aioson/locales/es/agents/architect.md +19 -0
  153. package/template/.aioson/locales/es/agents/dev.md +64 -4
  154. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  155. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  156. package/template/.aioson/locales/es/agents/genome.md +2 -0
  157. package/template/.aioson/locales/es/agents/neo.md +2 -0
  158. package/template/.aioson/locales/es/agents/orache.md +2 -0
  159. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  160. package/template/.aioson/locales/es/agents/pair.md +2 -0
  161. package/template/.aioson/locales/es/agents/pm.md +2 -0
  162. package/template/.aioson/locales/es/agents/product.md +52 -0
  163. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  164. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  165. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  166. package/template/.aioson/locales/es/agents/qa.md +2 -0
  167. package/template/.aioson/locales/es/agents/setup.md +2 -0
  168. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  169. package/template/.aioson/locales/es/agents/squad.md +16 -0
  170. package/template/.aioson/locales/es/agents/tester.md +9 -0
  171. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  172. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  173. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  174. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  175. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  176. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  177. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  178. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  179. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  180. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  181. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  182. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  183. package/template/.aioson/locales/fr/agents/product.md +52 -0
  184. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  185. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  186. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  187. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  188. package/template/.aioson/locales/fr/agents/setup.md +2 -0
  189. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  190. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  191. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  192. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  193. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  194. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  195. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  196. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  197. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  198. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  199. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  200. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  201. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  202. package/template/.aioson/locales/pt-BR/agents/setup.md +101 -18
  203. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  204. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  205. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  206. package/template/.aioson/rules/README.md +69 -0
  207. package/template/.aioson/rules/data-format-convention.md +136 -0
  208. package/template/.aioson/rules/example-monetary-values.md +30 -0
  209. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  210. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  211. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  212. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  213. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  214. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  215. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  216. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  217. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +1 -0
  218. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  219. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  220. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  221. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  222. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +35 -0
  223. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  224. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  225. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  226. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +4 -1
  227. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +15 -0
  228. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +32 -0
  229. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +20 -0
  230. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  231. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  232. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  233. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  234. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  235. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  236. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  237. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  238. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  239. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  240. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  241. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  242. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  243. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  244. package/template/.aioson/tasks/implementation-plan.md +21 -1
  245. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  246. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  247. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  248. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  249. package/template/AGENTS.md +55 -3
  250. package/template/CLAUDE.md +30 -0
  251. package/template/OPENCODE.md +4 -0
  252. package/template/researchs/.gitkeep +0 -0
@@ -0,0 +1,350 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Brief Validator — Plan 80, Script 1
5
+ *
6
+ * Validates completeness of a squad brief/spec before spawning workers.
7
+ * Prevents retries caused by incomplete briefs by catching issues early.
8
+ *
9
+ * Validated fields (6):
10
+ * 1. Phase name and objective (non-empty, ≤ 2 sentences)
11
+ * 2. Files to read (at least 1 existing path)
12
+ * 3. Files to write (at least 1 path with action)
13
+ * 4. Constraints (at least 1)
14
+ * 5. Out of scope (at least 1 item — BLOCKING)
15
+ * 6. Done criteria (must contain DONE | DONE_WITH_CONCERNS | BLOCKED)
16
+ *
17
+ * Output:
18
+ * Score: N/6 — READY | NOT READY (N blocking issues)
19
+ *
20
+ * Evaluator-Optimizer improvement: auto-fix for simple missing fields
21
+ * (out_of_scope, done_criteria template).
22
+ */
23
+
24
+ const fs = require('node:fs/promises');
25
+ const path = require('node:path');
26
+
27
+ // ─── Section matchers ────────────────────────────────────────────────────────
28
+
29
+ const SECTION_PATTERNS = {
30
+ phase_objective: /^#+\s*(phase|objective|goal|task)\b/i,
31
+ files_to_read: /^#+\s*(files?\s+to\s+read|read\s+first|input\s+files?)\b/i,
32
+ files_to_write: /^#+\s*(files?\s+to\s+(write|create)|output\s+files?)\b/i,
33
+ constraints: /^#+\s*(constraints?|hard\s+constraints?|rules?|guardrails?)\b/i,
34
+ out_of_scope: /^#+\s*(out\s+of\s+scope|exclusions?|not\s+in\s+scope)\b/i,
35
+ done_criteria: /^#+\s*(done\s+criteria|acceptance\s+criteria|definition\s+of\s+done|completion\s+criteria)\b/i
36
+ };
37
+
38
+ const DONE_VERDICTS = ['DONE', 'DONE_WITH_CONCERNS', 'BLOCKED'];
39
+ const FILE_ACTIONS = /\b(create|extend|modify|update|replace|overwrite|append|write)\b/i;
40
+
41
+ // ─── Brief parser ────────────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Parse a brief markdown into structured sections.
45
+ * Returns { sections: { name: string[] }, raw: string }
46
+ */
47
+ function parseBrief(content) {
48
+ const lines = content.split(/\r?\n/);
49
+ const sections = {};
50
+ let currentSection = null;
51
+
52
+ for (const line of lines) {
53
+ // Check if this line starts a recognized section
54
+ let matched = false;
55
+ for (const [name, pattern] of Object.entries(SECTION_PATTERNS)) {
56
+ if (pattern.test(line)) {
57
+ currentSection = name;
58
+ if (!sections[currentSection]) sections[currentSection] = [];
59
+ matched = true;
60
+ break;
61
+ }
62
+ }
63
+
64
+ // Also detect generic headings as potential section enders
65
+ if (!matched && /^#+\s/.test(line)) {
66
+ currentSection = null;
67
+ }
68
+
69
+ if (currentSection && !matched) {
70
+ sections[currentSection].push(line);
71
+ }
72
+ }
73
+
74
+ return { sections, raw: content };
75
+ }
76
+
77
+ /**
78
+ * Extract meaningful list items from section lines.
79
+ */
80
+ function extractItems(lines) {
81
+ return lines
82
+ .filter((l) => l.match(/^\s*[-*]\s+/) || l.match(/^\s*\d+\.\s+/) || l.match(/^\s*\[.\]\s+/))
83
+ .map((l) => l.replace(/^\s*[-*]\s+/, '').replace(/^\s*\d+\.\s+/, '').replace(/^\s*\[.\]\s+/, '').trim())
84
+ .filter(Boolean);
85
+ }
86
+
87
+ /**
88
+ * Extract non-empty text content from section lines.
89
+ */
90
+ function extractText(lines) {
91
+ return lines
92
+ .map((l) => l.trim())
93
+ .filter((l) => l && !l.startsWith('```'))
94
+ .join(' ')
95
+ .trim();
96
+ }
97
+
98
+ // ─── Validators ──────────────────────────────────────────────────────────────
99
+
100
+ function validatePhaseObjective(sections) {
101
+ const lines = sections.phase_objective || [];
102
+ const text = extractText(lines);
103
+
104
+ if (!text) {
105
+ return { valid: false, field: 'phase_objective', message: 'Phase name/objective is missing' };
106
+ }
107
+
108
+ // Check ≤ 2 sentences (heuristic: count periods/exclamation/question marks)
109
+ const sentenceCount = (text.match(/[.!?]+/g) || []).length;
110
+ if (sentenceCount > 3) {
111
+ return { valid: false, field: 'phase_objective', message: `Objective has ${sentenceCount} sentences — keep it ≤ 2 for clarity` };
112
+ }
113
+
114
+ return { valid: true, field: 'phase_objective' };
115
+ }
116
+
117
+ function validateFilesToRead(sections, projectDir) {
118
+ const lines = sections.files_to_read || [];
119
+ const items = extractItems(lines);
120
+
121
+ if (items.length === 0) {
122
+ return { valid: false, field: 'files_to_read', message: 'No files to read specified' };
123
+ }
124
+
125
+ // Extract file paths from items (first path-like token)
126
+ const paths = items
127
+ .map((item) => {
128
+ const match = item.match(/[\w./\\-]+\.\w+|[\w./\\-]+\//);
129
+ return match ? match[0] : null;
130
+ })
131
+ .filter(Boolean);
132
+
133
+ if (paths.length === 0) {
134
+ return { valid: false, field: 'files_to_read', message: 'No recognizable file paths in "Files to read"' };
135
+ }
136
+
137
+ return { valid: true, field: 'files_to_read', paths };
138
+ }
139
+
140
+ function validateFilesToWrite(sections) {
141
+ const lines = sections.files_to_write || [];
142
+ const items = extractItems(lines);
143
+
144
+ if (items.length === 0) {
145
+ return { valid: false, field: 'files_to_write', message: 'No files to write specified' };
146
+ }
147
+
148
+ // Check at least one item has an action keyword
149
+ const hasAction = items.some((item) => FILE_ACTIONS.test(item));
150
+ if (!hasAction) {
151
+ return {
152
+ valid: false,
153
+ field: 'files_to_write',
154
+ message: 'Files to write must include at least one action (create|extend|modify)'
155
+ };
156
+ }
157
+
158
+ return { valid: true, field: 'files_to_write' };
159
+ }
160
+
161
+ function validateConstraints(sections) {
162
+ const lines = sections.constraints || [];
163
+ const items = extractItems(lines);
164
+
165
+ if (items.length === 0) {
166
+ return { valid: false, field: 'constraints', message: 'No constraints specified' };
167
+ }
168
+
169
+ return { valid: true, field: 'constraints' };
170
+ }
171
+
172
+ function validateOutOfScope(sections) {
173
+ const lines = sections.out_of_scope || [];
174
+ const items = extractItems(lines);
175
+
176
+ if (items.length === 0) {
177
+ return {
178
+ valid: false,
179
+ field: 'out_of_scope',
180
+ message: 'Out of scope section is missing or empty — BLOCKING',
181
+ blocking: true,
182
+ autoFixable: true
183
+ };
184
+ }
185
+
186
+ return { valid: true, field: 'out_of_scope' };
187
+ }
188
+
189
+ function validateDoneCriteria(sections) {
190
+ const lines = sections.done_criteria || [];
191
+ const text = lines.join('\n');
192
+
193
+ if (!text.trim()) {
194
+ return {
195
+ valid: false,
196
+ field: 'done_criteria',
197
+ message: 'Done criteria section is missing',
198
+ autoFixable: true
199
+ };
200
+ }
201
+
202
+ const hasVerdict = DONE_VERDICTS.some((v) => text.includes(v));
203
+ if (!hasVerdict) {
204
+ return {
205
+ valid: false,
206
+ field: 'done_criteria',
207
+ message: 'Done criteria must contain DONE | DONE_WITH_CONCERNS | BLOCKED verdicts',
208
+ autoFixable: true
209
+ };
210
+ }
211
+
212
+ return { valid: true, field: 'done_criteria' };
213
+ }
214
+
215
+ // ─── Auto-fix generators ─────────────────────────────────────────────────────
216
+
217
+ /**
218
+ * Generate a default "Out of scope" section based on brief context.
219
+ */
220
+ function generateOutOfScope(sections) {
221
+ const items = ['Refactoring code outside the listed files'];
222
+
223
+ const writeItems = extractItems(sections.files_to_write || []);
224
+ if (writeItems.length > 0) {
225
+ items.push('Creating files not listed in "Files to write"');
226
+ }
227
+
228
+ items.push('Performance optimization beyond stated requirements');
229
+ items.push('Documentation updates outside this brief\'s scope');
230
+
231
+ return `\n## Out of scope\n${items.map((i) => `- ${i}`).join('\n')}\n`;
232
+ }
233
+
234
+ /**
235
+ * Generate a default "Done criteria" section template.
236
+ */
237
+ function generateDoneCriteria(sections) {
238
+ const items = ['All files listed in "Files to write" are created/modified'];
239
+
240
+ const constraintItems = extractItems(sections.constraints || []);
241
+ if (constraintItems.length > 0) {
242
+ items.push('All constraints are respected');
243
+ }
244
+
245
+ return `\n## Done criteria\n${items.map((i) => `- [ ] ${i}`).join('\n')}\n\nVerdict: DONE | DONE_WITH_CONCERNS | BLOCKED\n`;
246
+ }
247
+
248
+ // ─── Public API ──────────────────────────────────────────────────────────────
249
+
250
+ /**
251
+ * Validate a brief file for completeness.
252
+ *
253
+ * @param {string} briefPath — Absolute or relative path to the brief markdown
254
+ * @param {string} [projectDir] — Project root for path resolution
255
+ * @returns {Promise<object>} — { ready, score, total, issues, autoFixable }
256
+ */
257
+ async function validateBrief(briefPath, projectDir) {
258
+ const resolvedPath = projectDir
259
+ ? path.resolve(projectDir, briefPath)
260
+ : path.resolve(briefPath);
261
+
262
+ let content;
263
+ try {
264
+ content = await fs.readFile(resolvedPath, 'utf8');
265
+ } catch (err) {
266
+ return {
267
+ ready: false,
268
+ score: 0,
269
+ total: 6,
270
+ issues: [{ field: 'file', message: `Cannot read brief: ${err.message}` }],
271
+ autoFixable: false
272
+ };
273
+ }
274
+
275
+ const { sections } = parseBrief(content);
276
+
277
+ const validators = [
278
+ validatePhaseObjective,
279
+ validateFilesToRead,
280
+ validateFilesToWrite,
281
+ validateConstraints,
282
+ validateOutOfScope,
283
+ validateDoneCriteria
284
+ ];
285
+
286
+ const results = validators.map((fn) => fn(sections, projectDir));
287
+ const passed = results.filter((r) => r.valid).length;
288
+ const issues = results.filter((r) => !r.valid);
289
+ const autoFixable = issues.some((i) => i.autoFixable);
290
+
291
+ return {
292
+ ready: issues.length === 0,
293
+ score: passed,
294
+ total: 6,
295
+ issues,
296
+ autoFixable
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Auto-fix simple missing fields in a brief.
302
+ * Currently supports: out_of_scope, done_criteria.
303
+ *
304
+ * @param {string} briefPath — Path to the brief
305
+ * @param {string} [projectDir] — Project root
306
+ * @returns {Promise<object>} — { fixed, fieldsFixed, newContent }
307
+ */
308
+ async function autoFixBrief(briefPath, projectDir) {
309
+ const resolvedPath = projectDir
310
+ ? path.resolve(projectDir, briefPath)
311
+ : path.resolve(briefPath);
312
+
313
+ let content;
314
+ try {
315
+ content = await fs.readFile(resolvedPath, 'utf8');
316
+ } catch (err) {
317
+ return { fixed: false, error: err.message };
318
+ }
319
+
320
+ const { sections } = parseBrief(content);
321
+ const fieldsFixed = [];
322
+ let newContent = content;
323
+
324
+ // Fix out_of_scope
325
+ const oosResult = validateOutOfScope(sections);
326
+ if (!oosResult.valid && oosResult.autoFixable) {
327
+ newContent += generateOutOfScope(sections);
328
+ fieldsFixed.push('out_of_scope');
329
+ }
330
+
331
+ // Fix done_criteria
332
+ const dcResult = validateDoneCriteria(sections);
333
+ if (!dcResult.valid && dcResult.autoFixable) {
334
+ newContent += generateDoneCriteria(sections);
335
+ fieldsFixed.push('done_criteria');
336
+ }
337
+
338
+ if (fieldsFixed.length === 0) {
339
+ return { fixed: false, fieldsFixed: [] };
340
+ }
341
+
342
+ await fs.writeFile(resolvedPath, newContent, 'utf8');
343
+ return { fixed: true, fieldsFixed, newContent };
344
+ }
345
+
346
+ module.exports = {
347
+ validateBrief,
348
+ autoFixBrief,
349
+ parseBrief
350
+ };
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Bus Bridge — Plan 81, Phase 1.3
5
+ *
6
+ * Bidirectional bridge between Agent Teams mailbox and intra-bus JSONL.
7
+ * Ensures that when squads use Agent Teams engine, all communication
8
+ * is still persisted in the intra-bus for:
9
+ * - Historical analysis by learning-extractor
10
+ * - Cross-session context via recovery-context.js
11
+ * - Pattern detection by pattern-detector.js
12
+ *
13
+ * Directions:
14
+ * mailbox → bus: intercepts SendMessage via PostToolUse hook
15
+ * bus → mailbox: coordinator reads bus and relays to team-lead
16
+ */
17
+
18
+ const bus = require('./intra-bus');
19
+
20
+ // ─── Mailbox → Bus ──────────────────────────────────────────────────────────
21
+
22
+ /**
23
+ * Bridge a SendMessage tool call from Agent Teams mailbox to intra-bus.
24
+ * Called via PostToolUse hook when matcher='SendMessage'.
25
+ *
26
+ * @param {string} projectDir
27
+ * @param {string} squadSlug
28
+ * @param {string} sessionId
29
+ * @param {string} toolInput — JSON string from TOOL_INPUT env var
30
+ */
31
+ async function bridgeMailboxToBus(projectDir, squadSlug, sessionId, toolInput) {
32
+ let parsed;
33
+ try {
34
+ parsed = typeof toolInput === 'string' ? JSON.parse(toolInput) : toolInput;
35
+ } catch {
36
+ return { ok: false, error: 'invalid_tool_input' };
37
+ }
38
+
39
+ const { to, message, from } = parsed;
40
+ if (!message) return { ok: false, error: 'no_message' };
41
+
42
+ // Map mailbox message to bus message type
43
+ const type = inferMessageType(message);
44
+
45
+ const posted = await bus.post(projectDir, squadSlug, sessionId, {
46
+ from: from || 'agent-teams',
47
+ to: to || '*',
48
+ type,
49
+ content: message,
50
+ metadata: {
51
+ source: 'mailbox-bridge',
52
+ original_to: to
53
+ }
54
+ });
55
+
56
+ return { ok: true, busMessageId: posted.id };
57
+ }
58
+
59
+ /**
60
+ * Infer a bus message type from mailbox message content.
61
+ */
62
+ function inferMessageType(message) {
63
+ const lower = (message || '').toLowerCase();
64
+
65
+ if (/\b(block|stuck|cannot|unable|help)\b/i.test(lower)) return 'block';
66
+ if (/\b(done|completed|finished|result)\b/i.test(lower)) return 'result';
67
+ if (/\b(found|discovered|noticed)\b/i.test(lower)) return 'finding';
68
+ if (/\b(question|how|what|why|should)\b/i.test(lower)) return 'question';
69
+ if (/\b(review|feedback|suggest)\b/i.test(lower)) return 'feedback';
70
+
71
+ return 'status';
72
+ }
73
+
74
+ // ─── Bus → Mailbox ──────────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Read recent bus messages and format them for Agent Teams team-lead consumption.
78
+ * Used by coordinator to relay bus intelligence to the team.
79
+ *
80
+ * @param {string} projectDir
81
+ * @param {string} squadSlug
82
+ * @param {string} sessionId
83
+ * @param {object} [filters] — { since, types }
84
+ * @returns {Promise<object[]>} — formatted messages for mailbox relay
85
+ */
86
+ async function readBusForMailbox(projectDir, squadSlug, sessionId, filters = {}) {
87
+ const { since, types } = filters;
88
+ const messages = await bus.read(projectDir, squadSlug, sessionId, {
89
+ since,
90
+ type: types
91
+ });
92
+
93
+ // Filter out messages already from mailbox bridge (prevent loops)
94
+ const filtered = messages.filter(
95
+ (m) => !m.metadata || m.metadata.source !== 'mailbox-bridge'
96
+ );
97
+
98
+ return filtered.map((m) => ({
99
+ from: m.from,
100
+ to: m.to,
101
+ type: m.type,
102
+ content: m.content,
103
+ ts: m.ts,
104
+ mailboxFormat: `[${m.type}] ${m.from}: ${m.content}`
105
+ }));
106
+ }
107
+
108
+ /**
109
+ * Get a summary of bus state for team-lead injection.
110
+ * Returns a concise text block suitable for Agent Teams context.
111
+ */
112
+ async function busSummaryForTeam(projectDir, squadSlug, sessionId) {
113
+ const busSummary = await bus.summary(projectDir, squadSlug, sessionId);
114
+
115
+ if (!busSummary || busSummary.total === 0) {
116
+ return 'Bus: empty (no inter-executor messages yet)';
117
+ }
118
+
119
+ const lines = [
120
+ `Bus: ${busSummary.total} messages`,
121
+ ` Types: ${Object.entries(busSummary.by_type).map(([t, c]) => `${t}(${c})`).join(', ')}`,
122
+ ` Executors: ${Object.entries(busSummary.by_executor).map(([e, c]) => `${e}(${c})`).join(', ')}`
123
+ ];
124
+
125
+ if (busSummary.blocks.length > 0) {
126
+ lines.push(` ⚠ Unresolved blocks: ${busSummary.blocks.length}`);
127
+ for (const b of busSummary.blocks.slice(0, 3)) {
128
+ lines.push(` - ${b.from}: ${b.content.slice(0, 80)}`);
129
+ }
130
+ }
131
+
132
+ return lines.join('\n');
133
+ }
134
+
135
+ module.exports = {
136
+ bridgeMailboxToBus,
137
+ readBusForMailbox,
138
+ busSummaryForTeam,
139
+ inferMessageType
140
+ };