@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.
- package/CHANGELOG.md +49 -0
- package/README.md +729 -226
- package/docs/design-previews/aurora-command-ui-website.html +884 -0
- package/docs/design-previews/aurora-command-ui.html +682 -0
- package/docs/design-previews/bold-editorial-ui-website.html +658 -0
- package/docs/design-previews/bold-editorial-ui.html +717 -0
- package/docs/design-previews/clean-saas-ui-website.html +1202 -0
- package/docs/design-previews/clean-saas-ui.html +549 -0
- package/docs/design-previews/cognitive-core-ui-website.html +1009 -0
- package/docs/design-previews/cognitive-core-ui.html +463 -0
- package/docs/design-previews/glassmorphism-ui-website.html +572 -0
- package/docs/design-previews/glassmorphism-ui.html +886 -0
- package/docs/design-previews/index.html +699 -0
- package/docs/design-previews/interface-design-website.html +1187 -0
- package/docs/design-previews/interface-design.html +513 -0
- package/docs/design-previews/neo-brutalist-ui-website.html +621 -0
- package/docs/design-previews/neo-brutalist-ui.html +797 -0
- package/docs/design-previews/premium-command-center-ui-website.html +1217 -0
- package/docs/design-previews/premium-command-center-ui.html +552 -0
- package/docs/design-previews/pt.squarespace.com-homepage.html +889 -0
- package/docs/design-previews/warm-craft-ui-website.html +684 -0
- package/docs/design-previews/warm-craft-ui.html +739 -0
- package/docs/en/cli-reference.md +20 -9
- package/docs/integrations/sdlc-genius-boundary.md +76 -0
- package/docs/integrations/sdlc-genius-eval-matrix.md +75 -0
- package/docs/integrations/sdlc-genius-install-checklist.md +93 -0
- package/docs/integrations/sdlc-genius-review-samples.md +86 -0
- package/docs/pt/README.md +10 -0
- package/docs/pt/agent-sharding.md +132 -0
- package/docs/pt/agentes.md +9 -2
- package/docs/pt/busca-de-contexto.md +129 -0
- package/docs/pt/cache-de-contexto.md +156 -0
- package/docs/pt/comandos-cli.md +915 -1
- package/docs/pt/design-hybrid-forge.md +356 -0
- package/docs/pt/devlog-pipeline.md +270 -0
- package/docs/pt/fluxo-artefatos.md +178 -0
- package/docs/pt/hooks-session-guard.md +454 -0
- package/docs/pt/inicio-rapido.md +54 -3
- package/docs/pt/inteligencia-adaptativa.md +324 -0
- package/docs/pt/monitor-de-contexto.md +158 -0
- package/docs/pt/recuperacao-de-sessao.md +125 -0
- package/docs/pt/sandbox.md +125 -0
- package/docs/pt/sdd-automation-scripts.md +557 -0
- package/docs/pt/site-forge.md +309 -0
- package/docs/pt/skills.md +98 -6
- package/docs/pt/spec-learnings-pipeline.md +265 -0
- package/package.json +1 -1
- package/src/a2a/client.js +165 -0
- package/src/a2a/server.js +223 -0
- package/src/agent-loader.js +280 -0
- package/src/cli.js +329 -1
- package/src/commands/agent-audit.js +397 -0
- package/src/commands/agent-export-skill.js +229 -0
- package/src/commands/agent-loader.js +85 -0
- package/src/commands/artifact-validate.js +189 -0
- package/src/commands/brief-gen.js +405 -0
- package/src/commands/brief-validate.js +65 -0
- package/src/commands/classify.js +256 -0
- package/src/commands/context-cache.js +90 -0
- package/src/commands/context-compact.js +49 -0
- package/src/commands/context-health.js +175 -0
- package/src/commands/context-monitor.js +163 -0
- package/src/commands/context-search.js +66 -0
- package/src/commands/context-trim.js +177 -0
- package/src/commands/design-hybrid-options.js +385 -0
- package/src/commands/detect-test-runner.js +55 -0
- package/src/commands/devlog-export-brains.js +27 -0
- package/src/commands/devlog-process.js +292 -0
- package/src/commands/devlog-watch.js +131 -0
- package/src/commands/feature-close.js +165 -0
- package/src/commands/gate-check.js +228 -0
- package/src/commands/health.js +214 -0
- package/src/commands/hooks-emit.js +253 -0
- package/src/commands/hooks-install.js +347 -0
- package/src/commands/init.js +54 -13
- package/src/commands/install.js +52 -13
- package/src/commands/learning-auto-promote.js +195 -0
- package/src/commands/learning-evolve.js +364 -0
- package/src/commands/learning-export.js +103 -0
- package/src/commands/learning-rollback.js +164 -0
- package/src/commands/live.js +59 -1
- package/src/commands/pattern-detect.js +33 -0
- package/src/commands/preflight-context.js +30 -0
- package/src/commands/preflight.js +208 -0
- package/src/commands/pulse-update.js +130 -0
- package/src/commands/recovery.js +43 -0
- package/src/commands/runner-daemon.js +274 -0
- package/src/commands/runner-plan.js +70 -0
- package/src/commands/runner-queue-from-plan.js +166 -0
- package/src/commands/runner-queue.js +189 -0
- package/src/commands/runner-run.js +129 -0
- package/src/commands/runtime.js +47 -1
- package/src/commands/sandbox.js +37 -0
- package/src/commands/self-implement-loop.js +256 -0
- package/src/commands/session-guard.js +218 -0
- package/src/commands/setup-context.js +22 -2
- package/src/commands/setup.js +178 -0
- package/src/commands/sizing.js +165 -0
- package/src/commands/skill.js +144 -32
- package/src/commands/spec-checkpoint.js +177 -0
- package/src/commands/spec-status.js +79 -0
- package/src/commands/spec-sync.js +190 -0
- package/src/commands/spec-tasks.js +288 -0
- package/src/commands/squad-autorun.js +1220 -0
- package/src/commands/squad-bus.js +217 -0
- package/src/commands/squad-card.js +149 -0
- package/src/commands/squad-daemon.js +134 -0
- package/src/commands/squad-dependency-graph.js +164 -0
- package/src/commands/squad-review.js +106 -0
- package/src/commands/squad-scaffold.js +55 -0
- package/src/commands/squad-tool-register.js +157 -0
- package/src/commands/state-save.js +122 -0
- package/src/commands/tool-registry-cmd.js +232 -0
- package/src/commands/update.js +9 -0
- package/src/commands/verify-gate.js +572 -0
- package/src/commands/workflow-execute.js +241 -0
- package/src/constants.js +18 -0
- package/src/context-cache.js +159 -0
- package/src/context-search.js +326 -0
- package/src/design-variation-catalog.js +503 -0
- package/src/i18n/messages/en.js +32 -2
- package/src/i18n/messages/es.js +30 -2
- package/src/i18n/messages/fr.js +30 -2
- package/src/i18n/messages/pt-BR.js +32 -2
- package/src/install-animation.js +260 -0
- package/src/install-profile.js +143 -0
- package/src/install-wizard.js +475 -0
- package/src/installer.js +44 -10
- package/src/lib/health-check.js +158 -0
- package/src/lib/hook-protocol.js +76 -0
- package/src/mcp/apps/squad-dashboard/app.js +163 -0
- package/src/mcp/apps/squad-dashboard/index.html +261 -0
- package/src/mcp/apps/squad-dashboard/mcp-manifest.json +23 -0
- package/src/mcp/resources/squad-state.js +130 -0
- package/src/parser.js +7 -1
- package/src/preflight-engine.js +443 -0
- package/src/recovery-context-session.js +154 -0
- package/src/runner/cascade.js +97 -0
- package/src/runner/cli-launcher.js +109 -0
- package/src/runner/plan-importer.js +63 -0
- package/src/runner/queue-store.js +159 -0
- package/src/runtime-store.js +158 -4
- package/src/sandbox.js +177 -0
- package/src/squad/agent-teams-adapter.js +264 -0
- package/src/squad/brief-validator.js +350 -0
- package/src/squad/bus-bridge.js +140 -0
- package/src/squad/context-compactor.js +265 -0
- package/src/squad/cross-ai-synthesizer.js +250 -0
- package/src/squad/hooks-generator.js +196 -0
- package/src/squad/inter-squad-events.js +175 -0
- package/src/squad/intra-bus.js +345 -0
- package/src/squad/learning-extractor.js +213 -0
- package/src/squad/pattern-detector.js +365 -0
- package/src/squad/preflight-context.js +296 -0
- package/src/squad/recovery-context.js +242 -71
- package/src/squad/reflection.js +365 -0
- package/src/squad/squad-scaffold.js +177 -0
- package/src/squad/state-manager.js +310 -0
- package/src/squad/task-decomposer.js +652 -0
- package/src/squad/verify-gate.js +303 -0
- package/src/tool-executor.js +94 -0
- package/src/updater.js +10 -3
- package/src/worker-runner.js +186 -1
- package/template/.aioson/agents/analyst.md +119 -3
- package/template/.aioson/agents/architect.md +98 -0
- package/template/.aioson/agents/design-hybrid-forge.md +141 -0
- package/template/.aioson/agents/dev.md +335 -14
- package/template/.aioson/agents/deyvin.md +117 -2
- package/template/.aioson/agents/discovery-design-doc.md +44 -0
- package/template/.aioson/agents/genome.md +14 -0
- package/template/.aioson/agents/neo.md +78 -1
- package/template/.aioson/agents/orache.md +50 -4
- package/template/.aioson/agents/orchestrator.md +197 -1
- package/template/.aioson/agents/pm.md +93 -0
- package/template/.aioson/agents/product.md +77 -4
- package/template/.aioson/agents/profiler-enricher.md +14 -0
- package/template/.aioson/agents/profiler-forge.md +14 -0
- package/template/.aioson/agents/profiler-researcher.md +14 -0
- package/template/.aioson/agents/qa.md +249 -19
- package/template/.aioson/agents/setup.md +144 -12
- package/template/.aioson/agents/sheldon.md +237 -11
- package/template/.aioson/agents/site-forge.md +1753 -0
- package/template/.aioson/agents/squad.md +162 -0
- package/template/.aioson/agents/tester.md +209 -0
- package/template/.aioson/agents/ux-ui.md +34 -1
- package/template/.aioson/brains/README.md +128 -0
- package/template/.aioson/brains/_index.json +16 -0
- package/template/.aioson/brains/scripts/query.js +103 -0
- package/template/.aioson/brains/site-forge/visual-patterns.brain.json +205 -0
- package/template/.aioson/config.md +158 -13
- package/template/.aioson/constitution.md +33 -0
- package/template/.aioson/context/forensics/.gitkeep +0 -0
- package/template/.aioson/context/project-pulse.md +34 -0
- package/template/.aioson/context/seeds/seed-example.md +27 -0
- package/template/.aioson/context/user-profile.md +42 -0
- package/template/.aioson/docs/LAYERS.md +79 -0
- package/template/.aioson/docs/README.md +76 -0
- package/template/.aioson/docs/example-external-api-context.md +72 -0
- package/template/.aioson/locales/en/agents/architect.md +17 -0
- package/template/.aioson/locales/en/agents/dev.md +79 -13
- package/template/.aioson/locales/en/agents/orache.md +6 -0
- package/template/.aioson/locales/en/agents/orchestrator.md +24 -0
- package/template/.aioson/locales/en/agents/product.md +50 -0
- package/template/.aioson/locales/en/agents/setup.md +33 -1
- package/template/.aioson/locales/en/agents/sheldon.md +115 -0
- package/template/.aioson/locales/en/agents/squad.md +14 -0
- package/template/.aioson/locales/en/agents/tester.md +6 -0
- package/template/.aioson/locales/es/agents/analyst.md +2 -0
- package/template/.aioson/locales/es/agents/architect.md +19 -0
- package/template/.aioson/locales/es/agents/dev.md +64 -4
- package/template/.aioson/locales/es/agents/deyvin.md +2 -0
- package/template/.aioson/locales/es/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/es/agents/genome.md +2 -0
- package/template/.aioson/locales/es/agents/neo.md +2 -0
- package/template/.aioson/locales/es/agents/orache.md +2 -0
- package/template/.aioson/locales/es/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/es/agents/pair.md +2 -0
- package/template/.aioson/locales/es/agents/pm.md +2 -0
- package/template/.aioson/locales/es/agents/product.md +52 -0
- package/template/.aioson/locales/es/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/es/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/es/agents/qa.md +2 -0
- package/template/.aioson/locales/es/agents/setup.md +35 -1
- package/template/.aioson/locales/es/agents/sheldon.md +117 -0
- package/template/.aioson/locales/es/agents/squad.md +16 -0
- package/template/.aioson/locales/es/agents/tester.md +9 -0
- package/template/.aioson/locales/es/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/fr/agents/analyst.md +2 -0
- package/template/.aioson/locales/fr/agents/architect.md +19 -0
- package/template/.aioson/locales/fr/agents/dev.md +64 -4
- package/template/.aioson/locales/fr/agents/deyvin.md +2 -0
- package/template/.aioson/locales/fr/agents/discovery-design-doc.md +2 -0
- package/template/.aioson/locales/fr/agents/genome.md +2 -0
- package/template/.aioson/locales/fr/agents/neo.md +2 -0
- package/template/.aioson/locales/fr/agents/orache.md +2 -0
- package/template/.aioson/locales/fr/agents/orchestrator.md +26 -0
- package/template/.aioson/locales/fr/agents/pair.md +2 -0
- package/template/.aioson/locales/fr/agents/pm.md +2 -0
- package/template/.aioson/locales/fr/agents/product.md +52 -0
- package/template/.aioson/locales/fr/agents/profiler-enricher.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-forge.md +2 -0
- package/template/.aioson/locales/fr/agents/profiler-researcher.md +2 -0
- package/template/.aioson/locales/fr/agents/qa.md +2 -0
- package/template/.aioson/locales/fr/agents/setup.md +35 -1
- package/template/.aioson/locales/fr/agents/sheldon.md +117 -0
- package/template/.aioson/locales/fr/agents/squad.md +16 -0
- package/template/.aioson/locales/fr/agents/tester.md +9 -0
- package/template/.aioson/locales/fr/agents/ux-ui.md +2 -0
- package/template/.aioson/locales/pt-BR/agents/analyst.md +64 -3
- package/template/.aioson/locales/pt-BR/agents/architect.md +42 -0
- package/template/.aioson/locales/pt-BR/agents/dev.md +147 -14
- package/template/.aioson/locales/pt-BR/agents/deyvin.md +47 -0
- package/template/.aioson/locales/pt-BR/agents/neo.md +62 -1
- package/template/.aioson/locales/pt-BR/agents/orchestrator.md +158 -2
- package/template/.aioson/locales/pt-BR/agents/pm.md +95 -1
- package/template/.aioson/locales/pt-BR/agents/product.md +145 -18
- package/template/.aioson/locales/pt-BR/agents/qa.md +16 -0
- package/template/.aioson/locales/pt-BR/agents/setup.md +134 -19
- package/template/.aioson/locales/pt-BR/agents/sheldon.md +132 -1
- package/template/.aioson/locales/pt-BR/agents/squad.md +14 -0
- package/template/.aioson/locales/pt-BR/agents/tester.md +449 -0
- package/template/.aioson/rules/README.md +69 -0
- package/template/.aioson/rules/data-format-convention.md +136 -0
- package/template/.aioson/rules/example-monetary-values.md +30 -0
- package/template/.aioson/schemas/squad-manifest.schema.json +124 -3
- package/template/.aioson/skills/design/aurora-command-ui/SKILL.md +243 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/art-direction.md +293 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/components.md +827 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/dashboards.md +250 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/design-tokens.md +585 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/motion.md +365 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/patterns.md +482 -0
- package/template/.aioson/skills/design/aurora-command-ui/references/websites.md +387 -0
- package/template/.aioson/skills/design/glassmorphism-ui/SKILL.md +222 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/art-direction.md +159 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/components.md +498 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/dashboards.md +236 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/design-tokens.md +274 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/motion.md +355 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/patterns.md +198 -0
- package/template/.aioson/skills/design/glassmorphism-ui/references/websites.md +307 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/SKILL.md +213 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/art-direction.md +228 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/components.md +855 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/dashboards.md +334 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/design-tokens.md +342 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/motion.md +286 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/patterns.md +458 -0
- package/template/.aioson/skills/design/neo-brutalist-ui/references/websites.md +723 -0
- package/template/.aioson/skills/design/pt.squarespace.com/.skill-meta.json +31 -0
- package/template/.aioson/skills/design/pt.squarespace.com/SKILL.md +66 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/components.md +368 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/design-tokens.md +150 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/motion.md +270 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/patterns.md +189 -0
- package/template/.aioson/skills/design/pt.squarespace.com/references/websites.md +165 -0
- package/template/.aioson/skills/process/aioson-spec-driven/SKILL.md +46 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/analyst.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/approval-gates.md +109 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/architect.md +23 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/artifact-map.md +44 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/classification-map.md +37 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/dev.md +47 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/deyvin.md +27 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/hardening-lane.md +49 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/maintenance-and-state.md +101 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/product.md +25 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/qa.md +30 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/sheldon.md +25 -0
- package/template/.aioson/skills/process/aioson-spec-driven/references/ui-language.md +75 -0
- package/template/.aioson/skills/process/design-hybrid-forge/SKILL.md +147 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/crossover-protocol.md +221 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/naming-registry.md +88 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/output-contract.md +306 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/pair-compatibility.md +149 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/quality-gates.md +208 -0
- package/template/.aioson/skills/process/design-hybrid-forge/references/variation-library.md +125 -0
- package/template/.aioson/skills/process/simplify/SKILL.md +173 -0
- package/template/.aioson/skills/static/context-budget-guide.md +46 -0
- package/template/.aioson/skills/static/harness-sensors.md +74 -0
- package/template/.aioson/skills/static/multi-agent-patterns.md +43 -0
- package/template/.aioson/skills/static/react-motion-patterns.md +22 -0
- package/template/.aioson/skills/static/static-html-patterns/checklists.md +43 -0
- package/template/.aioson/skills/static/static-html-patterns/css-tokens.md +609 -0
- package/template/.aioson/skills/static/static-html-patterns/motion.md +193 -0
- package/template/.aioson/skills/static/static-html-patterns/premium.md +711 -0
- package/template/.aioson/skills/static/static-html-patterns/structure.md +209 -0
- package/template/.aioson/skills/static/static-html-patterns/utilities.md +190 -0
- package/template/.aioson/skills/static/static-html-patterns.md +58 -1913
- package/template/.aioson/skills/static/threejs-patterns.md +929 -0
- package/template/.aioson/skills/static/web-research-cache.md +112 -0
- package/template/.aioson/tasks/implementation-plan.md +21 -1
- package/template/.claude/commands/aioson/agent/design-hybrid-forge.md +5 -0
- package/template/.claude/commands/aioson/agent/orache.md +5 -0
- package/template/.claude/commands/aioson/agent/sheldon.md +5 -0
- package/template/.claude/commands/aioson/agent/site-forge.md +5 -0
- package/template/AGENTS.md +75 -1
- package/template/CLAUDE.md +31 -0
- package/template/OPENCODE.md +4 -0
- package/template/researchs/.gitkeep +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { AgentLoader } = require('../agent-loader');
|
|
5
|
+
|
|
6
|
+
async function runAgentLoad({ args, options, logger }) {
|
|
7
|
+
const agentId = args[0] || options.agent || '';
|
|
8
|
+
const goal = options.goal || '';
|
|
9
|
+
const cwd = path.resolve(process.cwd(), options.cwd || '.');
|
|
10
|
+
const agentsDir = path.join(cwd, options['agents-dir'] || '.aioson/agents');
|
|
11
|
+
const maxShards = Number(options['max-shards']) || 3;
|
|
12
|
+
const maxTokens = Number(options['max-tokens']) || 2000;
|
|
13
|
+
|
|
14
|
+
if (!agentId) {
|
|
15
|
+
logger.error('Usage: aioson agent:load <agent-id> --goal="..." [--cwd=.]');
|
|
16
|
+
return { ok: false, error: 'missing_agent' };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const loader = new AgentLoader();
|
|
20
|
+
await loader.open();
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Index agents dir if needed
|
|
24
|
+
await loader.indexAgentsDir(agentsDir, { force: Boolean(options.force) });
|
|
25
|
+
|
|
26
|
+
// Load relevant shards
|
|
27
|
+
const result = await loader.loadRelevantShards(agentId, goal, { maxShards, maxTokens });
|
|
28
|
+
|
|
29
|
+
if (result.shards.length === 0) {
|
|
30
|
+
logger.log(`No shards found for agent: ${agentId}`);
|
|
31
|
+
logger.log(`Make sure the agents directory exists: ${agentsDir}`);
|
|
32
|
+
return { ok: true, agentId, shards: [], tokens: 0 };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (options.json) {
|
|
36
|
+
return { ok: true, ...result };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
logger.log(`\n Agent: ${agentId} (${result.shards.length}/${result.totalShards} shards, ${result.tokens} tokens)\n`);
|
|
40
|
+
for (const shard of result.shards) {
|
|
41
|
+
logger.log(` ## ${shard.heading} (${shard.tokens} tokens)`);
|
|
42
|
+
}
|
|
43
|
+
logger.log('');
|
|
44
|
+
|
|
45
|
+
if (options.print) {
|
|
46
|
+
logger.log('\n---\n');
|
|
47
|
+
logger.log(AgentLoader.buildContext(result.shards));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { ok: true, ...result };
|
|
51
|
+
} finally {
|
|
52
|
+
loader.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runAgentShardIndex({ args, options, logger }) {
|
|
57
|
+
const cwd = path.resolve(process.cwd(), args[0] || '.');
|
|
58
|
+
const agentsDir = path.join(cwd, options['agents-dir'] || '.aioson/agents');
|
|
59
|
+
const force = Boolean(options.force);
|
|
60
|
+
|
|
61
|
+
logger.log(`Indexing agent shards from: ${agentsDir}`);
|
|
62
|
+
|
|
63
|
+
const loader = new AgentLoader();
|
|
64
|
+
await loader.open();
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const result = await loader.indexAgentsDir(agentsDir, { force });
|
|
68
|
+
const stats = loader.stats();
|
|
69
|
+
|
|
70
|
+
if (options.json) {
|
|
71
|
+
return { ok: true, ...result, stats };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
logger.log(` Agents indexed: ${result.agents}`);
|
|
75
|
+
logger.log(` Total shards: ${result.totalShards}`);
|
|
76
|
+
logger.log(` Index total docs: ${stats.totalDocs}`);
|
|
77
|
+
logger.log('');
|
|
78
|
+
|
|
79
|
+
return { ok: true, ...result, stats };
|
|
80
|
+
} finally {
|
|
81
|
+
loader.close();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = { runAgentLoad, runAgentShardIndex };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson artifact:validate — validate the complete artifact chain for a feature.
|
|
5
|
+
*
|
|
6
|
+
* Checks all expected artifacts (prd → sheldon → requirements → spec →
|
|
7
|
+
* architecture → implementation-plan → conformance) and reports chain integrity.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson artifact:validate . --feature=checkout
|
|
11
|
+
* aioson artifact:validate . --feature=checkout --json
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('node:path');
|
|
15
|
+
const {
|
|
16
|
+
scanArtifacts,
|
|
17
|
+
detectClassification,
|
|
18
|
+
parseGatesFromSpec,
|
|
19
|
+
parseFrontmatter,
|
|
20
|
+
contextDir
|
|
21
|
+
} = require('../preflight-engine');
|
|
22
|
+
|
|
23
|
+
const BAR = '━'.repeat(45);
|
|
24
|
+
|
|
25
|
+
function gateDisplay(gates) {
|
|
26
|
+
const letters = { requirements: 'A', design: 'B', plan: 'C', execution: 'D' };
|
|
27
|
+
return Object.entries(letters).map(([name, letter]) => {
|
|
28
|
+
const status = gates[name];
|
|
29
|
+
return status === 'approved' ? `${letter}✓` : `${letter}○`;
|
|
30
|
+
}).join(' ');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function runArtifactValidate({ args, options = {}, logger }) {
|
|
34
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
35
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
36
|
+
|
|
37
|
+
if (!slug) {
|
|
38
|
+
if (options.json) return { ok: false, reason: 'missing_feature' };
|
|
39
|
+
logger.log('--feature=<slug> is required.');
|
|
40
|
+
return { ok: false };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const artifacts = await scanArtifacts(targetDir, slug);
|
|
44
|
+
const classification = await detectClassification(targetDir, slug);
|
|
45
|
+
|
|
46
|
+
// Gates from spec
|
|
47
|
+
const specGates = artifacts.spec.exists ? parseGatesFromSpec(artifacts.spec.content) : {};
|
|
48
|
+
|
|
49
|
+
// Spec details
|
|
50
|
+
const specFm = artifacts.spec.exists ? parseFrontmatter(artifacts.spec.content) : {};
|
|
51
|
+
const specVersion = specFm.version || null;
|
|
52
|
+
const specGateDisplay = artifacts.spec.exists ? gateDisplay(specGates) : null;
|
|
53
|
+
|
|
54
|
+
// Sheldon readiness
|
|
55
|
+
const sheldonReady = artifacts.sheldon_enrichment.exists
|
|
56
|
+
? (artifacts.sheldon_enrichment.frontmatter.readiness === 'ready_for_downstream' ? 'ready_for_downstream' : 'present')
|
|
57
|
+
: null;
|
|
58
|
+
|
|
59
|
+
// Implementation plan status
|
|
60
|
+
const planStatus = artifacts.implementation_plan.exists
|
|
61
|
+
? (artifacts.implementation_plan.frontmatter.status || 'present')
|
|
62
|
+
: null;
|
|
63
|
+
|
|
64
|
+
// Requirement count
|
|
65
|
+
let reqCount = null;
|
|
66
|
+
if (artifacts.requirements.exists && artifacts.requirements.content) {
|
|
67
|
+
const reqs = artifacts.requirements.content.match(/\bREQ[-\s]?\d+\b/g) || [];
|
|
68
|
+
const acs = artifacts.requirements.content.match(/\bAC[-\s]?\d+\b/g) || [];
|
|
69
|
+
reqCount = `${reqs.length} REQs, ${acs.length} ACs`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Conformance required?
|
|
73
|
+
const conformanceRequired = classification === 'MEDIUM';
|
|
74
|
+
|
|
75
|
+
// Build chain items
|
|
76
|
+
const chain = [
|
|
77
|
+
{
|
|
78
|
+
name: 'project.context.md',
|
|
79
|
+
exists: artifacts.project_context.exists,
|
|
80
|
+
detail: artifacts.project_context.exists ? `${artifacts.project_context.size}B` : null,
|
|
81
|
+
required: true,
|
|
82
|
+
indent: 0
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: `prd-${slug}.md`,
|
|
86
|
+
exists: artifacts.prd.exists,
|
|
87
|
+
detail: artifacts.prd.exists ? `${artifacts.prd.size}B` : null,
|
|
88
|
+
required: true,
|
|
89
|
+
indent: 0
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: `sheldon-enrichment-${slug}.md`,
|
|
93
|
+
exists: artifacts.sheldon_enrichment.exists,
|
|
94
|
+
detail: sheldonReady ? `readiness: ${sheldonReady}` : null,
|
|
95
|
+
required: false,
|
|
96
|
+
indent: 1
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: `requirements-${slug}.md`,
|
|
100
|
+
exists: artifacts.requirements.exists,
|
|
101
|
+
detail: reqCount,
|
|
102
|
+
required: true,
|
|
103
|
+
indent: 1
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: `spec-${slug}.md`,
|
|
107
|
+
exists: artifacts.spec.exists,
|
|
108
|
+
detail: artifacts.spec.exists ? `version: ${specVersion || '?'}, gates: ${specGateDisplay || '?'}` : null,
|
|
109
|
+
required: true,
|
|
110
|
+
indent: 1
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'architecture.md',
|
|
114
|
+
exists: artifacts.architecture.exists,
|
|
115
|
+
detail: null,
|
|
116
|
+
required: true,
|
|
117
|
+
indent: 1
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: `implementation-plan-${slug}.md`,
|
|
121
|
+
exists: artifacts.implementation_plan.exists,
|
|
122
|
+
detail: planStatus ? `status: ${planStatus}` : null,
|
|
123
|
+
required: true,
|
|
124
|
+
indent: 1
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: `conformance-${slug}.yaml`,
|
|
128
|
+
exists: artifacts.conformance.exists,
|
|
129
|
+
detail: !conformanceRequired ? `required for MEDIUM — NOT required for ${classification || 'SMALL'}` : null,
|
|
130
|
+
required: conformanceRequired,
|
|
131
|
+
indent: 1
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
// Validate chain integrity
|
|
136
|
+
const missing = chain.filter((c) => c.required && !c.exists);
|
|
137
|
+
const missingOptional = chain.filter((c) => !c.required && !c.exists);
|
|
138
|
+
|
|
139
|
+
const valid = missing.length === 0;
|
|
140
|
+
|
|
141
|
+
const result = {
|
|
142
|
+
ok: valid,
|
|
143
|
+
feature: slug,
|
|
144
|
+
classification: classification || 'unknown',
|
|
145
|
+
chain: chain.map((c) => ({
|
|
146
|
+
name: c.name,
|
|
147
|
+
exists: c.exists,
|
|
148
|
+
required: c.required,
|
|
149
|
+
detail: c.detail
|
|
150
|
+
})),
|
|
151
|
+
missing_required: missing.map((c) => c.name),
|
|
152
|
+
missing_optional: missingOptional.map((c) => c.name),
|
|
153
|
+
integrity: valid ? 'VALID' : 'INVALID'
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
if (options.json) return result;
|
|
157
|
+
|
|
158
|
+
logger.log('');
|
|
159
|
+
logger.log(`Artifact Chain — ${slug}`);
|
|
160
|
+
logger.log(BAR);
|
|
161
|
+
|
|
162
|
+
for (const item of chain) {
|
|
163
|
+
const icon = item.exists ? '✓' : '✗';
|
|
164
|
+
const indent = ' '.repeat(item.indent) + (item.indent > 0 ? '→ ' : '');
|
|
165
|
+
const detail = item.detail ? ` (${item.detail})` : '';
|
|
166
|
+
logger.log(`${indent}${icon} ${item.name}${detail}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
logger.log('');
|
|
170
|
+
logger.log(`Chain integrity: ${valid ? 'VALID' : 'INVALID'}`);
|
|
171
|
+
|
|
172
|
+
if (missing.length > 0) {
|
|
173
|
+
logger.log(`Missing required: ${missing.map((c) => c.name).join(', ')}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (missingOptional.length > 0 && !valid) {
|
|
177
|
+
logger.log(`Missing optional: ${missingOptional.map((c) => c.name).join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (valid && missingOptional.length > 0) {
|
|
181
|
+
logger.log(`Missing optional: ${missingOptional.map((c) => c.name).join(', ')} (${classification || 'SMALL'} — acceptable)`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
logger.log('');
|
|
185
|
+
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = { runArtifactValidate };
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson brief:gen — Generate a 100% self-contained worker brief
|
|
5
|
+
*
|
|
6
|
+
* Reads the current implementation plan phase (or a named phase), combines
|
|
7
|
+
* it with the project architecture, spec, and any existing context files,
|
|
8
|
+
* and writes a fully self-contained brief that a worker can execute with
|
|
9
|
+
* zero additional lookups.
|
|
10
|
+
*
|
|
11
|
+
* Brief completeness checklist (from orchestrator.md):
|
|
12
|
+
* ✓ Phase name and goal
|
|
13
|
+
* ✓ Files to read before starting
|
|
14
|
+
* ✓ Files to create or modify
|
|
15
|
+
* ✓ Hard constraints (must not touch)
|
|
16
|
+
* ✓ Out-of-scope (what NOT to do)
|
|
17
|
+
* ✓ Done criteria (verifiable)
|
|
18
|
+
* ✓ Relevant excerpts from architecture / spec
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* aioson brief:gen .
|
|
22
|
+
* aioson brief:gen . --phase=2 Target a specific plan phase
|
|
23
|
+
* aioson brief:gen . --plan=my-plan.md Use a specific plan file
|
|
24
|
+
* aioson brief:gen . --out=briefs/phase-2.md Override output path
|
|
25
|
+
* aioson brief:gen . --squad=content-team Target squad directory instead of .aioson/context
|
|
26
|
+
* aioson brief:gen . --executor=writer Target executor inside squad
|
|
27
|
+
* aioson brief:gen . --json JSON output
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const fs = require('node:fs/promises');
|
|
31
|
+
const path = require('node:path');
|
|
32
|
+
|
|
33
|
+
// ─── File discovery helpers ───────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
async function tryRead(filePath) {
|
|
36
|
+
try {
|
|
37
|
+
return await fs.readFile(filePath, 'utf8');
|
|
38
|
+
} catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function findFile(candidates) {
|
|
44
|
+
for (const p of candidates) {
|
|
45
|
+
const content = await tryRead(p);
|
|
46
|
+
if (content !== null) return { path: p, content };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ─── Plan parser ──────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Parse phases from an implementation plan markdown.
|
|
55
|
+
* Phases are identified by ## or ### headings containing "Phase" or "Sprint" or
|
|
56
|
+
* "Step" followed by a number.
|
|
57
|
+
*/
|
|
58
|
+
function parsePlanPhases(content) {
|
|
59
|
+
const lines = content.split(/\r?\n/);
|
|
60
|
+
const phases = [];
|
|
61
|
+
const phaseHeadingRe = /^#{1,4}\s+(?:Phase|Sprint|Step|Fase|Etapa)\s*(\d+)\b(.*)$/i;
|
|
62
|
+
|
|
63
|
+
let current = null;
|
|
64
|
+
let currentLines = [];
|
|
65
|
+
|
|
66
|
+
function flush() {
|
|
67
|
+
if (current !== null) {
|
|
68
|
+
phases.push({
|
|
69
|
+
number: current.number,
|
|
70
|
+
title: current.title,
|
|
71
|
+
content: currentLines.join('\n').trim()
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
const match = line.match(phaseHeadingRe);
|
|
78
|
+
if (match) {
|
|
79
|
+
flush();
|
|
80
|
+
current = {
|
|
81
|
+
number: parseInt(match[1], 10),
|
|
82
|
+
title: line.trim()
|
|
83
|
+
};
|
|
84
|
+
currentLines = [line];
|
|
85
|
+
} else if (current !== null) {
|
|
86
|
+
currentLines.push(line);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
flush();
|
|
90
|
+
|
|
91
|
+
return phases;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Extract a named section (## heading) from markdown content.
|
|
96
|
+
* Returns the section body (without the heading line).
|
|
97
|
+
*/
|
|
98
|
+
function extractSection(content, sectionPattern) {
|
|
99
|
+
const lines = content.split(/\r?\n/);
|
|
100
|
+
const re = new RegExp(`^#{1,4}\\s+.*${sectionPattern}.*$`, 'i');
|
|
101
|
+
let inSection = false;
|
|
102
|
+
let sectionLevel = 0;
|
|
103
|
+
const result = [];
|
|
104
|
+
|
|
105
|
+
for (const line of lines) {
|
|
106
|
+
const headingMatch = line.match(/^(#{1,4})\s+/);
|
|
107
|
+
|
|
108
|
+
if (!inSection) {
|
|
109
|
+
if (re.test(line)) {
|
|
110
|
+
inSection = true;
|
|
111
|
+
sectionLevel = headingMatch ? headingMatch[1].length : 2;
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Stop if we hit a heading of equal or higher level
|
|
117
|
+
if (headingMatch && headingMatch[1].length <= sectionLevel) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
result.push(line);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result.join('\n').trim();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ─── Architecture excerpt extractor ──────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
const ARCH_SECTIONS = [
|
|
129
|
+
'tech stack', 'stack', 'architecture', 'folder structure', 'directory',
|
|
130
|
+
'conventions', 'database', 'api', 'services', 'modules', 'layers'
|
|
131
|
+
];
|
|
132
|
+
|
|
133
|
+
function extractArchitectureExcerpts(archContent, maxChars = 3000) {
|
|
134
|
+
if (!archContent) return null;
|
|
135
|
+
|
|
136
|
+
// Try to pull relevant sections
|
|
137
|
+
const excerpts = [];
|
|
138
|
+
for (const keyword of ARCH_SECTIONS) {
|
|
139
|
+
const section = extractSection(archContent, keyword);
|
|
140
|
+
if (section.length > 50) {
|
|
141
|
+
excerpts.push(section);
|
|
142
|
+
}
|
|
143
|
+
if (excerpts.reduce((s, e) => s + e.length, 0) >= maxChars) break;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (excerpts.length === 0) {
|
|
147
|
+
// Fall back to the first maxChars characters
|
|
148
|
+
return archContent.slice(0, maxChars) + (archContent.length > maxChars ? '\n\n[...truncated — read full file for details]' : '');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return excerpts.join('\n\n---\n\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ─── Brief builder ────────────────────────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
function buildBrief({
|
|
157
|
+
phase,
|
|
158
|
+
planPath,
|
|
159
|
+
architectureExcerpt,
|
|
160
|
+
specExcerpt,
|
|
161
|
+
contextNote,
|
|
162
|
+
squadSlug,
|
|
163
|
+
executorSlug,
|
|
164
|
+
projectDir
|
|
165
|
+
}) {
|
|
166
|
+
const now = new Date().toISOString();
|
|
167
|
+
const relPlan = path.relative(projectDir, planPath);
|
|
168
|
+
const squadLine = squadSlug ? `Squad : ${squadSlug}` : null;
|
|
169
|
+
const executorLine = executorSlug ? `Executor : ${executorSlug}` : null;
|
|
170
|
+
|
|
171
|
+
const lines = [
|
|
172
|
+
'---',
|
|
173
|
+
`generated_at : ${now}`,
|
|
174
|
+
`plan_file : ${relPlan}`,
|
|
175
|
+
`phase : ${phase.number}`,
|
|
176
|
+
...(squadLine ? [squadLine] : []),
|
|
177
|
+
...(executorLine ? [executorLine] : []),
|
|
178
|
+
'---',
|
|
179
|
+
'',
|
|
180
|
+
`# Worker Brief — ${phase.title}`,
|
|
181
|
+
'',
|
|
182
|
+
'> This brief is 100% self-contained. Do not look up additional context.',
|
|
183
|
+
'> Read only the files listed in "Files to read". Write only the files listed in "Files to write".',
|
|
184
|
+
''
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
// Phase task block
|
|
188
|
+
lines.push('## Phase goal and tasks');
|
|
189
|
+
lines.push('');
|
|
190
|
+
lines.push(phase.content);
|
|
191
|
+
lines.push('');
|
|
192
|
+
|
|
193
|
+
// Architecture
|
|
194
|
+
if (architectureExcerpt) {
|
|
195
|
+
lines.push('## Architecture reference (excerpts)');
|
|
196
|
+
lines.push('');
|
|
197
|
+
lines.push(architectureExcerpt);
|
|
198
|
+
lines.push('');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Spec
|
|
202
|
+
if (specExcerpt) {
|
|
203
|
+
lines.push('## Spec reference (excerpts)');
|
|
204
|
+
lines.push('');
|
|
205
|
+
lines.push(specExcerpt);
|
|
206
|
+
lines.push('');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Context note
|
|
210
|
+
if (contextNote) {
|
|
211
|
+
lines.push('## Project context');
|
|
212
|
+
lines.push('');
|
|
213
|
+
lines.push(contextNote);
|
|
214
|
+
lines.push('');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Done criteria placeholder (agent should fill in based on phase content)
|
|
218
|
+
lines.push('## Done criteria');
|
|
219
|
+
lines.push('');
|
|
220
|
+
lines.push('> Fill in the specific, verifiable done criteria for this phase before handing off.');
|
|
221
|
+
lines.push('> Example format:');
|
|
222
|
+
lines.push('> - [ ] `path/to/file.ts` exists and exports `FunctionName`');
|
|
223
|
+
lines.push('> - [ ] All existing tests pass (`npm test`)');
|
|
224
|
+
lines.push('> - [ ] No TypeScript errors (`tsc --noEmit`)');
|
|
225
|
+
lines.push('');
|
|
226
|
+
|
|
227
|
+
// Hard constraints placeholder
|
|
228
|
+
lines.push('## Hard constraints');
|
|
229
|
+
lines.push('');
|
|
230
|
+
lines.push('> Fill in what the worker MUST NOT touch or change.');
|
|
231
|
+
lines.push('> Example:');
|
|
232
|
+
lines.push('> - Do NOT modify `src/db/schema.ts` (owned by another phase)');
|
|
233
|
+
lines.push('> - Do NOT add new npm dependencies without coordinator approval');
|
|
234
|
+
lines.push('');
|
|
235
|
+
|
|
236
|
+
// Out of scope
|
|
237
|
+
lines.push('## Out of scope');
|
|
238
|
+
lines.push('');
|
|
239
|
+
lines.push('> Fill in what explicitly falls outside this phase.');
|
|
240
|
+
lines.push('> Example:');
|
|
241
|
+
lines.push('> - UI styling (handled in Phase 3)');
|
|
242
|
+
lines.push('> - Authentication (handled in Phase 4)');
|
|
243
|
+
lines.push('');
|
|
244
|
+
|
|
245
|
+
return lines.join('\n');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ─── Main command ─────────────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
async function runBriefGen({ args, options = {}, logger }) {
|
|
251
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
252
|
+
const phaseNumber = options.phase != null ? Number(options.phase) : null;
|
|
253
|
+
const squadSlug = String(options.squad || '').trim() || null;
|
|
254
|
+
const executorSlug = String(options.executor || '').trim() || null;
|
|
255
|
+
|
|
256
|
+
const contextDir = squadSlug
|
|
257
|
+
? path.join(targetDir, '.aioson', 'squads', squadSlug)
|
|
258
|
+
: path.join(targetDir, '.aioson', 'context');
|
|
259
|
+
|
|
260
|
+
// ── Locate plan file ─────────────────────────────────────────────────────
|
|
261
|
+
let planFile;
|
|
262
|
+
if (options.plan) {
|
|
263
|
+
const explicit = path.resolve(targetDir, options.plan);
|
|
264
|
+
const content = await tryRead(explicit);
|
|
265
|
+
if (!content) {
|
|
266
|
+
logger.error(`Plan file not found: ${options.plan}`);
|
|
267
|
+
return { ok: false, error: 'plan_not_found' };
|
|
268
|
+
}
|
|
269
|
+
planFile = { path: explicit, content };
|
|
270
|
+
} else {
|
|
271
|
+
planFile = await findFile([
|
|
272
|
+
path.join(contextDir, 'implementation-plan.md'),
|
|
273
|
+
path.join(targetDir, '.aioson', 'context', 'implementation-plan.md'),
|
|
274
|
+
path.join(targetDir, 'plans', 'implementation-plan.md'),
|
|
275
|
+
path.join(targetDir, 'implementation-plan.md')
|
|
276
|
+
]);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!planFile) {
|
|
280
|
+
logger.error('No implementation plan found. Run `aioson plan:show` or provide --plan=<path>.');
|
|
281
|
+
return { ok: false, error: 'no_plan' };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ── Parse phases ─────────────────────────────────────────────────────────
|
|
285
|
+
const phases = parsePlanPhases(planFile.content);
|
|
286
|
+
|
|
287
|
+
if (phases.length === 0) {
|
|
288
|
+
logger.error(`No phases found in plan: ${path.relative(targetDir, planFile.path)}`);
|
|
289
|
+
logger.error('Phases must use headings like "## Phase 1 — description" or "## Sprint 2".');
|
|
290
|
+
return { ok: false, error: 'no_phases' };
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Pick target phase
|
|
294
|
+
let phase;
|
|
295
|
+
if (phaseNumber != null) {
|
|
296
|
+
phase = phases.find((p) => p.number === phaseNumber);
|
|
297
|
+
if (!phase) {
|
|
298
|
+
logger.error(`Phase ${phaseNumber} not found. Available: ${phases.map((p) => p.number).join(', ')}`);
|
|
299
|
+
return { ok: false, error: 'phase_not_found' };
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
// Default: first incomplete phase (or first phase)
|
|
303
|
+
phase = phases[0];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ── Locate supporting files ───────────────────────────────────────────────
|
|
307
|
+
const [archFile, specFile, ctxFile] = await Promise.all([
|
|
308
|
+
findFile([
|
|
309
|
+
path.join(contextDir, 'architecture.md'),
|
|
310
|
+
path.join(targetDir, '.aioson', 'context', 'architecture.md'),
|
|
311
|
+
path.join(targetDir, 'docs', 'architecture.md'),
|
|
312
|
+
path.join(targetDir, 'ARCHITECTURE.md')
|
|
313
|
+
]),
|
|
314
|
+
findFile([
|
|
315
|
+
path.join(contextDir, 'spec.md'),
|
|
316
|
+
path.join(targetDir, '.aioson', 'context', 'spec.md'),
|
|
317
|
+
path.join(targetDir, 'docs', 'spec.md'),
|
|
318
|
+
path.join(targetDir, 'SPEC.md')
|
|
319
|
+
]),
|
|
320
|
+
findFile([
|
|
321
|
+
path.join(contextDir, 'project.context.md'),
|
|
322
|
+
path.join(targetDir, '.aioson', 'context', 'project.context.md')
|
|
323
|
+
])
|
|
324
|
+
]);
|
|
325
|
+
|
|
326
|
+
const architectureExcerpt = archFile
|
|
327
|
+
? extractArchitectureExcerpts(archFile.content)
|
|
328
|
+
: null;
|
|
329
|
+
|
|
330
|
+
const specExcerpt = specFile
|
|
331
|
+
? (specFile.content.length > 4000
|
|
332
|
+
? specFile.content.slice(0, 4000) + '\n\n[...truncated — read full file for details]'
|
|
333
|
+
: specFile.content)
|
|
334
|
+
: null;
|
|
335
|
+
|
|
336
|
+
// Context: pull a short summary from project.context.md
|
|
337
|
+
const contextNote = ctxFile
|
|
338
|
+
? extractSection(ctxFile.content, 'summary|overview|objetivo|goal') ||
|
|
339
|
+
ctxFile.content.slice(0, 800)
|
|
340
|
+
: null;
|
|
341
|
+
|
|
342
|
+
// ── Build brief ───────────────────────────────────────────────────────────
|
|
343
|
+
const briefContent = buildBrief({
|
|
344
|
+
phase,
|
|
345
|
+
planPath: planFile.path,
|
|
346
|
+
architectureExcerpt,
|
|
347
|
+
specExcerpt,
|
|
348
|
+
contextNote,
|
|
349
|
+
squadSlug,
|
|
350
|
+
executorSlug,
|
|
351
|
+
projectDir: targetDir
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
// ── Determine output path ─────────────────────────────────────────────────
|
|
355
|
+
let outPath;
|
|
356
|
+
if (options.out) {
|
|
357
|
+
outPath = path.resolve(targetDir, options.out);
|
|
358
|
+
} else {
|
|
359
|
+
const outDir = squadSlug
|
|
360
|
+
? path.join(targetDir, '.aioson', 'squads', squadSlug, 'briefs')
|
|
361
|
+
: path.join(targetDir, '.aioson', 'context', 'briefs');
|
|
362
|
+
const executorSuffix = executorSlug ? `-${executorSlug}` : '';
|
|
363
|
+
outPath = path.join(outDir, `phase-${phase.number}${executorSuffix}.md`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
await fs.mkdir(path.dirname(outPath), { recursive: true });
|
|
367
|
+
await fs.writeFile(outPath, briefContent, 'utf8');
|
|
368
|
+
|
|
369
|
+
const relOut = path.relative(targetDir, outPath);
|
|
370
|
+
|
|
371
|
+
if (options.json) {
|
|
372
|
+
return {
|
|
373
|
+
ok: true,
|
|
374
|
+
brief_path: relOut,
|
|
375
|
+
phase: phase.number,
|
|
376
|
+
phase_title: phase.title,
|
|
377
|
+
plan_file: path.relative(targetDir, planFile.path),
|
|
378
|
+
has_architecture: Boolean(architectureExcerpt),
|
|
379
|
+
has_spec: Boolean(specExcerpt),
|
|
380
|
+
has_context: Boolean(contextNote),
|
|
381
|
+
chars: briefContent.length,
|
|
382
|
+
tokens: Math.ceil(briefContent.length / 4)
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
logger.log('Brief generated');
|
|
387
|
+
logger.log('─'.repeat(60));
|
|
388
|
+
logger.log(`Phase : ${phase.number} — ${phase.title}`);
|
|
389
|
+
logger.log(`Plan : ${path.relative(targetDir, planFile.path)}`);
|
|
390
|
+
logger.log(`Architecture : ${archFile ? path.relative(targetDir, archFile.path) : '(not found)'}`);
|
|
391
|
+
logger.log(`Spec : ${specFile ? path.relative(targetDir, specFile.path) : '(not found)'}`);
|
|
392
|
+
logger.log(`Output : ${relOut}`);
|
|
393
|
+
logger.log(`Size : ${briefContent.length} chars (~${Math.ceil(briefContent.length / 4)} tokens)`);
|
|
394
|
+
logger.log('');
|
|
395
|
+
logger.log('Review the "Done criteria", "Hard constraints", and "Out of scope" sections');
|
|
396
|
+
logger.log('before handing the brief to a worker. These are left as placeholders intentionally.');
|
|
397
|
+
|
|
398
|
+
return {
|
|
399
|
+
ok: true,
|
|
400
|
+
brief_path: relOut,
|
|
401
|
+
phase: phase.number
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
module.exports = { runBriefGen };
|