@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
package/src/sandbox.js ADDED
@@ -0,0 +1,177 @@
1
+ 'use strict';
2
+
3
+ const { spawn } = require('node:child_process');
4
+
5
+ const DEFAULT_TIMEOUT_MS = 30_000;
6
+ const MAX_OUTPUT_BYTES = 5 * 1024; // 5KB before summarization
7
+
8
+ // Credential redaction patterns — covers the most common secret formats
9
+ const REDACTION_PATTERNS = [
10
+ // GitHub tokens (classic and fine-grained)
11
+ { pattern: /ghp_[A-Za-z0-9]{36}/g, replacement: 'ghp_[REDACTED]' },
12
+ { pattern: /github_pat_[A-Za-z0-9_]{82}/g, replacement: 'github_pat_[REDACTED]' },
13
+ // AWS access keys
14
+ { pattern: /AKIA[0-9A-Z]{16}/g, replacement: 'AKIA[REDACTED]' },
15
+ // Google OAuth tokens
16
+ { pattern: /ya29\.[A-Za-z0-9_\-]{50,}/g, replacement: 'ya29.[REDACTED]' },
17
+ // Generic Bearer tokens in headers
18
+ { pattern: /Bearer\s+[A-Za-z0-9\-._~+\/]+=*/gi, replacement: 'Bearer [REDACTED]' },
19
+ // Password in URL (e.g. postgres://user:password@host)
20
+ { pattern: /:[^/:@\s]{4,}@[a-z0-9.\-]+(?::\d+)?/gi, replacement: ':[REDACTED]@host' },
21
+ // Generic password= key=value pairs
22
+ { pattern: /password\s*=\s*["']?[^\s"'&;,]{4,}["']?/gi, replacement: 'password=[REDACTED]' },
23
+ { pattern: /passwd\s*=\s*["']?[^\s"'&;,]{4,}["']?/gi, replacement: 'passwd=[REDACTED]' },
24
+ // secret= key=value pairs
25
+ { pattern: /secret\s*=\s*["']?[^\s"'&;,]{4,}["']?/gi, replacement: 'secret=[REDACTED]' },
26
+ // api_key= or apikey= patterns
27
+ { pattern: /api[_-]?key\s*=\s*["']?[^\s"'&;,]{4,}["']?/gi, replacement: 'api_key=[REDACTED]' },
28
+ // Private key blocks
29
+ { pattern: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/g, replacement: '-----BEGIN PRIVATE KEY [REDACTED] END PRIVATE KEY-----' },
30
+ ];
31
+
32
+ /**
33
+ * Redact known credential patterns from a string.
34
+ * @param {string} text
35
+ * @returns {string}
36
+ */
37
+ function redactCredentials(text) {
38
+ if (!text) return text;
39
+ let result = text;
40
+ for (const { pattern, replacement } of REDACTION_PATTERNS) {
41
+ result = result.replace(pattern, replacement);
42
+ }
43
+ return result;
44
+ }
45
+
46
+ /**
47
+ * Summarize long output to stay within size budget.
48
+ * @param {string} output
49
+ * @param {string} intent — optional context about what was executed
50
+ * @param {number} maxSize — max bytes to return
51
+ * @returns {string}
52
+ */
53
+ function summarizeOutput(output, intent = '', maxSize = MAX_OUTPUT_BYTES) {
54
+ if (!output || output.length <= maxSize) return output;
55
+
56
+ const half = Math.floor(maxSize / 2);
57
+ const head = output.slice(0, half);
58
+ const tail = output.slice(-half);
59
+ const omitted = output.length - maxSize;
60
+ const intentNote = intent ? ` (${intent})` : '';
61
+
62
+ return `${head}\n\n[... ${omitted} bytes omitted${intentNote} ...]\n\n${tail}`;
63
+ }
64
+
65
+ /**
66
+ * Execute a shell command in a sandboxed subprocess with timeout and redaction.
67
+ *
68
+ * @param {string} command — shell command to run
69
+ * @param {object} opts — { cwd?, timeout?, env?, maxOutput?, intent?, shell? }
70
+ * @returns {{ ok: boolean, stdout: string, stderr: string, exitCode: number|null, timedOut: boolean }}
71
+ */
72
+ async function executeInSandbox(command, opts = {}) {
73
+ const timeout = opts.timeout || DEFAULT_TIMEOUT_MS;
74
+ const cwd = opts.cwd || process.cwd();
75
+ const maxOutput = opts.maxOutput || MAX_OUTPUT_BYTES;
76
+ const intent = opts.intent || command.slice(0, 60);
77
+ const shell = opts.shell !== false; // default true
78
+
79
+ return new Promise((resolve) => {
80
+ const controller = new AbortController();
81
+ let timedOut = false;
82
+ let killed = false;
83
+
84
+ const timer = setTimeout(() => {
85
+ timedOut = true;
86
+ controller.abort();
87
+ }, timeout);
88
+
89
+ const stdoutChunks = [];
90
+ const stderrChunks = [];
91
+ let stdoutSize = 0;
92
+ let stderrSize = 0;
93
+
94
+ const baseOpts = {
95
+ cwd,
96
+ env: { ...process.env, ...(opts.env || {}) },
97
+ signal: controller.signal
98
+ };
99
+
100
+ let child;
101
+ try {
102
+ if (shell) {
103
+ // Use Node's built-in shell wrapping
104
+ child = spawn(command, [], { ...baseOpts, shell: true });
105
+ } else {
106
+ const parts = command.split(/\s+/);
107
+ child = spawn(parts[0], parts.slice(1), { ...baseOpts, shell: false });
108
+ }
109
+ } catch (err) {
110
+ clearTimeout(timer);
111
+ resolve({ ok: false, stdout: '', stderr: err.message, exitCode: null, timedOut: false, error: err.message });
112
+ return;
113
+ }
114
+
115
+ child.stdout.on('data', (chunk) => {
116
+ if (stdoutSize < maxOutput * 2) {
117
+ stdoutChunks.push(chunk);
118
+ stdoutSize += chunk.length;
119
+ }
120
+ });
121
+
122
+ child.stderr.on('data', (chunk) => {
123
+ if (stderrSize < maxOutput * 2) {
124
+ stderrChunks.push(chunk);
125
+ stderrSize += chunk.length;
126
+ }
127
+ });
128
+
129
+ child.on('close', (code, signal) => {
130
+ if (killed) return;
131
+ clearTimeout(timer);
132
+
133
+ const rawStdout = Buffer.concat(stdoutChunks).toString('utf8');
134
+ const rawStderr = Buffer.concat(stderrChunks).toString('utf8');
135
+
136
+ const stdout = redactCredentials(summarizeOutput(rawStdout, intent, maxOutput));
137
+ const stderr = redactCredentials(summarizeOutput(rawStderr, intent, maxOutput));
138
+
139
+ resolve({
140
+ ok: !timedOut && code === 0,
141
+ stdout,
142
+ stderr,
143
+ exitCode: code,
144
+ timedOut,
145
+ signal: signal || null
146
+ });
147
+ });
148
+
149
+ child.on('error', (err) => {
150
+ if (killed) return;
151
+ clearTimeout(timer);
152
+
153
+ if (err.code === 'ABORT_ERR' || timedOut) {
154
+ resolve({
155
+ ok: false,
156
+ stdout: '',
157
+ stderr: `Command timed out after ${timeout}ms`,
158
+ exitCode: null,
159
+ timedOut: true,
160
+ signal: null
161
+ });
162
+ } else {
163
+ resolve({
164
+ ok: false,
165
+ stdout: '',
166
+ stderr: err.message,
167
+ exitCode: null,
168
+ timedOut: false,
169
+ error: err.message
170
+ });
171
+ }
172
+ killed = true;
173
+ });
174
+ });
175
+ }
176
+
177
+ module.exports = { executeInSandbox, redactCredentials, summarizeOutput };
@@ -0,0 +1,180 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const SESSIONS_DIR = path.join('.aioson', 'sessions');
7
+ const DEFAULT_TTL_HOURS = 24;
8
+
9
+ function sanitizeSessionId(sessionId) {
10
+ // Replace anything that isn't alphanumeric, hyphen, or underscore with a dash
11
+ return String(sessionId)
12
+ .replace(/[^a-zA-Z0-9_-]/g, '-')
13
+ .replace(/-{2,}/g, '-')
14
+ .replace(/^-|-$/g, '')
15
+ .slice(0, 128);
16
+ }
17
+
18
+ function sessionPath(projectDir, sessionId) {
19
+ return path.join(projectDir, SESSIONS_DIR, `${sanitizeSessionId(sessionId)}.json`);
20
+ }
21
+
22
+ async function ensureSessionsDir(projectDir) {
23
+ const dir = path.join(projectDir, SESSIONS_DIR);
24
+ await fs.mkdir(dir, { recursive: true });
25
+ return dir;
26
+ }
27
+
28
+ /**
29
+ * Load a session by ID. Returns null if not found or expired.
30
+ * @param {string} projectDir
31
+ * @param {string} sessionId
32
+ * @param {number} [ttlHours]
33
+ * @returns {Promise<object|null>}
34
+ */
35
+ async function loadSession(projectDir, sessionId, ttlHours = DEFAULT_TTL_HOURS) {
36
+ const filePath = sessionPath(projectDir, sessionId);
37
+ let raw;
38
+ try {
39
+ raw = await fs.readFile(filePath, 'utf8');
40
+ } catch {
41
+ return null;
42
+ }
43
+
44
+ let session;
45
+ try {
46
+ session = JSON.parse(raw);
47
+ } catch {
48
+ return null;
49
+ }
50
+
51
+ // Check TTL
52
+ if (ttlHours > 0 && session.last_active) {
53
+ const idleMs = Date.now() - new Date(session.last_active).getTime();
54
+ if (idleMs > ttlHours * 3_600_000) {
55
+ // Expired — delete and return null
56
+ await fs.unlink(filePath).catch(() => {});
57
+ return null;
58
+ }
59
+ }
60
+
61
+ return session;
62
+ }
63
+
64
+ /**
65
+ * Save (overwrite) a session file atomically.
66
+ * @param {string} projectDir
67
+ * @param {object} session Must have session.session_id
68
+ */
69
+ async function saveSession(projectDir, session) {
70
+ await ensureSessionsDir(projectDir);
71
+ const filePath = sessionPath(projectDir, session.session_id);
72
+ const tmpPath = filePath + '.tmp';
73
+ await fs.writeFile(tmpPath, JSON.stringify(session, null, 2), 'utf8');
74
+ await fs.rename(tmpPath, filePath);
75
+ }
76
+
77
+ /**
78
+ * Append a turn to a session. Creates the session file if it doesn't exist.
79
+ * @param {string} projectDir
80
+ * @param {string} sessionId
81
+ * @param {'user'|'assistant'} role
82
+ * @param {string} content
83
+ * @param {object} [metadata] Merged into session.metadata on first creation
84
+ * @param {number} [ttlHours]
85
+ * @returns {Promise<object>} Updated session
86
+ */
87
+ async function appendTurn(projectDir, sessionId, role, content, metadata = {}, ttlHours = DEFAULT_TTL_HOURS) {
88
+ let session = await loadSession(projectDir, sessionId, ttlHours);
89
+ const now = new Date().toISOString();
90
+
91
+ if (!session) {
92
+ session = {
93
+ session_id: sessionId,
94
+ channel: metadata.channel || 'webhook',
95
+ created_at: now,
96
+ last_active: now,
97
+ turns: [],
98
+ metadata: { ...metadata }
99
+ };
100
+ }
101
+
102
+ session.last_active = now;
103
+ session.turns.push({ role, content, ts: now });
104
+
105
+ // Merge any new metadata fields without overwriting existing ones
106
+ if (metadata && typeof metadata === 'object') {
107
+ for (const [k, v] of Object.entries(metadata)) {
108
+ if (session.metadata[k] === undefined) session.metadata[k] = v;
109
+ }
110
+ }
111
+
112
+ await saveSession(projectDir, session);
113
+ return session;
114
+ }
115
+
116
+ /**
117
+ * Build a context string from session history to inject into the squad input.
118
+ * @param {object} session
119
+ * @param {string} currentInput
120
+ * @returns {string}
121
+ */
122
+ function buildContextualInput(session, currentInput) {
123
+ if (!session || !session.turns || session.turns.length === 0) {
124
+ return currentInput;
125
+ }
126
+
127
+ const history = session.turns
128
+ .map(t => `${t.role}: ${t.content}`)
129
+ .join('\n');
130
+
131
+ return `[Conversation history]\n${history}\n\n[Current message]\n${currentInput}`;
132
+ }
133
+
134
+ /**
135
+ * Delete all session files that have been inactive for longer than ttlHours.
136
+ * @param {string} projectDir
137
+ * @param {number} [ttlHours]
138
+ * @returns {Promise<number>} Number of sessions deleted
139
+ */
140
+ async function cleanExpiredSessions(projectDir, ttlHours = DEFAULT_TTL_HOURS) {
141
+ const dir = path.join(projectDir, SESSIONS_DIR);
142
+ let entries;
143
+ try {
144
+ entries = await fs.readdir(dir, { withFileTypes: true });
145
+ } catch {
146
+ return 0;
147
+ }
148
+
149
+ let deleted = 0;
150
+ const cutoff = Date.now() - ttlHours * 3_600_000;
151
+
152
+ for (const entry of entries) {
153
+ if (!entry.isFile() || !entry.name.endsWith('.json')) continue;
154
+ const filePath = path.join(dir, entry.name);
155
+ try {
156
+ const raw = await fs.readFile(filePath, 'utf8');
157
+ const session = JSON.parse(raw);
158
+ const lastActive = session.last_active ? new Date(session.last_active).getTime() : 0;
159
+ if (lastActive < cutoff) {
160
+ await fs.unlink(filePath);
161
+ deleted++;
162
+ }
163
+ } catch {
164
+ // Corrupt file — remove it
165
+ await fs.unlink(filePath).catch(() => {});
166
+ deleted++;
167
+ }
168
+ }
169
+
170
+ return deleted;
171
+ }
172
+
173
+ module.exports = {
174
+ loadSession,
175
+ saveSession,
176
+ appendTurn,
177
+ buildContextualInput,
178
+ cleanExpiredSessions,
179
+ sanitizeSessionId
180
+ };
@@ -0,0 +1,74 @@
1
+ 'use strict';
2
+ const { randomUUID } = require('node:crypto');
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { openRuntimeDb, insertWorkerRun } = require('../runtime-store');
6
+
7
+ const INBOX_DIR = (projectDir, squadSlug) =>
8
+ path.join(projectDir, '.aioson', 'squads', squadSlug, 'inbox');
9
+
10
+ async function callSquad({ projectDir, from, to, worker, payload, conversationId, depth = 0 }) {
11
+ // 1. Cascade guard
12
+ if (depth > 5) return { ok: false, error: 'cascade_guard' };
13
+
14
+ conversationId = conversationId || randomUUID();
15
+
16
+ // 2. Resolver porta do squad destino no SQLite (manter DB aberto para log)
17
+ const handle = await openRuntimeDb(projectDir);
18
+ const db = handle?.db;
19
+ const port = db
20
+ ?.prepare("SELECT port FROM squad_daemons WHERE squad_slug = ? AND status = 'running'")
21
+ .get(to)?.port;
22
+
23
+ let result;
24
+
25
+ // 3. Tentar chamada direta
26
+ if (port) {
27
+ try {
28
+ const res = await fetch(`http://127.0.0.1:${port}/webhook/${worker}`, {
29
+ method: 'POST',
30
+ headers: { 'Content-Type': 'application/json' },
31
+ body: JSON.stringify({ ...payload, _inter_squad: { from, conversationId, depth: depth + 1 } }),
32
+ signal: AbortSignal.timeout(10000)
33
+ });
34
+ const json = await res.json();
35
+ result = { ok: res.ok, result: json, conversationId };
36
+ } catch {
37
+ // cai para inbox
38
+ }
39
+ }
40
+
41
+ // 4. Enfileirar na inbox do squad destino
42
+ if (!result) {
43
+ const inboxDir = INBOX_DIR(projectDir, to);
44
+ await fs.mkdir(inboxDir, { recursive: true });
45
+ const id = randomUUID();
46
+ await fs.writeFile(
47
+ path.join(inboxDir, `${id}.json`),
48
+ JSON.stringify({ id, from, to, worker, payload, conversationId, depth, created_at: new Date().toISOString() })
49
+ );
50
+ result = { ok: false, error: 'offline_queued', conversationId };
51
+ }
52
+
53
+ // 5. Gravar chamada emitida no runtime store (trigger_type = 'inter-squad')
54
+ if (db) {
55
+ try {
56
+ insertWorkerRun(db, {
57
+ squadSlug: from,
58
+ workerSlug: worker,
59
+ triggerType: 'inter-squad',
60
+ inputJson: JSON.stringify({ to, payload, conversationId }),
61
+ outputJson: result.ok ? JSON.stringify(result.result) : null,
62
+ status: result.ok ? 'completed' : 'failed',
63
+ errorMessage: result.ok ? null : result.error,
64
+ durationMs: 0,
65
+ attempt: 1
66
+ });
67
+ } catch { /* ignore */ }
68
+ db.close();
69
+ }
70
+
71
+ return result;
72
+ }
73
+
74
+ module.exports = { callSquad, INBOX_DIR };
@@ -0,0 +1,201 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const SQUADS_DIR = path.join('.aioson', 'squads');
7
+
8
+ // Events that trigger an automatic refresh of the recovery context
9
+ const REFRESH_EVENTS = new Set(['task_completed', 'decision_made', 'handoff']);
10
+
11
+ // Approximate token count (chars / 4)
12
+ function estimateTokens(str) {
13
+ return Math.ceil(str.length / 4);
14
+ }
15
+
16
+ /**
17
+ * Read squad manifest (best-effort, returns {} on failure).
18
+ */
19
+ async function readManifest(projectDir, squadSlug) {
20
+ const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'squad.manifest.json');
21
+ try {
22
+ return JSON.parse(await fs.readFile(p, 'utf8'));
23
+ } catch {
24
+ return {};
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Read recent events from session-log.json (last N entries).
30
+ */
31
+ async function readRecentEvents(projectDir, squadSlug, limit = 10) {
32
+ const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'session-log.json');
33
+ try {
34
+ const raw = JSON.parse(await fs.readFile(p, 'utf8'));
35
+ const entries = Array.isArray(raw) ? raw : (raw.entries || []);
36
+ return entries.slice(-limit);
37
+ } catch {
38
+ return [];
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Read recent tasks from tasks.json (last 5, enriched).
44
+ */
45
+ async function readRecentTasks(projectDir, squadSlug, limit = 5) {
46
+ const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'tasks.json');
47
+ try {
48
+ const raw = JSON.parse(await fs.readFile(p, 'utf8'));
49
+ const tasks = Array.isArray(raw) ? raw : (raw.tasks || []);
50
+ return tasks.slice(-limit);
51
+ } catch {
52
+ return [];
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Read context-monitor.json snapshot for an agent.
58
+ */
59
+ async function readContextSnapshot(projectDir, squadSlug, agentSlug) {
60
+ const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'context-monitor.json');
61
+ try {
62
+ const data = JSON.parse(await fs.readFile(p, 'utf8'));
63
+ if (agentSlug && data.agents && data.agents[agentSlug]) {
64
+ return data.agents[agentSlug];
65
+ }
66
+ return data;
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Build the markdown content for recovery-context.md.
74
+ * Target < 2000 tokens.
75
+ */
76
+ function buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events, ctxSnapshot) {
77
+ const lines = [];
78
+
79
+ lines.push(`# Recovery Context — ${squadSlug} / ${agentSlug}`);
80
+ lines.push(`> Generated: ${new Date().toISOString()}`);
81
+ lines.push('');
82
+
83
+ // Squad goal
84
+ if (manifest.goal) {
85
+ lines.push('## Squad Goal');
86
+ lines.push(manifest.goal);
87
+ lines.push('');
88
+ }
89
+
90
+ // Agent role (from executors array)
91
+ const executor = (manifest.executors || []).find(e => e.slug === agentSlug);
92
+ if (executor) {
93
+ lines.push('## Your Role');
94
+ lines.push(`**${executor.title || agentSlug}**: ${executor.role || ''}`);
95
+ lines.push('');
96
+ }
97
+
98
+ // Recent tasks
99
+ if (tasks.length > 0) {
100
+ lines.push('## Recent Tasks');
101
+ for (const t of tasks) {
102
+ const status = t.status || 'unknown';
103
+ const title = t.title || t.slug || t.id || '(untitled)';
104
+ lines.push(`- [${status}] ${title}`);
105
+ if (t.output && typeof t.output === 'string') {
106
+ // Truncate long outputs
107
+ const out = t.output.length > 200 ? t.output.slice(0, 200) + '…' : t.output;
108
+ lines.push(` Output: ${out}`);
109
+ }
110
+ }
111
+ lines.push('');
112
+ }
113
+
114
+ // Recent events
115
+ if (events.length > 0) {
116
+ lines.push('## Recent Events');
117
+ for (const ev of events) {
118
+ const ts = ev.created_at || ev.timestamp || '';
119
+ const type = ev.event_type || ev.type || 'event';
120
+ const msg = ev.message || ev.summary || '';
121
+ lines.push(`- [${ts}] ${type}: ${msg}`);
122
+ }
123
+ lines.push('');
124
+ }
125
+
126
+ // Context snapshot
127
+ if (ctxSnapshot) {
128
+ lines.push('## Context Window at Last Compact');
129
+ const used = ctxSnapshot.totalUsed || 0;
130
+ const win = ctxSnapshot.windowSize || 0;
131
+ const pct = win > 0 ? Math.round((used / win) * 100) : 0;
132
+ lines.push(`Used: ${used.toLocaleString()} / ${win.toLocaleString()} tokens (${pct}%)`);
133
+ lines.push('');
134
+ }
135
+
136
+ lines.push('---');
137
+ lines.push('*Inject this file at the top of your next session to restore context after a compact.*');
138
+
139
+ const content = lines.join('\n');
140
+
141
+ // Enforce token limit: if over budget, trim events section
142
+ if (estimateTokens(content) > 2000) {
143
+ // Rebuild with fewer events
144
+ return buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events.slice(-3), ctxSnapshot);
145
+ }
146
+
147
+ return content;
148
+ }
149
+
150
+ /**
151
+ * Generate and write recovery-context.md for an agent.
152
+ * @param {string} projectDir
153
+ * @param {string} squadSlug
154
+ * @param {string} agentSlug
155
+ * @returns {{ ok: boolean, path: string, tokens: number }}
156
+ */
157
+ async function generateRecovery(projectDir, squadSlug, agentSlug) {
158
+ const [manifest, tasks, events, ctxSnapshot] = await Promise.all([
159
+ readManifest(projectDir, squadSlug),
160
+ readRecentTasks(projectDir, squadSlug),
161
+ readRecentEvents(projectDir, squadSlug),
162
+ readContextSnapshot(projectDir, squadSlug, agentSlug)
163
+ ]);
164
+
165
+ const content = buildRecoveryMarkdown(squadSlug, agentSlug, manifest, tasks, events, ctxSnapshot);
166
+ const tokens = estimateTokens(content);
167
+
168
+ const outDir = path.join(projectDir, SQUADS_DIR, squadSlug);
169
+ const outPath = path.join(outDir, `recovery-context.md`);
170
+
171
+ try {
172
+ await fs.mkdir(outDir, { recursive: true });
173
+ await fs.writeFile(outPath, content, 'utf8');
174
+ } catch (err) {
175
+ return { ok: false, error: err.message, path: outPath, tokens };
176
+ }
177
+
178
+ return { ok: true, path: outPath, tokens, squadSlug, agentSlug };
179
+ }
180
+
181
+ /**
182
+ * Read the current recovery-context.md for an agent (returns null if missing).
183
+ */
184
+ async function readRecovery(projectDir, squadSlug) {
185
+ const p = path.join(projectDir, SQUADS_DIR, squadSlug, 'recovery-context.md');
186
+ try {
187
+ return await fs.readFile(p, 'utf8');
188
+ } catch {
189
+ return null;
190
+ }
191
+ }
192
+
193
+ /**
194
+ * Check if a runtime event should trigger a recovery refresh.
195
+ * @param {string} eventType
196
+ */
197
+ function shouldRefreshOnEvent(eventType) {
198
+ return REFRESH_EVENTS.has(eventType);
199
+ }
200
+
201
+ module.exports = { generateRecovery, readRecovery, shouldRefreshOnEvent, REFRESH_EVENTS };