@jaimevalasek/aioson 1.4.0 → 1.6.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 (301) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/LICENSE +661 -21
  3. package/README.md +9 -1
  4. package/docs/design-previews/aurora-command-ui-website.html +884 -0
  5. package/docs/design-previews/aurora-command-ui.html +682 -0
  6. package/docs/design-previews/bold-editorial-ui-website.html +658 -0
  7. package/docs/design-previews/bold-editorial-ui.html +717 -0
  8. package/docs/design-previews/clean-saas-ui-website.html +1202 -0
  9. package/docs/design-previews/clean-saas-ui.html +549 -0
  10. package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
  11. package/docs/design-previews/cognitive-core-ui.html +463 -0
  12. package/docs/design-previews/glassmorphism-ui-website.html +572 -0
  13. package/docs/design-previews/glassmorphism-ui.html +886 -0
  14. package/docs/design-previews/index.html +699 -0
  15. package/docs/design-previews/interface-design-website.html +1187 -0
  16. package/docs/design-previews/interface-design.html +513 -0
  17. package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
  18. package/docs/design-previews/neo-brutalist-ui.html +797 -0
  19. package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
  20. package/docs/design-previews/premium-command-center-ui.html +552 -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/en/squad-dashboard.md +372 -0
  25. package/docs/openclaw-bridge.md +308 -0
  26. package/docs/pt/README.md +7 -0
  27. package/docs/pt/agent-sharding.md +132 -0
  28. package/docs/pt/agentes.md +131 -11
  29. package/docs/pt/busca-de-contexto.md +129 -0
  30. package/docs/pt/cache-de-contexto.md +156 -0
  31. package/docs/pt/cenarios.md +46 -2
  32. package/docs/pt/comandos-cli.md +88 -1
  33. package/docs/pt/design-hybrid-forge.md +107 -0
  34. package/docs/pt/inicio-rapido.md +72 -5
  35. package/docs/pt/inteligencia-adaptativa.md +324 -0
  36. package/docs/pt/monitor-de-contexto.md +104 -0
  37. package/docs/pt/recuperacao-de-sessao.md +125 -0
  38. package/docs/pt/sandbox.md +125 -0
  39. package/docs/pt/skills.md +98 -6
  40. package/docs/pt/squad-dashboard.md +373 -0
  41. package/docs/testing/genome-2.0-matrix.md +5 -5
  42. package/docs/testing/genome-2.0-rollout.md +9 -9
  43. package/package.json +2 -2
  44. package/src/agent-loader.js +280 -0
  45. package/src/backup-local.js +74 -0
  46. package/src/cli.js +192 -0
  47. package/src/commands/agent-loader.js +85 -0
  48. package/src/commands/backup-local-cmd.js +25 -0
  49. package/src/commands/context-cache.js +90 -0
  50. package/src/commands/context-monitor.js +92 -0
  51. package/src/commands/context-search.js +66 -0
  52. package/src/commands/design-hybrid-options.js +385 -0
  53. package/src/commands/health.js +214 -0
  54. package/src/commands/init.js +54 -13
  55. package/src/commands/install.js +52 -13
  56. package/src/commands/learning-evolve.js +355 -0
  57. package/src/commands/live.js +34 -0
  58. package/src/commands/recovery.js +43 -0
  59. package/src/commands/runtime.js +242 -0
  60. package/src/commands/sandbox.js +37 -0
  61. package/src/commands/setup-context.js +29 -4
  62. package/src/commands/setup.js +178 -0
  63. package/src/commands/skill.js +79 -32
  64. package/src/commands/squad-daemon.js +209 -0
  65. package/src/commands/squad-dashboard.js +39 -0
  66. package/src/commands/squad-deploy.js +64 -0
  67. package/src/commands/squad-doctor.js +52 -0
  68. package/src/commands/squad-mcp.js +270 -0
  69. package/src/commands/squad-processes.js +56 -0
  70. package/src/commands/squad-recovery.js +42 -0
  71. package/src/commands/squad-roi.js +291 -0
  72. package/src/commands/squad-score.js +250 -0
  73. package/src/commands/squad-status.js +37 -1
  74. package/src/commands/squad-validate.js +62 -1
  75. package/src/commands/squad-webhook.js +160 -0
  76. package/src/commands/squad-worker.js +191 -0
  77. package/src/commands/squad-worktrees.js +75 -0
  78. package/src/commands/tool-registry-cmd.js +232 -0
  79. package/src/commands/update.js +7 -0
  80. package/src/commands/web-map.js +70 -0
  81. package/src/commands/web-scrape.js +71 -0
  82. package/src/constants.js +17 -0
  83. package/src/context-cache.js +159 -0
  84. package/src/context-search.js +326 -0
  85. package/src/context-writer.js +45 -1
  86. package/src/design-variation-catalog.js +503 -0
  87. package/src/i18n/messages/en.js +159 -3
  88. package/src/i18n/messages/es.js +147 -2
  89. package/src/i18n/messages/fr.js +147 -2
  90. package/src/i18n/messages/pt-BR.js +158 -3
  91. package/src/install-animation.js +260 -0
  92. package/src/install-profile.js +143 -0
  93. package/src/install-wizard.js +474 -0
  94. package/src/installer.js +38 -10
  95. package/src/lib/webhook-server.js +328 -0
  96. package/src/mcp-connectors/registry.js +602 -0
  97. package/src/parser.js +7 -1
  98. package/src/recovery-context-session.js +154 -0
  99. package/src/runtime-store.js +355 -2
  100. package/src/sandbox.js +177 -0
  101. package/src/squad/external-session.js +180 -0
  102. package/src/squad/inter-squad.js +74 -0
  103. package/src/squad/recovery-context.js +201 -0
  104. package/src/squad/worktree-manager.js +114 -0
  105. package/src/squad-daemon.js +490 -0
  106. package/src/squad-dashboard/api.js +223 -0
  107. package/src/squad-dashboard/attachment-handler.js +93 -0
  108. package/src/squad-dashboard/context-monitor.js +157 -0
  109. package/src/squad-dashboard/execution-logs.js +115 -0
  110. package/src/squad-dashboard/hunk-review.js +209 -0
  111. package/src/squad-dashboard/metrics.js +133 -0
  112. package/src/squad-dashboard/process-monitor.js +125 -0
  113. package/src/squad-dashboard/renderer.js +858 -0
  114. package/src/squad-dashboard/server.js +232 -0
  115. package/src/squad-dashboard/styles.js +525 -0
  116. package/src/squad-dashboard/token-tracker.js +99 -0
  117. package/src/tool-executor.js +94 -0
  118. package/src/updater.js +11 -3
  119. package/src/web.js +284 -0
  120. package/src/worker-runner.js +339 -0
  121. package/template/.aioson/agents/analyst.md +62 -3
  122. package/template/.aioson/agents/architect.md +42 -0
  123. package/template/.aioson/agents/design-hybrid-forge.md +127 -0
  124. package/template/.aioson/agents/dev.md +223 -11
  125. package/template/.aioson/agents/deyvin.md +65 -0
  126. package/template/.aioson/agents/neo.md +152 -0
  127. package/template/.aioson/agents/orache.md +17 -0
  128. package/template/.aioson/agents/orchestrator.md +26 -0
  129. package/template/.aioson/agents/pm.md +58 -0
  130. package/template/.aioson/agents/product.md +88 -12
  131. package/template/.aioson/agents/qa.md +80 -0
  132. package/template/.aioson/agents/setup.md +128 -22
  133. package/template/.aioson/agents/sheldon.md +704 -0
  134. package/template/.aioson/agents/squad.md +191 -0
  135. package/template/.aioson/agents/tester.md +410 -0
  136. package/template/.aioson/agents/ux-ui.md +12 -0
  137. package/template/.aioson/config.md +21 -0
  138. package/template/.aioson/context/forensics/.gitkeep +0 -0
  139. package/template/.aioson/context/seeds/seed-example.md +27 -0
  140. package/template/.aioson/context/user-profile.md +42 -0
  141. package/template/.aioson/locales/en/agents/analyst.md +8 -0
  142. package/template/.aioson/locales/en/agents/architect.md +8 -0
  143. package/template/.aioson/locales/en/agents/dev.md +66 -7
  144. package/template/.aioson/locales/en/agents/deyvin.md +8 -0
  145. package/template/.aioson/locales/en/agents/neo.md +8 -0
  146. package/template/.aioson/locales/en/agents/orchestrator.md +26 -0
  147. package/template/.aioson/locales/en/agents/qa.md +49 -0
  148. package/template/.aioson/locales/en/agents/setup.md +35 -2
  149. package/template/.aioson/locales/en/agents/sheldon.md +340 -0
  150. package/template/.aioson/locales/en/agents/ux-ui.md +8 -0
  151. package/template/.aioson/locales/es/agents/analyst.md +8 -0
  152. package/template/.aioson/locales/es/agents/architect.md +8 -0
  153. package/template/.aioson/locales/es/agents/dev.md +66 -7
  154. package/template/.aioson/locales/es/agents/deyvin.md +8 -0
  155. package/template/.aioson/locales/es/agents/neo.md +48 -0
  156. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  157. package/template/.aioson/locales/es/agents/qa.md +26 -0
  158. package/template/.aioson/locales/es/agents/setup.md +35 -2
  159. package/template/.aioson/locales/es/agents/sheldon.md +192 -0
  160. package/template/.aioson/locales/es/agents/squad.md +63 -0
  161. package/template/.aioson/locales/es/agents/ux-ui.md +8 -0
  162. package/template/.aioson/locales/fr/agents/analyst.md +8 -0
  163. package/template/.aioson/locales/fr/agents/architect.md +8 -0
  164. package/template/.aioson/locales/fr/agents/dev.md +66 -7
  165. package/template/.aioson/locales/fr/agents/deyvin.md +8 -0
  166. package/template/.aioson/locales/fr/agents/neo.md +48 -0
  167. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  168. package/template/.aioson/locales/fr/agents/qa.md +26 -0
  169. package/template/.aioson/locales/fr/agents/setup.md +35 -2
  170. package/template/.aioson/locales/fr/agents/sheldon.md +192 -0
  171. package/template/.aioson/locales/fr/agents/squad.md +63 -0
  172. package/template/.aioson/locales/fr/agents/ux-ui.md +8 -0
  173. package/template/.aioson/locales/pt-BR/agents/analyst.md +19 -0
  174. package/template/.aioson/locales/pt-BR/agents/architect.md +19 -0
  175. package/template/.aioson/locales/pt-BR/agents/dev.md +75 -12
  176. package/template/.aioson/locales/pt-BR/agents/deyvin.md +8 -0
  177. package/template/.aioson/locales/pt-BR/agents/neo.md +147 -0
  178. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +26 -0
  179. package/template/.aioson/locales/pt-BR/agents/product.md +8 -3
  180. package/template/.aioson/locales/pt-BR/agents/qa.md +60 -0
  181. package/template/.aioson/locales/pt-BR/agents/setup.md +35 -2
  182. package/template/.aioson/locales/pt-BR/agents/sheldon.md +192 -0
  183. package/template/.aioson/locales/pt-BR/agents/squad.md +105 -0
  184. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +8 -0
  185. package/template/.aioson/schemas/squad-blueprint.schema.json +21 -0
  186. package/template/.aioson/schemas/squad-manifest.schema.json +178 -1
  187. package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
  188. package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
  189. package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
  190. package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
  191. package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
  192. package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
  193. package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
  194. package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
  195. package/template/.aioson/skills/design/bold-editorial-ui/SKILL.md +205 -0
  196. package/template/.aioson/skills/design/bold-editorial-ui/references/art-direction.md +338 -0
  197. package/template/.aioson/skills/design/bold-editorial-ui/references/components.md +977 -0
  198. package/template/.aioson/skills/design/bold-editorial-ui/references/dashboards.md +218 -0
  199. package/template/.aioson/skills/design/bold-editorial-ui/references/design-tokens.md +326 -0
  200. package/template/.aioson/skills/design/bold-editorial-ui/references/motion.md +461 -0
  201. package/template/.aioson/skills/design/bold-editorial-ui/references/patterns.md +293 -0
  202. package/template/.aioson/skills/design/bold-editorial-ui/references/websites.md +352 -0
  203. package/template/.aioson/skills/design/clean-saas-ui/SKILL.md +210 -0
  204. package/template/.aioson/skills/design/clean-saas-ui/references/art-direction.md +319 -0
  205. package/template/.aioson/skills/design/clean-saas-ui/references/components.md +365 -0
  206. package/template/.aioson/skills/design/clean-saas-ui/references/dashboards.md +196 -0
  207. package/template/.aioson/skills/design/clean-saas-ui/references/design-tokens.md +244 -0
  208. package/template/.aioson/skills/design/clean-saas-ui/references/motion.md +235 -0
  209. package/template/.aioson/skills/design/clean-saas-ui/references/patterns.md +215 -0
  210. package/template/.aioson/skills/design/clean-saas-ui/references/websites.md +295 -0
  211. package/template/.aioson/skills/design/cognitive-core-ui/SKILL.md +55 -9
  212. package/template/.aioson/skills/design/cognitive-core-ui/references/art-direction.md +339 -0
  213. package/template/.aioson/skills/design/cognitive-core-ui/references/components.md +1 -1
  214. package/template/.aioson/skills/design/cognitive-core-ui/references/dashboards.md +100 -0
  215. package/template/.aioson/skills/design/cognitive-core-ui/references/design-tokens.md +43 -9
  216. package/template/.aioson/skills/design/cognitive-core-ui/references/motion.md +40 -0
  217. package/template/.aioson/skills/design/cognitive-core-ui/references/patterns.md +1 -1
  218. package/template/.aioson/skills/design/cognitive-core-ui/references/websites.md +99 -12
  219. package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
  220. package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
  221. package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
  222. package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
  223. package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
  224. package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
  225. package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
  226. package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
  227. package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
  228. package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
  229. package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
  230. package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
  231. package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
  232. package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
  233. package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
  234. package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
  235. package/template/.aioson/skills/design/warm-craft-ui/SKILL.md +209 -0
  236. package/template/.aioson/skills/design/warm-craft-ui/references/art-direction.md +324 -0
  237. package/template/.aioson/skills/design/warm-craft-ui/references/components.md +508 -0
  238. package/template/.aioson/skills/design/warm-craft-ui/references/dashboards.md +223 -0
  239. package/template/.aioson/skills/design/warm-craft-ui/references/design-tokens.md +374 -0
  240. package/template/.aioson/skills/design/warm-craft-ui/references/motion.md +356 -0
  241. package/template/.aioson/skills/design/warm-craft-ui/references/patterns.md +288 -0
  242. package/template/.aioson/skills/design/warm-craft-ui/references/websites.md +289 -0
  243. package/template/.aioson/skills/premium-visual-design/SKILL.md +83 -0
  244. package/template/.aioson/skills/premium-visual-design/components/agent-badge.md +92 -0
  245. package/template/.aioson/skills/premium-visual-design/components/dependency-node.md +102 -0
  246. package/template/.aioson/skills/premium-visual-design/components/mention-autocomplete.md +136 -0
  247. package/template/.aioson/skills/premium-visual-design/components/notification-center.md +136 -0
  248. package/template/.aioson/skills/premium-visual-design/components/review-action-bar.md +188 -0
  249. package/template/.aioson/skills/premium-visual-design/components/team-switcher.md +131 -0
  250. package/template/.aioson/skills/premium-visual-design/patterns/agent-message-thread.md +198 -0
  251. package/template/.aioson/skills/premium-visual-design/patterns/notification-panel.md +275 -0
  252. package/template/.aioson/skills/premium-visual-design/patterns/review-workflow-ui.md +234 -0
  253. package/template/.aioson/skills/premium-visual-design/patterns/task-dependency-graph.md +147 -0
  254. package/template/.aioson/skills/premium-visual-design/tokens/status-extended.md +142 -0
  255. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +45 -0
  256. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
  257. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
  258. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
  259. package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
  260. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +66 -0
  261. package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
  262. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +144 -0
  263. package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
  264. package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
  265. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +291 -0
  266. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +117 -0
  267. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +188 -0
  268. package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
  269. package/template/.aioson/skills/squad/formats/catalog.json +15 -0
  270. package/template/.aioson/skills/squad/formats/content/blog-post.md +47 -0
  271. package/template/.aioson/skills/squad/formats/content/newsletter.md +47 -0
  272. package/template/.aioson/skills/squad/formats/creative/podcast-script.md +43 -0
  273. package/template/.aioson/skills/squad/formats/creative/video-script.md +41 -0
  274. package/template/.aioson/skills/squad/formats/social/instagram-feed.md +42 -0
  275. package/template/.aioson/skills/squad/formats/social/linkedin-post.md +42 -0
  276. package/template/.aioson/skills/squad/formats/social/tiktok.md +39 -0
  277. package/template/.aioson/skills/squad/formats/social/twitter-thread.md +39 -0
  278. package/template/.aioson/skills/squad/formats/social/youtube-long.md +47 -0
  279. package/template/.aioson/skills/squad/formats/social/youtube-shorts.md +39 -0
  280. package/template/.aioson/skills/squad/patterns/multi-platform-pattern.md +108 -0
  281. package/template/.aioson/skills/squad/patterns/persona-based-pattern.md +98 -0
  282. package/template/.aioson/skills/squad/patterns/pipeline-pattern.md +106 -0
  283. package/template/.aioson/skills/squad/patterns/review-loop-pattern.md +81 -0
  284. package/template/.aioson/skills/squad/references/checklist-templates.md +122 -0
  285. package/template/.aioson/skills/squad/references/executor-archetypes.md +123 -0
  286. package/template/.aioson/skills/squad/references/workflow-templates.md +169 -0
  287. package/template/.aioson/skills/static/debugging-protocol.md +42 -0
  288. package/template/.aioson/skills/static/git-worktrees.md +36 -0
  289. package/template/.aioson/tasks/implementation-plan.md +19 -0
  290. package/template/.aioson/tasks/squad-design.md +28 -0
  291. package/template/.aioson/tasks/squad-profile.md +48 -0
  292. package/template/.aioson/tasks/squad-review.md +61 -0
  293. package/template/.aioson/tasks/squad-task-decompose.md +66 -0
  294. package/template/.claude/commands/aioson/agent/neo.md +5 -0
  295. package/template/.claude/commands/aioson/agent/tester.md +5 -0
  296. package/template/.gemini/GEMINI.md +1 -0
  297. package/template/.gemini/commands/aios-neo.toml +4 -0
  298. package/template/.gemini/commands/aios-tester.toml +6 -0
  299. package/template/AGENTS.md +26 -1
  300. package/template/CLAUDE.md +6 -2
  301. package/template/OPENCODE.md +2 -0
@@ -20,6 +20,7 @@ const {
20
20
  } = require('../runtime-store');
21
21
  const { runAutoDelivery } = require('../delivery-runner');
22
22
  const { writeHandoff, buildRuntimeLogHandoff } = require('../session-handoff');
23
+ const { backupAiosonDocs, isDocCreatingAgent } = require('../backup-local');
23
24
 
24
25
  const ALLOWED_LAYOUTS = new Set(['document', 'tabs', 'accordion', 'stack', 'mixed']);
25
26
  const DEFAULT_TEXT_FIELDS = ['content', 'text', 'body', 'lyrics', 'markdown'];
@@ -1159,6 +1160,80 @@ async function runRuntimeLog({ args, options = {}, logger, t }) {
1159
1160
  }
1160
1161
 
1161
1162
 
1163
+ /**
1164
+ * aioson agent:done . --agent=<name> --summary="..." [--title="..."] [--status=completed|failed]
1165
+ *
1166
+ * Safe self-registration for official agents invoked directly (not via workflow:next or live:start).
1167
+ * - If an active live session exists for the agent: appends a completion event without closing the session.
1168
+ * - If no session exists: creates a standalone task+run and immediately marks it completed.
1169
+ *
1170
+ * Intended to be called ONCE at the very end of an agent session, after delivering the main artifact.
1171
+ */
1172
+ async function runAgentDone({ args, options = {}, logger, t }) {
1173
+ const targetDir = resolveTargetDir(args);
1174
+ const agentName = String(options.agent || '').trim();
1175
+ if (!agentName) {
1176
+ throw new Error('--agent is required');
1177
+ }
1178
+ const normalizedAgent = agentName.startsWith('@') ? agentName : `@${agentName}`;
1179
+ const summary = String(options.summary || options.message || `${normalizedAgent} session completed`).trim();
1180
+ const title = options.title ? String(options.title).trim() : null;
1181
+ const status = options.status || 'completed';
1182
+
1183
+ const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
1184
+
1185
+ try {
1186
+ const session = await readAgentSession(runtimeDir, normalizedAgent);
1187
+ const hasActiveSession = session && !session.finished && session.runKey;
1188
+
1189
+ if (hasActiveSession) {
1190
+ // Live or tracked session is already open — only append a completion note.
1191
+ // Do NOT close the session: live:handoff or live:close owns the lifecycle.
1192
+ appendRunEvent(db, {
1193
+ runKey: session.runKey,
1194
+ eventType: 'agent_done',
1195
+ phase: 'live',
1196
+ status: 'running',
1197
+ message: summary
1198
+ });
1199
+
1200
+ if (!options.json) {
1201
+ logger.log(`agent:done — ${normalizedAgent} | live session active, event logged | run: ${session.runKey} (${dbPath})`);
1202
+ }
1203
+
1204
+ if (isDocCreatingAgent(normalizedAgent)) {
1205
+ backupAiosonDocs(targetDir).catch(() => {});
1206
+ }
1207
+
1208
+ return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'live_event', runKey: session.runKey };
1209
+ }
1210
+
1211
+ // No active session — create a standalone task+run and immediately complete it.
1212
+ const { runKey, taskKey } = await logAgentEvent(db, runtimeDir, {
1213
+ agentName: normalizedAgent,
1214
+ message: summary,
1215
+ type: 'completed',
1216
+ taskTitle: title || normalizedAgent,
1217
+ finish: true,
1218
+ status,
1219
+ summary
1220
+ });
1221
+
1222
+ if (!options.json) {
1223
+ logger.log(`agent:done — ${normalizedAgent} | task: ${taskKey} | run: ${runKey} (${dbPath})`);
1224
+ }
1225
+
1226
+ if (isDocCreatingAgent(normalizedAgent)) {
1227
+ backupAiosonDocs(targetDir).catch(() => {});
1228
+ }
1229
+
1230
+ return { ok: true, targetDir, dbPath, agent: normalizedAgent, mode: 'standalone', runKey, taskKey };
1231
+ } finally {
1232
+ db.close();
1233
+ }
1234
+ }
1235
+
1236
+
1162
1237
  async function runRuntimeSessionStart({ args, options = {}, logger, t }) {
1163
1238
  const targetDir = resolveTargetDir(args);
1164
1239
  const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
@@ -1683,6 +1758,171 @@ function parseFrontmatter(content) {
1683
1758
  return result;
1684
1759
  }
1685
1760
 
1761
+ /**
1762
+ * Parses a duration string like "24h", "30m", "7d" into milliseconds.
1763
+ * Falls back to treating the raw value as hours.
1764
+ */
1765
+ function parseDurationMs(value, defaultHours = 24) {
1766
+ const text = String(value || '').trim().toLowerCase();
1767
+ if (!text) return defaultHours * 60 * 60 * 1000;
1768
+
1769
+ const match = text.match(/^(\d+(?:\.\d+)?)\s*([hmd]?)$/);
1770
+ if (!match) return defaultHours * 60 * 60 * 1000;
1771
+
1772
+ const n = parseFloat(match[1]);
1773
+ const unit = match[2] || 'h';
1774
+ if (unit === 'd') return n * 24 * 60 * 60 * 1000;
1775
+ if (unit === 'm') return n * 60 * 1000;
1776
+ return n * 60 * 60 * 1000; // hours (default)
1777
+ }
1778
+
1779
+ /**
1780
+ * aioson agent:recover [targetDir] [--older-than=<duration>] [--dry-run]
1781
+ *
1782
+ * Detects and closes agent sessions that were abandoned (Claude Code closed before
1783
+ * agent:done was called, or live:start session was never closed).
1784
+ *
1785
+ * Sources checked:
1786
+ * 1. Session files in .aioson/.sessions/ with finished=false older than threshold.
1787
+ * 2. agent_runs rows with status='running'/'queued' and started_at older than threshold
1788
+ * that have no corresponding live session file (orphaned DB records).
1789
+ *
1790
+ * --older-than Duration threshold. Accepts: 24h (default), 8h, 30m, 7d.
1791
+ * --dry-run Report what would be recovered without making any changes.
1792
+ * --json Output JSON result.
1793
+ */
1794
+ async function runAgentRecover({ args, options = {}, logger }) {
1795
+ const targetDir = resolveTargetDir(args);
1796
+ const dryRun = Boolean(options['dry-run'] || options.dryRun);
1797
+ const olderThanMs = parseDurationMs(options['older-than'] || options.olderThan, 24);
1798
+ const cutoffMs = Date.now() - olderThanMs;
1799
+ const cutoffIso = new Date(cutoffMs).toISOString();
1800
+ const now = new Date().toISOString();
1801
+
1802
+ const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
1803
+
1804
+ const recovered = [];
1805
+ const skipped = [];
1806
+
1807
+ try {
1808
+ // ── 1. Scan session files ─────────────────────────────────────────────────
1809
+ const sessionsDir = path.join(runtimeDir, '.sessions');
1810
+ let sessionFiles = [];
1811
+ try {
1812
+ const entries = await fs.readdir(sessionsDir);
1813
+ sessionFiles = entries.filter((f) => f.endsWith('.json'));
1814
+ } catch {
1815
+ // .sessions dir may not exist — that's fine
1816
+ }
1817
+
1818
+ for (const file of sessionFiles) {
1819
+ const filePath = path.join(sessionsDir, file);
1820
+ let session;
1821
+ try {
1822
+ session = JSON.parse(await fs.readFile(filePath, 'utf8'));
1823
+ } catch {
1824
+ continue;
1825
+ }
1826
+
1827
+ if (session.finished) continue;
1828
+
1829
+ const startedAt = session.startedAt ? new Date(session.startedAt).getTime() : 0;
1830
+ if (startedAt > cutoffMs) {
1831
+ skipped.push({ source: 'session_file', file, reason: 'within_threshold', startedAt: session.startedAt });
1832
+ continue;
1833
+ }
1834
+
1835
+ const agentName = file.replace(/\.json$/, '');
1836
+ const runKey = session.runKey || null;
1837
+ const taskKey = session.taskKey || null;
1838
+
1839
+ if (!dryRun) {
1840
+ // Mark run as abandoned
1841
+ if (runKey) {
1842
+ const runRow = db.prepare('SELECT run_key, status FROM agent_runs WHERE run_key = ?').get(runKey);
1843
+ if (runRow && (runRow.status === 'running' || runRow.status === 'queued')) {
1844
+ db.prepare(`
1845
+ UPDATE agent_runs
1846
+ SET status = 'abandoned', summary = 'Recovered: session abandoned without close', updated_at = ?, finished_at = ?
1847
+ WHERE run_key = ?
1848
+ `).run(now, now, runKey);
1849
+ }
1850
+ }
1851
+ // Mark task as abandoned
1852
+ if (taskKey) {
1853
+ const taskRow = db.prepare('SELECT task_key, status FROM tasks WHERE task_key = ?').get(taskKey);
1854
+ if (taskRow && (taskRow.status === 'running' || taskRow.status === 'queued')) {
1855
+ db.prepare(`
1856
+ UPDATE tasks
1857
+ SET status = 'abandoned', updated_at = ?, finished_at = ?
1858
+ WHERE task_key = ?
1859
+ `).run(now, now, taskKey);
1860
+ }
1861
+ }
1862
+ // Remove session file
1863
+ try { await fs.unlink(filePath); } catch { /* noop */ }
1864
+ }
1865
+
1866
+ recovered.push({ source: 'session_file', agent: agentName, runKey, taskKey, startedAt: session.startedAt });
1867
+ }
1868
+
1869
+ // ── 2. Scan DB for orphaned running runs (no session file) ────────────────
1870
+ const orphanedRuns = db.prepare(`
1871
+ SELECT run_key, task_key, agent_name, started_at
1872
+ FROM agent_runs
1873
+ WHERE status IN ('running', 'queued')
1874
+ AND source = 'direct'
1875
+ AND started_at < ?
1876
+ `).all(cutoffIso);
1877
+
1878
+ for (const run of orphanedRuns) {
1879
+ // Skip if already recovered via session file
1880
+ if (recovered.some((r) => r.runKey === run.run_key)) continue;
1881
+
1882
+ if (!dryRun) {
1883
+ db.prepare(`
1884
+ UPDATE agent_runs
1885
+ SET status = 'abandoned', summary = 'Recovered: orphaned run with no session file', updated_at = ?, finished_at = ?
1886
+ WHERE run_key = ?
1887
+ `).run(now, now, run.run_key);
1888
+
1889
+ if (run.task_key) {
1890
+ const taskRow = db.prepare('SELECT task_key, status FROM tasks WHERE task_key = ?').get(run.task_key);
1891
+ if (taskRow && (taskRow.status === 'running' || taskRow.status === 'queued')) {
1892
+ db.prepare(`
1893
+ UPDATE tasks
1894
+ SET status = 'abandoned', updated_at = ?, finished_at = ?
1895
+ WHERE task_key = ?
1896
+ `).run(now, now, run.task_key);
1897
+ }
1898
+ }
1899
+ }
1900
+
1901
+ recovered.push({ source: 'orphaned_run', agent: run.agent_name, runKey: run.run_key, taskKey: run.task_key, startedAt: run.started_at });
1902
+ }
1903
+
1904
+ // ── Output ────────────────────────────────────────────────────────────────
1905
+ const olderThanLabel = options['older-than'] || options.olderThan || '24h';
1906
+ if (recovered.length === 0) {
1907
+ logger.log(`agent:recover — no abandoned sessions found older than ${olderThanLabel} (${dbPath})`);
1908
+ } else {
1909
+ const verb = dryRun ? '[dry-run] would recover' : 'recovered';
1910
+ logger.log(`agent:recover — ${verb} ${recovered.length} abandoned session(s) older than ${olderThanLabel} (${dbPath})`);
1911
+ for (const r of recovered) {
1912
+ logger.log(` ${r.agent} started: ${r.startedAt || '?'} run: ${r.runKey || '—'} [${r.source}]`);
1913
+ }
1914
+ }
1915
+ if (skipped.length > 0) {
1916
+ logger.log(` skipped ${skipped.length} session(s) within threshold.`);
1917
+ }
1918
+
1919
+ return { ok: true, targetDir, dbPath, dryRun, cutoff: cutoffIso, recovered, skipped };
1920
+ } finally {
1921
+ db.close();
1922
+ }
1923
+ }
1924
+
1925
+
1686
1926
  /**
1687
1927
  * aioson runtime:prune [targetDir] --older-than=<days>
1688
1928
  *
@@ -1767,6 +2007,8 @@ module.exports = {
1767
2007
  runRuntimeFail,
1768
2008
  runRuntimeStatus,
1769
2009
  runRuntimeLog,
2010
+ runAgentDone,
2011
+ runAgentRecover,
1770
2012
  runRuntimeSessionStart,
1771
2013
  runRuntimeSessionLog,
1772
2014
  runRuntimeSessionFinish,
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const { executeInSandbox } = require('../sandbox');
5
+
6
+ async function runSandboxExec({ args, options, logger }) {
7
+ const command = args[0] || options.command || '';
8
+ const cwd = path.resolve(process.cwd(), options.cwd || '.');
9
+ const timeout = Number(options.timeout) || 30_000;
10
+ const intent = options.intent || undefined;
11
+
12
+ if (!command) {
13
+ logger.error('Usage: aioson sandbox:exec "<command>" [--timeout=30000] [--cwd=.]');
14
+ return { ok: false, error: 'missing_command' };
15
+ }
16
+
17
+ const result = await executeInSandbox(command, { cwd, timeout, intent });
18
+
19
+ if (options.json) {
20
+ return { ok: result.ok, ...result };
21
+ }
22
+
23
+ if (result.stdout) {
24
+ logger.log(result.stdout);
25
+ }
26
+ if (result.stderr) {
27
+ logger.error(result.stderr);
28
+ }
29
+
30
+ if (result.timedOut) {
31
+ logger.error(`Command timed out after ${timeout}ms`);
32
+ }
33
+
34
+ return { ok: result.ok, ...result };
35
+ }
36
+
37
+ module.exports = { runSandboxExec };
@@ -3,12 +3,32 @@
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,
9
28
  normalizeBoolean,
10
29
  renderProjectContext,
11
- writeProjectContext
30
+ writeProjectContext,
31
+ renderSquadApiSection
12
32
  } = require('../context-writer');
13
33
  const { applyAgentLocale } = require('../locales');
14
34
  const { openRuntimeDb, logAgentEvent } = require('../runtime-store');
@@ -208,6 +228,7 @@ function applyExplicitOverrides(data, options, detectedInstalled) {
208
228
  const langValue = options.language ?? options.lang;
209
229
  if (langValue !== undefined) output.conversationLanguage = String(langValue);
210
230
  if (hasOption(options, 'design-skill')) output.designSkill = String(options['design-skill']);
231
+ if (hasOption(options, 'test-runner')) output.testRunner = String(options['test-runner']);
211
232
  if (hasOption(options, 'web3-enabled')) {
212
233
  output.web3Enabled = normalizeBoolean(options['web3-enabled'], output.web3Enabled);
213
234
  }
@@ -467,8 +488,9 @@ async function runSetupContext({ args, options, logger, t }) {
467
488
  profile: 'developer',
468
489
  framework: detectedFramework,
469
490
  frameworkInstalled: detectedInstalled,
470
- conversationLanguage: 'en',
491
+ conversationLanguage: detectSystemLanguage(),
471
492
  designSkill: '',
493
+ testRunner: '',
472
494
  web3Enabled: inferredWeb3Enabled,
473
495
  web3Networks: inferredWeb3Enabled ? inferWeb3Network(detectedFramework) : '',
474
496
  contractFramework: inferredWeb3Enabled ? detectedFramework : '',
@@ -616,7 +638,9 @@ async function runSetupContext({ args, options, logger, t }) {
616
638
  }
617
639
 
618
640
  const content = renderProjectContext(data);
619
- const filePath = await writeProjectContext(targetDir, content);
641
+ const squadApiSection = await renderSquadApiSection(targetDir);
642
+ const fullContent = squadApiSection ? content + '\n' + squadApiSection + '\n' : content;
643
+ const filePath = await writeProjectContext(targetDir, fullContent);
620
644
  const localeApplyResult = await applyAgentLocale(targetDir, data.conversationLanguage, {
621
645
  dryRun: false
622
646
  });
@@ -669,5 +693,6 @@ module.exports = {
669
693
  runSetupContext,
670
694
  servicesToContextFields,
671
695
  mergeProfileData,
672
- applyExplicitOverrides
696
+ applyExplicitOverrides,
697
+ detectSystemLanguage
673
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 };