@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,310 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Squad STATE.md manager
5
+ *
6
+ * Maintains a cross-session memory file per squad at:
7
+ * .aioson/squads/{slug}/STATE.md
8
+ *
9
+ * The STATE.md survives /clear and gives the next session instant context on:
10
+ * - Current position in the squad's lifecycle
11
+ * - Velocity metrics
12
+ * - Active blockers
13
+ * - Key decisions made
14
+ * - Pending tasks for the next session
15
+ *
16
+ * Uses YAML frontmatter for machine-parseable metadata + markdown body
17
+ * for human-readable context.
18
+ */
19
+
20
+ const fs = require('node:fs/promises');
21
+ const path = require('node:path');
22
+
23
+ const SQUADS_DIR = path.join('.aioson', 'squads');
24
+
25
+ function statePath(projectDir, squadSlug) {
26
+ return path.join(projectDir, SQUADS_DIR, squadSlug, 'STATE.md');
27
+ }
28
+
29
+ function nowIso() {
30
+ return new Date().toISOString();
31
+ }
32
+
33
+ // ─── Frontmatter parsing ──────────────────────────────────────────────────────
34
+
35
+ function parseFrontmatter(content) {
36
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
37
+ if (!match) return { meta: {}, body: content };
38
+
39
+ const meta = {};
40
+ for (const line of match[1].split('\n')) {
41
+ const kv = line.match(/^(\w[\w_]*):\s*(.+)$/);
42
+ if (kv) {
43
+ const val = kv[2].trim();
44
+ // Parse numbers and booleans
45
+ if (val === 'true') meta[kv[1]] = true;
46
+ else if (val === 'false') meta[kv[1]] = false;
47
+ else if (/^\d+(\.\d+)?$/.test(val)) meta[kv[1]] = Number(val);
48
+ else meta[kv[1]] = val.replace(/^["']|["']$/g, '');
49
+ }
50
+ }
51
+
52
+ return { meta, body: match[2] };
53
+ }
54
+
55
+ function serializeFrontmatter(meta) {
56
+ const lines = ['---'];
57
+ for (const [k, v] of Object.entries(meta)) {
58
+ lines.push(`${k}: ${v}`);
59
+ }
60
+ lines.push('---');
61
+ return lines.join('\n');
62
+ }
63
+
64
+ // ─── State structure ──────────────────────────────────────────────────────────
65
+
66
+ function defaultState(squadSlug) {
67
+ return {
68
+ meta: {
69
+ squad: squadSlug,
70
+ current_session: '',
71
+ sessions_completed: 0,
72
+ tasks_completed_total: 0,
73
+ avg_tasks_per_session: 0,
74
+ last_activity: nowIso()
75
+ },
76
+ decisions: [],
77
+ blockers: [],
78
+ pending: [],
79
+ notes: []
80
+ };
81
+ }
82
+
83
+ // ─── Parse body sections ──────────────────────────────────────────────────────
84
+
85
+ function parseSection(body, sectionName) {
86
+ const pattern = new RegExp(`## ${sectionName}\\n([\\s\\S]*?)(?=\\n## |$)`);
87
+ const match = body.match(pattern);
88
+ if (!match) return [];
89
+
90
+ return match[1]
91
+ .split('\n')
92
+ .filter((l) => l.startsWith('- '))
93
+ .map((l) => l.slice(2).trim());
94
+ }
95
+
96
+ function buildSection(title, items) {
97
+ if (items.length === 0) return `## ${title}\n*(none)*`;
98
+ return `## ${title}\n${items.map((i) => `- ${i}`).join('\n')}`;
99
+ }
100
+
101
+ // ─── Public API ───────────────────────────────────────────────────────────────
102
+
103
+ /**
104
+ * Read and parse the squad STATE.md.
105
+ * Returns a default state object if the file does not exist.
106
+ *
107
+ * @returns {Promise<object>} { meta, decisions, blockers, pending, notes }
108
+ */
109
+ async function readState(projectDir, squadSlug) {
110
+ const p = statePath(projectDir, squadSlug);
111
+ let content;
112
+ try {
113
+ content = await fs.readFile(p, 'utf8');
114
+ } catch {
115
+ return defaultState(squadSlug);
116
+ }
117
+
118
+ const { meta, body } = parseFrontmatter(content);
119
+
120
+ return {
121
+ meta: { ...defaultState(squadSlug).meta, ...meta },
122
+ decisions: parseSection(body, 'Decisions Made'),
123
+ blockers: parseSection(body, 'Active Blockers'),
124
+ pending: parseSection(body, 'Pending'),
125
+ notes: parseSection(body, 'Notes')
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Write the squad STATE.md from a state object.
131
+ *
132
+ * @param {string} projectDir
133
+ * @param {string} squadSlug
134
+ * @param {object} state — { meta, decisions, blockers, pending, notes }
135
+ */
136
+ async function writeState(projectDir, squadSlug, state) {
137
+ const p = statePath(projectDir, squadSlug);
138
+ await fs.mkdir(path.dirname(p), { recursive: true });
139
+
140
+ const frontmatter = serializeFrontmatter({ ...state.meta, last_activity: nowIso() });
141
+
142
+ const body = [
143
+ '',
144
+ buildSection('Decisions Made', state.decisions || []),
145
+ '',
146
+ buildSection('Active Blockers', state.blockers || []),
147
+ '',
148
+ buildSection('Pending', state.pending || []),
149
+ '',
150
+ buildSection('Notes', state.notes || [])
151
+ ].join('\n');
152
+
153
+ await fs.writeFile(p, frontmatter + body + '\n', 'utf8');
154
+ }
155
+
156
+ /**
157
+ * Update specific fields in the STATE.md.
158
+ * Merges meta, appends to list fields.
159
+ *
160
+ * @param {string} projectDir
161
+ * @param {string} squadSlug
162
+ * @param {object} updates
163
+ * @param {object} [updates.meta] — Shallow merge into meta
164
+ * @param {string[]} [updates.addDecision] — Prepend to decisions list
165
+ * @param {string[]} [updates.addBlocker] — Prepend to blockers list
166
+ * @param {string[]} [updates.addPending] — Prepend to pending list
167
+ * @param {string[]} [updates.resolveBlocker] — Remove matching entries from blockers
168
+ * @param {string[]} [updates.resolvePending] — Remove matching entries from pending
169
+ * @param {number} [updates.tasksCompleted] — Number to add to tasks_completed_total
170
+ */
171
+ async function updateState(projectDir, squadSlug, updates = {}) {
172
+ const state = await readState(projectDir, squadSlug);
173
+
174
+ // Merge meta
175
+ if (updates.meta) {
176
+ Object.assign(state.meta, updates.meta);
177
+ }
178
+
179
+ // Add decisions (newest first, cap at 20)
180
+ if (updates.addDecision) {
181
+ const dated = updates.addDecision.map((d) => `${nowIso().slice(0, 10)}: ${d}`);
182
+ state.decisions = [...dated, ...state.decisions].slice(0, 20);
183
+ }
184
+
185
+ // Add blockers
186
+ if (updates.addBlocker) {
187
+ state.blockers = [...updates.addBlocker, ...state.blockers];
188
+ }
189
+
190
+ // Resolve blockers (remove by substring match)
191
+ if (updates.resolveBlocker) {
192
+ for (const pattern of updates.resolveBlocker) {
193
+ state.blockers = state.blockers.filter((b) => !b.toLowerCase().includes(pattern.toLowerCase()));
194
+ }
195
+ }
196
+
197
+ // Add pending items
198
+ if (updates.addPending) {
199
+ state.pending = [...updates.addPending, ...state.pending];
200
+ }
201
+
202
+ // Resolve pending items
203
+ if (updates.resolvePending) {
204
+ for (const pattern of updates.resolvePending) {
205
+ state.pending = state.pending.filter((p) => !p.toLowerCase().includes(pattern.toLowerCase()));
206
+ }
207
+ }
208
+
209
+ // Update velocity metrics
210
+ if (updates.tasksCompleted) {
211
+ state.meta.tasks_completed_total = (state.meta.tasks_completed_total || 0) + updates.tasksCompleted;
212
+ const sessions = state.meta.sessions_completed || 0;
213
+ if (sessions > 0) {
214
+ state.meta.avg_tasks_per_session = Math.round(
215
+ (state.meta.tasks_completed_total / sessions) * 10
216
+ ) / 10;
217
+ }
218
+ }
219
+
220
+ await writeState(projectDir, squadSlug, state);
221
+ return state;
222
+ }
223
+
224
+ /**
225
+ * Record the start of a new session in the STATE.md.
226
+ */
227
+ async function recordSessionStart(projectDir, squadSlug, sessionId, goal) {
228
+ await updateState(projectDir, squadSlug, {
229
+ meta: { current_session: sessionId }
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Record the completion of a session in the STATE.md.
235
+ * Updates velocity metrics and clears session-specific blockers.
236
+ */
237
+ async function recordSessionEnd(projectDir, squadSlug, sessionId, results) {
238
+ const completedCount = results.filter((r) => r.finalStatus === 'completed').length;
239
+ const failedCount = results.filter((r) => r.finalStatus === 'failed').length;
240
+ const escalatedCount = results.filter((r) => r.finalStatus === 'escalated').length;
241
+
242
+ const state = await readState(projectDir, squadSlug);
243
+ const sessionCount = (state.meta.sessions_completed || 0) + 1;
244
+
245
+ const pending = [];
246
+ for (const r of results) {
247
+ if (r.finalStatus === 'escalated') {
248
+ pending.push(`[escalated] ${r.task.title}`);
249
+ }
250
+ }
251
+
252
+ await updateState(projectDir, squadSlug, {
253
+ meta: {
254
+ sessions_completed: sessionCount,
255
+ last_session: sessionId
256
+ },
257
+ tasksCompleted: completedCount,
258
+ addPending: pending,
259
+ addDecision: failedCount + escalatedCount > 0
260
+ ? [`Session ${sessionId.slice(0, 8)}: ${completedCount} completed, ${failedCount} failed, ${escalatedCount} escalated`]
261
+ : [`Session ${sessionId.slice(0, 8)}: ${completedCount} tasks completed`]
262
+ });
263
+ }
264
+
265
+ // ─── RuntimeState Serialization (Plan 81 §Sprint 4) ─────────────────────────
266
+
267
+ /**
268
+ * Serialize complete runtime state for handoff between agents.
269
+ * Eliminates the need for the next agent to reread STATE.md + bus + budget.
270
+ *
271
+ * Inspired by CrewAI v1.13 RuntimeState serialization.
272
+ *
273
+ * @param {string} projectDir
274
+ * @param {string} squadSlug
275
+ * @param {object} sessionContext — { sessionId, currentWave, completedTasks, budgetUsed, budgetLimit, busSummary }
276
+ * @returns {Promise<object>} — serialized runtime state
277
+ */
278
+ async function serializeRuntime(projectDir, squadSlug, sessionContext = {}) {
279
+ const state = await readState(projectDir, squadSlug);
280
+
281
+ return {
282
+ runtime_state: {
283
+ squad: squadSlug,
284
+ current_session: state.meta.current_session,
285
+ current_wave: sessionContext.currentWave || null,
286
+ completed_tasks: sessionContext.completedTasks || [],
287
+ active_decisions: state.decisions.slice(0, 10),
288
+ active_blockers: state.blockers,
289
+ pending: state.pending,
290
+ budget_remaining: sessionContext.budgetLimit
291
+ ? sessionContext.budgetLimit - (sessionContext.budgetUsed || 0)
292
+ : null,
293
+ budget_used: sessionContext.budgetUsed || 0,
294
+ budget_limit: sessionContext.budgetLimit || null,
295
+ bus_summary: sessionContext.busSummary || null,
296
+ sessions_completed: state.meta.sessions_completed,
297
+ avg_tasks_per_session: state.meta.avg_tasks_per_session,
298
+ serialized_at: nowIso()
299
+ }
300
+ };
301
+ }
302
+
303
+ module.exports = {
304
+ readState,
305
+ writeState,
306
+ updateState,
307
+ recordSessionStart,
308
+ recordSessionEnd,
309
+ serializeRuntime
310
+ };