@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,365 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Squad executor reflection module
5
+ *
6
+ * Before marking a task DONE, an executor runs a self-critique pass
7
+ * against its output. If the output fails the quality checklist, the
8
+ * executor iterates (up to max_iterations) before escalating to the
9
+ * coordinator or marking as DONE_WITH_CONCERNS.
10
+ *
11
+ * Reflection is triggered automatically when:
12
+ * - A worker calls reflect() before returning its result
13
+ * - The task-decomposer runs a plan step with reflection enabled
14
+ * - The squad:autorun command is invoked with --reflect
15
+ *
16
+ * Checklist sources (in priority order):
17
+ * 1. squad.json → executors[slug].reflection.checklist
18
+ * 2. .aioson/squads/{slug}/quality.md (freeform checklist file)
19
+ * 3. Built-in generic quality criteria (fallback)
20
+ *
21
+ * Verdict:
22
+ * DONE — passed all checks, no issues
23
+ * DONE_WITH_CONCERNS — passed minimally but has minor issues (flagged)
24
+ * NEEDS_ITERATION — failed critical checks, should retry
25
+ * ESCALATE — exhausted iterations, coordinator must decide
26
+ */
27
+
28
+ const fs = require('node:fs/promises');
29
+ const path = require('node:path');
30
+ const { checkMustHaves } = require('./verify-gate');
31
+
32
+ // ─── Built-in quality criteria (generic fallback) ────────────────────────────
33
+
34
+ const GENERIC_CHECKLIST = [
35
+ { id: 'non_empty', label: 'Output is not empty', critical: true },
36
+ { id: 'on_topic', label: 'Output addresses the task objective', critical: true },
37
+ { id: 'no_truncation', label: 'Output is not abruptly cut off', critical: true },
38
+ { id: 'no_filler', label: 'Output has no generic filler content', critical: false },
39
+ { id: 'actionable', label: 'Output contains concrete information', critical: false }
40
+ ];
41
+
42
+ // ─── Checklist loading ────────────────────────────────────────────────────────
43
+
44
+ async function loadSquadJson(projectDir, squadSlug) {
45
+ const p = path.join(projectDir, '.aioson', 'squads', squadSlug, 'squad.json');
46
+ try {
47
+ return JSON.parse(await fs.readFile(p, 'utf8'));
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+
53
+ async function loadQualityFile(projectDir, squadSlug) {
54
+ const p = path.join(projectDir, '.aioson', 'squads', squadSlug, 'quality.md');
55
+ try {
56
+ const raw = await fs.readFile(p, 'utf8');
57
+ return parseQualityMarkdown(raw);
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ function parseQualityMarkdown(content) {
64
+ const criteria = [];
65
+ const lines = content.split(/\r?\n/);
66
+ let id = 0;
67
+
68
+ for (const line of lines) {
69
+ // Support: "- [critical] Label" or "- Label" or "* Label"
70
+ const match = line.match(/^[-*]\s+(?:\[(\w+)\]\s+)?(.+)$/);
71
+ if (!match) continue;
72
+
73
+ const tag = (match[1] || '').toLowerCase();
74
+ const label = match[2].trim();
75
+ if (!label) continue;
76
+
77
+ criteria.push({
78
+ id: `custom_${++id}`,
79
+ label,
80
+ critical: tag === 'critical'
81
+ });
82
+ }
83
+
84
+ return criteria.length > 0 ? criteria : null;
85
+ }
86
+
87
+ async function loadChecklist(projectDir, squadSlug, executorSlug) {
88
+ // 1. squad.json executor-specific checklist
89
+ const squadJson = await loadSquadJson(projectDir, squadSlug);
90
+ if (squadJson) {
91
+ const executorConfig = squadJson.executors && squadJson.executors[executorSlug];
92
+ const checklist = executorConfig && executorConfig.reflection && executorConfig.reflection.checklist;
93
+ if (Array.isArray(checklist) && checklist.length > 0) {
94
+ return checklist.map((item, i) => {
95
+ if (typeof item === 'string') {
96
+ return { id: `exec_${i}`, label: item, critical: false };
97
+ }
98
+ return { id: item.id || `exec_${i}`, label: item.label || item, critical: !!item.critical };
99
+ });
100
+ }
101
+ }
102
+
103
+ // 2. quality.md file
104
+ const fromFile = await loadQualityFile(projectDir, squadSlug);
105
+ if (fromFile) return fromFile;
106
+
107
+ // 3. Generic fallback
108
+ return GENERIC_CHECKLIST;
109
+ }
110
+
111
+ function loadMaxIterations(squadJson, executorSlug) {
112
+ const config = squadJson && squadJson.executors && squadJson.executors[executorSlug];
113
+ const val = config && config.reflection && config.reflection.max_iterations;
114
+ return Number.isFinite(val) && val > 0 ? Math.min(val, 5) : 2;
115
+ }
116
+
117
+ // ─── Deterministic checks ────────────────────────────────────────────────────
118
+
119
+ const FILLER_PATTERNS = [
120
+ /\bi will\b/i,
121
+ /\bof course\b/i,
122
+ /\bcertainly\b/i,
123
+ /\bsure,?\s+here\b/i,
124
+ /\bas an ai\b/i,
125
+ /\bgreat question\b/i,
126
+ /\bhappy to help\b/i,
127
+ /\bI'?d be happy\b/i
128
+ ];
129
+
130
+ function runBuiltinCheck(id, output) {
131
+ const text = String(output || '').trim();
132
+ switch (id) {
133
+ case 'non_empty':
134
+ return text.length > 0;
135
+ case 'on_topic':
136
+ // heuristic: output has at least 50 chars and is not just whitespace
137
+ return text.length >= 50;
138
+ case 'no_truncation':
139
+ // heuristic: doesn't end mid-sentence (no trailing comma or open paren)
140
+ return !/[,(\[{]$/.test(text.replace(/\s+$/, ''));
141
+ case 'no_filler':
142
+ return !FILLER_PATTERNS.some((re) => re.test(text));
143
+ case 'actionable':
144
+ // heuristic: contains at least one noun or verb indicator
145
+ return text.split(/\s+/).length >= 10;
146
+ default:
147
+ // Custom criteria without a built-in check — mark as needs-llm-review
148
+ return null;
149
+ }
150
+ }
151
+
152
+ // ─── Core reflection ─────────────────────────────────────────────────────────
153
+
154
+ /**
155
+ * Run a reflection pass on an executor's output.
156
+ *
157
+ * @param {string} output — The text output to evaluate
158
+ * @param {object} context — { projectDir, squadSlug, executorSlug, taskTitle?, iteration?, task? }
159
+ * task: the full task object (optional) — enables must_haves verification
160
+ * @param {object} [options] — { checklist?, verbose? }
161
+ * @returns {Promise<ReflectionResult>}
162
+ *
163
+ * ReflectionResult:
164
+ * {
165
+ * verdict: 'DONE' | 'DONE_WITH_CONCERNS' | 'NEEDS_ITERATION' | 'ESCALATE',
166
+ * passed: boolean,
167
+ * score: number, // 0.0–1.0
168
+ * iteration: number, // current iteration number
169
+ * max_iterations: number,
170
+ * issues: string[], // failed criteria labels
171
+ * critical_failures: string[],
172
+ * needs_llm_review: string[], // criteria that couldn't be checked deterministically
173
+ * summary: string, // one-line human-readable result
174
+ * checklist: object[] // full results per criterion
175
+ * }
176
+ */
177
+ async function reflect(output, context, options = {}) {
178
+ const { projectDir, squadSlug, executorSlug, taskTitle = 'task', iteration = 1, task } = context;
179
+
180
+ const squadJson = await loadSquadJson(projectDir, squadSlug);
181
+ const maxIterations = loadMaxIterations(squadJson, executorSlug);
182
+
183
+ const checklist = options.checklist
184
+ ? options.checklist.map((item, i) => (
185
+ typeof item === 'string'
186
+ ? { id: `opt_${i}`, label: item, critical: false }
187
+ : item
188
+ ))
189
+ : await loadChecklist(projectDir, squadSlug, executorSlug);
190
+
191
+ const results = [];
192
+ const issues = [];
193
+ const criticalFailures = [];
194
+ const needsLlmReview = [];
195
+
196
+ for (const criterion of checklist) {
197
+ const checkResult = runBuiltinCheck(criterion.id, output);
198
+
199
+ if (checkResult === null) {
200
+ needsLlmReview.push(criterion.label);
201
+ results.push({ ...criterion, result: 'needs_review', passed: null });
202
+ continue;
203
+ }
204
+
205
+ results.push({ ...criterion, result: checkResult ? 'pass' : 'fail', passed: checkResult });
206
+
207
+ if (!checkResult) {
208
+ issues.push(criterion.label);
209
+ if (criterion.critical) criticalFailures.push(criterion.label);
210
+ }
211
+ }
212
+
213
+ // ── must_haves verification (4-tier gate) ─────────────────────────────────
214
+ let mustHavesResult = null;
215
+ if (task && task.must_haves) {
216
+ mustHavesResult = await checkMustHaves(task.must_haves, output, projectDir).catch(() => null);
217
+
218
+ if (mustHavesResult) {
219
+ // Artifact failures are critical (file must exist and be substantive)
220
+ for (const failure of mustHavesResult.failures) {
221
+ criticalFailures.push(`[must_have] ${failure}`);
222
+ issues.push(`[must_have] ${failure}`);
223
+ }
224
+ // Warnings are non-critical (truths, key_links)
225
+ for (const warning of mustHavesResult.warnings) {
226
+ issues.push(`[must_have] ${warning}`);
227
+ }
228
+ }
229
+ }
230
+
231
+ const evaluated = results.filter((r) => r.passed !== null);
232
+ const passedCount = evaluated.filter((r) => r.passed).length;
233
+ const score = evaluated.length > 0 ? passedCount / evaluated.length : 1.0;
234
+ const passed = criticalFailures.length === 0;
235
+
236
+ let verdict;
237
+ if (criticalFailures.length > 0 && iteration < maxIterations) {
238
+ verdict = 'NEEDS_ITERATION';
239
+ } else if (criticalFailures.length > 0 && iteration >= maxIterations) {
240
+ verdict = 'ESCALATE';
241
+ } else if (issues.length > 0) {
242
+ verdict = 'DONE_WITH_CONCERNS';
243
+ } else {
244
+ verdict = 'DONE';
245
+ }
246
+
247
+ const summary = buildSummary(verdict, score, issues, criticalFailures, taskTitle, iteration, maxIterations);
248
+
249
+ return {
250
+ verdict,
251
+ passed,
252
+ score: Math.round(score * 100) / 100,
253
+ iteration,
254
+ max_iterations: maxIterations,
255
+ issues,
256
+ critical_failures: criticalFailures,
257
+ needs_llm_review: needsLlmReview,
258
+ must_haves_result: mustHavesResult,
259
+ summary,
260
+ checklist: results
261
+ };
262
+ }
263
+
264
+ function buildSummary(verdict, score, issues, criticalFailures, taskTitle, iteration, maxIterations) {
265
+ const scoreStr = `${Math.round(score * 100)}%`;
266
+ switch (verdict) {
267
+ case 'DONE':
268
+ return `[DONE] "${taskTitle}" passed all checks (${scoreStr})`;
269
+ case 'DONE_WITH_CONCERNS':
270
+ return `[DONE_WITH_CONCERNS] "${taskTitle}" passed (${scoreStr}) with ${issues.length} minor issue(s): ${issues.slice(0, 2).join(', ')}`;
271
+ case 'NEEDS_ITERATION':
272
+ return `[NEEDS_ITERATION] "${taskTitle}" failed ${criticalFailures.length} critical check(s) — iteration ${iteration}/${maxIterations}: ${criticalFailures.slice(0, 2).join(', ')}`;
273
+ case 'ESCALATE':
274
+ return `[ESCALATE] "${taskTitle}" exhausted ${maxIterations} iterations — coordinator must decide. Failed: ${criticalFailures.join(', ')}`;
275
+ default:
276
+ return `[${verdict}] ${scoreStr}`;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Decide whether to iterate based on a reflection result.
282
+ * Returns true if another attempt is warranted.
283
+ */
284
+ function shouldIterate(reflectionResult) {
285
+ return reflectionResult.verdict === 'NEEDS_ITERATION';
286
+ }
287
+
288
+ /**
289
+ * Run a full reflection loop: reflect → iterate if needed → return final result.
290
+ *
291
+ * @param {function} executeFn — async function that produces output: async () => string
292
+ * @param {object} context — same as reflect()
293
+ * @param {object} [options] — { checklist?, onIteration?, verbose? }
294
+ * @returns {Promise<{ output: string, reflection: ReflectionResult, iterations: number }>}
295
+ */
296
+ async function reflectLoop(executeFn, context, options = {}) {
297
+ const { projectDir, squadSlug, executorSlug } = context;
298
+ const squadJson = await loadSquadJson(projectDir, squadSlug);
299
+ const maxIterations = loadMaxIterations(squadJson, executorSlug);
300
+
301
+ let lastOutput = null;
302
+ let lastReflection = null;
303
+ let iteration = 1;
304
+
305
+ while (iteration <= maxIterations) {
306
+ lastOutput = await executeFn(iteration, lastReflection);
307
+
308
+ lastReflection = await reflect(lastOutput, { ...context, iteration }, options);
309
+
310
+ if (options.onIteration) {
311
+ try { await options.onIteration(iteration, lastOutput, lastReflection); } catch { /* ignore */ }
312
+ }
313
+
314
+ if (!shouldIterate(lastReflection)) break;
315
+ iteration++;
316
+ }
317
+
318
+ return {
319
+ output: lastOutput,
320
+ reflection: lastReflection,
321
+ iterations: iteration
322
+ };
323
+ }
324
+
325
+ /**
326
+ * Format a reflection result as a markdown report.
327
+ * Useful for the bus (posting reflection results as feedback messages).
328
+ */
329
+ function formatReport(result, executorSlug) {
330
+ const lines = [
331
+ `## Reflection: ${result.verdict}`,
332
+ `Executor: ${executorSlug || 'unknown'}`,
333
+ `Score: ${Math.round(result.score * 100)}% | Iteration: ${result.iteration}/${result.max_iterations}`,
334
+ '',
335
+ `**Summary:** ${result.summary}`
336
+ ];
337
+
338
+ if (result.critical_failures.length > 0) {
339
+ lines.push('', '**Critical failures:**');
340
+ for (const f of result.critical_failures) lines.push(`- ❌ ${f}`);
341
+ }
342
+
343
+ if (result.issues.length > result.critical_failures.length) {
344
+ lines.push('', '**Minor issues:**');
345
+ for (const issue of result.issues) {
346
+ if (!result.critical_failures.includes(issue)) lines.push(`- ⚠ ${issue}`);
347
+ }
348
+ }
349
+
350
+ if (result.needs_llm_review.length > 0) {
351
+ lines.push('', '**Needs LLM review (could not evaluate deterministically):**');
352
+ for (const c of result.needs_llm_review) lines.push(`- 🔍 ${c}`);
353
+ }
354
+
355
+ return lines.join('\n');
356
+ }
357
+
358
+ module.exports = {
359
+ reflect,
360
+ reflectLoop,
361
+ shouldIterate,
362
+ formatReport,
363
+ loadChecklist,
364
+ GENERIC_CHECKLIST
365
+ };
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Squad Scaffold — Plan 80, Script 3
5
+ *
6
+ * Deterministic generator of squad directory structure.
7
+ * Eliminates ~2,000 tokens of LLM usage by creating all 15+ files/directories
8
+ * that every squad needs via templates.
9
+ *
10
+ * Integrates with state-manager.js for STATE.md generation.
11
+ *
12
+ * Usage:
13
+ * node squad-scaffold.js --slug=<slug> --name="Name" --mode=content|code|hybrid
14
+ */
15
+
16
+ const fs = require('node:fs/promises');
17
+ const path = require('node:path');
18
+ const stateManager = require('./state-manager');
19
+
20
+ const SQUADS_DIR = path.join('.aioson', 'squads');
21
+
22
+ // ─── Templates ───────────���─────────────────────────��─────────────────────────
23
+
24
+ function agentsSkeleton(name, mode) {
25
+ const executorTypes = {
26
+ content: ['writer', 'editor', 'researcher'],
27
+ code: ['developer', 'reviewer', 'tester'],
28
+ hybrid: ['researcher', 'developer', 'writer']
29
+ };
30
+
31
+ const types = executorTypes[mode] || executorTypes.hybrid;
32
+ const slots = types.map((t) => `### ${t}\n- **Role:** (define)\n- **Tools:** (define)\n- **Checklist:** (define)`);
33
+
34
+ return `# ${name} — Agent Roster\n\n${slots.join('\n\n')}\n`;
35
+ }
36
+
37
+ function manifestSkeleton(slug, name, mode) {
38
+ return JSON.stringify({
39
+ slug,
40
+ name,
41
+ mode,
42
+ created_at: new Date().toISOString(),
43
+ budget: {
44
+ max_tokens_per_session: null,
45
+ max_tokens_per_task: null,
46
+ action_on_exceed: 'pause'
47
+ },
48
+ depends_on: [],
49
+ subscriptions: [],
50
+ hooks: {
51
+ pre_run: null,
52
+ post_run: null
53
+ },
54
+ anti_loop: {
55
+ threshold: 8,
56
+ action: 'feedback'
57
+ }
58
+ }, null, 2);
59
+ }
60
+
61
+ function squadMdSkeleton(name, mode) {
62
+ return `# ${name}\n\n## Overview\n(describe the squad's purpose)\n\n## Mode\n${mode}\n\n## Executors\nSee agents/agents.md\n\n## Workflows\n(define execution workflows)\n\n## Quality Gates\nSee checklists/quality.md\n`;
63
+ }
64
+
65
+ function designDocSkeleton(name) {
66
+ return `# ${name} — Design Document\n\n## Problem Statement\n(what problem does this squad solve?)\n\n## Approach\n(how will it be solved?)\n\n## Executors & Responsibilities\n(who does what?)\n\n## Data Flow\n(how do executors communicate?)\n\n## Risks & Mitigations\n(what could go wrong?)\n`;
67
+ }
68
+
69
+ function readinessSkeleton(name) {
70
+ return `# ${name} — Readiness Checklist\n\n- [ ] Squad manifest configured\n- [ ] All executors defined in agents.md\n- [ ] Quality checklist in place\n- [ ] At least one workflow defined\n- [ ] Design doc reviewed\n- [ ] Test run completed\n`;
71
+ }
72
+
73
+ function qualitySkeleton(name) {
74
+ return `# ${name} — Quality Checklist\n\n## Per-Task Checks\n- [ ] Output matches acceptance criteria\n- [ ] No placeholder or TODO content\n- [ ] Files listed in brief are created/modified\n\n## Per-Session Checks\n- [ ] All tasks completed or properly escalated\n- [ ] Bus has no unresolved blocks\n- [ ] STATE.md updated with decisions\n\n## Per-Deliverable Checks\n- [ ] verify:gate passes on final output\n- [ ] No sensitive data in output files\n`;
75
+ }
76
+
77
+ function learningsIndexSkeleton(name) {
78
+ return `# ${name} — Learnings Index\n\nsession_count: 0\n\n## Extracted Learnings\n*(populated automatically by learning-extractor after sessions)*\n\n## Manual Observations\n*(add observations here)*\n`;
79
+ }
80
+
81
+ // ─── Public API ──────────────────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Scaffold a new squad directory structure.
85
+ *
86
+ * @param {string} projectDir — Project root
87
+ * @param {object} options — { slug, name, mode }
88
+ * @returns {Promise<object>} — { ok, slug, files, directories }
89
+ */
90
+ async function scaffoldSquad(projectDir, options = {}) {
91
+ const { slug, name, mode = 'hybrid' } = options;
92
+
93
+ if (!slug) return { ok: false, error: 'slug is required' };
94
+ if (!name) return { ok: false, error: 'name is required' };
95
+ if (!['content', 'code', 'hybrid'].includes(mode)) {
96
+ return { ok: false, error: `Invalid mode "${mode}" — use content|code|hybrid` };
97
+ }
98
+
99
+ const squadDir = path.join(projectDir, SQUADS_DIR, slug);
100
+
101
+ // Check if slug already exists
102
+ try {
103
+ await fs.access(squadDir);
104
+ return { ok: false, error: `Squad "${slug}" already exists at ${squadDir}` };
105
+ } catch { /* expected — directory doesn't exist yet */ }
106
+
107
+ const createdFiles = [];
108
+ const createdDirs = [];
109
+
110
+ // Helper
111
+ async function writeFile(relPath, content) {
112
+ const fullPath = path.join(projectDir, relPath);
113
+ await fs.mkdir(path.dirname(fullPath), { recursive: true });
114
+ await fs.writeFile(fullPath, content, 'utf8');
115
+ createdFiles.push(relPath);
116
+ }
117
+
118
+ async function ensureDir(relPath) {
119
+ const fullPath = path.join(projectDir, relPath);
120
+ await fs.mkdir(fullPath, { recursive: true });
121
+ createdDirs.push(relPath);
122
+ }
123
+
124
+ const base = path.join(SQUADS_DIR, slug);
125
+
126
+ // Squad directory files
127
+ await writeFile(path.join(base, 'agents', 'agents.md'), agentsSkeleton(name, mode));
128
+ await writeFile(path.join(base, 'squad.manifest.json'), manifestSkeleton(slug, name, mode));
129
+ await writeFile(path.join(base, 'squad.md'), squadMdSkeleton(name, mode));
130
+ await writeFile(path.join(base, 'docs', 'design-doc.md'), designDocSkeleton(name));
131
+ await writeFile(path.join(base, 'docs', 'readiness.md'), readinessSkeleton(name));
132
+ await writeFile(path.join(base, 'checklists', 'quality.md'), qualitySkeleton(name));
133
+ await writeFile(path.join(base, 'learnings', 'index.md'), learningsIndexSkeleton(name));
134
+
135
+ // Empty directories
136
+ await ensureDir(path.join(base, 'workflows'));
137
+ await ensureDir(path.join(base, 'scripts'));
138
+ await ensureDir(path.join(base, 'script-plans'));
139
+ await ensureDir(path.join(base, 'bus'));
140
+
141
+ // Output directories
142
+ await ensureDir(path.join('output', slug));
143
+ await ensureDir(path.join('aioson-logs', slug));
144
+ await ensureDir(path.join('media', slug));
145
+
146
+ // STATE.md via state-manager (already formatted)
147
+ await stateManager.writeState(projectDir, slug, stateManager.readState
148
+ ? await stateManager.readState(projectDir, slug)
149
+ : {
150
+ meta: {
151
+ squad: slug,
152
+ current_session: '',
153
+ sessions_completed: 0,
154
+ tasks_completed_total: 0,
155
+ avg_tasks_per_session: 0,
156
+ last_activity: new Date().toISOString()
157
+ },
158
+ decisions: [],
159
+ blockers: [],
160
+ pending: [],
161
+ notes: [`Squad "${name}" scaffolded (mode: ${mode})`]
162
+ }
163
+ );
164
+ createdFiles.push(path.join(base, 'STATE.md'));
165
+
166
+ return {
167
+ ok: true,
168
+ slug,
169
+ name,
170
+ mode,
171
+ files: createdFiles,
172
+ directories: createdDirs,
173
+ total: createdFiles.length + createdDirs.length
174
+ };
175
+ }
176
+
177
+ module.exports = { scaffoldSquad };