@jaimevalasek/aioson 1.5.1 → 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 (341) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +729 -226
  3. package/docs/design-previews/aurora-command-ui-website.html +884 -0
  4. package/docs/design-previews/aurora-command-ui.html +682 -0
  5. package/docs/design-previews/bold-editorial-ui-website.html +658 -0
  6. package/docs/design-previews/bold-editorial-ui.html +717 -0
  7. package/docs/design-previews/clean-saas-ui-website.html +1202 -0
  8. package/docs/design-previews/clean-saas-ui.html +549 -0
  9. package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
  10. package/docs/design-previews/cognitive-core-ui.html +463 -0
  11. package/docs/design-previews/glassmorphism-ui-website.html +572 -0
  12. package/docs/design-previews/glassmorphism-ui.html +886 -0
  13. package/docs/design-previews/index.html +699 -0
  14. package/docs/design-previews/interface-design-website.html +1187 -0
  15. package/docs/design-previews/interface-design.html +513 -0
  16. package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
  17. package/docs/design-previews/neo-brutalist-ui.html +797 -0
  18. package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
  19. package/docs/design-previews/premium-command-center-ui.html +552 -0
  20. package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
  21. package/docs/design-previews/warm-craft-ui-website.html +684 -0
  22. package/docs/design-previews/warm-craft-ui.html +739 -0
  23. package/docs/en/cli-reference.md +20 -9
  24. package/docs/integrations/sdlc-genius-boundary.md +76 -0
  25. package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
  26. package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
  27. package/docs/integrations/sdlc-genius-review-samples.md +86 -0
  28. package/docs/pt/README.md +10 -0
  29. package/docs/pt/agent-sharding.md +132 -0
  30. package/docs/pt/agentes.md +9 -2
  31. package/docs/pt/busca-de-contexto.md +129 -0
  32. package/docs/pt/cache-de-contexto.md +156 -0
  33. package/docs/pt/comandos-cli.md +915 -1
  34. package/docs/pt/design-hybrid-forge.md +356 -0
  35. package/docs/pt/devlog-pipeline.md +270 -0
  36. package/docs/pt/fluxo-artefatos.md +178 -0
  37. package/docs/pt/hooks-session-guard.md +454 -0
  38. package/docs/pt/inicio-rapido.md +54 -3
  39. package/docs/pt/inteligencia-adaptativa.md +324 -0
  40. package/docs/pt/monitor-de-contexto.md +158 -0
  41. package/docs/pt/recuperacao-de-sessao.md +125 -0
  42. package/docs/pt/sandbox.md +125 -0
  43. package/docs/pt/sdd-automation-scripts.md +557 -0
  44. package/docs/pt/site-forge.md +309 -0
  45. package/docs/pt/skills.md +98 -6
  46. package/docs/pt/spec-learnings-pipeline.md +265 -0
  47. package/package.json +1 -1
  48. package/src/a2a/client.js +165 -0
  49. package/src/a2a/server.js +223 -0
  50. package/src/agent-loader.js +280 -0
  51. package/src/cli.js +329 -1
  52. package/src/commands/agent-audit.js +397 -0
  53. package/src/commands/agent-export-skill.js +229 -0
  54. package/src/commands/agent-loader.js +85 -0
  55. package/src/commands/artifact-validate.js +189 -0
  56. package/src/commands/brief-gen.js +405 -0
  57. package/src/commands/brief-validate.js +65 -0
  58. package/src/commands/classify.js +256 -0
  59. package/src/commands/context-cache.js +90 -0
  60. package/src/commands/context-compact.js +49 -0
  61. package/src/commands/context-health.js +175 -0
  62. package/src/commands/context-monitor.js +163 -0
  63. package/src/commands/context-search.js +66 -0
  64. package/src/commands/context-trim.js +177 -0
  65. package/src/commands/design-hybrid-options.js +385 -0
  66. package/src/commands/detect-test-runner.js +55 -0
  67. package/src/commands/devlog-export-brains.js +27 -0
  68. package/src/commands/devlog-process.js +292 -0
  69. package/src/commands/devlog-watch.js +131 -0
  70. package/src/commands/feature-close.js +165 -0
  71. package/src/commands/gate-check.js +228 -0
  72. package/src/commands/health.js +214 -0
  73. package/src/commands/hooks-emit.js +253 -0
  74. package/src/commands/hooks-install.js +347 -0
  75. package/src/commands/init.js +54 -13
  76. package/src/commands/install.js +52 -13
  77. package/src/commands/learning-auto-promote.js +195 -0
  78. package/src/commands/learning-evolve.js +364 -0
  79. package/src/commands/learning-export.js +103 -0
  80. package/src/commands/learning-rollback.js +164 -0
  81. package/src/commands/live.js +59 -1
  82. package/src/commands/pattern-detect.js +33 -0
  83. package/src/commands/preflight-context.js +30 -0
  84. package/src/commands/preflight.js +208 -0
  85. package/src/commands/pulse-update.js +130 -0
  86. package/src/commands/recovery.js +43 -0
  87. package/src/commands/runner-daemon.js +274 -0
  88. package/src/commands/runner-plan.js +70 -0
  89. package/src/commands/runner-queue-from-plan.js +166 -0
  90. package/src/commands/runner-queue.js +189 -0
  91. package/src/commands/runner-run.js +129 -0
  92. package/src/commands/runtime.js +47 -1
  93. package/src/commands/sandbox.js +37 -0
  94. package/src/commands/self-implement-loop.js +256 -0
  95. package/src/commands/session-guard.js +218 -0
  96. package/src/commands/setup-context.js +22 -2
  97. package/src/commands/setup.js +178 -0
  98. package/src/commands/sizing.js +165 -0
  99. package/src/commands/skill.js +144 -32
  100. package/src/commands/spec-checkpoint.js +177 -0
  101. package/src/commands/spec-status.js +79 -0
  102. package/src/commands/spec-sync.js +190 -0
  103. package/src/commands/spec-tasks.js +288 -0
  104. package/src/commands/squad-autorun.js +1220 -0
  105. package/src/commands/squad-bus.js +217 -0
  106. package/src/commands/squad-card.js +149 -0
  107. package/src/commands/squad-daemon.js +134 -0
  108. package/src/commands/squad-dependency-graph.js +164 -0
  109. package/src/commands/squad-review.js +106 -0
  110. package/src/commands/squad-scaffold.js +55 -0
  111. package/src/commands/squad-tool-register.js +157 -0
  112. package/src/commands/state-save.js +122 -0
  113. package/src/commands/tool-registry-cmd.js +232 -0
  114. package/src/commands/update.js +9 -0
  115. package/src/commands/verify-gate.js +572 -0
  116. package/src/commands/workflow-execute.js +241 -0
  117. package/src/constants.js +18 -0
  118. package/src/context-cache.js +159 -0
  119. package/src/context-search.js +326 -0
  120. package/src/design-variation-catalog.js +503 -0
  121. package/src/i18n/messages/en.js +32 -2
  122. package/src/i18n/messages/es.js +30 -2
  123. package/src/i18n/messages/fr.js +30 -2
  124. package/src/i18n/messages/pt-BR.js +32 -2
  125. package/src/install-animation.js +260 -0
  126. package/src/install-profile.js +143 -0
  127. package/src/install-wizard.js +475 -0
  128. package/src/installer.js +44 -10
  129. package/src/lib/health-check.js +158 -0
  130. package/src/lib/hook-protocol.js +76 -0
  131. package/src/mcp/apps/squad-dashboard/app.js +163 -0
  132. package/src/mcp/apps/squad-dashboard/index.html +261 -0
  133. package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
  134. package/src/mcp/resources/squad-state.js +130 -0
  135. package/src/parser.js +7 -1
  136. package/src/preflight-engine.js +443 -0
  137. package/src/recovery-context-session.js +154 -0
  138. package/src/runner/cascade.js +97 -0
  139. package/src/runner/cli-launcher.js +109 -0
  140. package/src/runner/plan-importer.js +63 -0
  141. package/src/runner/queue-store.js +159 -0
  142. package/src/runtime-store.js +158 -4
  143. package/src/sandbox.js +177 -0
  144. package/src/squad/agent-teams-adapter.js +264 -0
  145. package/src/squad/brief-validator.js +350 -0
  146. package/src/squad/bus-bridge.js +140 -0
  147. package/src/squad/context-compactor.js +265 -0
  148. package/src/squad/cross-ai-synthesizer.js +250 -0
  149. package/src/squad/hooks-generator.js +196 -0
  150. package/src/squad/inter-squad-events.js +175 -0
  151. package/src/squad/intra-bus.js +345 -0
  152. package/src/squad/learning-extractor.js +213 -0
  153. package/src/squad/pattern-detector.js +365 -0
  154. package/src/squad/preflight-context.js +296 -0
  155. package/src/squad/recovery-context.js +242 -71
  156. package/src/squad/reflection.js +365 -0
  157. package/src/squad/squad-scaffold.js +177 -0
  158. package/src/squad/state-manager.js +310 -0
  159. package/src/squad/task-decomposer.js +652 -0
  160. package/src/squad/verify-gate.js +303 -0
  161. package/src/tool-executor.js +94 -0
  162. package/src/updater.js +10 -3
  163. package/src/worker-runner.js +186 -1
  164. package/template/.aioson/agents/analyst.md +119 -3
  165. package/template/.aioson/agents/architect.md +98 -0
  166. package/template/.aioson/agents/design-hybrid-forge.md +141 -0
  167. package/template/.aioson/agents/dev.md +335 -14
  168. package/template/.aioson/agents/deyvin.md +117 -2
  169. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  170. package/template/.aioson/agents/genome.md +14 -0
  171. package/template/.aioson/agents/neo.md +78 -1
  172. package/template/.aioson/agents/orache.md +50 -4
  173. package/template/.aioson/agents/orchestrator.md +197 -1
  174. package/template/.aioson/agents/pm.md +93 -0
  175. package/template/.aioson/agents/product.md +77 -4
  176. package/template/.aioson/agents/profiler-enricher.md +14 -0
  177. package/template/.aioson/agents/profiler-forge.md +14 -0
  178. package/template/.aioson/agents/profiler-researcher.md +14 -0
  179. package/template/.aioson/agents/qa.md +249 -19
  180. package/template/.aioson/agents/setup.md +144 -12
  181. package/template/.aioson/agents/sheldon.md +237 -11
  182. package/template/.aioson/agents/site-forge.md +1753 -0
  183. package/template/.aioson/agents/squad.md +162 -0
  184. package/template/.aioson/agents/tester.md +209 -0
  185. package/template/.aioson/agents/ux-ui.md +34 -1
  186. package/template/.aioson/brains/README.md +128 -0
  187. package/template/.aioson/brains/_index.json +16 -0
  188. package/template/.aioson/brains/scripts/query.js +103 -0
  189. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  190. package/template/.aioson/config.md +158 -13
  191. package/template/.aioson/constitution.md +33 -0
  192. package/template/.aioson/context/forensics/.gitkeep +0 -0
  193. package/template/.aioson/context/project-pulse.md +34 -0
  194. package/template/.aioson/context/seeds/seed-example.md +27 -0
  195. package/template/.aioson/context/user-profile.md +42 -0
  196. package/template/.aioson/docs/LAYERS.md +79 -0
  197. package/template/.aioson/docs/README.md +76 -0
  198. package/template/.aioson/docs/example-external-api-context.md +72 -0
  199. package/template/.aioson/locales/en/agents/architect.md +17 -0
  200. package/template/.aioson/locales/en/agents/dev.md +79 -13
  201. package/template/.aioson/locales/en/agents/orache.md +6 -0
  202. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  203. package/template/.aioson/locales/en/agents/product.md +50 -0
  204. package/template/.aioson/locales/en/agents/setup.md +33 -1
  205. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  206. package/template/.aioson/locales/en/agents/squad.md +14 -0
  207. package/template/.aioson/locales/en/agents/tester.md +6 -0
  208. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  209. package/template/.aioson/locales/es/agents/architect.md +19 -0
  210. package/template/.aioson/locales/es/agents/dev.md +64 -4
  211. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  212. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  213. package/template/.aioson/locales/es/agents/genome.md +2 -0
  214. package/template/.aioson/locales/es/agents/neo.md +2 -0
  215. package/template/.aioson/locales/es/agents/orache.md +2 -0
  216. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  217. package/template/.aioson/locales/es/agents/pair.md +2 -0
  218. package/template/.aioson/locales/es/agents/pm.md +2 -0
  219. package/template/.aioson/locales/es/agents/product.md +52 -0
  220. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  221. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  222. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  223. package/template/.aioson/locales/es/agents/qa.md +2 -0
  224. package/template/.aioson/locales/es/agents/setup.md +35 -1
  225. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  226. package/template/.aioson/locales/es/agents/squad.md +16 -0
  227. package/template/.aioson/locales/es/agents/tester.md +9 -0
  228. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  229. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  230. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  231. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  232. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  233. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  234. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  235. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  236. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  237. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  238. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  239. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  240. package/template/.aioson/locales/fr/agents/product.md +52 -0
  241. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  242. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  243. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  244. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  245. package/template/.aioson/locales/fr/agents/setup.md +35 -1
  246. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  247. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  248. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  249. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  250. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  251. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  252. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  253. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  254. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  255. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  256. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  257. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  258. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  259. package/template/.aioson/locales/pt-BR/agents/setup.md +134 -19
  260. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  261. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  262. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  263. package/template/.aioson/rules/README.md +69 -0
  264. package/template/.aioson/rules/data-format-convention.md +136 -0
  265. package/template/.aioson/rules/example-monetary-values.md +30 -0
  266. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  267. package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
  268. package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
  269. package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
  270. package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
  271. package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
  272. package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
  273. package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
  274. package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
  275. package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
  276. package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
  277. package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
  278. package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
  279. package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
  280. package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
  281. package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
  282. package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
  283. package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
  284. package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
  285. package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
  286. package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
  287. package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
  288. package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
  289. package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
  290. package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
  291. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  292. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  293. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  294. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  295. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  296. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  297. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  298. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +46 -0
  299. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  300. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
  301. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  302. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
  303. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
  304. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  305. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  306. package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
  307. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +101 -0
  308. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  309. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  310. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  311. package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
  312. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +147 -0
  313. package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
  314. package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
  315. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +306 -0
  316. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +149 -0
  317. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +208 -0
  318. package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
  319. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  320. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  321. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  322. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  323. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  324. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  325. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  326. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  327. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  328. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  329. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  330. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  331. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  332. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  333. package/template/.aioson/tasks/implementation-plan.md +21 -1
  334. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  335. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  336. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  337. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  338. package/template/AGENTS.md +75 -1
  339. package/template/CLAUDE.md +31 -0
  340. package/template/OPENCODE.md +4 -0
  341. package/template/researchs/.gitkeep +0 -0
@@ -0,0 +1,218 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson session:guard [projectDir] --agent=<name> --tool=<tool>
5
+ *
6
+ * Background supervisor that keeps a live session alive.
7
+ * - If no live session exists: auto-starts one (no-launch mode)
8
+ * - Polls every 30s to verify the session is still open
9
+ * - Detects inactivity (no events for --idle-minutes, default: 60) and closes gracefully
10
+ * - Works alongside hooks:emit — guard handles session lifecycle, hooks handle events
11
+ *
12
+ * Run in background:
13
+ * aioson session:guard . --agent=dev --tool=claude &
14
+ *
15
+ * Or as a foreground check (--once):
16
+ * aioson session:guard . --agent=dev --tool=claude --once
17
+ */
18
+
19
+ const path = require('node:path');
20
+ const fs = require('node:fs/promises');
21
+ const {
22
+ openRuntimeDb,
23
+ resolveRuntimePaths,
24
+ readAgentSession,
25
+ writeAgentSession,
26
+ startTask,
27
+ startRun,
28
+ updateRun,
29
+ updateTask,
30
+ appendRunEvent
31
+ } = require('../runtime-store');
32
+
33
+ const POLL_INTERVAL_MS = 30_000;
34
+ const DEFAULT_IDLE_MINUTES = 60;
35
+
36
+ function nowIso() { return new Date().toISOString(); }
37
+ function log(msg) { process.stderr.write(`[session:guard] ${msg}\n`); }
38
+
39
+ async function getLastEventTime(runtimeDir, sessionKey) {
40
+ const eventsPath = path.join(runtimeDir, 'live', sessionKey, 'events.ndjson');
41
+ try {
42
+ const content = await fs.readFile(eventsPath, 'utf8');
43
+ const lines = content.trim().split('\n').filter(Boolean);
44
+ if (lines.length === 0) return null;
45
+ const last = JSON.parse(lines[lines.length - 1]);
46
+ return last.ts ? new Date(last.ts) : null;
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ async function startLiveSession(targetDir, runtimeDir, agentName, tool) {
53
+ const now = nowIso();
54
+ const sessionKey = `guard-${agentName}-${Date.now()}`;
55
+ const title = `[guard] ${agentName} via ${tool}`;
56
+
57
+ const { db } = await openRuntimeDb(targetDir);
58
+ try {
59
+ const taskKey = startTask(db, {
60
+ sessionKey,
61
+ title,
62
+ status: 'running',
63
+ createdBy: agentName,
64
+ taskKind: 'live_session',
65
+ metaJson: { tool_session: tool, path: targetDir, guarded: true }
66
+ });
67
+
68
+ const runKey = startRun(db, {
69
+ taskKey,
70
+ agentName,
71
+ agentKind: 'official',
72
+ sessionKey,
73
+ source: 'live',
74
+ title,
75
+ eventType: 'session_started',
76
+ phase: 'live',
77
+ message: `Session auto-started by session:guard (${tool})`,
78
+ payload: { tool_session: tool, path: targetDir, guarded: true }
79
+ });
80
+
81
+ await writeAgentSession(runtimeDir, agentName, {
82
+ runKey, taskKey, sessionKey,
83
+ startedAt: now, finished: false, source: 'live'
84
+ });
85
+
86
+ // Create state.json for dashboard
87
+ const stateDir = path.join(runtimeDir, 'live', sessionKey);
88
+ await fs.mkdir(stateDir, { recursive: true });
89
+ await fs.writeFile(path.join(stateDir, 'state.json'), JSON.stringify({
90
+ session_key: sessionKey, run_key: runKey, task_key: taskKey,
91
+ agent_name: agentName, tool_session: tool,
92
+ status: 'running', started_at: now, updated_at: now, guarded: true,
93
+ last_events: [{ ts: now, type: 'session_started', summary: `Auto-started by session:guard (${tool})` }]
94
+ }, null, 2), 'utf8');
95
+
96
+ log(`Session started: ${sessionKey} (run: ${runKey})`);
97
+ return { runKey, taskKey, sessionKey };
98
+ } finally {
99
+ db.close();
100
+ }
101
+ }
102
+
103
+ async function closeSession(targetDir, runtimeDir, agentName, runKey, taskKey, reason) {
104
+ const now = nowIso();
105
+ const { db } = await openRuntimeDb(targetDir, { mustExist: true });
106
+ try {
107
+ appendRunEvent(db, {
108
+ runKey, eventType: 'session_ended', phase: 'live',
109
+ status: 'completed', message: `Session closed by session:guard: ${reason}`,
110
+ createdAt: now
111
+ });
112
+ updateRun(db, runKey, { status: 'completed', summary: reason, finishedAt: now });
113
+ if (taskKey) updateTask(db, taskKey, { status: 'completed', finishedAt: now });
114
+
115
+ // Update state.json
116
+ const { db: _, ...rest } = await readAgentSession(runtimeDir, agentName).catch(() => ({}));
117
+ const sessionKey = rest?.sessionKey;
118
+ if (sessionKey) {
119
+ const statePath = path.join(runtimeDir, 'live', sessionKey, 'state.json');
120
+ try {
121
+ const state = JSON.parse(await fs.readFile(statePath, 'utf8'));
122
+ state.status = 'closed';
123
+ state.updated_at = now;
124
+ await fs.writeFile(statePath, JSON.stringify(state, null, 2), 'utf8');
125
+ } catch { /* non-fatal */ }
126
+ }
127
+
128
+ // Clear session file
129
+ const sessionFile = path.join(runtimeDir, '.sessions', `${agentName}.json`);
130
+ try { await fs.unlink(sessionFile); } catch { /* already gone */ }
131
+
132
+ log(`Session closed: ${runKey} (${reason})`);
133
+ } finally {
134
+ db.close();
135
+ }
136
+ }
137
+
138
+ async function tick(targetDir, runtimeDir, agentName, tool, idleMs, state) {
139
+ const session = await readAgentSession(runtimeDir, agentName);
140
+
141
+ if (!session || session.finished) {
142
+ // No session — start one
143
+ const created = await startLiveSession(targetDir, runtimeDir, agentName, tool);
144
+ state.runKey = created.runKey;
145
+ state.taskKey = created.taskKey;
146
+ state.sessionKey = created.sessionKey;
147
+ state.startedAt = Date.now();
148
+ return;
149
+ }
150
+
151
+ // Session exists — check for idle timeout
152
+ const sessionKey = session.sessionKey;
153
+ const lastEvent = await getLastEventTime(runtimeDir, sessionKey);
154
+ const now = Date.now();
155
+ const lastActivity = lastEvent ? lastEvent.getTime() : state.startedAt;
156
+ const idleFor = now - lastActivity;
157
+
158
+ if (idleFor > idleMs) {
159
+ const idleMin = Math.round(idleFor / 60000);
160
+ log(`Idle for ${idleMin}m — closing session`);
161
+ await closeSession(targetDir, runtimeDir, agentName, session.runKey, session.taskKey,
162
+ `Idle for ${idleMin} minutes`);
163
+ state.runKey = null;
164
+ state.taskKey = null;
165
+ state.sessionKey = null;
166
+ }
167
+ }
168
+
169
+ async function runSessionGuard({ args, options = {}, logger }) {
170
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
171
+ const agentName = options.agent ? String(options.agent).replace(/^@/, '') : 'dev';
172
+ const tool = options.tool ? String(options.tool).trim() : 'claude';
173
+ const once = options.once || options['once'] || false;
174
+ const idleMinutes = Number(options['idle-minutes'] || options.idleMinutes || DEFAULT_IDLE_MINUTES);
175
+ const idleMs = idleMinutes * 60 * 1000;
176
+ const intervalMs = Number(options.interval || POLL_INTERVAL_MS);
177
+
178
+ const { runtimeDir } = resolveRuntimePaths(targetDir);
179
+ const state = { runKey: null, taskKey: null, sessionKey: null, startedAt: Date.now() };
180
+
181
+ if (!options.json) {
182
+ logger.log(`[session:guard] Watching: ${targetDir}`);
183
+ logger.log(`[session:guard] Agent: @${agentName} | Tool: ${tool} | Idle timeout: ${idleMinutes}m`);
184
+ logger.log(`[session:guard] Press Ctrl+C to stop.`);
185
+ }
186
+
187
+ await tick(targetDir, runtimeDir, agentName, tool, idleMs, state);
188
+
189
+ if (once) {
190
+ return { ok: true, runKey: state.runKey, sessionKey: state.sessionKey };
191
+ }
192
+
193
+ return new Promise((resolve) => {
194
+ const timer = setInterval(async () => {
195
+ try {
196
+ await tick(targetDir, runtimeDir, agentName, tool, idleMs, state);
197
+ } catch (err) {
198
+ log(`Error: ${err.message}`);
199
+ }
200
+ }, intervalMs);
201
+
202
+ const shutdown = async () => {
203
+ clearInterval(timer);
204
+ if (state.runKey) {
205
+ try {
206
+ await closeSession(targetDir, runtimeDir, agentName, state.runKey, state.taskKey, 'session:guard stopped');
207
+ } catch { /* best-effort */ }
208
+ }
209
+ if (!options.json) logger.log('[session:guard] Stopped.');
210
+ resolve({ ok: true });
211
+ };
212
+
213
+ process.on('SIGINT', shutdown);
214
+ process.on('SIGTERM', shutdown);
215
+ });
216
+ }
217
+
218
+ module.exports = { runSessionGuard };
@@ -3,6 +3,25 @@
3
3
  const path = require('node:path');
4
4
  const readline = require('node:readline/promises');
5
5
  const { detectFramework, isMonorepoDetection } = require('../detector');
6
+
7
+ /**
8
+ * Infer conversation language from the OS locale environment variables.
9
+ * Supports LANGUAGE, LANG, and LC_ALL in priority order.
10
+ * Maps POSIX locale codes (e.g. pt_BR.UTF-8) to AIOSON locale codes (e.g. pt-BR).
11
+ */
12
+ function detectSystemLanguage() {
13
+ const raw = process.env.LANGUAGE || process.env.LANG || process.env.LC_ALL || '';
14
+ const base = raw.split(':')[0].split('.')[0].trim();
15
+ if (!base || base === 'C' || base === 'POSIX') return 'en';
16
+ const normalized = base.replace('_', '-');
17
+ const supported = ['en', 'pt-BR', 'es', 'fr'];
18
+ if (supported.includes(normalized)) return normalized;
19
+ const lang = normalized.split('-')[0].toLowerCase();
20
+ if (lang === 'pt') return 'pt-BR';
21
+ if (lang === 'es') return 'es';
22
+ if (lang === 'fr') return 'fr';
23
+ return 'en';
24
+ }
6
25
  const { getCliVersionSync } = require('../version');
7
26
  const {
8
27
  calculateClassification,
@@ -469,7 +488,7 @@ async function runSetupContext({ args, options, logger, t }) {
469
488
  profile: 'developer',
470
489
  framework: detectedFramework,
471
490
  frameworkInstalled: detectedInstalled,
472
- conversationLanguage: 'en',
491
+ conversationLanguage: detectSystemLanguage(),
473
492
  designSkill: '',
474
493
  testRunner: '',
475
494
  web3Enabled: inferredWeb3Enabled,
@@ -674,5 +693,6 @@ module.exports = {
674
693
  runSetupContext,
675
694
  servicesToContextFields,
676
695
  mergeProfileData,
677
- applyExplicitOverrides
696
+ applyExplicitOverrides,
697
+ detectSystemLanguage
678
698
  };
@@ -0,0 +1,178 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const readline = require('node:readline/promises');
5
+ const { installTemplate, readInstallProfile } = require('../installer');
6
+ const { detectFramework } = require('../detector');
7
+ const { detectSystemLanguage } = require('./setup-context');
8
+ const { runSetupContext } = require('./setup-context');
9
+ const { resolvePromptTool } = require('../prompt-tool');
10
+ const { normalizeBoolean } = require('../context-writer');
11
+ const { runInstallWizard } = require('../install-wizard');
12
+
13
+ async function ask(rl, question, fallback = '') {
14
+ const suffix = fallback ? ` (${fallback})` : '';
15
+ const value = await rl.question(`${question}${suffix}: `);
16
+ const cleaned = String(value || '').trim();
17
+ if (!cleaned) return fallback;
18
+ return cleaned;
19
+ }
20
+
21
+ async function runSetup({ args, options, logger, t }) {
22
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
23
+ const dryRun = Boolean(options['dry-run']);
24
+ const force = Boolean(options.force);
25
+ const defaultsMode = Boolean(options.defaults);
26
+ const promptTool = resolvePromptTool(options.tool);
27
+
28
+ // Step 1 — detect install profile (wizard if first time in TTY)
29
+ const isTTY = process.stdin.isTTY && process.stdout.isTTY;
30
+ let installProfile = null;
31
+
32
+ if (!dryRun && isTTY) {
33
+ const existingProfile = await readInstallProfile(targetDir);
34
+ if (!existingProfile) {
35
+ installProfile = await runInstallWizard({});
36
+ } else {
37
+ installProfile = existingProfile;
38
+ }
39
+ }
40
+
41
+ // Step 2 — install template
42
+ logger.log(t('setup.installing'));
43
+ const installResult = await installTemplate(targetDir, {
44
+ overwrite: force,
45
+ dryRun,
46
+ mode: 'install',
47
+ installProfile
48
+ });
49
+ logger.log(t('setup.installed', { count: installResult.copied.length }));
50
+
51
+ // Step 3 — detect framework and system language
52
+ const detection = await detectFramework(targetDir);
53
+ const detectedFramework = detection.framework;
54
+ const detectedInstalled = detection.installed;
55
+ const systemLang = detectSystemLanguage();
56
+
57
+ // Build setup:context options by merging detected state with explicit flags
58
+ const contextOptions = { defaults: true };
59
+
60
+ // Propagate any explicit overrides the user passed to `setup`
61
+ const passthroughFlags = [
62
+ 'project-name', 'project-type', 'framework', 'framework-installed',
63
+ 'classification', 'lang', 'language', 'profile', 'backend', 'frontend',
64
+ 'database', 'auth', 'uiux', 'design-skill', 'test-runner',
65
+ 'web3-enabled', 'web3-networks', 'contract-framework',
66
+ 'wallet-provider', 'indexer', 'rpc-provider',
67
+ 'queues', 'storage', 'websockets', 'payments', 'email', 'cache', 'search'
68
+ ];
69
+ for (const flag of passthroughFlags) {
70
+ if (Object.prototype.hasOwnProperty.call(options, flag)) {
71
+ contextOptions[flag] = options[flag];
72
+ }
73
+ }
74
+
75
+ // Apply language: explicit flag > system detection
76
+ if (!contextOptions.lang && !contextOptions.language) {
77
+ contextOptions.lang = systemLang;
78
+ }
79
+
80
+ // For greenfield projects (nothing detected), ask minimal interactive questions
81
+ // unless --defaults is set or the user already passed --framework
82
+ const isGreenfield = !detectedFramework;
83
+ const frameworkProvided = Object.prototype.hasOwnProperty.call(options, 'framework');
84
+
85
+ if (!defaultsMode && isGreenfield && !frameworkProvided) {
86
+ const rl = readline.createInterface({
87
+ input: process.stdin,
88
+ output: process.stdout
89
+ });
90
+
91
+ try {
92
+ logger.log(t('setup.no_framework_detected'));
93
+
94
+ const projectName = await ask(
95
+ rl,
96
+ t('setup.q_project_name'),
97
+ path.basename(targetDir) || 'my-project'
98
+ );
99
+ if (projectName !== path.basename(targetDir)) {
100
+ contextOptions['project-name'] = projectName;
101
+ }
102
+
103
+ const framework = await ask(rl, t('setup.q_framework'), '');
104
+ if (framework) {
105
+ contextOptions.framework = framework;
106
+ contextOptions['framework-installed'] = 'false';
107
+ }
108
+
109
+ const detectedLang = contextOptions.lang || systemLang;
110
+ const lang = await ask(rl, t('setup.q_lang'), detectedLang);
111
+ contextOptions.lang = lang;
112
+ } finally {
113
+ rl.close();
114
+ }
115
+ } else if (!defaultsMode && detectedFramework) {
116
+ // Existing project with detected framework — confirm before proceeding
117
+ const rl = readline.createInterface({
118
+ input: process.stdin,
119
+ output: process.stdout
120
+ });
121
+
122
+ try {
123
+ logger.log(
124
+ t('setup.framework_detected', {
125
+ framework: detectedFramework,
126
+ installed: String(detectedInstalled)
127
+ })
128
+ );
129
+
130
+ const confirmed = normalizeBoolean(
131
+ await ask(rl, t('setup.q_confirm_framework'), 'true'),
132
+ true
133
+ );
134
+
135
+ if (!confirmed) {
136
+ const override = await ask(rl, t('setup.q_override_framework'), detectedFramework);
137
+ contextOptions.framework = override;
138
+ contextOptions['framework-installed'] = await ask(
139
+ rl,
140
+ t('setup.q_framework_installed'),
141
+ 'false'
142
+ );
143
+ }
144
+
145
+ const detectedLang = contextOptions.lang || systemLang;
146
+ const lang = await ask(rl, t('setup.q_lang'), detectedLang);
147
+ contextOptions.lang = lang;
148
+ } finally {
149
+ rl.close();
150
+ }
151
+ }
152
+
153
+ // Step 4 — run setup:context with fully resolved options
154
+ logger.log(t('setup.writing_context'));
155
+ const contextResult = await runSetupContext({
156
+ args: [targetDir],
157
+ options: contextOptions,
158
+ logger,
159
+ t
160
+ });
161
+
162
+ if (!dryRun) {
163
+ logger.log('');
164
+ logger.log(t('setup.done'));
165
+ logger.log(t('setup.step_agents'));
166
+ logger.log(t('setup.step_agent_prompt', { tool: promptTool }));
167
+ }
168
+
169
+ return {
170
+ ok: true,
171
+ targetDir,
172
+ installResult,
173
+ contextResult,
174
+ detection
175
+ };
176
+ }
177
+
178
+ module.exports = { runSetup };
@@ -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 };