@jaimevalasek/aioson 1.6.0 → 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 (252) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +729 -232
  3. package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
  4. package/docs/integrations/sdlc-genius-boundary.md +76 -0
  5. package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
  6. package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
  7. package/docs/integrations/sdlc-genius-review-samples.md +86 -0
  8. package/docs/pt/README.md +3 -0
  9. package/docs/pt/agentes.md +1 -0
  10. package/docs/pt/comandos-cli.md +888 -2
  11. package/docs/pt/design-hybrid-forge.md +255 -6
  12. package/docs/pt/devlog-pipeline.md +270 -0
  13. package/docs/pt/fluxo-artefatos.md +178 -0
  14. package/docs/pt/hooks-session-guard.md +454 -0
  15. package/docs/pt/monitor-de-contexto.md +59 -5
  16. package/docs/pt/sdd-automation-scripts.md +557 -0
  17. package/docs/pt/site-forge.md +309 -0
  18. package/docs/pt/spec-learnings-pipeline.md +265 -0
  19. package/package.json +1 -1
  20. package/src/a2a/client.js +165 -0
  21. package/src/a2a/server.js +223 -0
  22. package/src/cli.js +235 -1
  23. package/src/commands/agent-audit.js +397 -0
  24. package/src/commands/agent-export-skill.js +229 -0
  25. package/src/commands/artifact-validate.js +189 -0
  26. package/src/commands/brief-gen.js +405 -0
  27. package/src/commands/brief-validate.js +65 -0
  28. package/src/commands/classify.js +256 -0
  29. package/src/commands/context-compact.js +49 -0
  30. package/src/commands/context-health.js +175 -0
  31. package/src/commands/context-monitor.js +71 -0
  32. package/src/commands/context-trim.js +177 -0
  33. package/src/commands/detect-test-runner.js +55 -0
  34. package/src/commands/devlog-export-brains.js +27 -0
  35. package/src/commands/devlog-process.js +292 -0
  36. package/src/commands/devlog-watch.js +131 -0
  37. package/src/commands/feature-close.js +165 -0
  38. package/src/commands/gate-check.js +228 -0
  39. package/src/commands/hooks-emit.js +253 -0
  40. package/src/commands/hooks-install.js +347 -0
  41. package/src/commands/learning-auto-promote.js +195 -0
  42. package/src/commands/learning-evolve.js +18 -9
  43. package/src/commands/learning-export.js +103 -0
  44. package/src/commands/learning-rollback.js +164 -0
  45. package/src/commands/live.js +25 -1
  46. package/src/commands/pattern-detect.js +33 -0
  47. package/src/commands/preflight-context.js +30 -0
  48. package/src/commands/preflight.js +208 -0
  49. package/src/commands/pulse-update.js +130 -0
  50. package/src/commands/runner-daemon.js +274 -0
  51. package/src/commands/runner-plan.js +70 -0
  52. package/src/commands/runner-queue-from-plan.js +166 -0
  53. package/src/commands/runner-queue.js +189 -0
  54. package/src/commands/runner-run.js +129 -0
  55. package/src/commands/runtime.js +47 -1
  56. package/src/commands/self-implement-loop.js +256 -0
  57. package/src/commands/session-guard.js +218 -0
  58. package/src/commands/sizing.js +165 -0
  59. package/src/commands/skill.js +65 -0
  60. package/src/commands/spec-checkpoint.js +177 -0
  61. package/src/commands/spec-status.js +79 -0
  62. package/src/commands/spec-sync.js +190 -0
  63. package/src/commands/spec-tasks.js +288 -0
  64. package/src/commands/squad-autorun.js +1220 -0
  65. package/src/commands/squad-bus.js +217 -0
  66. package/src/commands/squad-card.js +149 -0
  67. package/src/commands/squad-daemon.js +134 -0
  68. package/src/commands/squad-dependency-graph.js +164 -0
  69. package/src/commands/squad-review.js +106 -0
  70. package/src/commands/squad-scaffold.js +55 -0
  71. package/src/commands/squad-tool-register.js +157 -0
  72. package/src/commands/state-save.js +122 -0
  73. package/src/commands/update.js +2 -0
  74. package/src/commands/verify-gate.js +572 -0
  75. package/src/commands/workflow-execute.js +241 -0
  76. package/src/constants.js +9 -0
  77. package/src/install-profile.js +2 -2
  78. package/src/install-wizard.js +3 -2
  79. package/src/installer.js +6 -0
  80. package/src/lib/health-check.js +158 -0
  81. package/src/lib/hook-protocol.js +76 -0
  82. package/src/mcp/apps/squad-dashboard/app.js +163 -0
  83. package/src/mcp/apps/squad-dashboard/index.html +261 -0
  84. package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
  85. package/src/mcp/resources/squad-state.js +130 -0
  86. package/src/preflight-engine.js +443 -0
  87. package/src/runner/cascade.js +97 -0
  88. package/src/runner/cli-launcher.js +109 -0
  89. package/src/runner/plan-importer.js +63 -0
  90. package/src/runner/queue-store.js +159 -0
  91. package/src/runtime-store.js +61 -3
  92. package/src/squad/agent-teams-adapter.js +264 -0
  93. package/src/squad/brief-validator.js +350 -0
  94. package/src/squad/bus-bridge.js +140 -0
  95. package/src/squad/context-compactor.js +265 -0
  96. package/src/squad/cross-ai-synthesizer.js +250 -0
  97. package/src/squad/hooks-generator.js +196 -0
  98. package/src/squad/inter-squad-events.js +175 -0
  99. package/src/squad/intra-bus.js +345 -0
  100. package/src/squad/learning-extractor.js +213 -0
  101. package/src/squad/pattern-detector.js +365 -0
  102. package/src/squad/preflight-context.js +296 -0
  103. package/src/squad/recovery-context.js +242 -71
  104. package/src/squad/reflection.js +365 -0
  105. package/src/squad/squad-scaffold.js +177 -0
  106. package/src/squad/state-manager.js +310 -0
  107. package/src/squad/task-decomposer.js +652 -0
  108. package/src/squad/verify-gate.js +303 -0
  109. package/src/updater.js +4 -5
  110. package/src/worker-runner.js +186 -1
  111. package/template/.aioson/agents/analyst.md +62 -1
  112. package/template/.aioson/agents/architect.md +61 -1
  113. package/template/.aioson/agents/design-hybrid-forge.md +14 -0
  114. package/template/.aioson/agents/dev.md +242 -24
  115. package/template/.aioson/agents/deyvin.md +66 -8
  116. package/template/.aioson/agents/discovery-design-doc.md +44 -0
  117. package/template/.aioson/agents/genome.md +14 -0
  118. package/template/.aioson/agents/neo.md +78 -1
  119. package/template/.aioson/agents/orache.md +50 -4
  120. package/template/.aioson/agents/orchestrator.md +197 -1
  121. package/template/.aioson/agents/pm.md +35 -0
  122. package/template/.aioson/agents/product.md +50 -5
  123. package/template/.aioson/agents/profiler-enricher.md +14 -0
  124. package/template/.aioson/agents/profiler-forge.md +14 -0
  125. package/template/.aioson/agents/profiler-researcher.md +14 -0
  126. package/template/.aioson/agents/qa.md +172 -21
  127. package/template/.aioson/agents/setup.md +79 -9
  128. package/template/.aioson/agents/sheldon.md +131 -6
  129. package/template/.aioson/agents/site-forge.md +1753 -0
  130. package/template/.aioson/agents/squad.md +162 -0
  131. package/template/.aioson/agents/tester.md +53 -0
  132. package/template/.aioson/agents/ux-ui.md +34 -1
  133. package/template/.aioson/brains/README.md +128 -0
  134. package/template/.aioson/brains/_index.json +16 -0
  135. package/template/.aioson/brains/scripts/query.js +103 -0
  136. package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
  137. package/template/.aioson/config.md +143 -13
  138. package/template/.aioson/constitution.md +33 -0
  139. package/template/.aioson/context/project-pulse.md +34 -0
  140. package/template/.aioson/docs/LAYERS.md +79 -0
  141. package/template/.aioson/docs/README.md +76 -0
  142. package/template/.aioson/docs/example-external-api-context.md +72 -0
  143. package/template/.aioson/locales/en/agents/architect.md +17 -0
  144. package/template/.aioson/locales/en/agents/dev.md +79 -13
  145. package/template/.aioson/locales/en/agents/orache.md +6 -0
  146. package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
  147. package/template/.aioson/locales/en/agents/product.md +50 -0
  148. package/template/.aioson/locales/en/agents/sheldon.md +115 -0
  149. package/template/.aioson/locales/en/agents/squad.md +14 -0
  150. package/template/.aioson/locales/en/agents/tester.md +6 -0
  151. package/template/.aioson/locales/es/agents/analyst.md +2 -0
  152. package/template/.aioson/locales/es/agents/architect.md +19 -0
  153. package/template/.aioson/locales/es/agents/dev.md +64 -4
  154. package/template/.aioson/locales/es/agents/deyvin.md +2 -0
  155. package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
  156. package/template/.aioson/locales/es/agents/genome.md +2 -0
  157. package/template/.aioson/locales/es/agents/neo.md +2 -0
  158. package/template/.aioson/locales/es/agents/orache.md +2 -0
  159. package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
  160. package/template/.aioson/locales/es/agents/pair.md +2 -0
  161. package/template/.aioson/locales/es/agents/pm.md +2 -0
  162. package/template/.aioson/locales/es/agents/product.md +52 -0
  163. package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
  164. package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
  165. package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
  166. package/template/.aioson/locales/es/agents/qa.md +2 -0
  167. package/template/.aioson/locales/es/agents/setup.md +2 -0
  168. package/template/.aioson/locales/es/agents/sheldon.md +117 -0
  169. package/template/.aioson/locales/es/agents/squad.md +16 -0
  170. package/template/.aioson/locales/es/agents/tester.md +9 -0
  171. package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
  172. package/template/.aioson/locales/fr/agents/analyst.md +2 -0
  173. package/template/.aioson/locales/fr/agents/architect.md +19 -0
  174. package/template/.aioson/locales/fr/agents/dev.md +64 -4
  175. package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
  176. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
  177. package/template/.aioson/locales/fr/agents/genome.md +2 -0
  178. package/template/.aioson/locales/fr/agents/neo.md +2 -0
  179. package/template/.aioson/locales/fr/agents/orache.md +2 -0
  180. package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
  181. package/template/.aioson/locales/fr/agents/pair.md +2 -0
  182. package/template/.aioson/locales/fr/agents/pm.md +2 -0
  183. package/template/.aioson/locales/fr/agents/product.md +52 -0
  184. package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
  185. package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
  186. package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
  187. package/template/.aioson/locales/fr/agents/qa.md +2 -0
  188. package/template/.aioson/locales/fr/agents/setup.md +2 -0
  189. package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
  190. package/template/.aioson/locales/fr/agents/squad.md +16 -0
  191. package/template/.aioson/locales/fr/agents/tester.md +9 -0
  192. package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
  193. package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
  194. package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
  195. package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
  196. package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
  197. package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
  198. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
  199. package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
  200. package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
  201. package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
  202. package/template/.aioson/locales/pt-BR/agents/setup.md +101 -18
  203. package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
  204. package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
  205. package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
  206. package/template/.aioson/rules/README.md +69 -0
  207. package/template/.aioson/rules/data-format-convention.md +136 -0
  208. package/template/.aioson/rules/example-monetary-values.md +30 -0
  209. package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
  210. package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
  211. package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
  212. package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
  213. package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
  214. package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
  215. package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
  216. package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
  217. package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +1 -0
  218. package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
  219. package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
  220. package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
  221. package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
  222. package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +35 -0
  223. package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
  224. package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
  225. package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
  226. package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +4 -1
  227. package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +15 -0
  228. package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +32 -0
  229. package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +20 -0
  230. package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
  231. package/template/.aioson/skills/static/context-budget-guide.md +46 -0
  232. package/template/.aioson/skills/static/harness-sensors.md +74 -0
  233. package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
  234. package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
  235. package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
  236. package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
  237. package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
  238. package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
  239. package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
  240. package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
  241. package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
  242. package/template/.aioson/skills/static/threejs-patterns.md +929 -0
  243. package/template/.aioson/skills/static/web-research-cache.md +112 -0
  244. package/template/.aioson/tasks/implementation-plan.md +21 -1
  245. package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
  246. package/template/.claude/commands/aioson/agent/orache.md +5 -0
  247. package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
  248. package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
  249. package/template/AGENTS.md +55 -3
  250. package/template/CLAUDE.md +30 -0
  251. package/template/OPENCODE.md +4 -0
  252. package/template/researchs/.gitkeep +0 -0
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson squad:review [projectDir] --squad=<slug> --output=<file>
5
+ * [--criteria=<text,...>] [--synthesize-to=<path>]
6
+ * [--include-current] [--timeout=<seconds>]
7
+ *
8
+ * Cross-AI adversarial review of a squad output.
9
+ *
10
+ * Detects available AI CLIs (excluding the current runtime), sends the same
11
+ * review prompt to each, and synthesizes results into REVIEWS.md.
12
+ *
13
+ * Usage:
14
+ * aioson squad:review . --squad=content-team --output=outputs/ep3.md
15
+ * aioson squad:review . --squad=content-team --output=outputs/ep3.md \
16
+ * --criteria="Check factual accuracy,Check tone consistency"
17
+ * aioson squad:review . --squad=content-team --output=outputs/ep3.md \
18
+ * --synthesize-to=outputs/ep3-reviews.md
19
+ */
20
+
21
+ const path = require('node:path');
22
+ const { runCrossAIReview, detectAvailableCLIs } = require('../squad/cross-ai-synthesizer');
23
+
24
+ async function runSquadReview({ args, options = {}, logger }) {
25
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
26
+ const squadSlug = String(options.squad || '').trim();
27
+ const outputFile = String(options.output || '').trim();
28
+
29
+ if (!squadSlug) {
30
+ logger.error('Error: --squad is required');
31
+ return { ok: false, error: 'missing_squad' };
32
+ }
33
+
34
+ if (!outputFile) {
35
+ logger.error('Error: --output <file-to-review> is required');
36
+ return { ok: false, error: 'missing_output' };
37
+ }
38
+
39
+ const outputPath = path.isAbsolute(outputFile)
40
+ ? outputFile
41
+ : path.join(projectDir, outputFile);
42
+
43
+ // Parse criteria
44
+ const rawCriteria = String(options.criteria || '').trim();
45
+ const reviewCriteria = rawCriteria
46
+ ? rawCriteria.split(',').map((c) => c.trim()).filter(Boolean)
47
+ : [];
48
+
49
+ const excludeCurrent = options['include-current'] !== true && options['include-current'] !== 'true';
50
+ const timeoutMs = (Number(options.timeout || 60)) * 1000;
51
+
52
+ const synthesizeTo = options['synthesize-to']
53
+ ? path.resolve(projectDir, String(options['synthesize-to']))
54
+ : null;
55
+
56
+ // Show what CLIs will be queried
57
+ const clis = detectAvailableCLIs({ excludeCurrent });
58
+ if (clis.length === 0) {
59
+ logger.error('No AI CLIs detected. Install claude, gemini, or codex in PATH.');
60
+ logger.log('You can override with --include-current to include the current runtime.');
61
+ return { ok: false, error: 'no_clis_detected' };
62
+ }
63
+
64
+ logger.log(`Squad Review — ${squadSlug}`);
65
+ logger.log(`Output file: ${path.relative(projectDir, outputPath)}`);
66
+ logger.log(`Reviewers: ${clis.join(', ')}`);
67
+ if (reviewCriteria.length > 0) {
68
+ logger.log(`Criteria: ${reviewCriteria.join('; ')}`);
69
+ }
70
+ logger.log('');
71
+ logger.log('Querying reviewers...');
72
+
73
+ const result = await runCrossAIReview({
74
+ projectDir,
75
+ outputFile: outputPath,
76
+ reviewCriteria,
77
+ squadSlug,
78
+ excludeCurrent,
79
+ synthesizeTo,
80
+ timeoutMs
81
+ });
82
+
83
+ if (!result.ok) {
84
+ logger.error(`✗ Review failed: ${result.error}`);
85
+ return result;
86
+ }
87
+
88
+ logger.log('');
89
+ logger.log(`✓ Reviews complete`);
90
+ logger.log(` Reviewers: ${result.reviewers.join(', ')}`);
91
+ logger.log(` Successful: ${result.successCount}/${result.reviewers.length}`);
92
+ logger.log(` Written to: ${path.relative(projectDir, result.reviewsPath)}`);
93
+
94
+ if (result.failCount > 0) {
95
+ const failed = result.reviews.filter((r) => !r.ok);
96
+ logger.log('');
97
+ logger.log(` ⚠ Failed reviewers:`);
98
+ for (const f of failed) {
99
+ logger.log(` ${f.cli}: ${f.error}`);
100
+ }
101
+ }
102
+
103
+ return result;
104
+ }
105
+
106
+ module.exports = { runSquadReview };
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson squad:scaffold — Deterministic squad directory generator
5
+ *
6
+ * Usage:
7
+ * aioson squad:scaffold . --slug=content-team --name="Content Team" --mode=content
8
+ * aioson squad:scaffold . --slug=dev-core --name="Dev Core" --mode=code
9
+ * aioson squad:scaffold . --slug=research --name="Research Hub" --mode=hybrid
10
+ * aioson squad:scaffold . --slug=test --json
11
+ */
12
+
13
+ const path = require('node:path');
14
+ const { scaffoldSquad } = require('../squad/squad-scaffold');
15
+
16
+ async function runSquadScaffold({ args, options = {}, logger }) {
17
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
18
+ const slug = String(options.slug || '').trim();
19
+ const name = String(options.name || slug || '').trim();
20
+ const mode = String(options.mode || 'hybrid').trim();
21
+
22
+ if (!slug) {
23
+ logger.error('Error: --slug is required');
24
+ return { ok: false, error: 'missing_slug' };
25
+ }
26
+
27
+ const result = await scaffoldSquad(targetDir, { slug, name, mode });
28
+
29
+ if (!result.ok) {
30
+ logger.error(`Error: ${result.error}`);
31
+ return result;
32
+ }
33
+
34
+ if (options.json) return result;
35
+
36
+ logger.log(`Squad "${result.name}" scaffolded (mode: ${result.mode})`);
37
+ logger.log('');
38
+ logger.log('Files created:');
39
+ for (const f of result.files) {
40
+ logger.log(` ✓ ${f}`);
41
+ }
42
+ if (result.directories.length > 0) {
43
+ logger.log('');
44
+ logger.log('Directories created:');
45
+ for (const d of result.directories) {
46
+ logger.log(` ✓ ${d}/`);
47
+ }
48
+ }
49
+ logger.log('');
50
+ logger.log(`Total: ${result.total} items`);
51
+
52
+ return result;
53
+ }
54
+
55
+ module.exports = { runSquadScaffold };
@@ -0,0 +1,157 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson squad:tool:register [projectDir] --squad=<slug> --name=<tool-name>
5
+ * --description=<desc> --handler=<shell-command>
6
+ * [--handler-type=shell|script] [--handler-path=<path>]
7
+ * [--input-schema=<json>] [--registered-by=<executor-slug>]
8
+ *
9
+ * Register a dynamic tool for a squad at runtime.
10
+ * Tools registered here are available to executors in subsequent squad:autorun sessions.
11
+ *
12
+ * Security: handler only receives AIOSON_TOOL_INPUT env var — no API keys, no PATH injection.
13
+ *
14
+ * Usage:
15
+ * aioson squad:tool:register . --squad=content-team --name=fetch-rss \
16
+ * --description="Fetch RSS feed and return items" \
17
+ * --handler='curl -s "$AIOSON_TOOL_INPUT" | python3 -c "import sys,xml.etree.ElementTree as ET; ..."'
18
+ *
19
+ * aioson squad:tool:register . --squad=content-team --list
20
+ * aioson squad:tool:register . --squad=content-team --name=fetch-rss --delete
21
+ */
22
+
23
+ const path = require('node:path');
24
+ const { openRuntimeDb } = require('../runtime-store');
25
+
26
+ function nowIso() { return new Date().toISOString(); }
27
+
28
+ async function handleList(db, squadSlug, logger) {
29
+ const tools = db.prepare(
30
+ 'SELECT * FROM dynamic_squad_tools WHERE squad_slug = ? ORDER BY registered_at DESC'
31
+ ).all(squadSlug);
32
+
33
+ if (tools.length === 0) {
34
+ logger.log(`No dynamic tools registered for squad "${squadSlug}"`);
35
+ logger.log('Register one with: aioson squad:tool:register . --squad=' + squadSlug + ' --name=<name> --description=<desc> --handler=<cmd>');
36
+ return { ok: true, tools: [] };
37
+ }
38
+
39
+ logger.log(`Dynamic tools for "${squadSlug}" (${tools.length}):`);
40
+ for (const t of tools) {
41
+ logger.log(` • ${t.name} [${t.handler_type}]${t.registered_by ? ' by ' + t.registered_by : ''}`);
42
+ logger.log(` ${t.description}`);
43
+ if (t.handler_code) logger.log(` Handler: ${t.handler_code.slice(0, 80)}${t.handler_code.length > 80 ? '...' : ''}`);
44
+ if (t.handler_path) logger.log(` Script: ${t.handler_path}`);
45
+ }
46
+
47
+ return { ok: true, tools };
48
+ }
49
+
50
+ async function handleDelete(db, squadSlug, toolName, logger) {
51
+ const existing = db.prepare(
52
+ 'SELECT name FROM dynamic_squad_tools WHERE name = ? AND squad_slug = ?'
53
+ ).get(toolName, squadSlug);
54
+
55
+ if (!existing) {
56
+ logger.error(`Tool "${toolName}" not found for squad "${squadSlug}"`);
57
+ return { ok: false, error: 'tool_not_found' };
58
+ }
59
+
60
+ db.prepare('DELETE FROM dynamic_squad_tools WHERE name = ? AND squad_slug = ?').run(toolName, squadSlug);
61
+ logger.log(`Deleted tool "${toolName}" from squad "${squadSlug}"`);
62
+ return { ok: true, deleted: toolName };
63
+ }
64
+
65
+ async function runSquadToolRegister({ args, options = {}, logger }) {
66
+ const projectDir = path.resolve(process.cwd(), args[0] || '.');
67
+ const squadSlug = String(options.squad || '').trim();
68
+
69
+ if (!squadSlug) {
70
+ logger.error('Error: --squad is required');
71
+ return { ok: false, error: 'missing_squad' };
72
+ }
73
+
74
+ const handle = await openRuntimeDb(projectDir);
75
+ if (!handle) {
76
+ logger.error('Runtime database unavailable. Run: aioson runtime:init .');
77
+ return { ok: false, error: 'no_db' };
78
+ }
79
+ const { db } = handle;
80
+
81
+ try {
82
+ // List mode
83
+ if (options.list) {
84
+ return handleList(db, squadSlug, logger);
85
+ }
86
+
87
+ const toolName = String(options.name || '').trim();
88
+ if (!toolName) {
89
+ logger.error('Error: --name is required');
90
+ return { ok: false, error: 'missing_name' };
91
+ }
92
+
93
+ // Delete mode
94
+ if (options.delete) {
95
+ return handleDelete(db, squadSlug, toolName, logger);
96
+ }
97
+
98
+ // Register mode
99
+ const description = String(options.description || options.desc || '').trim();
100
+ if (!description) {
101
+ logger.error('Error: --description is required');
102
+ return { ok: false, error: 'missing_description' };
103
+ }
104
+
105
+ const handlerType = String(options['handler-type'] || options.handlerType || 'shell').trim();
106
+ const handlerCode = String(options.handler || options['handler-code'] || '').trim() || null;
107
+ const handlerPath = String(options['handler-path'] || options.handlerPath || '').trim() || null;
108
+
109
+ if (!handlerCode && !handlerPath) {
110
+ logger.error('Error: --handler (shell command) or --handler-path (script path) is required');
111
+ return { ok: false, error: 'missing_handler' };
112
+ }
113
+
114
+ let inputSchema = '{}';
115
+ if (options['input-schema'] || options.inputSchema) {
116
+ try {
117
+ const raw = String(options['input-schema'] || options.inputSchema);
118
+ JSON.parse(raw); // validate
119
+ inputSchema = raw;
120
+ } catch {
121
+ logger.error('Error: --input-schema must be valid JSON');
122
+ return { ok: false, error: 'invalid_input_schema' };
123
+ }
124
+ }
125
+
126
+ const registeredBy = String(options['registered-by'] || options.registeredBy || '').trim() || null;
127
+
128
+ db.prepare(`
129
+ INSERT INTO dynamic_squad_tools
130
+ (name, squad_slug, description, input_schema, handler_type, handler_code, handler_path, registered_at, registered_by)
131
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
132
+ ON CONFLICT(name, squad_slug) DO UPDATE SET
133
+ description = excluded.description,
134
+ input_schema = excluded.input_schema,
135
+ handler_type = excluded.handler_type,
136
+ handler_code = excluded.handler_code,
137
+ handler_path = excluded.handler_path,
138
+ registered_at = excluded.registered_at,
139
+ registered_by = excluded.registered_by
140
+ `).run(toolName, squadSlug, description, inputSchema, handlerType, handlerCode, handlerPath, nowIso(), registeredBy);
141
+
142
+ logger.log(`✓ Tool "${toolName}" registered for squad "${squadSlug}"`);
143
+ logger.log(` Type: ${handlerType}`);
144
+ logger.log(` Description: ${description}`);
145
+ if (handlerCode) logger.log(` Handler: ${handlerCode.slice(0, 80)}${handlerCode.length > 80 ? '...' : ''}`);
146
+ if (handlerPath) logger.log(` Script: ${handlerPath}`);
147
+ logger.log('');
148
+ logger.log('Executors can request this tool via the bus (type: tool_request):');
149
+ logger.log(` { "type": "tool_request", "content": "run:${toolName}", "metadata": { "input": "..." } }`);
150
+
151
+ return { ok: true, tool: { name: toolName, squad: squadSlug, handlerType, description } };
152
+ } finally {
153
+ db.close();
154
+ }
155
+ }
156
+
157
+ module.exports = { runSquadToolRegister };
@@ -0,0 +1,122 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * aioson state:save — create/update dev-state.md for @dev session resumption.
5
+ *
6
+ * Replaces the manual dev-state.md update block. Stores active feature,
7
+ * phase, next step, spec version, and context package.
8
+ *
9
+ * Usage:
10
+ * aioson state:save . --feature=checkout --phase=3 --next="Implement notification listeners" \
11
+ * --spec-version=3 --status=in_progress
12
+ * aioson state:save . --feature=checkout --next="Continue payment webhook" --status=in_progress
13
+ */
14
+
15
+ const fs = require('node:fs/promises');
16
+ const path = require('node:path');
17
+ const { contextDir, readFileSafe, parseFrontmatter, scanArtifacts } = require('../preflight-engine');
18
+
19
+ function nowDate() {
20
+ return new Date().toISOString().slice(0, 10);
21
+ }
22
+
23
+ async function runStateSave({ args, options = {}, logger }) {
24
+ const targetDir = path.resolve(process.cwd(), args[0] || '.');
25
+ const slug = options.feature ? String(options.feature) : null;
26
+ const phase = options.phase ? String(options.phase) : null;
27
+ const next = options.next ? String(options.next) : null;
28
+ const specVersion = options['spec-version'] ? String(options['spec-version']) : null;
29
+ const status = options.status ? String(options.status) : 'in_progress';
30
+ const plan = options.plan ? String(options.plan) : null;
31
+
32
+ if (!slug) {
33
+ if (options.json) return { ok: false, reason: 'missing_feature' };
34
+ logger.log('--feature=<slug> is required.');
35
+ return { ok: false };
36
+ }
37
+
38
+ if (!next) {
39
+ if (options.json) return { ok: false, reason: 'missing_next' };
40
+ logger.log('--next="<next step>" is required.');
41
+ return { ok: false };
42
+ }
43
+
44
+ // Build context package based on what exists
45
+ const artifacts = await scanArtifacts(targetDir, slug);
46
+ const contextPackage = [];
47
+ if (artifacts.project_context.exists) contextPackage.push('project.context.md');
48
+ if (artifacts.spec.exists) contextPackage.push(`spec-${slug}.md`);
49
+ if (plan) contextPackage.push(plan);
50
+ else if (artifacts.implementation_plan.exists) contextPackage.push(`implementation-plan-${slug}.md`);
51
+
52
+ const today = nowDate();
53
+ const statePath = path.join(contextDir(targetDir), 'dev-state.md');
54
+
55
+ const existingContent = await readFileSafe(statePath);
56
+ const existingFm = existingContent ? parseFrontmatter(existingContent) : {};
57
+
58
+ // Build history entry
59
+ const historyLine = `- ${today}: phase ${phase || existingFm.active_phase || '?'} — ${next}`;
60
+ const existingHistory = [];
61
+ if (existingContent) {
62
+ const historyMatch = existingContent.match(/## History\n([\s\S]*?)(?=\n##|\s*$)/);
63
+ if (historyMatch) {
64
+ const lines = historyMatch[1].split('\n').filter((l) => l.trim().startsWith('-'));
65
+ existingHistory.push(...lines.slice(-4)); // keep last 4 + new = 5 total
66
+ }
67
+ }
68
+ const history = [...existingHistory, historyLine];
69
+
70
+ const lines = [
71
+ '---',
72
+ `last_updated: ${today}`,
73
+ `active_feature: ${slug}`,
74
+ phase ? `active_phase: ${phase}` : (existingFm.active_phase ? `active_phase: ${existingFm.active_phase}` : null),
75
+ `next_step: "${next}"`,
76
+ specVersion ? `last_spec_version: ${specVersion}` : (existingFm.last_spec_version ? `last_spec_version: ${existingFm.last_spec_version}` : null),
77
+ `status: ${status}`,
78
+ '---',
79
+ '',
80
+ '# Dev State',
81
+ '',
82
+ `**Feature:** ${slug}`,
83
+ phase ? `**Phase:** ${phase}` : null,
84
+ `**Status:** ${status}`,
85
+ `**Next step:** ${next}`,
86
+ '',
87
+ '## Context package',
88
+ '',
89
+ ...contextPackage.map((f, i) => `${i + 1}. ${f}`),
90
+ '',
91
+ '## History',
92
+ '',
93
+ ...history,
94
+ ''
95
+ ].filter((l) => l !== null);
96
+
97
+ await fs.mkdir(path.dirname(statePath), { recursive: true });
98
+ await fs.writeFile(statePath, lines.join('\n'), 'utf8');
99
+
100
+ const result = {
101
+ ok: true,
102
+ path: path.relative(targetDir, statePath),
103
+ active_feature: slug,
104
+ active_phase: phase,
105
+ next_step: next,
106
+ last_spec_version: specVersion,
107
+ context_package: contextPackage
108
+ };
109
+
110
+ if (options.json) return result;
111
+
112
+ logger.log('dev-state.md updated:');
113
+ logger.log(` active_feature: ${slug}`);
114
+ if (phase) logger.log(` active_phase: ${phase}`);
115
+ logger.log(` next_step: "${next}"`);
116
+ if (specVersion) logger.log(` last_spec_version: ${specVersion}`);
117
+ logger.log(` context_package: [${contextPackage.join(', ')}]`);
118
+
119
+ return result;
120
+ }
121
+
122
+ module.exports = { runStateSave };
@@ -9,11 +9,13 @@ const { applyAgentLocale } = require('../locales');
9
9
  async function runUpdate({ args, options, logger, t }) {
10
10
  const targetDir = path.resolve(process.cwd(), args[0] || '.');
11
11
  const dryRun = Boolean(options['dry-run']);
12
+ const all = Boolean(options.all);
12
13
  const requestedLanguage = options.lang || options.language;
13
14
 
14
15
  const detection = await detectFramework(targetDir);
15
16
  const result = await updateInstallation(targetDir, {
16
17
  dryRun,
18
+ all,
17
19
  frameworkDetection: detection.framework
18
20
  });
19
21