@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,165 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson sizing — Sheldon's sizing decision (inplace / phased_inplace / phased_external).
5
+ *
6
+ * Reads a PRD file and counts entities, phases, integrations, user flows, and ACs.
7
+ * Returns a sizing score and delivery recommendation.
8
+ *
9
+ * Usage:
10
+ * aioson sizing . --prd=.aioson/context/prd-checkout.md
11
+ * aioson sizing . --feature=checkout
12
+ * aioson sizing . --feature=checkout --json
13
+ */
14
+
15
+ const path = require('node:path');
16
+ const { readFileSafe, contextDir } = require('../preflight-engine');
17
+
18
+ const BAR = '━'.repeat(30);
19
+
20
+ // Scoring:
21
+ // main entities > 3 → +1
22
+ // delivery phases > 1 → +2
23
+ // external integrations → +1
24
+ // user flows > 3 → +0 (no penalty)
25
+ // AC count > 10 → +1
26
+ // Score 0-2 → inplace
27
+ // Score 3 → phased_inplace
28
+ // Score 4+ → phased_external
29
+
30
+ function countEntities(content) {
31
+ // Look for entity mentions: model/entity/table patterns
32
+ const patterns = [
33
+ /\b(model|entity|table|resource|object)\s+["`']?([A-Z][a-zA-Z]+)["`']?/g,
34
+ /## [A-Z][a-zA-Z]+ (Model|Entity|Table)/g,
35
+ /\b([A-Z][a-zA-Z]+Model)\b/g
36
+ ];
37
+ const entities = new Set();
38
+ for (const pattern of patterns) {
39
+ let m;
40
+ while ((m = pattern.exec(content)) !== null) {
41
+ entities.add((m[2] || m[1]).toLowerCase());
42
+ }
43
+ }
44
+ // Also count H3 headings as potential entities
45
+ const h3 = content.match(/^### [A-Z][a-zA-Z ]+$/gm) || [];
46
+ return Math.max(entities.size, Math.floor(h3.length / 2));
47
+ }
48
+
49
+ function countPhases(content) {
50
+ // Look for delivery phase / phase N patterns
51
+ const phaseRe = /\b(phase|stage|sprint|iteration)\s+\d+/gi;
52
+ const deliveryRe = /##\s+(phase|stage|delivery|sprint)\s+\d+/gi;
53
+ const phases = new Set();
54
+ let m;
55
+ while ((m = phaseRe.exec(content)) !== null) phases.add(m[0].toLowerCase());
56
+ while ((m = deliveryRe.exec(content)) !== null) phases.add(m[0].toLowerCase());
57
+ return phases.size;
58
+ }
59
+
60
+ function countIntegrations(content) {
61
+ const integrations = [
62
+ /\b(stripe|paypal|braintree|square|mercadopago)\b/gi,
63
+ /\b(sendgrid|mailchimp|ses|postmark|smtp)\b/gi,
64
+ /\b(twilio|vonage|nexmo|sms)\b/gi,
65
+ /\b(s3|cloudinary|gcs|azure)\b/gi,
66
+ /\b(oauth|auth0|firebase|cognito)\b/gi,
67
+ /\b(redis|elasticsearch|algolia)\b/gi,
68
+ /\bAPI\s+(call|integration)\b/gi,
69
+ /\bwebhook[s]?\b/gi,
70
+ /\bexternal\s+service[s]?\b/gi
71
+ ];
72
+ const found = new Set();
73
+ for (const pattern of integrations) {
74
+ let m;
75
+ while ((m = pattern.exec(content)) !== null) found.add(m[0].toLowerCase());
76
+ }
77
+ return found.size;
78
+ }
79
+
80
+ function countUserFlows(content) {
81
+ // User flow = "as a X, I want to Y" or numbered flow steps
82
+ const asAre = content.match(/As an? [a-z]+, I want/gi) || [];
83
+ const flowRe = content.match(/\bflow\s+\d+\b/gi) || [];
84
+ return asAre.length + flowRe.length;
85
+ }
86
+
87
+ function countACs(content) {
88
+ // Acceptance criteria: checkboxes or "AC-N" patterns
89
+ const checkboxes = content.match(/^[-*]\s+\[[ x]\]/gmi) || [];
90
+ const acRe = content.match(/\bAC[-\s]?\d+\b/g) || [];
91
+ return Math.max(checkboxes.length, acRe.length);
92
+ }
93
+
94
+ function sizingDecision(score) {
95
+ if (score <= 2) return { decision: 'inplace', instruction: 'Implement directly in PRD' };
96
+ if (score === 3) return { decision: 'phased_inplace', instruction: 'Add ## Delivery plan section to PRD' };
97
+ return { decision: 'phased_external', instruction: 'Create separate delivery plan document' };
98
+ }
99
+
100
+ async function runSizing({ args, options = {}, logger }) {
101
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
102
+ const slug = options.feature ? String(options.feature) : null;
103
+
104
+ let prdPath = options.prd ? path.resolve(targetDir, options.prd) : null;
105
+
106
+ if (!prdPath && slug) {
107
+ prdPath = path.join(contextDir(targetDir), `prd-${slug}.md`);
108
+ }
109
+
110
+ if (!prdPath) {
111
+ if (options.json) return { ok: false, reason: 'no_prd', message: 'Provide --prd=<path> or --feature=<slug>' };
112
+ logger.log('Provide --prd=<path> or --feature=<slug>');
113
+ return { ok: false };
114
+ }
115
+
116
+ const content = await readFileSafe(prdPath);
117
+ if (!content) {
118
+ if (options.json) return { ok: false, reason: 'file_not_found', path: prdPath };
119
+ logger.log(`File not found: ${path.relative(targetDir, prdPath)}`);
120
+ return { ok: false };
121
+ }
122
+
123
+ const entities = countEntities(content);
124
+ const phases = countPhases(content);
125
+ const integrations = countIntegrations(content);
126
+ const flows = countUserFlows(content);
127
+ const acs = countACs(content);
128
+
129
+ const entityScore = entities > 3 ? 1 : 0;
130
+ const phaseScore = phases > 1 ? 2 : 0;
131
+ const intScore = integrations >= 1 ? 1 : 0;
132
+ const flowScore = 0; // flows ≤ 3 → +0; only informational
133
+ const acScore = acs > 10 ? 1 : 0;
134
+
135
+ const totalScore = entityScore + phaseScore + intScore + flowScore + acScore;
136
+ const { decision, instruction } = sizingDecision(totalScore);
137
+
138
+ const result = {
139
+ ok: true,
140
+ prd_path: path.relative(targetDir, prdPath),
141
+ metrics: { entities, phases, integrations, user_flows: flows, ac_count: acs },
142
+ scores: { entities: entityScore, phases: phaseScore, integrations: intScore, acs: acScore, total: totalScore },
143
+ decision,
144
+ instruction
145
+ };
146
+
147
+ if (options.json) return result;
148
+
149
+ const header = slug ? `Sizing — ${slug}` : `Sizing — ${path.relative(targetDir, prdPath)}`;
150
+ logger.log('');
151
+ logger.log(header);
152
+ logger.log(BAR);
153
+ logger.log(`Main entities: ${entities} → +${entityScore}${entities > 3 ? ' (above 3)' : ''}`);
154
+ logger.log(`Delivery phases: ${phases} → +${phaseScore}${phases > 1 ? ' (above 1)' : ''}`);
155
+ logger.log(`External integrations: ${integrations} → +${intScore}`);
156
+ logger.log(`User flows: ${flows} → +0${flows > 3 ? ' (above 3 — informational)' : ''}`);
157
+ logger.log(`AC count: ${acs} → +${acScore}${acs > 10 ? ' (above 10)' : ''}`);
158
+ logger.log(BAR);
159
+ logger.log(`Score: ${totalScore} → ${decision} (${instruction})`);
160
+ logger.log('');
161
+
162
+ return result;
163
+ }
164
+
165
+ module.exports = { runSizing };
@@ -397,6 +397,58 @@ async function runSkillInstall({ args, options = {}, logger, t }) {
397
397
  };
398
398
  }
399
399
 
400
+ /**
401
+ * Parse a minimal extension.yml manifest if present in a skill directory.
402
+ * Reads only top-level scalar fields and one level of nesting.
403
+ * Returns null if the file is absent or unreadable.
404
+ */
405
+ async function parseExtensionManifest(skillDir) {
406
+ const manifestPath = path.join(skillDir, 'extension.yml');
407
+ let raw;
408
+ try {
409
+ raw = await fs.readFile(manifestPath, 'utf8');
410
+ } catch {
411
+ return null; // file not present — this is the normal case for old skills
412
+ }
413
+
414
+ const manifest = {};
415
+ let currentSection = null;
416
+
417
+ for (const line of raw.split(/\r?\n/)) {
418
+ const trimmed = line.trim();
419
+ if (!trimmed || trimmed.startsWith('#')) continue;
420
+
421
+ // Detect top-level section (no leading spaces, ends with colon, no value)
422
+ if (/^\w[\w-]*:$/.test(trimmed)) {
423
+ currentSection = trimmed.slice(0, -1);
424
+ manifest[currentSection] = {};
425
+ continue;
426
+ }
427
+
428
+ // Nested key: value (indented with spaces or tab)
429
+ if (currentSection && /^\s+/.test(line)) {
430
+ const idx = trimmed.indexOf(':');
431
+ if (idx === -1) continue;
432
+ const key = trimmed.slice(0, idx).trim();
433
+ const val = trimmed.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
434
+ if (key) manifest[currentSection][key] = val;
435
+ continue;
436
+ }
437
+
438
+ // Top-level scalar key: value
439
+ const idx = trimmed.indexOf(':');
440
+ if (idx === -1) continue;
441
+ const key = trimmed.slice(0, idx).trim();
442
+ const val = trimmed.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
443
+ if (key) {
444
+ currentSection = null;
445
+ manifest[key] = val;
446
+ }
447
+ }
448
+
449
+ return manifest;
450
+ }
451
+
400
452
  /**
401
453
  * Scan a directory for .md files with SKILL.md or frontmatter descriptions.
402
454
  * Returns array of { slug, name, description, type, path }.
@@ -478,6 +530,9 @@ async function runSkillList({ args, options = {}, logger, t }) {
478
530
  meta?.generated_by_model ||
479
531
  null;
480
532
 
533
+ // Read optional extension.yml manifest — additive, does not affect existing behavior
534
+ const extManifest = showAll ? await parseExtensionManifest(path.join(skillsDir, slug)) : null;
535
+
481
536
  installed.push({
482
537
  slug,
483
538
  name: fm.name || slug,
@@ -485,6 +540,7 @@ async function runSkillList({ args, options = {}, logger, t }) {
485
540
  source,
486
541
  author,
487
542
  model,
543
+ manifest: extManifest,
488
544
  path: path.relative(targetDir, path.join(skillsDir, slug))
489
545
  });
490
546
  }
@@ -519,6 +575,15 @@ async function runSkillList({ args, options = {}, logger, t }) {
519
575
  }
520
576
  if (s.author) logger.log(` author: ${s.author}`);
521
577
  if (s.model) logger.log(` model: ${s.model}`);
578
+ if (showAll && s.manifest) {
579
+ const ext = s.manifest.extension || {};
580
+ if (ext.version) logger.log(` version: ${ext.version}`);
581
+ const hooks = s.manifest.hooks;
582
+ if (hooks && typeof hooks === 'object') {
583
+ const hookNames = Object.keys(hooks).filter(h => hooks[h]?.enabled !== 'false' && hooks[h]?.enabled !== false);
584
+ if (hookNames.length > 0) logger.log(` hooks declared: ${hookNames.join(', ')}`);
585
+ }
586
+ }
522
587
  logger.log(` ${s.path}/SKILL.md`);
523
588
  logger.log('');
524
589
  }
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { openRuntimeDb, appendRunEvent } = require('../runtime-store');
6
+
7
+ function nowIso() {
8
+ return new Date().toISOString();
9
+ }
10
+
11
+ function parseFrontmatter(content) {
12
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
13
+ if (!match) return {};
14
+ const result = {};
15
+ for (const line of match[1].split(/\r?\n/)) {
16
+ const colonIdx = line.indexOf(':');
17
+ if (colonIdx === -1) continue;
18
+ const key = line.slice(0, colonIdx).trim();
19
+ const value = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, '');
20
+ if (key) result[key] = value;
21
+ }
22
+ return result;
23
+ }
24
+
25
+ function extractLastCheckpoint(content) {
26
+ // Try frontmatter first
27
+ const fmMatch = content.match(/^---[\s\S]*?last_checkpoint:\s*(.+)/m);
28
+ if (fmMatch) return fmMatch[1].trim().replace(/^["']|["']$/g, '');
29
+ // Try section header
30
+ const sectionMatch = content.match(/##\s+last_checkpoint[^\n]*\n([\s\S]*?)(?=\n##|\s*$)/i);
31
+ if (sectionMatch) return sectionMatch[1].replace(/^[-*]\s*/, '').trim();
32
+ return null;
33
+ }
34
+
35
+ function extractPhaseGates(content) {
36
+ const fm = parseFrontmatter(content);
37
+ if (!fm.phase_gates) return null;
38
+ try {
39
+ return JSON.parse(fm.phase_gates.replace(/'/g, '"'));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ async function runSpecCheckpoint({ args, options = {}, logger }) {
46
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
47
+ const featureSlug = options.feature ? String(options.feature).trim() : null;
48
+ const agentName = options.agent ? String(options.agent).trim() : 'dev';
49
+ const contextDir = path.join(targetDir, '.aioson', 'context');
50
+
51
+ if (!featureSlug) {
52
+ if (!options.json) logger.log('Error: --feature=<slug> is required.');
53
+ return { ok: false, reason: 'missing_feature' };
54
+ }
55
+
56
+ // Find spec file
57
+ const candidates = [
58
+ path.join(contextDir, `spec-${featureSlug}.md`),
59
+ path.join(contextDir, 'spec.md')
60
+ ];
61
+
62
+ let specPath = null;
63
+ let specContent = null;
64
+ for (const candidate of candidates) {
65
+ try {
66
+ specContent = await fs.readFile(candidate, 'utf8');
67
+ specPath = candidate;
68
+ break;
69
+ } catch { /* try next */ }
70
+ }
71
+
72
+ if (!specContent) {
73
+ if (!options.json) logger.log(`No spec file found for feature: ${featureSlug}`);
74
+ return { ok: false, reason: 'no_spec_file', featureSlug };
75
+ }
76
+
77
+ const lastCheckpoint = extractLastCheckpoint(specContent);
78
+ const phaseGates = extractPhaseGates(specContent);
79
+
80
+ if (!lastCheckpoint) {
81
+ if (!options.json) logger.log(`No last_checkpoint found in ${path.basename(specPath)}.`);
82
+ return { ok: false, reason: 'no_checkpoint', specPath };
83
+ }
84
+
85
+ const { db, dbPath } = await openRuntimeDb(targetDir, { mustExist: true });
86
+
87
+ if (!db) {
88
+ if (!options.json) logger.log('No runtime database found. Run aioson agent:done first.');
89
+ return { ok: false, reason: 'no_db' };
90
+ }
91
+
92
+ try {
93
+ // Find latest agent run for this feature
94
+ const run = db.prepare(`
95
+ SELECT r.run_key, r.status, r.summary, r.updated_at
96
+ FROM agent_runs r
97
+ WHERE r.agent_name = ?
98
+ AND (r.run_key LIKE ? OR r.task_key LIKE ?)
99
+ ORDER BY r.updated_at DESC
100
+ LIMIT 1
101
+ `).get(agentName, `%${featureSlug}%`, `%${featureSlug}%`);
102
+
103
+ // If no run with feature slug, try latest run by agent name
104
+ const activeRun = run || db.prepare(`
105
+ SELECT run_key, status, summary, updated_at
106
+ FROM agent_runs
107
+ WHERE agent_name = ? AND status IN ('running', 'completed')
108
+ ORDER BY updated_at DESC
109
+ LIMIT 1
110
+ `).get(agentName);
111
+
112
+ if (!activeRun) {
113
+ if (!options.json) {
114
+ logger.log(`No active run found for agent @${agentName}.`);
115
+ logger.log('Tip: run aioson runtime:start first, or specify --agent=<name>.');
116
+ }
117
+ return { ok: false, reason: 'no_run', featureSlug, agentName };
118
+ }
119
+
120
+ // Append checkpoint event
121
+ appendRunEvent(db, {
122
+ runKey: activeRun.run_key,
123
+ eventType: 'plan_checkpoint',
124
+ phase: 'spec',
125
+ status: 'in_progress',
126
+ message: lastCheckpoint,
127
+ payload: phaseGates ? { phase_gates: phaseGates } : null,
128
+ createdAt: nowIso()
129
+ });
130
+
131
+ // Update run summary to last_checkpoint if run is still in_progress
132
+ if (activeRun.status !== 'completed') {
133
+ db.prepare(
134
+ 'UPDATE agent_runs SET summary = ?, updated_at = ? WHERE run_key = ?'
135
+ ).run(lastCheckpoint, nowIso(), activeRun.run_key);
136
+ }
137
+
138
+ if (options.json) {
139
+ return {
140
+ ok: true,
141
+ featureSlug,
142
+ specPath,
143
+ lastCheckpoint,
144
+ phaseGates,
145
+ runKey: activeRun.run_key,
146
+ dbPath
147
+ };
148
+ }
149
+
150
+ logger.log(`Reading ${path.basename(specPath)}...`);
151
+ logger.log(`last_checkpoint: "${lastCheckpoint}"`);
152
+ if (phaseGates) {
153
+ logger.log(`phase_gates: ${JSON.stringify(phaseGates)}`);
154
+ }
155
+ logger.log('');
156
+ logger.log('Checkpoint registered:');
157
+ logger.log(` run_key: ${activeRun.run_key}`);
158
+ logger.log(` summary: "${lastCheckpoint}"`);
159
+ logger.log(` status: in_progress (checkpoint only — use agent:done to close)`);
160
+ logger.log('');
161
+ logger.log(`Next: continue with /${agentName} — start from last_checkpoint`);
162
+
163
+ return {
164
+ ok: true,
165
+ featureSlug,
166
+ specPath,
167
+ lastCheckpoint,
168
+ phaseGates,
169
+ runKey: activeRun.run_key,
170
+ dbPath
171
+ };
172
+ } finally {
173
+ db.close();
174
+ }
175
+ }
176
+
177
+ module.exports = { runSpecCheckpoint };
@@ -0,0 +1,79 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { openRuntimeDb } = require('../runtime-store');
6
+
7
+ async function runSpecStatus({ args, options = {}, logger }) {
8
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
9
+ const { db, dbPath } = await openRuntimeDb(targetDir, { mustExist: true });
10
+
11
+ if (!db) {
12
+ if (!options.json) logger.log('No runtime database found. Run aioson agent:done first.');
13
+ return { ok: false, reason: 'no_db' };
14
+ }
15
+
16
+ try {
17
+ const plans = db.prepare(`
18
+ SELECT plan_id, feature_slug, status, phases_total, phases_completed, created_at, updated_at
19
+ FROM implementation_plans
20
+ WHERE status != 'archived'
21
+ ORDER BY updated_at DESC
22
+ `).all();
23
+
24
+ const rows = [];
25
+ for (const plan of plans) {
26
+ const lastRun = db.prepare(`
27
+ SELECT r.agent_name, r.summary, r.updated_at
28
+ FROM agent_runs r
29
+ JOIN tasks t ON r.task_key = t.task_key
30
+ WHERE r.status IN ('running', 'completed')
31
+ AND (t.session_key LIKE ? OR r.agent_name IS NOT NULL)
32
+ ORDER BY r.updated_at DESC
33
+ LIMIT 1
34
+ `).get(`%${plan.feature_slug || ''}%`);
35
+
36
+ rows.push({
37
+ feature: plan.feature_slug || '(project)',
38
+ phase: `${plan.phases_completed}/${plan.phases_total}`,
39
+ status: plan.status,
40
+ lastAgent: lastRun?.agent_name || '—',
41
+ checkpoint: lastRun?.summary ? lastRun.summary.slice(0, 60) : '—'
42
+ });
43
+ }
44
+
45
+ const totalLearnings = db.prepare(
46
+ "SELECT COUNT(*) as cnt FROM project_learnings WHERE status = 'active'"
47
+ ).get()?.cnt || 0;
48
+
49
+ const promotable = db.prepare(
50
+ "SELECT COUNT(*) as cnt FROM project_learnings WHERE status = 'active' AND frequency >= 3"
51
+ ).get()?.cnt || 0;
52
+
53
+ if (options.json) {
54
+ return { ok: true, features: rows, totalLearnings, promotable, dbPath };
55
+ }
56
+
57
+ logger.log(`Project Status — ${targetDir}`);
58
+ logger.log('─'.repeat(80));
59
+ logger.log('Feature'.padEnd(20) + 'Phase'.padEnd(10) + 'Status'.padEnd(16) + 'Last Agent'.padEnd(16) + 'Checkpoint');
60
+ logger.log('─'.repeat(80));
61
+ for (const r of rows) {
62
+ logger.log(
63
+ r.feature.padEnd(20) +
64
+ r.phase.padEnd(10) +
65
+ r.status.padEnd(16) +
66
+ r.lastAgent.padEnd(16) +
67
+ r.checkpoint
68
+ );
69
+ }
70
+ logger.log('─'.repeat(80));
71
+ logger.log(`Active learnings: ${totalLearnings} | Promotable (freq≥3): ${promotable}`);
72
+
73
+ return { ok: true, features: rows, totalLearnings, promotable, dbPath };
74
+ } finally {
75
+ db.close();
76
+ }
77
+ }
78
+
79
+ module.exports = { runSpecStatus };