@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,256 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson classify — deterministic classification scoring (MICRO/SMALL/MEDIUM).
5
+ *
6
+ * Reads prd-{slug}.md or requirements-{slug}.md and counts complexity indicators.
7
+ * Falls back to --interactive mode if insufficient data.
8
+ *
9
+ * Usage:
10
+ * aioson classify . --feature=checkout
11
+ * aioson classify . --feature=checkout --json
12
+ * aioson classify . --interactive
13
+ */
14
+
15
+ const path = require('node:path');
16
+ const readline = require('node:readline');
17
+ const { readFileSafe, contextDir } = require('../preflight-engine');
18
+
19
+ const BAR = '━'.repeat(30);
20
+
21
+ // Scoring thresholds
22
+ // user_types: 1→0, 2→1, 3+→2
23
+ // external_integrations: 0→0, 1-2→1, 3+→2
24
+ // rule_complexity: none→0, some→1, complex→2
25
+ // Score: 0-1=MICRO, 2-3=SMALL, 4-6=MEDIUM
26
+
27
+ function scoreUserTypes(count) {
28
+ if (count >= 3) return 2;
29
+ if (count >= 2) return 1;
30
+ return 0;
31
+ }
32
+
33
+ function scoreIntegrations(count) {
34
+ if (count >= 3) return 2;
35
+ if (count >= 1) return 1;
36
+ return 0;
37
+ }
38
+
39
+ function scoreComplexity(level) {
40
+ if (level === 'complex') return 2;
41
+ if (level === 'some') return 1;
42
+ return 0;
43
+ }
44
+
45
+ function scoreToClassification(score) {
46
+ if (score <= 1) return 'MICRO';
47
+ if (score <= 3) return 'SMALL';
48
+ return 'MEDIUM';
49
+ }
50
+
51
+ function classificationToPhaseDepth(classification) {
52
+ if (classification === 'MICRO') {
53
+ return {
54
+ specify: 'brief note or inline',
55
+ research: 'not needed',
56
+ requirements: 'optional',
57
+ design: 'skip',
58
+ plan: 'optional',
59
+ execute: 'direct from task description'
60
+ };
61
+ }
62
+ if (classification === 'SMALL') {
63
+ return {
64
+ specify: 'full PRD',
65
+ research: 'recommended (@sheldon)',
66
+ requirements: 'required (requirements-{slug}.md)',
67
+ design: 'selective (only if new pattern)',
68
+ plan: 'recommended',
69
+ execute: 'from requirements + spec'
70
+ };
71
+ }
72
+ return {
73
+ specify: 'full PRD + stakeholder review',
74
+ research: 'required (@sheldon)',
75
+ requirements: 'required + conformance YAML',
76
+ design: 'required (@ux-ui + @architect)',
77
+ plan: 'required + @pm backlog',
78
+ execute: 'from approved plan, phased delivery'
79
+ };
80
+ }
81
+
82
+ // Pattern-based auto-detection from markdown content
83
+
84
+ const USER_TYPE_PATTERNS = [
85
+ /\b(admin|administrator)\b/gi,
86
+ /\b(user|customer|client|buyer|seller|vendor|manager|operator|guest|visitor|member|owner|reviewer|moderator)\b/gi,
87
+ /\bAs an? ([a-z]+)/gi,
88
+ /\brole[s]?\b.*?:\s*([^,\n]+)/gi
89
+ ];
90
+
91
+ const INTEGRATION_PATTERNS = [
92
+ /\b(stripe|paypal|braintree|square)\b/gi,
93
+ /\b(sendgrid|mailchimp|ses|postmark|smtp)\b/gi,
94
+ /\b(twilio|vonage|nexmo)\b/gi,
95
+ /\b(s3|cloudinary|gcs|azure blob)\b/gi,
96
+ /\b(oauth|jwt|saml|sso|auth0|firebase auth)\b/gi,
97
+ /\b(redis|memcached|elasticsearch|algolia)\b/gi,
98
+ /\bAPI\s+(integration|endpoint|call)\b/gi,
99
+ /\bthird.party\b/gi,
100
+ /\bwebhook[s]?\b/gi,
101
+ /\bexternal\s+service\b/gi
102
+ ];
103
+
104
+ const COMPLEXITY_HIGH_PATTERNS = [
105
+ /\b(multi.step|multi-phase|pipeline|workflow)\b/gi,
106
+ /\b(state machine|finite state|transition)\b/gi,
107
+ /\b(calculation|formula|algorithm|score|pricing engine)\b/gi,
108
+ /\b(complex|intricate|elaborate)\s+(logic|rule|condition)/gi,
109
+ /\b(concurrent|parallel|async|queue)\b/gi,
110
+ /\b(if.+then.+else|conditional|depends on)\b/gi
111
+ ];
112
+
113
+ const COMPLEXITY_SOME_PATTERNS = [
114
+ /\b(validation|constraint|rule)\b/gi,
115
+ /\b(permission|role.based|access control)\b/gi,
116
+ /\b(notification|trigger|event)\b/gi
117
+ ];
118
+
119
+ function analyzeContent(content) {
120
+ // Count unique user types
121
+ const userTypeSet = new Set();
122
+ for (const pattern of USER_TYPE_PATTERNS) {
123
+ let m;
124
+ while ((m = pattern.exec(content)) !== null) {
125
+ userTypeSet.add(m[1] ? m[1].toLowerCase() : m[0].toLowerCase());
126
+ }
127
+ }
128
+ const userTypeCount = Math.min(userTypeSet.size, 5);
129
+
130
+ // Count integrations
131
+ const integrationSet = new Set();
132
+ for (const pattern of INTEGRATION_PATTERNS) {
133
+ let m;
134
+ while ((m = pattern.exec(content)) !== null) {
135
+ integrationSet.add(m[0].toLowerCase());
136
+ }
137
+ }
138
+ const integrationCount = integrationSet.size;
139
+
140
+ // Complexity level
141
+ let complexityLevel = 'none';
142
+ const highMatches = COMPLEXITY_HIGH_PATTERNS.some((p) => p.test(content));
143
+ if (highMatches) {
144
+ complexityLevel = 'complex';
145
+ } else {
146
+ const someMatches = COMPLEXITY_SOME_PATTERNS.some((p) => p.test(content));
147
+ if (someMatches) complexityLevel = 'some';
148
+ }
149
+
150
+ return { userTypeCount, integrationCount, complexityLevel };
151
+ }
152
+
153
+ async function runInteractive(logger) {
154
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
155
+ const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
156
+
157
+ try {
158
+ logger.log('');
159
+ logger.log('Classification — Interactive Mode');
160
+ logger.log(BAR);
161
+
162
+ const utRaw = await ask('User types (1 / 2 / 3+): ');
163
+ const userTypeCount = parseInt(utRaw) || 1;
164
+
165
+ const intRaw = await ask('External integrations (0 / 1-2 / 3+): ');
166
+ const integrationCount = parseInt(intRaw) || 0;
167
+
168
+ const cxRaw = await ask('Business rule complexity (none / some / complex): ');
169
+ const complexityLevel = ['none', 'some', 'complex'].includes(cxRaw.trim().toLowerCase())
170
+ ? cxRaw.trim().toLowerCase()
171
+ : 'none';
172
+
173
+ rl.close();
174
+ return { userTypeCount, integrationCount, complexityLevel };
175
+ } catch {
176
+ rl.close();
177
+ return { userTypeCount: 1, integrationCount: 0, complexityLevel: 'none' };
178
+ }
179
+ }
180
+
181
+ async function runClassify({ args, options = {}, logger }) {
182
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
183
+ const slug = options.feature ? String(options.feature) : null;
184
+ const interactive = Boolean(options.interactive);
185
+
186
+ let userTypeCount, integrationCount, complexityLevel;
187
+ let sourceFile = null;
188
+
189
+ if (interactive) {
190
+ ({ userTypeCount, integrationCount, complexityLevel } = await runInteractive(logger));
191
+ } else {
192
+ // Auto-detect from PRD or requirements file
193
+ const dir = contextDir(targetDir);
194
+ const candidates = slug
195
+ ? [
196
+ path.join(dir, `requirements-${slug}.md`),
197
+ path.join(dir, `prd-${slug}.md`),
198
+ path.join(dir, `sheldon-enrichment-${slug}.md`)
199
+ ]
200
+ : [path.join(dir, 'requirements.md'), path.join(dir, 'prd.md')];
201
+
202
+ let content = null;
203
+ for (const candidate of candidates) {
204
+ content = await readFileSafe(candidate);
205
+ if (content) { sourceFile = path.relative(targetDir, candidate); break; }
206
+ }
207
+
208
+ if (!content) {
209
+ if (options.json) return { ok: false, reason: 'no_source', message: 'No prd or requirements file found. Use --interactive or --feature=<slug>.' };
210
+ logger.log('No source file found. Use --interactive or provide --feature=<slug>.');
211
+ return { ok: false };
212
+ }
213
+
214
+ ({ userTypeCount, integrationCount, complexityLevel } = analyzeContent(content));
215
+ }
216
+
217
+ const utScore = scoreUserTypes(userTypeCount);
218
+ const intScore = scoreIntegrations(integrationCount);
219
+ const cxScore = scoreComplexity(complexityLevel);
220
+ const totalScore = utScore + intScore + cxScore;
221
+ const classification = scoreToClassification(totalScore);
222
+ const phaseDepth = classificationToPhaseDepth(classification);
223
+
224
+ const result = {
225
+ ok: true,
226
+ feature_slug: slug,
227
+ source_file: sourceFile,
228
+ inputs: { user_types: userTypeCount, external_integrations: integrationCount, rule_complexity: complexityLevel },
229
+ scores: { user_types: utScore, integrations: intScore, complexity: cxScore, total: totalScore },
230
+ classification,
231
+ phase_depth: phaseDepth
232
+ };
233
+
234
+ if (options.json) return result;
235
+
236
+ const header = slug ? `Classification — ${slug}` : 'Classification';
237
+ logger.log('');
238
+ logger.log(header);
239
+ logger.log(BAR);
240
+ if (sourceFile) logger.log(`Source: ${sourceFile}`);
241
+ logger.log(`User types: ${userTypeCount} → +${utScore}`);
242
+ logger.log(`External integrations: ${integrationCount} → +${intScore}`);
243
+ logger.log(`Business rule complexity: ${complexityLevel} → +${cxScore}`);
244
+ logger.log(BAR);
245
+ logger.log(`Score: ${totalScore} → ${classification}`);
246
+ logger.log('');
247
+ logger.log('Phase depth:');
248
+ for (const [phase, desc] of Object.entries(phaseDepth)) {
249
+ logger.log(` ${phase.padEnd(14)}: ${desc}`);
250
+ }
251
+ logger.log('');
252
+
253
+ return result;
254
+ }
255
+
256
+ module.exports = { runClassify };
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson context:compact — Standalone context compaction
5
+ *
6
+ * Usage:
7
+ * aioson context:compact . --agent=dev --input=devlog.md
8
+ * aioson context:compact . --agent=orache --input=notes.md --session=abc-123
9
+ * aioson context:compact . --agent=dev --json
10
+ */
11
+
12
+ const path = require('node:path');
13
+ const { compactContext } = require('../squad/context-compactor');
14
+
15
+ async function runContextCompact({ args, options = {}, logger }) {
16
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
17
+ const agent = String(options.agent || options.a || 'dev').trim();
18
+ const input = options.input ? String(options.input).trim() : undefined;
19
+ const session = options.session ? String(options.session).trim() : undefined;
20
+
21
+ if (!input) {
22
+ logger.error('Error: --input=<path> is required (path to devlog, notes, or output)');
23
+ return { ok: false, error: 'missing_input' };
24
+ }
25
+
26
+ const result = await compactContext(targetDir, { agent, input, session });
27
+
28
+ if (!result.ok) {
29
+ logger.error(`Error: ${result.error}`);
30
+ return result;
31
+ }
32
+
33
+ if (options.json) return result.summary;
34
+
35
+ const s = result.summary.summary;
36
+ logger.log(`Context compacted for @${agent}`);
37
+ logger.log(` Session: ${result.summary.session_id}`);
38
+ logger.log(` Tools: ${s.tools_used.length} detected`);
39
+ logger.log(` Requests: ${s.recent_requests.length} extracted`);
40
+ logger.log(` Pending: ${s.pending_work.length} items`);
41
+ logger.log(` Files: ${s.key_files.length} referenced`);
42
+ logger.log(` Timeline: ${s.timeline.length} events`);
43
+ logger.log('');
44
+ logger.log(`Output: ${path.relative(targetDir, result.path)}`);
45
+
46
+ return { ok: true, ...result.summary };
47
+ }
48
+
49
+ module.exports = { runContextCompact };
@@ -0,0 +1,175 @@
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
+ const CHARS_PER_TOKEN = 4;
8
+ const HEAVY_TOKEN_THRESHOLD = 5000; // ~20KB
9
+ const CRITICAL_TOKEN_THRESHOLD = 12500; // ~50KB
10
+
11
+ function estimateTokens(content) {
12
+ return Math.ceil(content.length / CHARS_PER_TOKEN);
13
+ }
14
+
15
+ function formatBytes(bytes) {
16
+ if (bytes < 1024) return `${bytes}B`;
17
+ return `${(bytes / 1024).toFixed(1)}KB`;
18
+ }
19
+
20
+ function formatTokens(n) {
21
+ return `~${n.toLocaleString()}`;
22
+ }
23
+
24
+ async function loadFeatureStatuses(contextDir) {
25
+ const featuresPath = path.join(contextDir, 'features.md');
26
+ try {
27
+ const content = await fs.readFile(featuresPath, 'utf8');
28
+ const done = new Set();
29
+ for (const line of content.split(/\r?\n/)) {
30
+ // Match lines like: - auth: done or | auth | done |
31
+ const m = line.match(/[-|]\s*([a-z0-9_-]+)\s*[:|]\s*done/i);
32
+ if (m) done.add(m[1].toLowerCase());
33
+ }
34
+ return done;
35
+ } catch {
36
+ return new Set();
37
+ }
38
+ }
39
+
40
+ async function getCacheHitRate(db) {
41
+ if (!db) return null;
42
+ try {
43
+ const rows = db.prepare(`
44
+ SELECT COUNT(*) as total,
45
+ SUM(CASE WHEN event_type = 'cache_hit' THEN 1 ELSE 0 END) as hits
46
+ FROM execution_events
47
+ WHERE created_at >= datetime('now', '-7 days')
48
+ `).get();
49
+ if (!rows || rows.total === 0) return null;
50
+ return Math.round((rows.hits / rows.total) * 100);
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ async function runContextHealth({ args, options = {}, logger }) {
57
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
58
+ const contextDir = path.join(targetDir, '.aioson', 'context');
59
+
60
+ let entries;
61
+ try {
62
+ entries = await fs.readdir(contextDir);
63
+ } catch {
64
+ if (!options.json) logger.log('No .aioson/context/ directory found.');
65
+ return { ok: false, reason: 'no_context_dir' };
66
+ }
67
+
68
+ const mdFiles = entries.filter((f) => f.endsWith('.md'));
69
+ const report = [];
70
+ let totalTokens = 0;
71
+
72
+ for (const file of mdFiles) {
73
+ try {
74
+ const content = await fs.readFile(path.join(contextDir, file), 'utf8');
75
+ const tokens = estimateTokens(content);
76
+ totalTokens += tokens;
77
+ report.push({
78
+ file,
79
+ sizeBytes: content.length,
80
+ tokens,
81
+ heavy: tokens > HEAVY_TOKEN_THRESHOLD,
82
+ critical: tokens > CRITICAL_TOKEN_THRESHOLD
83
+ });
84
+ } catch { /* skip unreadable files */ }
85
+ }
86
+
87
+ report.sort((a, b) => b.tokens - a.tokens);
88
+
89
+ const doneFeatures = await loadFeatureStatuses(contextDir);
90
+ const staleSpecs = report.filter((r) => {
91
+ if (!r.file.startsWith('spec-')) return false;
92
+ const slug = r.file.replace(/^spec-/, '').replace(/\.md$/, '');
93
+ return doneFeatures.has(slug);
94
+ });
95
+
96
+ const { db, dbPath } = await openRuntimeDb(targetDir, { mustExist: true }).catch(() => ({ db: null, dbPath: null }));
97
+ const cacheHitRate = await getCacheHitRate(db);
98
+ if (db) db.close();
99
+
100
+ const skeletonPresent = entries.includes('skeleton-system.md') || entries.includes('skeleton.md');
101
+
102
+ if (options.json) {
103
+ return {
104
+ ok: true,
105
+ totalTokens,
106
+ files: report,
107
+ staleSpecs: staleSpecs.map((s) => s.file),
108
+ cacheHitRate,
109
+ skeletonPresent,
110
+ dbPath
111
+ };
112
+ }
113
+
114
+ const COL_FILE = 28;
115
+ const COL_SIZE = 10;
116
+ const COL_TOKENS = 16;
117
+
118
+ logger.log(`Context Health Report — ${path.basename(targetDir)}`);
119
+ logger.log('─'.repeat(56));
120
+ logger.log('Files'.padEnd(COL_FILE) + 'Size'.padEnd(COL_SIZE) + 'Tokens (est.)');
121
+ logger.log('─'.repeat(56));
122
+
123
+ for (const r of report) {
124
+ const flag = r.critical ? ' !! CRITICAL' : r.heavy ? ' ⚠ HEAVY' : '';
125
+ logger.log(
126
+ r.file.padEnd(COL_FILE) +
127
+ formatBytes(r.sizeBytes).padEnd(COL_SIZE) +
128
+ formatTokens(r.tokens) + flag
129
+ );
130
+ }
131
+
132
+ logger.log('─'.repeat(56));
133
+ logger.log(`Total context load:`.padEnd(COL_FILE + COL_SIZE) + formatTokens(totalTokens) + ' tokens');
134
+ logger.log('');
135
+
136
+ const heavyFiles = report.filter((r) => r.heavy);
137
+ if (heavyFiles.length > 0) {
138
+ for (const r of heavyFiles) {
139
+ const label = r.critical ? 'CRITICAL' : 'heavy';
140
+ logger.log(`⚠ ${r.file} is ${label} (${formatBytes(r.sizeBytes)}). Consider:`);
141
+ logger.log(` → Run: aioson context:pack . --scope=<feature>`);
142
+ logger.log(` Creates a scoped context for a specific feature`);
143
+ }
144
+ logger.log('');
145
+ }
146
+
147
+ if (staleSpecs.length > 0) {
148
+ logger.log(`⚠ ${staleSpecs.length} stale spec file(s) (features: done):`);
149
+ for (const s of staleSpecs) {
150
+ const slug = s.file.replace(/^spec-/, '').replace(/\.md$/, '');
151
+ logger.log(` → ${s.file} (feature: ${slug} is done)`);
152
+ }
153
+ logger.log(` Run: aioson context:trim . to archive them`);
154
+ logger.log('');
155
+ }
156
+
157
+ if (cacheHitRate !== null) {
158
+ logger.log(`✓ Cache hit rate: ${cacheHitRate}% (last 7 days)`);
159
+ }
160
+ if (skeletonPresent) {
161
+ logger.log(`✓ skeleton-system.md present — agents can use as lightweight index`);
162
+ }
163
+
164
+ return {
165
+ ok: true,
166
+ totalTokens,
167
+ files: report,
168
+ staleSpecs: staleSpecs.map((s) => s.file),
169
+ cacheHitRate,
170
+ skeletonPresent,
171
+ dbPath
172
+ };
173
+ }
174
+
175
+ module.exports = { runContextHealth };
@@ -6,6 +6,13 @@ const {
6
6
  computeWarningLevel,
7
7
  THRESHOLDS
8
8
  } = require('../squad-dashboard/context-monitor');
9
+ const { openRuntimeDb, appendRunEvent } = require('../runtime-store');
10
+
11
+ const PROJECT_BUDGET_ZONES = {
12
+ safe: 0.60,
13
+ warning: 0.80,
14
+ critical: 1.00
15
+ };
9
16
 
10
17
  const BAR_WIDTH = 20;
11
18
  const LEVEL_ICONS = { normal: ' ', warning: '⚠', critical: '!', overflow: 'X', unknown: '?' };
@@ -36,15 +43,79 @@ function renderAgent(slug, agent) {
36
43
  return line;
37
44
  }
38
45
 
46
+ async function emitBudgetEvent(cwd, { tokens, budget, pct, zone, agentName }) {
47
+ const { db } = await openRuntimeDb(cwd, { mustExist: true }).catch(() => ({ db: null }));
48
+ if (!db) return;
49
+ try {
50
+ const run = db.prepare(
51
+ "SELECT run_key FROM agent_runs WHERE status = 'running' ORDER BY updated_at DESC LIMIT 1"
52
+ ).get();
53
+ if (run) {
54
+ appendRunEvent(db, {
55
+ runKey: run.run_key,
56
+ eventType: zone === 'critical' ? 'context_budget_critical' : 'context_budget_warning',
57
+ phase: 'live',
58
+ status: 'running',
59
+ message: `Context at ${pct}% of budget (${tokens.toLocaleString()} tokens)`,
60
+ payload: { tokens, budget, pct, zone, agentName: agentName || null },
61
+ createdAt: new Date().toISOString()
62
+ });
63
+ }
64
+ } finally {
65
+ db.close();
66
+ }
67
+ }
68
+
39
69
  async function runContextMonitor({ args, options, logger }) {
40
70
  const cwd = path.resolve(process.cwd(), args[0] || '.');
41
71
  const squadSlug = options.squad || null;
42
72
  const agentSlug = options.agent || null;
73
+ const budget = options.budget ? Number(options.budget) : null;
74
+
75
+ // Project-level budget monitoring (--budget=<tokens>)
76
+ if (budget && !squadSlug) {
77
+ const tokens = options.tokens ? Number(options.tokens) : null;
78
+ if (tokens !== null) {
79
+ const pct = Math.round((tokens / budget) * 100);
80
+ const zone = pct >= 100 ? 'overflow'
81
+ : pct >= PROJECT_BUDGET_ZONES.warning * 100 ? 'critical'
82
+ : pct >= PROJECT_BUDGET_ZONES.safe * 100 ? 'warning'
83
+ : 'safe';
84
+
85
+ const icon = zone === 'overflow' ? 'X' : zone === 'critical' ? '!' : zone === 'warning' ? '⚠' : '✓';
86
+
87
+ if (!options.json) {
88
+ logger.log(` ${icon} Context: ${tokens.toLocaleString()} tokens (${pct}%) — ${zone.toUpperCase()}`);
89
+ if (zone === 'warning') {
90
+ logger.log(` Suggestion: /clear before next agent activation`);
91
+ } else if (zone === 'critical' || zone === 'overflow') {
92
+ logger.log(` Run: aioson context:health . for reduction options`);
93
+ }
94
+ }
95
+
96
+ if (zone === 'warning' || zone === 'critical' || zone === 'overflow') {
97
+ await emitBudgetEvent(cwd, { tokens, budget, pct, zone, agentName: agentSlug });
98
+ }
99
+
100
+ if (options.json) {
101
+ return { ok: true, tokens, budget, pct, zone };
102
+ }
103
+ return { ok: true, tokens, budget, pct, zone };
104
+ }
105
+
106
+ if (!options.json) {
107
+ logger.log(` Budget: ${budget.toLocaleString()} tokens`);
108
+ logger.log(` Zones: safe=<${PROJECT_BUDGET_ZONES.safe * 100}% warning=${PROJECT_BUDGET_ZONES.safe * 100}-${PROJECT_BUDGET_ZONES.warning * 100}% critical=>=${PROJECT_BUDGET_ZONES.warning * 100}%`);
109
+ logger.log(` Use --tokens=<n> to check against budget`);
110
+ }
111
+ return { ok: true, budget, zones: PROJECT_BUDGET_ZONES };
112
+ }
43
113
 
44
114
  if (!squadSlug) {
45
115
  logger.log('\n Context Monitor\n');
46
116
  logger.log(' No squad specified. Use --squad=<slug> to monitor a squad.');
47
117
  logger.log(' Example: aioson context:monitor . --squad=my-squad');
118
+ logger.log(' Or use --budget=<tokens> --tokens=<current> for project-level monitoring.');
48
119
  logger.log('');
49
120
  return { ok: true, squads: [] };
50
121
  }