@jaimevalasek/aioson 1.5.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +729 -226
  3. package/docs/design-previews/aurora-command-ui-website.html +884 -0
  4. package/docs/design-previews/aurora-command-ui.html +682 -0
  5. package/docs/design-previews/bold-editorial-ui-website.html +658 -0
  6. package/docs/design-previews/bold-editorial-ui.html +717 -0
  7. package/docs/design-previews/clean-saas-ui-website.html +1202 -0
  8. package/docs/design-previews/clean-saas-ui.html +549 -0
  9. package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
  10. package/docs/design-previews/cognitive-core-ui.html +463 -0
  11. package/docs/design-previews/glassmorphism-ui-website.html +572 -0
  12. package/docs/design-previews/glassmorphism-ui.html +886 -0
  13. package/docs/design-previews/index.html +699 -0
  14. package/docs/design-previews/interface-design-website.html +1187 -0
  15. package/docs/design-previews/interface-design.html +513 -0
  16. package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
  17. package/docs/design-previews/neo-brutalist-ui.html +797 -0
  18. package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
  19. package/docs/design-previews/premium-command-center-ui.html +552 -0
  20. package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
  21. package/docs/design-previews/warm-craft-ui-website.html +684 -0
  22. package/docs/design-previews/warm-craft-ui.html +739 -0
  23. package/docs/en/cli-reference.md +20 -9
  24. package/docs/integrations/sdlc-genius-boundary.md +76 -0
  25. package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
  26. package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
  27. package/docs/integrations/sdlc-genius-review-samples.md +86 -0
  28. package/docs/pt/README.md +10 -0
  29. package/docs/pt/agent-sharding.md +132 -0
  30. package/docs/pt/agentes.md +9 -2
  31. package/docs/pt/busca-de-contexto.md +129 -0
  32. package/docs/pt/cache-de-contexto.md +156 -0
  33. package/docs/pt/comandos-cli.md +915 -1
  34. package/docs/pt/design-hybrid-forge.md +356 -0
  35. package/docs/pt/devlog-pipeline.md +270 -0
  36. package/docs/pt/fluxo-artefatos.md +178 -0
  37. package/docs/pt/hooks-session-guard.md +454 -0
  38. package/docs/pt/inicio-rapido.md +54 -3
  39. package/docs/pt/inteligencia-adaptativa.md +324 -0
  40. package/docs/pt/monitor-de-contexto.md +158 -0
  41. package/docs/pt/recuperacao-de-sessao.md +125 -0
  42. package/docs/pt/sandbox.md +125 -0
  43. package/docs/pt/sdd-automation-scripts.md +557 -0
  44. package/docs/pt/site-forge.md +309 -0
  45. package/docs/pt/skills.md +98 -6
  46. package/docs/pt/spec-learnings-pipeline.md +265 -0
  47. package/package.json +1 -1
  48. package/src/a2a/client.js +165 -0
  49. package/src/a2a/server.js +223 -0
  50. package/src/agent-loader.js +280 -0
  51. package/src/cli.js +329 -1
  52. package/src/commands/agent-audit.js +397 -0
  53. package/src/commands/agent-export-skill.js +229 -0
  54. package/src/commands/agent-loader.js +85 -0
  55. package/src/commands/artifact-validate.js +189 -0
  56. package/src/commands/brief-gen.js +405 -0
  57. package/src/commands/brief-validate.js +65 -0
  58. package/src/commands/classify.js +256 -0
  59. package/src/commands/context-cache.js +90 -0
  60. package/src/commands/context-compact.js +49 -0
  61. package/src/commands/context-health.js +175 -0
  62. package/src/commands/context-monitor.js +163 -0
  63. package/src/commands/context-search.js +66 -0
  64. package/src/commands/context-trim.js +177 -0
  65. package/src/commands/design-hybrid-options.js +385 -0
  66. package/src/commands/detect-test-runner.js +55 -0
  67. package/src/commands/devlog-export-brains.js +27 -0
  68. package/src/commands/devlog-process.js +292 -0
  69. package/src/commands/devlog-watch.js +131 -0
  70. package/src/commands/feature-close.js +165 -0
  71. package/src/commands/gate-check.js +228 -0
  72. package/src/commands/health.js +214 -0
  73. package/src/commands/hooks-emit.js +253 -0
  74. package/src/commands/hooks-install.js +347 -0
  75. package/src/commands/init.js +54 -13
  76. package/src/commands/install.js +52 -13
  77. package/src/commands/learning-auto-promote.js +195 -0
  78. package/src/commands/learning-evolve.js +364 -0
  79. package/src/commands/learning-export.js +103 -0
  80. package/src/commands/learning-rollback.js +164 -0
  81. package/src/commands/live.js +59 -1
  82. package/src/commands/pattern-detect.js +33 -0
  83. package/src/commands/preflight-context.js +30 -0
  84. package/src/commands/preflight.js +208 -0
  85. package/src/commands/pulse-update.js +130 -0
  86. package/src/commands/recovery.js +43 -0
  87. package/src/commands/runner-daemon.js +274 -0
  88. package/src/commands/runner-plan.js +70 -0
  89. package/src/commands/runner-queue-from-plan.js +166 -0
  90. package/src/commands/runner-queue.js +189 -0
  91. package/src/commands/runner-run.js +129 -0
  92. package/src/commands/runtime.js +47 -1
  93. package/src/commands/sandbox.js +37 -0
  94. package/src/commands/self-implement-loop.js +256 -0
  95. package/src/commands/session-guard.js +218 -0
  96. package/src/commands/setup-context.js +22 -2
  97. package/src/commands/setup.js +178 -0
  98. package/src/commands/sizing.js +165 -0
  99. package/src/commands/skill.js +144 -32
  100. package/src/commands/spec-checkpoint.js +177 -0
  101. package/src/commands/spec-status.js +79 -0
  102. package/src/commands/spec-sync.js +190 -0
  103. package/src/commands/spec-tasks.js +288 -0
  104. package/src/commands/squad-autorun.js +1220 -0
  105. package/src/commands/squad-bus.js +217 -0
  106. package/src/commands/squad-card.js +149 -0
  107. package/src/commands/squad-daemon.js +134 -0
  108. package/src/commands/squad-dependency-graph.js +164 -0
  109. package/src/commands/squad-review.js +106 -0
  110. package/src/commands/squad-scaffold.js +55 -0
  111. package/src/commands/squad-tool-register.js +157 -0
  112. package/src/commands/state-save.js +122 -0
  113. package/src/commands/tool-registry-cmd.js +232 -0
  114. package/src/commands/update.js +9 -0
  115. package/src/commands/verify-gate.js +572 -0
  116. package/src/commands/workflow-execute.js +241 -0
  117. package/src/constants.js +18 -0
  118. package/src/context-cache.js +159 -0
  119. package/src/context-search.js +326 -0
  120. package/src/design-variation-catalog.js +503 -0
  121. package/src/i18n/messages/en.js +32 -2
  122. package/src/i18n/messages/es.js +30 -2
  123. package/src/i18n/messages/fr.js +30 -2
  124. package/src/i18n/messages/pt-BR.js +32 -2
  125. package/src/install-animation.js +260 -0
  126. package/src/install-profile.js +143 -0
  127. package/src/install-wizard.js +475 -0
  128. package/src/installer.js +44 -10
  129. package/src/lib/health-check.js +158 -0
  130. package/src/lib/hook-protocol.js +76 -0
  131. package/src/mcp/apps/squad-dashboard/app.js +163 -0
  132. package/src/mcp/apps/squad-dashboard/index.html +261 -0
  133. package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
  134. package/src/mcp/resources/squad-state.js +130 -0
  135. package/src/parser.js +7 -1
  136. package/src/preflight-engine.js +443 -0
  137. package/src/recovery-context-session.js +154 -0
  138. package/src/runner/cascade.js +97 -0
  139. package/src/runner/cli-launcher.js +109 -0
  140. package/src/runner/plan-importer.js +63 -0
  141. package/src/runner/queue-store.js +159 -0
  142. package/src/runtime-store.js +158 -4
  143. package/src/sandbox.js +177 -0
  144. package/src/squad/agent-teams-adapter.js +264 -0
  145. package/src/squad/brief-validator.js +350 -0
  146. package/src/squad/bus-bridge.js +140 -0
  147. package/src/squad/context-compactor.js +265 -0
  148. package/src/squad/cross-ai-synthesizer.js +250 -0
  149. package/src/squad/hooks-generator.js +196 -0
  150. package/src/squad/inter-squad-events.js +175 -0
  151. package/src/squad/intra-bus.js +345 -0
  152. package/src/squad/learning-extractor.js +213 -0
  153. package/src/squad/pattern-detector.js +365 -0
  154. package/src/squad/preflight-context.js +296 -0
  155. package/src/squad/recovery-context.js +242 -71
  156. package/src/squad/reflection.js +365 -0
  157. package/src/squad/squad-scaffold.js +177 -0
  158. package/src/squad/state-manager.js +310 -0
  159. package/src/squad/task-decomposer.js +652 -0
  160. package/src/squad/verify-gate.js +303 -0
  161. package/src/tool-executor.js +94 -0
  162. package/src/updater.js +10 -3
  163. package/src/worker-runner.js +186 -1
  164. package/template/.aioson/agents/analyst.md +119 -3
  165. package/template/.aioson/agents/architect.md +98 -0
  166. package/template/.aioson/agents/design-hybrid-forge.md +141 -0
  167. package/template/.aioson/agents/dev.md +335 -14
  168. package/template/.aioson/agents/deyvin.md +117 -2
  169. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  170. package/template/.aioson/agents/genome.md +14 -0
  171. package/template/.aioson/agents/neo.md +78 -1
  172. package/template/.aioson/agents/orache.md +50 -4
  173. package/template/.aioson/agents/orchestrator.md +197 -1
  174. package/template/.aioson/agents/pm.md +93 -0
  175. package/template/.aioson/agents/product.md +77 -4
  176. package/template/.aioson/agents/profiler-enricher.md +14 -0
  177. package/template/.aioson/agents/profiler-forge.md +14 -0
  178. package/template/.aioson/agents/profiler-researcher.md +14 -0
  179. package/template/.aioson/agents/qa.md +249 -19
  180. package/template/.aioson/agents/setup.md +144 -12
  181. package/template/.aioson/agents/sheldon.md +237 -11
  182. package/template/.aioson/agents/site-forge.md +1753 -0
  183. package/template/.aioson/agents/squad.md +162 -0
  184. package/template/.aioson/agents/tester.md +209 -0
  185. package/template/.aioson/agents/ux-ui.md +34 -1
  186. package/template/.aioson/brains/README.md +128 -0
  187. package/template/.aioson/brains/_index.json +16 -0
  188. package/template/.aioson/brains/scripts/query.js +103 -0
  189. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  190. package/template/.aioson/config.md +158 -13
  191. package/template/.aioson/constitution.md +33 -0
  192. package/template/.aioson/context/forensics/.gitkeep +0 -0
  193. package/template/.aioson/context/project-pulse.md +34 -0
  194. package/template/.aioson/context/seeds/seed-example.md +27 -0
  195. package/template/.aioson/context/user-profile.md +42 -0
  196. package/template/.aioson/docs/LAYERS.md +79 -0
  197. package/template/.aioson/docs/README.md +76 -0
  198. package/template/.aioson/docs/example-external-api-context.md +72 -0
  199. package/template/.aioson/locales/en/agents/architect.md +17 -0
  200. package/template/.aioson/locales/en/agents/dev.md +79 -13
  201. package/template/.aioson/locales/en/agents/orache.md +6 -0
  202. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  203. package/template/.aioson/locales/en/agents/product.md +50 -0
  204. package/template/.aioson/locales/en/agents/setup.md +33 -1
  205. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  206. package/template/.aioson/locales/en/agents/squad.md +14 -0
  207. package/template/.aioson/locales/en/agents/tester.md +6 -0
  208. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  209. package/template/.aioson/locales/es/agents/architect.md +19 -0
  210. package/template/.aioson/locales/es/agents/dev.md +64 -4
  211. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  212. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  213. package/template/.aioson/locales/es/agents/genome.md +2 -0
  214. package/template/.aioson/locales/es/agents/neo.md +2 -0
  215. package/template/.aioson/locales/es/agents/orache.md +2 -0
  216. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  217. package/template/.aioson/locales/es/agents/pair.md +2 -0
  218. package/template/.aioson/locales/es/agents/pm.md +2 -0
  219. package/template/.aioson/locales/es/agents/product.md +52 -0
  220. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  221. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  222. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  223. package/template/.aioson/locales/es/agents/qa.md +2 -0
  224. package/template/.aioson/locales/es/agents/setup.md +35 -1
  225. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  226. package/template/.aioson/locales/es/agents/squad.md +16 -0
  227. package/template/.aioson/locales/es/agents/tester.md +9 -0
  228. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  229. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  230. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  231. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  232. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  233. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  234. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  235. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  236. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  237. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  238. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  239. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  240. package/template/.aioson/locales/fr/agents/product.md +52 -0
  241. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  242. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  243. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  244. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  245. package/template/.aioson/locales/fr/agents/setup.md +35 -1
  246. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  247. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  248. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  249. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  250. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  251. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  252. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  253. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  254. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  255. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  256. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  257. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  258. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  259. package/template/.aioson/locales/pt-BR/agents/setup.md +134 -19
  260. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  261. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  262. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  263. package/template/.aioson/rules/README.md +69 -0
  264. package/template/.aioson/rules/data-format-convention.md +136 -0
  265. package/template/.aioson/rules/example-monetary-values.md +30 -0
  266. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  267. package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
  268. package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
  269. package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
  270. package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
  271. package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
  272. package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
  273. package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
  274. package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
  275. package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
  276. package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
  277. package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
  278. package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
  279. package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
  280. package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
  281. package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
  282. package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
  283. package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
  284. package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
  285. package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
  286. package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
  287. package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
  288. package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
  289. package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
  290. package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
  291. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  292. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  293. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  294. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  295. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  296. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  297. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  298. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +46 -0
  299. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  300. package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
  301. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  302. package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
  303. package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
  304. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  305. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  306. package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
  307. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +101 -0
  308. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  309. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  310. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  311. package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
  312. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +147 -0
  313. package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
  314. package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
  315. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +306 -0
  316. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +149 -0
  317. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +208 -0
  318. package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
  319. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  320. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  321. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  322. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  323. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  324. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  325. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  326. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  327. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  328. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  329. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  330. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  331. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  332. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  333. package/template/.aioson/tasks/implementation-plan.md +21 -1
  334. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  335. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  336. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  337. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  338. package/template/AGENTS.md +75 -1
  339. package/template/CLAUDE.md +31 -0
  340. package/template/OPENCODE.md +4 -0
  341. package/template/researchs/.gitkeep +0 -0
@@ -0,0 +1,303 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Squad 4-tier verification gate
5
+ *
6
+ * Verifies task deliverables beyond pass/fail:
7
+ *
8
+ * Tier 1 — Exists: File/path exists on disk
9
+ * Tier 2 — Substantive: Not a stub/placeholder (min lines + anti-pattern scan)
10
+ * Tier 3 — Wired: Referenced/imported in expected target location
11
+ * Tier 4 — Functional: Smoke command returns expected output (opt-in, expensive)
12
+ *
13
+ * Used by reflection.js when a task has a `must_haves` contract.
14
+ */
15
+
16
+ const fs = require('node:fs/promises');
17
+ const { execFile } = require('node:child_process');
18
+ const { promisify } = require('node:util');
19
+
20
+ const execFileAsync = promisify(execFile);
21
+
22
+ // Patterns that indicate a file is a stub, not real implementation
23
+ const ANTI_PATTERNS = [
24
+ { pattern: /\bTODO\b/, label: 'TODO marker' },
25
+ { pattern: /\bFIXME\b/, label: 'FIXME marker' },
26
+ { pattern: /\bplaceholder\b/i, label: 'placeholder text' },
27
+ { pattern: /not\s+implemented/i, label: '"not implemented"' },
28
+ { pattern: /return\s+null;\s*\n?\s*\}/m, label: 'empty return null' },
29
+ { pattern: /throw\s+new\s+Error\s*\(['"]not\s+impl/i, label: 'NotImplemented throw' },
30
+ { pattern: /^\s*pass\s*$/m, label: 'Python stub (pass)' },
31
+ { pattern: /^\s*\.\.\.\s*$/m, label: 'ellipsis stub' }
32
+ ];
33
+
34
+ // ─── Artifact string parser ───────────────────────────────────────────────────
35
+
36
+ /**
37
+ * Parse an artifact descriptor string into structured fields.
38
+ *
39
+ * Examples:
40
+ * "src/routes/auth.ts"
41
+ * "src/routes/auth.ts (>50 lines)"
42
+ * "src/routes/auth.ts (>50 lines, exports router)"
43
+ *
44
+ * Returns: { filePath, minLines, wiredPattern }
45
+ */
46
+ function parseArtifact(str, projectDir) {
47
+ const s = String(str).trim();
48
+
49
+ // Extract optional annotations in parentheses
50
+ const parenMatch = s.match(/^(.+?)\s*\(([^)]*)\)\s*$/);
51
+ const rawPath = parenMatch ? parenMatch[1].trim() : s;
52
+ const annotations = parenMatch ? parenMatch[2] : '';
53
+
54
+ // Build absolute path (relative to projectDir if given)
55
+ const filePath = projectDir
56
+ ? require('node:path').resolve(projectDir, rawPath)
57
+ : rawPath;
58
+
59
+ // Parse min lines: ">50 lines" or "50 lines"
60
+ const linesMatch = annotations.match(/>?\s*(\d+)\s+lines?/i);
61
+ const minLines = linesMatch ? parseInt(linesMatch[1], 10) : 5;
62
+
63
+ // Parse wired pattern: any text after "exports" or "imports" or "registers"
64
+ const wiredMatch = annotations.match(/(?:exports?|imports?|registers?)\s+(.+)/i);
65
+ const wiredPattern = wiredMatch ? wiredMatch[1].trim() : null;
66
+
67
+ return { filePath, rawPath, minLines, wiredPattern };
68
+ }
69
+
70
+ /**
71
+ * Parse a key_link descriptor string.
72
+ *
73
+ * Example: "auth router registered in src/app.ts"
74
+ * Returns: { pattern, inFile }
75
+ *
76
+ * Pattern is extracted heuristically from the string.
77
+ */
78
+ function parseKeyLink(str, projectDir) {
79
+ const path = require('node:path');
80
+ const s = String(str).trim();
81
+
82
+ // Pattern: "<thing> in <filepath>" or "<thing> registered/imported/used in <filepath>"
83
+ const inMatch = s.match(/^(.+?)\s+(?:in|from|inside)\s+(\S+\.(?:ts|js|tsx|jsx|py|rb|go|java|php|vue|svelte))\s*$/i);
84
+ if (inMatch) {
85
+ const rawFile = inMatch[2].trim();
86
+ const inFile = projectDir ? path.resolve(projectDir, rawFile) : rawFile;
87
+
88
+ // Extract meaningful keywords from the pattern part (first 3 significant words)
89
+ const patternWords = inMatch[1]
90
+ .replace(/\b(?:registered|imported|used|exported|referenced|wired|connected|added)\b/gi, '')
91
+ .trim()
92
+ .split(/\s+/)
93
+ .filter((w) => w.length > 2)
94
+ .slice(0, 3);
95
+
96
+ return { pattern: patternWords.join('|'), inFile, rawFile };
97
+ }
98
+
99
+ return null;
100
+ }
101
+
102
+ // ─── Tier implementations ─────────────────────────────────────────────────────
103
+
104
+ /** Tier 1: file exists on disk */
105
+ async function verifyExists(filePath) {
106
+ try {
107
+ await fs.access(filePath);
108
+ return { passed: true, tier: 1, file: filePath };
109
+ } catch {
110
+ return { passed: false, tier: 1, file: filePath, reason: 'file does not exist' };
111
+ }
112
+ }
113
+
114
+ /** Tier 2: file is substantive (not a stub) */
115
+ async function verifySubstantive(filePath, minLines = 5) {
116
+ let content;
117
+ try {
118
+ content = await fs.readFile(filePath, 'utf8');
119
+ } catch {
120
+ return { passed: false, tier: 2, file: filePath, reason: 'cannot read file' };
121
+ }
122
+
123
+ const nonEmptyLines = content.split('\n').filter((l) => l.trim().length > 0).length;
124
+ if (nonEmptyLines < minLines) {
125
+ return {
126
+ passed: false, tier: 2, file: filePath,
127
+ reason: `only ${nonEmptyLines} non-empty lines (min: ${minLines})`
128
+ };
129
+ }
130
+
131
+ for (const { pattern, label } of ANTI_PATTERNS) {
132
+ if (pattern.test(content)) {
133
+ return { passed: false, tier: 2, file: filePath, reason: `contains ${label}` };
134
+ }
135
+ }
136
+
137
+ return { passed: true, tier: 2, file: filePath, lines: nonEmptyLines };
138
+ }
139
+
140
+ /** Tier 3: pattern found in a target file (wired/imported/registered) */
141
+ async function verifyWired(pattern, inFile) {
142
+ if (!pattern || !inFile) {
143
+ return { passed: true, tier: 3, skipped: true, reason: 'no wired constraint to check' };
144
+ }
145
+
146
+ let content;
147
+ try {
148
+ content = await fs.readFile(inFile, 'utf8');
149
+ } catch {
150
+ return { passed: false, tier: 3, file: inFile, reason: `cannot read target file: ${inFile}` };
151
+ }
152
+
153
+ const regex = typeof pattern === 'string'
154
+ ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i')
155
+ : pattern;
156
+
157
+ if (regex.test(content)) {
158
+ return { passed: true, tier: 3, pattern, inFile };
159
+ }
160
+
161
+ return {
162
+ passed: false, tier: 3, pattern, inFile,
163
+ reason: `pattern "${pattern}" not found in ${inFile}`
164
+ };
165
+ }
166
+
167
+ /** Tier 4: smoke command returns expected output (optional, expensive) */
168
+ async function verifyFunctional(command, args = [], expectedPattern = null, timeoutMs = 10_000) {
169
+ try {
170
+ const { stdout, stderr } = await execFileAsync(command, args, {
171
+ timeout: timeoutMs,
172
+ shell: false
173
+ });
174
+ const output = stdout + stderr;
175
+
176
+ if (expectedPattern) {
177
+ const regex = typeof expectedPattern === 'string'
178
+ ? new RegExp(expectedPattern, 'i')
179
+ : expectedPattern;
180
+ if (!regex.test(output)) {
181
+ return {
182
+ passed: false, tier: 4, command,
183
+ reason: `expected pattern "${expectedPattern}" not found in command output`
184
+ };
185
+ }
186
+ }
187
+
188
+ return { passed: true, tier: 4, command, output: output.slice(0, 300) };
189
+ } catch (err) {
190
+ return { passed: false, tier: 4, command, reason: err.message.slice(0, 200) };
191
+ }
192
+ }
193
+
194
+ // ─── must_haves checker ───────────────────────────────────────────────────────
195
+
196
+ /**
197
+ * Run must_haves verification against a task's contract.
198
+ *
199
+ * @param {object} mustHaves — { truths?, artifacts?, key_links? }
200
+ * @param {string} output — Task output text (used for truths checks)
201
+ * @param {string} projectDir
202
+ * @returns {Promise<MustHavesResult>}
203
+ *
204
+ * MustHavesResult:
205
+ * {
206
+ * passed: boolean,
207
+ * failures: string[],
208
+ * warnings: string[],
209
+ * details: object[]
210
+ * }
211
+ */
212
+ async function checkMustHaves(mustHaves, output, projectDir) {
213
+ if (!mustHaves) return { passed: true, failures: [], warnings: [], details: [] };
214
+
215
+ const failures = [];
216
+ const warnings = [];
217
+ const details = [];
218
+ const outputText = String(output || '').toLowerCase();
219
+
220
+ // ── Truths: heuristic — check if output mentions the expected state ──────
221
+ for (const truth of (mustHaves.truths || [])) {
222
+ // Extract key nouns/verbs from truth statement and check they appear in output
223
+ const keywords = String(truth)
224
+ .replace(/\b(?:the|a|an|is|are|can|will|should|must|to|of|in|and|or|that)\b/gi, '')
225
+ .split(/\s+/)
226
+ .filter((w) => w.length > 3)
227
+ .slice(0, 4);
228
+
229
+ const found = keywords.some((kw) => outputText.includes(kw.toLowerCase()));
230
+ const result = { type: 'truth', statement: truth, passed: found };
231
+ details.push(result);
232
+
233
+ if (!found) {
234
+ warnings.push(`Truth not evident in output: "${truth.slice(0, 80)}"`);
235
+ }
236
+ }
237
+
238
+ // ── Artifacts: Tier 1 + Tier 2 checks ────────────────────────────────────
239
+ for (const artifactStr of (mustHaves.artifacts || [])) {
240
+ const { filePath, rawPath, minLines, wiredPattern } = parseArtifact(artifactStr, projectDir);
241
+
242
+ const t1 = await verifyExists(filePath);
243
+ details.push({ type: 'artifact', descriptor: artifactStr, ...t1 });
244
+
245
+ if (!t1.passed) {
246
+ failures.push(`Artifact missing: ${rawPath}`);
247
+ continue;
248
+ }
249
+
250
+ const t2 = await verifySubstantive(filePath, minLines);
251
+ details.push({ type: 'artifact_substantive', descriptor: artifactStr, ...t2 });
252
+
253
+ if (!t2.passed) {
254
+ failures.push(`Artifact is a stub: ${rawPath} — ${t2.reason}`);
255
+ continue;
256
+ }
257
+
258
+ // If wired pattern specified, verify it exists in the same file
259
+ if (wiredPattern) {
260
+ const t3 = await verifyWired(wiredPattern, filePath);
261
+ details.push({ type: 'artifact_wired', descriptor: artifactStr, ...t3 });
262
+ if (!t3.passed) {
263
+ warnings.push(`Artifact wiring issue: ${rawPath} — ${t3.reason}`);
264
+ }
265
+ }
266
+ }
267
+
268
+ // ── Key links: Tier 3 checks ──────────────────────────────────────────────
269
+ for (const keyLink of (mustHaves.key_links || [])) {
270
+ const parsed = parseKeyLink(keyLink, projectDir);
271
+
272
+ if (!parsed) {
273
+ // Cannot parse — skip silently (heuristic limitation)
274
+ details.push({ type: 'key_link', descriptor: keyLink, passed: true, skipped: true });
275
+ continue;
276
+ }
277
+
278
+ const t3 = await verifyWired(parsed.pattern, parsed.inFile);
279
+ details.push({ type: 'key_link', descriptor: keyLink, ...t3 });
280
+
281
+ if (!t3.passed) {
282
+ warnings.push(`Key link not wired: "${keyLink.slice(0, 80)}" — ${t3.reason}`);
283
+ }
284
+ }
285
+
286
+ return {
287
+ passed: failures.length === 0,
288
+ failures,
289
+ warnings,
290
+ details
291
+ };
292
+ }
293
+
294
+ module.exports = {
295
+ verifyExists,
296
+ verifySubstantive,
297
+ verifyWired,
298
+ verifyFunctional,
299
+ checkMustHaves,
300
+ parseArtifact,
301
+ parseKeyLink,
302
+ ANTI_PATTERNS
303
+ };
@@ -0,0 +1,94 @@
1
+ 'use strict';
2
+
3
+ const { spawnSync } = require('node:child_process');
4
+ const path = require('node:path');
5
+
6
+ const SAFE_ENV_KEYS = new Set(['PATH', 'HOME', 'LANG', 'TERM', 'USER', 'SHELL', 'TMPDIR', 'TMP', 'TEMP']);
7
+ const DEFAULT_TIMEOUT_MS = 30_000;
8
+
9
+ function buildSafeEnv(inputJson) {
10
+ const safe = {};
11
+ for (const key of SAFE_ENV_KEYS) {
12
+ if (process.env[key] !== undefined) {
13
+ safe[key] = process.env[key];
14
+ }
15
+ }
16
+ safe.TOOL_INPUT = typeof inputJson === 'string' ? inputJson : JSON.stringify(inputJson ?? {});
17
+ return safe;
18
+ }
19
+
20
+ /**
21
+ * Executa uma dynamic tool de forma segura via subprocess.
22
+ * @param {object} toolDef - Registro da tool (da tabela dynamic_tools)
23
+ * @param {object|string} inputJson - Input para a tool
24
+ * @param {object} opts
25
+ * @param {string} [opts.projectDir] - Diretório do projeto (para resolver caminhos relativos)
26
+ * @param {number} [opts.timeoutMs] - Timeout em ms (default: 30s)
27
+ * @returns {{ ok: boolean, stdout: string, stderr: string, exitCode: number, error?: string }}
28
+ */
29
+ function executeTool(toolDef, inputJson, opts = {}) {
30
+ const timeoutMs = opts.timeoutMs || DEFAULT_TIMEOUT_MS;
31
+ const projectDir = opts.projectDir || process.cwd();
32
+ const safeEnv = buildSafeEnv(inputJson);
33
+
34
+ let result;
35
+
36
+ if (toolDef.handler_type === 'shell') {
37
+ if (!toolDef.handler_code) {
38
+ return { ok: false, stdout: '', stderr: '', exitCode: 1, error: 'handler_code is required for shell tools' };
39
+ }
40
+ result = spawnSync('bash', ['-c', toolDef.handler_code], {
41
+ env: safeEnv,
42
+ encoding: 'utf8',
43
+ timeout: timeoutMs,
44
+ maxBuffer: 1024 * 1024
45
+ });
46
+ } else if (toolDef.handler_type === 'script') {
47
+ if (!toolDef.handler_path) {
48
+ return { ok: false, stdout: '', stderr: '', exitCode: 1, error: 'handler_path is required for script tools' };
49
+ }
50
+ const scriptPath = path.isAbsolute(toolDef.handler_path)
51
+ ? toolDef.handler_path
52
+ : path.resolve(projectDir, toolDef.handler_path);
53
+
54
+ result = spawnSync('node', ['--env-file=', scriptPath], {
55
+ env: safeEnv,
56
+ encoding: 'utf8',
57
+ timeout: timeoutMs,
58
+ maxBuffer: 1024 * 1024,
59
+ input: safeEnv.TOOL_INPUT
60
+ });
61
+
62
+ // Fallback: node sem --env-file= (versões antigas do Node não suportam)
63
+ if (result.error && result.error.code === 'ERR_INVALID_ARG_VALUE') {
64
+ result = spawnSync('node', [scriptPath], {
65
+ env: safeEnv,
66
+ encoding: 'utf8',
67
+ timeout: timeoutMs,
68
+ maxBuffer: 1024 * 1024,
69
+ input: safeEnv.TOOL_INPUT
70
+ });
71
+ }
72
+ } else {
73
+ return { ok: false, stdout: '', stderr: '', exitCode: 1, error: `Unknown handler_type: ${toolDef.handler_type}` };
74
+ }
75
+
76
+ const stdout = String(result.stdout || '').trim();
77
+ const stderr = String(result.stderr || '').trim();
78
+ const exitCode = result.status ?? 1;
79
+
80
+ if (result.error) {
81
+ const isTimeout = result.error.code === 'ETIMEDOUT' || result.error.killed;
82
+ return {
83
+ ok: false,
84
+ stdout,
85
+ stderr,
86
+ exitCode,
87
+ error: isTimeout ? `Tool timed out after ${timeoutMs}ms` : result.error.message
88
+ };
89
+ }
90
+
91
+ return { ok: exitCode === 0, stdout, stderr, exitCode };
92
+ }
93
+
94
+ module.exports = { executeTool, buildSafeEnv };
package/src/updater.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const path = require('node:path');
4
- const { detectExistingInstall, installTemplate } = require('./installer');
4
+ const { detectExistingInstall, installTemplate, readInstallProfile } = require('./installer');
5
5
 
6
6
  async function updateInstallation(targetDir, options = {}) {
7
7
  const installed = await detectExistingInstall(targetDir);
@@ -13,17 +13,24 @@ async function updateInstallation(targetDir, options = {}) {
13
13
  };
14
14
  }
15
15
 
16
+ const savedProfile = await readInstallProfile(targetDir);
17
+
18
+ // Default: only update files already present in the target (selective update).
19
+ // With --all: install every file from the template, including new ones not yet installed.
16
20
  const result = await installTemplate(targetDir, {
17
21
  overwrite: true,
18
22
  dryRun: Boolean(options.dryRun),
19
23
  mode: 'update',
20
24
  backupOnOverwrite: true,
21
- frameworkDetection: options.frameworkDetection || null
25
+ frameworkDetection: options.frameworkDetection || null,
26
+ installProfile: null,
27
+ selectiveUpdate: !options.all
22
28
  });
23
29
 
24
30
  return {
25
31
  ok: true,
26
- ...result
32
+ ...result,
33
+ savedProfile
27
34
  };
28
35
  }
29
36
 
@@ -123,12 +123,188 @@ function sleep(ms) {
123
123
  return new Promise((resolve) => setTimeout(resolve, ms));
124
124
  }
125
125
 
126
+ // ─── Research Worker ──────────────────────────────────────────────────────────
127
+
128
+ /**
129
+ * Handle a `type: 'research'` worker.
130
+ *
131
+ * Checks the researchs/ cache first (7-day default TTL), falls back to
132
+ * scraping declared URLs or the topic keyword via web.js fetchPage.
133
+ *
134
+ * Cache location: researchs/{topic}/summary.md
135
+ */
136
+ async function runResearchWorker(projectDir, config, inputPayload) {
137
+ const { fetchPage } = require('./web');
138
+ const research = config.research || {};
139
+ const topic = String(research.topic || inputPayload?.topic || 'general').replace(/[^a-z0-9-]/gi, '-').toLowerCase();
140
+ const cacheHours = Number(research.cache_hours || 168); // 7 days default
141
+ const cacheDir = path.join(projectDir, research.cache_dir || 'researchs', topic);
142
+ const summaryPath = path.join(cacheDir, 'summary.md');
143
+
144
+ // ── Cache check ────────────────────────────────────────────────────────────
145
+ try {
146
+ const stat = await fs.stat(summaryPath);
147
+ const ageMs = Date.now() - stat.mtimeMs;
148
+ const ageHours = ageMs / (1000 * 60 * 60);
149
+ if (ageHours < cacheHours) {
150
+ const cached = await fs.readFile(summaryPath, 'utf8');
151
+ return {
152
+ ok: true,
153
+ output: { topic, summary: cached, cached: true, cache_age_hours: Math.round(ageHours) },
154
+ attempt: 1
155
+ };
156
+ }
157
+ } catch { /* no cache yet */ }
158
+
159
+ // ── Scrape sources ─────────────────────────────────────────────────────────
160
+ const urls = research.urls || inputPayload?.urls || [];
161
+ const maxSources = Number(research.max_sources || 5);
162
+ const pages = [];
163
+
164
+ for (const url of urls.slice(0, maxSources)) {
165
+ try {
166
+ const result = await fetchPage(url, { timeoutMs: 15000, extractLinks: false });
167
+ if (result.ok && result.text) {
168
+ pages.push({ url, content: result.text.slice(0, 3000) });
169
+ }
170
+ } catch { /* skip unreachable sources */ }
171
+ }
172
+
173
+ if (pages.length === 0) {
174
+ return {
175
+ ok: false,
176
+ error: `Research worker "${topic}": no URLs declared and no cached summary. Add "research.urls" to worker.json or provide ?topic= with cached data.`,
177
+ attempts: 1
178
+ };
179
+ }
180
+
181
+ // ── Build summary ──────────────────────────────────────────────────────────
182
+ const ts = new Date().toISOString();
183
+ const summary = [
184
+ `# Research: ${topic}`,
185
+ `_Generated: ${ts} · Sources: ${pages.length}_`,
186
+ '',
187
+ ...pages.map((p, i) => [
188
+ `## Source ${i + 1}: ${p.url}`,
189
+ '',
190
+ p.content.slice(0, 2000),
191
+ ''
192
+ ].join('\n'))
193
+ ].join('\n');
194
+
195
+ await fs.mkdir(cacheDir, { recursive: true });
196
+ await fs.writeFile(summaryPath, summary, 'utf8');
197
+
198
+ return {
199
+ ok: true,
200
+ output: { topic, summary, cached: false, sources: pages.length, generated_at: ts },
201
+ attempt: 1
202
+ };
203
+ }
204
+
205
+ // ─── Skill Worker (Plan 81 §2.2) ─────────────────────────────────────────────
206
+
207
+ /**
208
+ * Handle a `type: 'skill'` worker.
209
+ * Resolves an external Agent Skills Standard skill and executes it.
210
+ *
211
+ * Skill sources:
212
+ * - Local path: ./skills/my-skill/ or .claude/skills/my-skill/
213
+ * - NPM package: npm:@org/skill-name (resolved from node_modules)
214
+ */
215
+ async function runSkillWorker(projectDir, config, inputPayload) {
216
+ const skillRef = config.skill || config.source || '';
217
+ let skillDir;
218
+
219
+ if (skillRef.startsWith('npm:')) {
220
+ // Resolve from node_modules
221
+ const pkgName = skillRef.slice(4);
222
+ skillDir = path.join(projectDir, 'node_modules', pkgName);
223
+ } else {
224
+ // Local path
225
+ skillDir = path.resolve(projectDir, skillRef);
226
+ }
227
+
228
+ // Check SKILL.md exists
229
+ const skillMdPath = path.join(skillDir, 'SKILL.md');
230
+ if (!(await pathExists(skillMdPath))) {
231
+ return {
232
+ ok: false,
233
+ error: `Skill not found: ${skillRef} (expected SKILL.md at ${skillMdPath})`,
234
+ attempts: 0
235
+ };
236
+ }
237
+
238
+ // Check for executable scripts
239
+ const scriptsDir = path.join(skillDir, 'scripts');
240
+ const runScript = path.join(scriptsDir, 'run.js');
241
+ const runPyScript = path.join(scriptsDir, 'run.py');
242
+
243
+ if (await pathExists(runScript)) {
244
+ return spawnWorker(runScript, inputPayload || {}, {}, config.timeout_ms || DEFAULT_TIMEOUT);
245
+ }
246
+
247
+ if (await pathExists(runPyScript)) {
248
+ return spawnWorker(runPyScript, inputPayload || {}, {}, config.timeout_ms || DEFAULT_TIMEOUT);
249
+ }
250
+
251
+ // No executable script — return skill content for LLM-based execution
252
+ const skillContent = await fs.readFile(skillMdPath, 'utf8');
253
+ return {
254
+ ok: true,
255
+ output: {
256
+ type: 'skill-prompt',
257
+ skillPath: skillMdPath,
258
+ content: skillContent.slice(0, 4000),
259
+ message: `Skill "${skillRef}" loaded. No run script found — use skill content as agent instructions.`
260
+ },
261
+ attempt: 1
262
+ };
263
+ }
264
+
265
+ // ─── Agent Memory Loader (Plan 81 §Sprint 4) ────────────────────────────────
266
+
267
+ /**
268
+ * Load per-agent persistent memory if it exists.
269
+ * Returns memory content or null.
270
+ */
271
+ async function loadAgentMemory(projectDir, squadSlug, executorSlug) {
272
+ const memoryPath = path.join(
273
+ projectDir, SQUADS_DIR, squadSlug, 'agent-memory', `${executorSlug}.md`
274
+ );
275
+ try {
276
+ return await fs.readFile(memoryPath, 'utf8');
277
+ } catch {
278
+ return null;
279
+ }
280
+ }
281
+
126
282
  async function runWorker(projectDir, squadSlug, workerSlug, inputPayload, options = {}) {
127
283
  const config = await loadWorkerConfig(projectDir, squadSlug, workerSlug);
128
284
  if (!config) {
129
285
  return { ok: false, error: `Worker config not found: ${workerSlug}`, attempts: 0 };
130
286
  }
131
287
 
288
+ // Skill worker — external skill execution (Plan 81 §2.2)
289
+ if (config.type === 'skill') {
290
+ return runSkillWorker(projectDir, config, inputPayload || {});
291
+ }
292
+
293
+ // Research worker — special handler (4.1)
294
+ if (config.type === 'research') {
295
+ return runResearchWorker(projectDir, config, inputPayload || {});
296
+ }
297
+
298
+ // Load per-agent persistent memory (Plan 81 §Sprint 4)
299
+ const agentMemory = await loadAgentMemory(projectDir, squadSlug, workerSlug);
300
+ if (agentMemory && inputPayload) {
301
+ // Inject into _agent_memory field (readable by Node.js workers via process.argv[2])
302
+ inputPayload._agent_memory = agentMemory;
303
+ // Prefix into context so LLM-based workers receive it as part of their task context
304
+ const existingContext = inputPayload.context || '';
305
+ inputPayload.context = `## Your accumulated knowledge:\n${agentMemory}\n\n---\n\n${existingContext}`.trimEnd();
306
+ }
307
+
132
308
  // Validate inputs
133
309
  const validation = validateInputs(inputPayload || {}, config.inputs);
134
310
  if (!validation.valid) {
@@ -149,6 +325,13 @@ async function runWorker(projectDir, squadSlug, workerSlug, inputPayload, option
149
325
  // Resolve env vars
150
326
  const env = resolveEnvVars(config.env);
151
327
 
328
+ // Expose agent memory path as env var so workers can read it directly
329
+ const memoryFilePath = path.join(projectDir, SQUADS_DIR, squadSlug, 'agent-memory', `${workerSlug}.md`);
330
+ try {
331
+ await fs.access(memoryFilePath);
332
+ env.AIOSON_AGENT_MEMORY_PATH = memoryFilePath;
333
+ } catch { /* no memory file yet — env var omitted */ }
334
+
152
335
  // Resolve MCP env vars if worker declares uses_mcp
153
336
  if (config.uses_mcp && config.uses_mcp.length > 0) {
154
337
  try {
@@ -335,5 +518,7 @@ module.exports = {
335
518
  generateRunJs,
336
519
  generateWorkerReadme,
337
520
  validateInputs,
338
- resolveEnvVars
521
+ resolveEnvVars,
522
+ runSkillWorker,
523
+ loadAgentMemory
339
524
  };