@jaimevalasek/aioson 1.7.2 → 1.8.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 (362) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +153 -10
  3. package/docs/en/cli-reference.md +56 -1
  4. package/docs/en/i18n.md +18 -18
  5. package/docs/en/schemas/index.json +10 -0
  6. package/docs/en/schemas/parallel-assign.schema.json +9 -0
  7. package/docs/en/schemas/parallel-doctor.schema.json +36 -0
  8. package/docs/en/schemas/parallel-guard.schema.json +63 -0
  9. package/docs/en/schemas/parallel-merge.schema.json +84 -0
  10. package/docs/en/schemas/parallel-status.schema.json +91 -1
  11. package/docs/integrations/apps-publish-marketplace.md +94 -0
  12. package/docs/pt/README.md +9 -0
  13. package/docs/pt/agentes.md +324 -3
  14. package/docs/pt/clientes-ai.md +7 -3
  15. package/docs/pt/comandos-cli.md +160 -13
  16. package/docs/pt/compress-agents.md +304 -0
  17. package/docs/pt/design-docs-governance.md +59 -0
  18. package/docs/pt/feature-archive.md +191 -0
  19. package/docs/pt/genome-3.0-spec.md +115 -4
  20. package/docs/pt/genome-distribution.md +232 -0
  21. package/docs/pt/inicio-rapido.md +1 -0
  22. package/docs/pt/motor-hardening.md +492 -0
  23. package/docs/pt/runner-system.md +113 -0
  24. package/package.json +2 -1
  25. package/src/agent-manifests.js +66 -0
  26. package/src/agents.js +27 -7
  27. package/src/autonomy-policy.js +139 -0
  28. package/src/brain-query.js +161 -0
  29. package/src/cli.js +1377 -1099
  30. package/src/commands/agents.js +102 -7
  31. package/src/commands/artifact-validate.js +33 -4
  32. package/src/commands/auth.js +272 -0
  33. package/src/commands/brain-query.js +44 -0
  34. package/src/commands/briefing.js +344 -0
  35. package/src/commands/commit-prepare.js +547 -0
  36. package/src/commands/compress-agents.js +416 -0
  37. package/src/commands/context-health.js +4 -2
  38. package/src/commands/context-trim.js +17 -11
  39. package/src/commands/design-hybrid-options.js +3 -3
  40. package/src/commands/devlog-process.js +6 -4
  41. package/src/commands/dossier.js +423 -0
  42. package/src/commands/feature-archive.js +513 -0
  43. package/src/commands/feature-close.js +123 -18
  44. package/src/commands/gate-approve.js +198 -0
  45. package/src/commands/gate-check.js +24 -5
  46. package/src/commands/genome-doctor.js +166 -9
  47. package/src/commands/git-guard.js +170 -0
  48. package/src/commands/harness.js +121 -0
  49. package/src/commands/implementation-plan.js +47 -20
  50. package/src/commands/init.js +6 -2
  51. package/src/commands/install.js +6 -2
  52. package/src/commands/live.js +497 -56
  53. package/src/commands/locale-apply.js +9 -6
  54. package/src/commands/locale-diff.js +11 -112
  55. package/src/commands/mcp-doctor.js +2 -1
  56. package/src/commands/mcp-init.js +4 -10
  57. package/src/commands/memory.js +234 -0
  58. package/src/commands/parallel-assign.js +107 -27
  59. package/src/commands/parallel-doctor.js +416 -3
  60. package/src/commands/parallel-guard.js +241 -0
  61. package/src/commands/parallel-init.js +66 -4
  62. package/src/commands/parallel-merge.js +299 -0
  63. package/src/commands/parallel-status.js +147 -3
  64. package/src/commands/preflight.js +63 -4
  65. package/src/commands/qa-init.js +10 -5
  66. package/src/commands/revision.js +235 -0
  67. package/src/commands/scaffold-complete.js +188 -0
  68. package/src/commands/security-audit.js +275 -0
  69. package/src/commands/security-scan.js +376 -0
  70. package/src/commands/self-implement-loop.js +46 -2
  71. package/src/commands/setup-context.js +11 -10
  72. package/src/commands/squad-agent-create.js +51 -9
  73. package/src/commands/squad-investigate.js +53 -0
  74. package/src/commands/squad-plan.js +33 -1
  75. package/src/commands/squad-scaffold.js +4 -3
  76. package/src/commands/squad-score.js +71 -14
  77. package/src/commands/squad-status.js +22 -1
  78. package/src/commands/squad-validate.js +93 -2
  79. package/src/commands/store-genome.js +304 -0
  80. package/src/commands/store-skill.js +247 -0
  81. package/src/commands/store-squad.js +431 -0
  82. package/src/commands/store-system.js +392 -0
  83. package/src/commands/tool-capabilities.js +63 -0
  84. package/src/commands/update.js +3 -3
  85. package/src/commands/verify-gate.js +40 -0
  86. package/src/commands/workflow-execute.js +644 -155
  87. package/src/commands/workflow-harden.js +231 -0
  88. package/src/commands/workflow-heal.js +136 -0
  89. package/src/commands/workflow-next.js +460 -22
  90. package/src/commands/workflow-status.js +328 -138
  91. package/src/commands/workspace.js +144 -0
  92. package/src/constants.js +42 -75
  93. package/src/context-memory.js +133 -4
  94. package/src/context-writer.js +2 -1
  95. package/src/context.js +32 -2
  96. package/src/doctor.js +46 -6
  97. package/src/dossier/codemap-store.js +267 -0
  98. package/src/dossier/dossier-bootstrap.js +222 -0
  99. package/src/dossier/dossier-compact.js +159 -0
  100. package/src/dossier/lock.js +128 -0
  101. package/src/dossier/revision-store.js +313 -0
  102. package/src/dossier/schema.js +155 -0
  103. package/src/dossier/store.js +400 -0
  104. package/src/execution-gateway.js +3 -0
  105. package/src/friction-scanner.js +202 -0
  106. package/src/genome-schema.js +24 -1
  107. package/src/genomes.js +33 -0
  108. package/src/handoff-contract.js +363 -0
  109. package/src/handoff-validator.js +45 -0
  110. package/src/harness/circuit-breaker.js +135 -0
  111. package/src/i18n/messages/en.js +317 -22
  112. package/src/i18n/messages/es.js +259 -18
  113. package/src/i18n/messages/fr.js +260 -18
  114. package/src/i18n/messages/pt-BR.js +313 -22
  115. package/src/install-profile.js +0 -16
  116. package/src/installer.js +70 -6
  117. package/src/lib/git-commit-guard.js +691 -0
  118. package/src/lib/security/artifact-reader.js +167 -0
  119. package/src/lib/security/exit-codes.js +51 -0
  120. package/src/lib/security/findings-writer.js +176 -0
  121. package/src/lib/security/runtime-events.js +77 -0
  122. package/src/lib/security/secrets-regex.js +115 -0
  123. package/src/lib/store/security-scan.js +173 -0
  124. package/src/lib/terminal-checkbox.js +130 -0
  125. package/src/lib/tmux-launcher.js +163 -0
  126. package/src/lib/tool-capabilities.js +102 -0
  127. package/src/locales.js +12 -8
  128. package/src/parallel-workspace.js +756 -0
  129. package/src/parser.js +8 -1
  130. package/src/path-guard.js +47 -0
  131. package/src/preflight-engine.js +237 -26
  132. package/src/self-healing.js +142 -0
  133. package/src/session-handoff.js +111 -1
  134. package/src/squad/squad-scaffold.js +183 -19
  135. package/src/test-briefing.js +226 -0
  136. package/src/updater.js +1 -1
  137. package/src/utils.js +3 -0
  138. package/src/workflow-gates.js +185 -0
  139. package/template/.aioson/agents/analyst.md +76 -130
  140. package/template/.aioson/agents/architect.md +53 -86
  141. package/template/.aioson/agents/committer.md +161 -0
  142. package/template/.aioson/agents/cypher.md +252 -0
  143. package/template/.aioson/agents/dev.md +112 -628
  144. package/template/.aioson/agents/deyvin.md +33 -236
  145. package/template/.aioson/agents/discover.md +235 -0
  146. package/template/.aioson/agents/discovery-design-doc.md +17 -252
  147. package/template/.aioson/agents/genome.md +76 -26
  148. package/template/.aioson/agents/manifests/analyst.manifest.json +26 -0
  149. package/template/.aioson/agents/manifests/architect.manifest.json +23 -0
  150. package/template/.aioson/agents/manifests/committer.manifest.json +23 -0
  151. package/template/.aioson/agents/manifests/dev.manifest.json +37 -0
  152. package/template/.aioson/agents/manifests/orchestrator.manifest.json +30 -0
  153. package/template/.aioson/agents/manifests/pentester.manifest.json +39 -0
  154. package/template/.aioson/agents/manifests/pm.manifest.json +26 -0
  155. package/template/.aioson/agents/manifests/product.manifest.json +23 -0
  156. package/template/.aioson/agents/manifests/qa.manifest.json +25 -0
  157. package/template/.aioson/agents/manifests/setup.manifest.json +20 -0
  158. package/template/.aioson/agents/manifests/ux-ui.manifest.json +24 -0
  159. package/template/.aioson/agents/neo.md +5 -7
  160. package/template/.aioson/agents/orache.md +2 -6
  161. package/template/.aioson/agents/orchestrator.md +81 -182
  162. package/template/.aioson/agents/pentester.md +235 -0
  163. package/template/.aioson/agents/pm.md +40 -104
  164. package/template/.aioson/agents/product.md +99 -344
  165. package/template/.aioson/agents/profiler-enricher.md +57 -6
  166. package/template/.aioson/agents/profiler-forge.md +17 -7
  167. package/template/.aioson/agents/profiler-researcher.md +29 -6
  168. package/template/.aioson/agents/qa.md +168 -514
  169. package/template/.aioson/agents/setup.md +52 -278
  170. package/template/.aioson/agents/sheldon.md +122 -754
  171. package/template/.aioson/agents/site-forge.md +111 -1583
  172. package/template/.aioson/agents/squad.md +139 -2010
  173. package/template/.aioson/agents/tester.md +10 -0
  174. package/template/.aioson/agents/ux-ui.md +104 -812
  175. package/template/.aioson/agents/validator.md +69 -0
  176. package/template/.aioson/brains/scripts/query.js +5 -1
  177. package/template/.aioson/config/autonomy-protocol.json +43 -0
  178. package/template/.aioson/config.md +43 -15
  179. package/template/.aioson/constitution.md +36 -33
  180. package/template/.aioson/context/design-doc.md +136 -0
  181. package/template/.aioson/context/project-map.md +57 -0
  182. package/template/.aioson/design-docs/code-reuse.md +48 -0
  183. package/template/.aioson/design-docs/componentization.md +47 -0
  184. package/template/.aioson/design-docs/file-size.md +52 -0
  185. package/template/.aioson/design-docs/folder-structure.md +51 -0
  186. package/template/.aioson/design-docs/naming.md +54 -0
  187. package/template/.aioson/docs/LAYERS.md +12 -2
  188. package/template/.aioson/docs/dev/execution-discipline.md +106 -0
  189. package/template/.aioson/docs/dev/stack-conventions.md +83 -0
  190. package/template/.aioson/docs/deyvin/continuity-recovery.md +57 -0
  191. package/template/.aioson/docs/deyvin/debugging-escalation.md +30 -0
  192. package/template/.aioson/docs/deyvin/pair-execution.md +44 -0
  193. package/template/.aioson/docs/deyvin/runtime-handoffs.md +36 -0
  194. package/template/.aioson/docs/product/conversation-playbook.md +116 -0
  195. package/template/.aioson/docs/product/prd-contract.md +107 -0
  196. package/template/.aioson/docs/product/quality-lens.md +57 -0
  197. package/template/.aioson/docs/product/research-loop.md +65 -0
  198. package/template/.aioson/docs/sheldon/enrichment-paths.md +134 -0
  199. package/template/.aioson/docs/sheldon/quality-lens.md +57 -0
  200. package/template/.aioson/docs/sheldon/research-loop.md +56 -0
  201. package/template/.aioson/docs/sheldon/web-intelligence.md +75 -0
  202. package/template/.aioson/docs/site-forge-build.md +195 -0
  203. package/template/.aioson/docs/site-forge-extraction.md +135 -0
  204. package/template/.aioson/docs/site-forge-qa.md +155 -0
  205. package/template/.aioson/docs/site-forge-recon.md +434 -0
  206. package/template/.aioson/docs/site-forge-transform.md +249 -0
  207. package/template/.aioson/docs/squad/content-output.md +91 -0
  208. package/template/.aioson/docs/squad/creation-flow.md +135 -0
  209. package/template/.aioson/docs/squad/domain-classification.md +117 -0
  210. package/template/.aioson/docs/squad/genome-bindings.md +47 -0
  211. package/template/.aioson/docs/squad/package-contract.md +234 -0
  212. package/template/.aioson/docs/squad/quality-lens.md +56 -0
  213. package/template/.aioson/docs/squad/research-loop.md +59 -0
  214. package/template/.aioson/docs/squad/session-operations.md +117 -0
  215. package/template/.aioson/docs/squad/workflow-quality.md +165 -0
  216. package/template/.aioson/docs/ux-ui/accessibility-audit.md +55 -0
  217. package/template/.aioson/docs/ux-ui/audit-mode.md +86 -0
  218. package/template/.aioson/docs/ux-ui/component-map.md +35 -0
  219. package/template/.aioson/docs/ux-ui/design-execution.md +111 -0
  220. package/template/.aioson/docs/ux-ui/design-gate.md +27 -0
  221. package/template/.aioson/docs/ux-ui/research-mode.md +39 -0
  222. package/template/.aioson/docs/ux-ui/site-delivery.md +156 -0
  223. package/template/.aioson/docs/ux-ui/token-contract.md +57 -0
  224. package/template/.aioson/genomes/copywriting.meta.json +48 -0
  225. package/template/.aioson/git-guard.json +11 -0
  226. package/template/.aioson/mcp/servers.md +0 -1
  227. package/template/.aioson/rules/agent-language-policy.md +93 -0
  228. package/template/.aioson/rules/aioson-context-boundary.md +63 -0
  229. package/template/.aioson/rules/canonical-path-contract.md +47 -0
  230. package/template/.aioson/rules/data-format-convention.md +24 -86
  231. package/template/.aioson/rules/disk-first-artifacts.md +44 -0
  232. package/template/.aioson/rules/output-brevity.md +44 -0
  233. package/template/.aioson/rules/prd-section-ownership.md +49 -0
  234. package/template/.aioson/rules/security-baseline.md +139 -0
  235. package/template/.aioson/rules/spec-level-ownership.md +61 -0
  236. package/template/.aioson/rules/squad-driver-pattern.md +81 -0
  237. package/template/.aioson/schemas/squad-blueprint.schema.json +24 -0
  238. package/template/.aioson/schemas/squad-manifest.schema.json +44 -0
  239. package/template/.aioson/skills/process/aioson-spec-driven/references/pm.md +30 -0
  240. package/template/.aioson/skills/process/secure-tdd/SKILL.md +97 -0
  241. package/template/.aioson/skills/process/secure-tdd/references/nextjs.md +81 -0
  242. package/template/.aioson/skills/process/secure-tdd/references/node-express.md +91 -0
  243. package/template/.aioson/skills/process/secure-tdd/references/planned-stacks.md +33 -0
  244. package/template/.aioson/skills/static/harness-validate/SKILL.md +46 -0
  245. package/template/.aioson/skills/static/web-research-cache.md +3 -0
  246. package/template/.aioson/tasks/squad-create.md +35 -8
  247. package/template/.aioson/tasks/squad-design.md +50 -2
  248. package/template/.aioson/tasks/squad-investigate.md +14 -1
  249. package/template/.claude/commands/aioson/agent/committer.md +5 -0
  250. package/template/.claude/commands/aioson/agent/copywriter.md +5 -0
  251. package/template/.claude/commands/aioson/agent/cypher.md +5 -0
  252. package/template/.claude/commands/aioson/agent/pair.md +5 -0
  253. package/template/.claude/commands/aioson/agent/validator.md +5 -0
  254. package/template/.gemini/commands/aios-analyst.toml +6 -3
  255. package/template/.gemini/commands/aios-architect.toml +7 -6
  256. package/template/.gemini/commands/aios-committer.toml +7 -0
  257. package/template/.gemini/commands/aios-copywriter.toml +7 -0
  258. package/template/.gemini/commands/aios-cypher.toml +7 -0
  259. package/template/.gemini/commands/aios-dev.toml +8 -7
  260. package/template/.gemini/commands/aios-deyvin.toml +6 -5
  261. package/template/.gemini/commands/aios-discovery-design-doc.toml +6 -3
  262. package/template/.gemini/commands/aios-genome.toml +7 -0
  263. package/template/.gemini/commands/aios-neo.toml +5 -3
  264. package/template/.gemini/commands/aios-orache.toml +7 -0
  265. package/template/.gemini/commands/aios-orchestrator.toml +8 -7
  266. package/template/.gemini/commands/aios-pair.toml +6 -5
  267. package/template/.gemini/commands/aios-pm.toml +8 -7
  268. package/template/.gemini/commands/aios-product.toml +5 -3
  269. package/template/.gemini/commands/aios-qa.toml +6 -5
  270. package/template/.gemini/commands/aios-setup.toml +5 -2
  271. package/template/.gemini/commands/aios-sheldon.toml +7 -0
  272. package/template/.gemini/commands/aios-site-forge.toml +7 -0
  273. package/template/.gemini/commands/aios-squad.toml +7 -0
  274. package/template/.gemini/commands/aios-tester.toml +6 -5
  275. package/template/.gemini/commands/aios-ux-ui.toml +8 -7
  276. package/template/.gemini/commands/aios-validator.toml +7 -0
  277. package/template/AGENTS.md +12 -1
  278. package/template/CLAUDE.md +5 -1
  279. package/template/.aioson/locales/en/agents/analyst.md +0 -244
  280. package/template/.aioson/locales/en/agents/architect.md +0 -245
  281. package/template/.aioson/locales/en/agents/dev.md +0 -397
  282. package/template/.aioson/locales/en/agents/deyvin.md +0 -137
  283. package/template/.aioson/locales/en/agents/discovery-design-doc.md +0 -27
  284. package/template/.aioson/locales/en/agents/genome.md +0 -212
  285. package/template/.aioson/locales/en/agents/neo.md +0 -8
  286. package/template/.aioson/locales/en/agents/orache.md +0 -6
  287. package/template/.aioson/locales/en/agents/orchestrator.md +0 -189
  288. package/template/.aioson/locales/en/agents/pair.md +0 -5
  289. package/template/.aioson/locales/en/agents/pm.md +0 -84
  290. package/template/.aioson/locales/en/agents/product.md +0 -378
  291. package/template/.aioson/locales/en/agents/profiler-enricher.md +0 -5
  292. package/template/.aioson/locales/en/agents/profiler-forge.md +0 -5
  293. package/template/.aioson/locales/en/agents/profiler-researcher.md +0 -5
  294. package/template/.aioson/locales/en/agents/qa.md +0 -270
  295. package/template/.aioson/locales/en/agents/setup.md +0 -421
  296. package/template/.aioson/locales/en/agents/sheldon.md +0 -455
  297. package/template/.aioson/locales/en/agents/squad.md +0 -449
  298. package/template/.aioson/locales/en/agents/tester.md +0 -6
  299. package/template/.aioson/locales/en/agents/ux-ui.md +0 -668
  300. package/template/.aioson/locales/es/agents/analyst.md +0 -225
  301. package/template/.aioson/locales/es/agents/architect.md +0 -245
  302. package/template/.aioson/locales/es/agents/dev.md +0 -370
  303. package/template/.aioson/locales/es/agents/deyvin.md +0 -99
  304. package/template/.aioson/locales/es/agents/discovery-design-doc.md +0 -21
  305. package/template/.aioson/locales/es/agents/genome.md +0 -104
  306. package/template/.aioson/locales/es/agents/neo.md +0 -50
  307. package/template/.aioson/locales/es/agents/orache.md +0 -105
  308. package/template/.aioson/locales/es/agents/orchestrator.md +0 -194
  309. package/template/.aioson/locales/es/agents/pair.md +0 -7
  310. package/template/.aioson/locales/es/agents/pm.md +0 -90
  311. package/template/.aioson/locales/es/agents/product.md +0 -372
  312. package/template/.aioson/locales/es/agents/profiler-enricher.md +0 -7
  313. package/template/.aioson/locales/es/agents/profiler-forge.md +0 -7
  314. package/template/.aioson/locales/es/agents/profiler-researcher.md +0 -7
  315. package/template/.aioson/locales/es/agents/qa.md +0 -198
  316. package/template/.aioson/locales/es/agents/setup.md +0 -405
  317. package/template/.aioson/locales/es/agents/sheldon.md +0 -309
  318. package/template/.aioson/locales/es/agents/squad.md +0 -532
  319. package/template/.aioson/locales/es/agents/tester.md +0 -9
  320. package/template/.aioson/locales/es/agents/ux-ui.md +0 -212
  321. package/template/.aioson/locales/fr/agents/analyst.md +0 -225
  322. package/template/.aioson/locales/fr/agents/architect.md +0 -245
  323. package/template/.aioson/locales/fr/agents/dev.md +0 -370
  324. package/template/.aioson/locales/fr/agents/deyvin.md +0 -99
  325. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +0 -21
  326. package/template/.aioson/locales/fr/agents/genome.md +0 -104
  327. package/template/.aioson/locales/fr/agents/neo.md +0 -50
  328. package/template/.aioson/locales/fr/agents/orache.md +0 -106
  329. package/template/.aioson/locales/fr/agents/orchestrator.md +0 -194
  330. package/template/.aioson/locales/fr/agents/pair.md +0 -7
  331. package/template/.aioson/locales/fr/agents/pm.md +0 -90
  332. package/template/.aioson/locales/fr/agents/product.md +0 -372
  333. package/template/.aioson/locales/fr/agents/profiler-enricher.md +0 -7
  334. package/template/.aioson/locales/fr/agents/profiler-forge.md +0 -7
  335. package/template/.aioson/locales/fr/agents/profiler-researcher.md +0 -7
  336. package/template/.aioson/locales/fr/agents/qa.md +0 -198
  337. package/template/.aioson/locales/fr/agents/setup.md +0 -405
  338. package/template/.aioson/locales/fr/agents/sheldon.md +0 -309
  339. package/template/.aioson/locales/fr/agents/squad.md +0 -532
  340. package/template/.aioson/locales/fr/agents/tester.md +0 -9
  341. package/template/.aioson/locales/fr/agents/ux-ui.md +0 -212
  342. package/template/.aioson/locales/pt-BR/agents/analyst.md +0 -319
  343. package/template/.aioson/locales/pt-BR/agents/architect.md +0 -284
  344. package/template/.aioson/locales/pt-BR/agents/dev.md +0 -483
  345. package/template/.aioson/locales/pt-BR/agents/deyvin.md +0 -184
  346. package/template/.aioson/locales/pt-BR/agents/discovery-design-doc.md +0 -198
  347. package/template/.aioson/locales/pt-BR/agents/genome.md +0 -297
  348. package/template/.aioson/locales/pt-BR/agents/neo.md +0 -208
  349. package/template/.aioson/locales/pt-BR/agents/orache.md +0 -137
  350. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +0 -324
  351. package/template/.aioson/locales/pt-BR/agents/pair.md +0 -5
  352. package/template/.aioson/locales/pt-BR/agents/pm.md +0 -182
  353. package/template/.aioson/locales/pt-BR/agents/product.md +0 -466
  354. package/template/.aioson/locales/pt-BR/agents/profiler-enricher.md +0 -5
  355. package/template/.aioson/locales/pt-BR/agents/profiler-forge.md +0 -5
  356. package/template/.aioson/locales/pt-BR/agents/profiler-researcher.md +0 -5
  357. package/template/.aioson/locales/pt-BR/agents/qa.md +0 -300
  358. package/template/.aioson/locales/pt-BR/agents/setup.md +0 -533
  359. package/template/.aioson/locales/pt-BR/agents/sheldon.md +0 -323
  360. package/template/.aioson/locales/pt-BR/agents/squad.md +0 -1330
  361. package/template/.aioson/locales/pt-BR/agents/tester.md +0 -449
  362. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +0 -669
@@ -0,0 +1,431 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs/promises');
4
+ const path = require('node:path');
5
+ const { exists, ensureDir } = require('../utils');
6
+ const { readConfig } = require('./config');
7
+ const { readWorkspace, findProjectRoot } = require('./workspace');
8
+ const { scanPackage, formatScanReport } = require('../lib/store/security-scan');
9
+
10
+ const DEFAULT_BASE_URL = 'https://aioson.com';
11
+ const SQUADS_DIR = '.aioson/squads';
12
+ const INSTALLED_SKILLS_DIR = '.aioson/installed-skills';
13
+ const GENOMES_DIR = '.aioson/genomes';
14
+ const BACKUPS_DIR = '.aioson/.backups';
15
+
16
+ function resolveBaseUrl(config) {
17
+ return String(config.aiosonBaseUrl || DEFAULT_BASE_URL).replace(/\/+$/, '');
18
+ }
19
+
20
+ function requireToken(config, t) {
21
+ const token = config.aiosonToken;
22
+ if (!token) throw new Error(t('store.error_not_authenticated'));
23
+ return token;
24
+ }
25
+
26
+ async function storeGet(url, token) {
27
+ const response = await fetch(url, {
28
+ headers: { authorization: `Bearer ${token}`, accept: 'application/json' },
29
+ signal: AbortSignal.timeout(15000)
30
+ });
31
+ const text = await response.text();
32
+ let parsed = null;
33
+ try { parsed = JSON.parse(text); } catch { /* */ }
34
+ if (!response.ok) {
35
+ const detail = (parsed && parsed.error) ? String(parsed.error) : `${response.status} ${response.statusText}`;
36
+ throw new Error(`HTTP ${response.status}: ${detail}`);
37
+ }
38
+ return parsed;
39
+ }
40
+
41
+ async function storePost(url, payload, token) {
42
+ const response = await fetch(url, {
43
+ method: 'POST',
44
+ headers: {
45
+ authorization: `Bearer ${token}`,
46
+ 'content-type': 'application/json',
47
+ accept: 'application/json'
48
+ },
49
+ body: JSON.stringify(payload),
50
+ signal: AbortSignal.timeout(60000)
51
+ });
52
+
53
+ const text = await response.text();
54
+ let parsed = null;
55
+ try { parsed = JSON.parse(text); } catch { /* */ }
56
+
57
+ if (!response.ok) {
58
+ const detail = (parsed && parsed.error) ? String(parsed.error) : `${response.status} ${response.statusText}`;
59
+ throw new Error(`HTTP ${response.status}: ${detail}`);
60
+ }
61
+
62
+ return parsed;
63
+ }
64
+
65
+ /**
66
+ * Collect all files in a directory recursively.
67
+ * Returns { relativePath: fileContent }
68
+ */
69
+ async function collectDirFiles(dir, baseLabel) {
70
+ const files = {};
71
+
72
+ async function walk(current, rel) {
73
+ const entries = await fs.readdir(current, { withFileTypes: true });
74
+ for (const entry of entries) {
75
+ const fullPath = path.join(current, entry.name);
76
+ const relPath = rel ? `${rel}/${entry.name}` : entry.name;
77
+ if (entry.isDirectory()) {
78
+ await walk(fullPath, relPath);
79
+ } else {
80
+ try {
81
+ files[`${baseLabel}/${relPath}`] = await fs.readFile(fullPath, 'utf8');
82
+ } catch { /* binary files skipped */ }
83
+ }
84
+ }
85
+ }
86
+
87
+ if (await exists(dir)) await walk(dir, '');
88
+ return files;
89
+ }
90
+
91
+ /**
92
+ * Parse squad.md / manifest to find bundled skills and genomes.
93
+ * Looks for frontmatter fields: bundled_skills, bundled_genomes
94
+ */
95
+ function parseBundledDeps(content) {
96
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
97
+ if (!match) return { skills: [], genomes: [] };
98
+
99
+ const skills = [];
100
+ const genomes = [];
101
+
102
+ for (const line of match[1].split('\n')) {
103
+ const [key, ...rest] = line.split(':');
104
+ const val = rest.join(':').trim().replace(/^["'\[]|["'\]]$/g, '');
105
+ const k = (key || '').trim();
106
+ if (k === 'bundled_skills') skills.push(...val.split(',').map(s => s.trim()).filter(Boolean));
107
+ if (k === 'bundled_genomes') genomes.push(...val.split(',').map(s => s.trim()).filter(Boolean));
108
+ }
109
+
110
+ return { skills, genomes };
111
+ }
112
+
113
+ // ── squad:publish ───────────────────────────────────────────────────────────
114
+
115
+ async function runSquadPublish({ args, options, logger, t }) {
116
+ const config = await readConfig();
117
+ const token = requireToken(config, t);
118
+ const projectDir = await findProjectRoot(path.resolve(process.cwd(), args[0] || '.'));
119
+ const slug = String(options.slug || '').trim();
120
+ if (!slug) throw new Error(t('store.error_missing_slug'));
121
+
122
+ const squadDir = path.join(projectDir, SQUADS_DIR, slug);
123
+ if (!(await exists(squadDir))) {
124
+ throw new Error(t('store.error_squad_not_found', { slug, path: squadDir }));
125
+ }
126
+
127
+ logger.log(t('store.publish_squad_analyzing_agents'));
128
+ const agentsDir = path.join(squadDir, 'agents');
129
+ const agentFiles = await collectDirFiles(agentsDir, 'agents');
130
+ const agentCount = Object.keys(agentFiles).length;
131
+ logger.log(t('store.publish_squad_agents_found', { count: agentCount }));
132
+
133
+ // Read squad.md to discover bundled deps
134
+ const squadMdPath = path.join(squadDir, 'squad.md');
135
+ let bundledSkillSlugs = String(options['bundle-skills'] || '').split(',').map(s => s.trim()).filter(Boolean);
136
+ let bundledGenomeSlugs = String(options['bundle-genomes'] || '').split(',').map(s => s.trim()).filter(Boolean);
137
+
138
+ if (await exists(squadMdPath)) {
139
+ const squadMdContent = await fs.readFile(squadMdPath, 'utf8');
140
+ const parsed = parseBundledDeps(squadMdContent);
141
+ bundledSkillSlugs = [...new Set([...bundledSkillSlugs, ...parsed.skills])];
142
+ bundledGenomeSlugs = [...new Set([...bundledGenomeSlugs, ...parsed.genomes])];
143
+ }
144
+
145
+ logger.log(t('store.publish_squad_analyzing_deps'));
146
+
147
+ // Collect bundled skills
148
+ const skillFiles = {};
149
+ for (const skillSlug of bundledSkillSlugs) {
150
+ const skillDir = path.join(projectDir, INSTALLED_SKILLS_DIR, skillSlug);
151
+ const altSkillDir = path.join(projectDir, '.aioson/skills', skillSlug);
152
+ const src = (await exists(path.join(skillDir, 'SKILL.md'))) ? skillDir : altSkillDir;
153
+ if (await exists(path.join(src, 'SKILL.md'))) {
154
+ const files = await collectDirFiles(src, '');
155
+ for (const [k, v] of Object.entries(files)) {
156
+ skillFiles[`skills/${skillSlug}/${k}`] = v;
157
+ }
158
+ logger.log(t('store.publish_squad_bundling_skill', { slug: skillSlug }));
159
+ } else {
160
+ logger.log(t('store.publish_squad_skill_missing', { slug: skillSlug }));
161
+ }
162
+ }
163
+
164
+ // Collect bundled genomes
165
+ const genomeFiles = {};
166
+ for (const genomeSlug of bundledGenomeSlugs) {
167
+ const genomePath = path.join(projectDir, GENOMES_DIR, `${genomeSlug}.md`);
168
+ const metaPath = path.join(projectDir, GENOMES_DIR, `${genomeSlug}.meta.json`);
169
+ if (await exists(genomePath)) {
170
+ genomeFiles[`genomes/${genomeSlug}.md`] = await fs.readFile(genomePath, 'utf8');
171
+ if (await exists(metaPath)) {
172
+ genomeFiles[`genomes/${genomeSlug}.meta.json`] = await fs.readFile(metaPath, 'utf8');
173
+ }
174
+ logger.log(t('store.publish_squad_bundling_genome', { slug: genomeSlug }));
175
+ } else {
176
+ logger.log(t('store.publish_squad_genome_missing', { slug: genomeSlug }));
177
+ }
178
+ }
179
+
180
+ // Collect squad root files (squad.md, etc.)
181
+ const squadRootFiles = await collectDirFiles(squadDir, 'squad');
182
+
183
+ const allFiles = { ...squadRootFiles, ...skillFiles, ...genomeFiles };
184
+
185
+ // Security scan — squads carry the highest risk (arbitrary dir contents)
186
+ logger.log(t('store.publish_scanning'));
187
+ const scan = scanPackage(allFiles, 'squad');
188
+ formatScanReport(scan, logger);
189
+ if (!scan.ok) throw new Error(t('store.error_scan_failed'));
190
+ if (scan.warnings.length > 0 && !options.force) {
191
+ throw new Error(t('store.error_scan_warnings', { count: scan.warnings.length }));
192
+ }
193
+
194
+ const manifest = {
195
+ slug,
196
+ version: String(options.version || '1.0.0'),
197
+ bundled: {
198
+ skills: bundledSkillSlugs,
199
+ genomes: bundledGenomeSlugs
200
+ }
201
+ };
202
+
203
+ const ws = await readWorkspace(projectDir);
204
+ const visibility = options.private ? 'private' : 'public';
205
+ const paid = Boolean(options.paid);
206
+
207
+ if (options['dry-run']) {
208
+ logger.log(t('store.publish_dry_run', { type: 'squad', slug, visibility }));
209
+ logger.log(t('store.publish_squad_summary', {
210
+ agents: agentCount,
211
+ skills: bundledSkillSlugs.length,
212
+ genomes: bundledGenomeSlugs.length
213
+ }));
214
+ logger.log(t('store.publish_scan_ok', { hash: scan.hash.slice(0, 12) }));
215
+ return { ok: true, dryRun: true, slug, visibility, paid, agentCount, manifest, hash: scan.hash };
216
+ }
217
+
218
+ logger.log(t('store.publish_scan_ok', { hash: scan.hash.slice(0, 12) }));
219
+ logger.log(t('store.publish_squad_sending'));
220
+ const baseUrl = resolveBaseUrl(config);
221
+ const response = await storePost(`${baseUrl}/api/store/squads/publish`, {
222
+ kind: 'aioson.store.squad',
223
+ slug,
224
+ files: allFiles,
225
+ manifest,
226
+ visibility,
227
+ paid,
228
+ hash: scan.hash,
229
+ workspaceSlug: ws?.slug || null
230
+ }, token);
231
+
232
+ logger.log(t('store.publish_squad_done', { slug, url: `${baseUrl}/store/squads/${slug}` }));
233
+ logger.log(t('store.publish_squad_summary', {
234
+ agents: agentCount,
235
+ skills: bundledSkillSlugs.length,
236
+ genomes: bundledGenomeSlugs.length
237
+ }));
238
+ return { ok: true, slug, visibility, paid, agentCount, manifest, hash: scan.hash, response };
239
+ }
240
+
241
+ // ── squad:install ───────────────────────────────────────────────────────────
242
+
243
+ async function runSquadInstall({ args, options, logger, t }) {
244
+ const config = await readConfig();
245
+ const token = requireToken(config, t);
246
+ const projectDir = await findProjectRoot(path.resolve(process.cwd(), args[0] || '.'));
247
+ const baseUrl = resolveBaseUrl(config);
248
+
249
+ const ref = String(options.slug || options.code || args[1] || args[0] || '').trim();
250
+ const grantEmail = String(options.email || args[2] || '').trim();
251
+ if (!ref) throw new Error(t('store.error_missing_code_or_slug'));
252
+
253
+ const ws = await readWorkspace(projectDir);
254
+ logger.log(t('store.install_squad_fetching', { ref }));
255
+
256
+ const response = await storePost(`${baseUrl}/api/store/squads/install`, {
257
+ ref,
258
+ email: grantEmail || null,
259
+ workspaceSlug: ws?.slug || null
260
+ }, token);
261
+
262
+ const slug = response.manifest?.slug || response.slug;
263
+ if (!slug || !response.files) throw new Error(t('store.error_invalid_response'));
264
+
265
+ // Install-side preview and scan
266
+ const publisher = response.publisher || 'unknown';
267
+ const version = response.manifest?.version || response.version || '?';
268
+ const serverHash = response.hash || null;
269
+ const trusted = Boolean(response.trusted);
270
+ const downloads = response.downloads != null ? response.downloads : null;
271
+ const rating = response.rating != null ? `${Number(response.rating).toFixed(1)}/5` : null;
272
+
273
+ logger.log(t('store.install_preview_header', { slug, publisher, version }));
274
+ if (trusted) logger.log(t('store.install_preview_trusted'));
275
+ else logger.log(t('store.install_preview_unverified'));
276
+ if (downloads != null) logger.log(t('store.install_preview_downloads', { count: downloads }));
277
+ if (rating) logger.log(t('store.install_preview_rating', { rating }));
278
+ if (serverHash) logger.log(t('store.install_preview_hash', { hash: serverHash.slice(0, 12) }));
279
+
280
+ // Scan files received from server — squads are the highest-risk package type
281
+ logger.log(t('store.install_scanning'));
282
+ const stringFiles = Object.fromEntries(
283
+ Object.entries(response.files).filter(([, v]) => typeof v === 'string')
284
+ );
285
+ const scan = scanPackage(stringFiles, 'squad');
286
+ formatScanReport(scan, logger);
287
+ if (!scan.ok) throw new Error(t('store.error_install_scan_failed', { slug }));
288
+
289
+ if (serverHash && scan.hash !== serverHash) {
290
+ throw new Error(t('store.error_hash_mismatch', { slug }));
291
+ }
292
+
293
+ if (options.inspect) {
294
+ logger.log(t('store.install_inspect_files', { count: Object.keys(stringFiles).length }));
295
+ for (const f of Object.keys(stringFiles).sort()) logger.log(` ${f}`);
296
+ logger.log(t('store.install_inspect_hint'));
297
+ return { ok: true, slug, inspect: true, files: Object.keys(stringFiles) };
298
+ }
299
+
300
+ if (!trusted && !options.force) {
301
+ logger.log(t('store.install_unverified_hint', { slug }));
302
+ }
303
+
304
+ const squadDir = path.join(projectDir, SQUADS_DIR, slug);
305
+
306
+ // Handle existing squad
307
+ if ((await exists(squadDir)) && !options.force) {
308
+ const backupDir = path.join(projectDir, BACKUPS_DIR, `squads/${slug}`);
309
+ logger.log(t('store.install_backing_up', { path: backupDir }));
310
+ await fs.rm(backupDir, { recursive: true, force: true });
311
+ await fs.cp(squadDir, backupDir, { recursive: true });
312
+ await fs.rm(squadDir, { recursive: true, force: true });
313
+ }
314
+
315
+ // Write squad files
316
+ logger.log(t('store.install_squad_writing'));
317
+ for (const [relPath, content] of Object.entries(response.files)) {
318
+ if (!relPath.startsWith('squad/') && !relPath.startsWith('agents/') && !relPath.startsWith('skills/') && !relPath.startsWith('genomes/')) continue;
319
+
320
+ let destPath;
321
+
322
+ if (relPath.startsWith('skills/')) {
323
+ // skills/{skill-slug}/... → .aioson/installed-skills/{skill-slug}/...
324
+ const rest = relPath.slice('skills/'.length);
325
+ const [skillSlug, ...parts] = rest.split('/');
326
+ const existingSkillDir = path.join(projectDir, INSTALLED_SKILLS_DIR, skillSlug);
327
+
328
+ if ((await exists(existingSkillDir)) && !options.force) {
329
+ logger.log(t('store.install_squad_dep_skip', { type: 'skill', slug: skillSlug }));
330
+ continue;
331
+ }
332
+ destPath = path.join(projectDir, INSTALLED_SKILLS_DIR, skillSlug, ...parts);
333
+
334
+ } else if (relPath.startsWith('genomes/')) {
335
+ const rest = relPath.slice('genomes/'.length);
336
+ const destFile = path.join(projectDir, GENOMES_DIR, rest);
337
+ const genomeSlug = rest.replace(/\.(md|meta\.json)$/, '');
338
+
339
+ if ((await exists(destFile)) && !options.force) {
340
+ logger.log(t('store.install_squad_dep_skip', { type: 'genome', slug: genomeSlug }));
341
+ continue;
342
+ }
343
+ destPath = destFile;
344
+
345
+ } else {
346
+ // squad/ or agents/ → .aioson/squads/{slug}/...
347
+ const rest = relPath.startsWith('squad/') ? relPath.slice('squad/'.length) : relPath;
348
+ destPath = path.join(squadDir, rest);
349
+ }
350
+
351
+ await ensureDir(path.dirname(destPath));
352
+ await fs.writeFile(destPath, content, 'utf8');
353
+ }
354
+
355
+ logger.log(t('store.install_squad_done', { slug, path: squadDir }));
356
+ return { ok: true, slug, path: squadDir, manifest: response.manifest };
357
+ }
358
+
359
+ // ── squad:grant ─────────────────────────────────────────────────────────────
360
+
361
+ async function runSquadGrant({ args, options, logger, t }) {
362
+ const config = await readConfig();
363
+ const token = requireToken(config, t);
364
+ const baseUrl = resolveBaseUrl(config);
365
+
366
+ const code = String(options.code || args[0] || '').trim();
367
+ const email = String(options.email || args[1] || '').trim();
368
+
369
+ if (!code) throw new Error(t('store.grant_error_missing_code'));
370
+ if (!email) throw new Error(t('store.grant_error_missing_email'));
371
+
372
+ logger.log(t('store.grant_sending', { email, code }));
373
+
374
+ const response = await storePost(`${baseUrl}/api/store/grants`, {
375
+ code,
376
+ email
377
+ }, token);
378
+
379
+ logger.log(t('store.grant_ok', { email, code }));
380
+ return { ok: true, code, email, response };
381
+ }
382
+
383
+ // ── squad:list ───────────────────────────────────────────────────────────────
384
+
385
+ async function runSquadList({ args, options, logger, t }) {
386
+ // --remote: list squads published on aioson.com
387
+ if (options.remote) {
388
+ const config = await readConfig();
389
+ const token = requireToken(config, t);
390
+ const baseUrl = resolveBaseUrl(config);
391
+ logger.log(t('store.list_remote_fetching', { type: 'squads' }));
392
+ const response = await storeGet(`${baseUrl}/api/store/squads`, token);
393
+ const squads = response.squads || [];
394
+ if (squads.length === 0) {
395
+ logger.log(t('store.list_remote_empty', { type: 'squads' }));
396
+ } else {
397
+ logger.log(t('store.list_remote_header', { count: squads.length, type: 'squads' }));
398
+ for (const s of squads) {
399
+ logger.log(t('store.list_remote_item', { slug: s.slug, name: s.name || s.slug, visibility: s.visibility || '?' }));
400
+ }
401
+ }
402
+ return { ok: true, squads, remote: true };
403
+ }
404
+
405
+ // local: list squad dirs under .aioson/squads/
406
+ const projectDir = await findProjectRoot(path.resolve(process.cwd(), args[0] || '.'));
407
+ const squadsDir = path.join(projectDir, SQUADS_DIR);
408
+
409
+ if (!(await exists(squadsDir))) {
410
+ logger.log(t('store.list_squad_empty'));
411
+ return { ok: true, squads: [] };
412
+ }
413
+
414
+ const entries = await fs.readdir(squadsDir, { withFileTypes: true });
415
+ const squads = entries
416
+ .filter(e => e.isDirectory())
417
+ .map(e => ({ slug: e.name }));
418
+
419
+ if (squads.length === 0) {
420
+ logger.log(t('store.list_squad_empty'));
421
+ } else {
422
+ logger.log(t('store.list_squad_header', { count: squads.length }));
423
+ for (const s of squads) {
424
+ logger.log(t('store.list_squad_item', { slug: s.slug, visibility: 'local' }));
425
+ }
426
+ }
427
+
428
+ return { ok: true, squads };
429
+ }
430
+
431
+ module.exports = { runSquadPublish, runSquadInstall, runSquadGrant, runSquadList };