@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,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { generateSessionRecovery, readSessionRecovery } = require('../recovery-context-session');
|
|
5
|
+
|
|
6
|
+
async function runRecoveryGenerate({ args, options, logger }) {
|
|
7
|
+
const cwd = path.resolve(process.cwd(), args[0] || '.');
|
|
8
|
+
const sessionState = {
|
|
9
|
+
goal: options.goal || undefined,
|
|
10
|
+
agent: options.agent || undefined,
|
|
11
|
+
tasks: [],
|
|
12
|
+
notes: []
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const result = await generateSessionRecovery(cwd, sessionState);
|
|
16
|
+
|
|
17
|
+
if (!result.ok) {
|
|
18
|
+
logger.error(`recovery:generate failed: ${result.error}`);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
logger.log(`Recovery context generated: ${result.path} (${result.tokens} tokens)`);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function runRecoveryShow({ args, options, logger }) {
|
|
27
|
+
const cwd = path.resolve(process.cwd(), args[0] || '.');
|
|
28
|
+
const content = await readSessionRecovery(cwd);
|
|
29
|
+
|
|
30
|
+
if (!content) {
|
|
31
|
+
logger.log('No recovery context found. Run: aioson recovery:generate');
|
|
32
|
+
return { ok: false, error: 'not_found' };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (options.json) {
|
|
36
|
+
return { ok: true, content };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
logger.log(content);
|
|
40
|
+
return { ok: true, content };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { runRecoveryGenerate, runRecoveryShow };
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
6
|
+
const {
|
|
7
|
+
ensureRunnerQueue,
|
|
8
|
+
listTasks,
|
|
9
|
+
nextPending,
|
|
10
|
+
updateTaskStatus
|
|
11
|
+
} = require('../runner/queue-store');
|
|
12
|
+
const { launchCLI } = require('../runner/cli-launcher');
|
|
13
|
+
const { runWithCascade, parseCascadeChain } = require('../runner/cascade');
|
|
14
|
+
|
|
15
|
+
const DAEMON_DDL = `
|
|
16
|
+
CREATE TABLE IF NOT EXISTS runner_daemon (
|
|
17
|
+
id INTEGER PRIMARY KEY,
|
|
18
|
+
status TEXT NOT NULL DEFAULT 'stopped',
|
|
19
|
+
pid INTEGER,
|
|
20
|
+
agent TEXT NOT NULL DEFAULT 'dev',
|
|
21
|
+
poll_ms INTEGER NOT NULL DEFAULT 10000,
|
|
22
|
+
current_task INTEGER,
|
|
23
|
+
heartbeat TEXT,
|
|
24
|
+
started_at TEXT,
|
|
25
|
+
stopped_at TEXT
|
|
26
|
+
);
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
const DAEMON_ROW_ID = 1;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* aioson runner:daemon — daemon que processa a fila do runner em background.
|
|
33
|
+
*
|
|
34
|
+
* Subcomandos:
|
|
35
|
+
* start <path> [--agent=dev] [--poll=10]
|
|
36
|
+
* stop <path>
|
|
37
|
+
* status <path>
|
|
38
|
+
*/
|
|
39
|
+
async function runRunnerDaemon({ args, options = {}, logger }) {
|
|
40
|
+
const sub = options.sub || args[1] || 'status';
|
|
41
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
42
|
+
|
|
43
|
+
switch (sub) {
|
|
44
|
+
case 'start': return await handleStart(projectDir, options, logger);
|
|
45
|
+
case 'stop': return await handleStop(projectDir, logger);
|
|
46
|
+
case 'status': return await handleStatus(projectDir, logger);
|
|
47
|
+
default:
|
|
48
|
+
logger.error(`Unknown subcommand: ${sub}. Use start, stop, or status.`);
|
|
49
|
+
return { ok: false };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
function ensureDaemonTable(db) {
|
|
56
|
+
db.exec(DAEMON_DDL);
|
|
57
|
+
ensureRunnerQueue(db);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function getDaemonRow(db) {
|
|
61
|
+
return db.prepare('SELECT * FROM runner_daemon WHERE id = ?').get(DAEMON_ROW_ID);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function upsertDaemonRow(db, fields) {
|
|
65
|
+
const existing = getDaemonRow(db);
|
|
66
|
+
if (existing) {
|
|
67
|
+
const keys = Object.keys(fields);
|
|
68
|
+
const sets = keys.map((k) => `${k} = ?`).join(', ');
|
|
69
|
+
db.prepare(`UPDATE runner_daemon SET ${sets} WHERE id = ?`).run(...Object.values(fields), DAEMON_ROW_ID);
|
|
70
|
+
} else {
|
|
71
|
+
db.prepare(`
|
|
72
|
+
INSERT INTO runner_daemon (id, ${Object.keys(fields).join(', ')})
|
|
73
|
+
VALUES (${DAEMON_ROW_ID}, ${Object.keys(fields).map(() => '?').join(', ')})
|
|
74
|
+
`).run(...Object.values(fields));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ── Subcommand handlers ───────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
async function handleStatus(projectDir, logger) {
|
|
81
|
+
let handle;
|
|
82
|
+
try {
|
|
83
|
+
handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
84
|
+
} catch { /* noop */ }
|
|
85
|
+
|
|
86
|
+
if (!handle) {
|
|
87
|
+
logger.log('[runner:daemon] No runtime database found. Use `runner:daemon start` to begin.');
|
|
88
|
+
return { ok: true, status: 'not_initialized' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const { db } = handle;
|
|
92
|
+
ensureDaemonTable(db);
|
|
93
|
+
const row = getDaemonRow(db);
|
|
94
|
+
|
|
95
|
+
const pending = listTasks(db, { status: 'pending' }).length;
|
|
96
|
+
const running = listTasks(db, { status: 'running' }).length;
|
|
97
|
+
const completed = listTasks(db, { status: 'completed' }).length;
|
|
98
|
+
const failed = listTasks(db, { status: 'failed' }).length;
|
|
99
|
+
|
|
100
|
+
try { db.close(); } catch { /* noop */ }
|
|
101
|
+
|
|
102
|
+
if (!row || row.status === 'stopped') {
|
|
103
|
+
logger.log('[runner:daemon] Daemon is stopped.');
|
|
104
|
+
} else {
|
|
105
|
+
const icon = row.status === 'running' ? '[*]' : '[ ]';
|
|
106
|
+
logger.log(`${icon} runner-daemon ${row.status} (pid: ${row.pid || '-'})`);
|
|
107
|
+
logger.log(` Queue: ${pending} pending | ${running} running | ${completed} completed | ${failed} failed`);
|
|
108
|
+
if (row.current_task) logger.log(` Current task: #${row.current_task}`);
|
|
109
|
+
if (row.heartbeat) logger.log(` Last heartbeat: ${row.heartbeat}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { ok: true, row, stats: { pending, running, completed, failed } };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function handleStop(projectDir, logger) {
|
|
116
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
117
|
+
if (!handle) {
|
|
118
|
+
logger.error('[runner:daemon] No runtime database found.');
|
|
119
|
+
return { ok: false };
|
|
120
|
+
}
|
|
121
|
+
const { db } = handle;
|
|
122
|
+
ensureDaemonTable(db);
|
|
123
|
+
const row = getDaemonRow(db);
|
|
124
|
+
|
|
125
|
+
if (!row || row.status === 'stopped') {
|
|
126
|
+
logger.log('[runner:daemon] Daemon is not running.');
|
|
127
|
+
try { db.close(); } catch { /* noop */ }
|
|
128
|
+
return { ok: true };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (row.pid) {
|
|
132
|
+
try {
|
|
133
|
+
process.kill(row.pid, 'SIGTERM');
|
|
134
|
+
logger.log(`[runner:daemon] Sent SIGTERM to pid ${row.pid}`);
|
|
135
|
+
} catch {
|
|
136
|
+
logger.log(`[runner:daemon] Process ${row.pid} already gone.`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
upsertDaemonRow(db, { status: 'stopped', pid: null, stopped_at: new Date().toISOString() });
|
|
141
|
+
try { db.close(); } catch { /* noop */ }
|
|
142
|
+
|
|
143
|
+
logger.log('[runner:daemon] Daemon stopped.');
|
|
144
|
+
return { ok: true };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function handleStart(projectDir, options, logger) {
|
|
148
|
+
const agent = options.agent || 'dev';
|
|
149
|
+
const pollMs = options.poll ? Number(options.poll) * 1000 : 10000;
|
|
150
|
+
const timeout = options.timeout ? Number(options.timeout) * 1000 : 120000;
|
|
151
|
+
|
|
152
|
+
const handle = await openRuntimeDb(projectDir, {});
|
|
153
|
+
if (!handle) {
|
|
154
|
+
logger.error('Could not open runtime database.');
|
|
155
|
+
return { ok: false };
|
|
156
|
+
}
|
|
157
|
+
const { db } = handle;
|
|
158
|
+
ensureDaemonTable(db);
|
|
159
|
+
|
|
160
|
+
// Marca daemon como running
|
|
161
|
+
upsertDaemonRow(db, {
|
|
162
|
+
status: 'running',
|
|
163
|
+
pid: process.pid,
|
|
164
|
+
agent,
|
|
165
|
+
poll_ms: pollMs,
|
|
166
|
+
started_at: new Date().toISOString(),
|
|
167
|
+
heartbeat: new Date().toISOString()
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
logger.log(`[runner:daemon] Started (pid: ${process.pid}, agent: @${agent}, poll: ${pollMs / 1000}s)`);
|
|
171
|
+
logger.log('[runner:daemon] Press Ctrl+C to stop gracefully.');
|
|
172
|
+
|
|
173
|
+
let stopping = false;
|
|
174
|
+
let currentTaskId = null;
|
|
175
|
+
|
|
176
|
+
const onSignal = () => {
|
|
177
|
+
if (stopping) return;
|
|
178
|
+
stopping = true;
|
|
179
|
+
logger.log('\n[runner:daemon] Stopping after current task completes...');
|
|
180
|
+
upsertDaemonRow(db, { status: 'stopping' });
|
|
181
|
+
};
|
|
182
|
+
process.once('SIGINT', onSignal);
|
|
183
|
+
process.once('SIGTERM', onSignal);
|
|
184
|
+
|
|
185
|
+
// Heartbeat a cada 30s
|
|
186
|
+
const heartbeatInterval = setInterval(() => {
|
|
187
|
+
try {
|
|
188
|
+
upsertDaemonRow(db, { heartbeat: new Date().toISOString() });
|
|
189
|
+
} catch { /* noop */ }
|
|
190
|
+
}, 30000);
|
|
191
|
+
|
|
192
|
+
// Loop principal
|
|
193
|
+
while (!stopping) {
|
|
194
|
+
const task = nextPending(db);
|
|
195
|
+
|
|
196
|
+
if (!task) {
|
|
197
|
+
await sleep(pollMs);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
currentTaskId = task.id;
|
|
202
|
+
upsertDaemonRow(db, { current_task: task.id });
|
|
203
|
+
updateTaskStatus(db, task.id, { status: 'running' });
|
|
204
|
+
|
|
205
|
+
const taskAgent = task.agent || agent;
|
|
206
|
+
const agentFile = path.join(projectDir, '.aioson', 'agents', `${taskAgent}.md`);
|
|
207
|
+
const prompt = buildDaemonPrompt(task.task, agentFile);
|
|
208
|
+
|
|
209
|
+
logger.log(`\n[runner:daemon] Running task #${task.id}: ${task.task}`);
|
|
210
|
+
logger.log(` Agent: @${taskAgent}`);
|
|
211
|
+
|
|
212
|
+
let result;
|
|
213
|
+
const cascadeChain = parseCascadeChain(task.cascade);
|
|
214
|
+
|
|
215
|
+
try {
|
|
216
|
+
if (cascadeChain.length > 0) {
|
|
217
|
+
const cr = await runWithCascade(projectDir, prompt, cascadeChain, {
|
|
218
|
+
timeout,
|
|
219
|
+
onProgress: ({ model, attempt, maxAttempts, status: s, reason }) => {
|
|
220
|
+
if (s === 'running') logger.log(` [cascade] ${model} attempt ${attempt}/${maxAttempts}...`);
|
|
221
|
+
else if (s === 'gate_failed') logger.log(` [cascade] ${model} attempt ${attempt} — gate failed${reason ? ': ' + reason : ''}`);
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
result = cr.ok ? cr.result : { ok: false, error: cr.error };
|
|
225
|
+
} else {
|
|
226
|
+
result = await launchCLI(projectDir, prompt, { timeout });
|
|
227
|
+
}
|
|
228
|
+
} catch (err) {
|
|
229
|
+
result = { ok: false, error: err.message };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (result.ok) {
|
|
233
|
+
updateTaskStatus(db, task.id, { status: 'completed', resultOk: true });
|
|
234
|
+
logger.log(` [runner:daemon] Task #${task.id} completed`);
|
|
235
|
+
} else {
|
|
236
|
+
const errorMsg = result.error || result.stderr || 'unknown error';
|
|
237
|
+
updateTaskStatus(db, task.id, { status: 'failed', resultOk: false, errorMsg });
|
|
238
|
+
logger.error(` [runner:daemon] Task #${task.id} failed: ${errorMsg}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
currentTaskId = null;
|
|
242
|
+
upsertDaemonRow(db, { current_task: null, heartbeat: new Date().toISOString() });
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
clearInterval(heartbeatInterval);
|
|
246
|
+
upsertDaemonRow(db, {
|
|
247
|
+
status: 'stopped',
|
|
248
|
+
pid: null,
|
|
249
|
+
current_task: null,
|
|
250
|
+
stopped_at: new Date().toISOString()
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
try { db.close(); } catch { /* noop */ }
|
|
254
|
+
logger.log('[runner:daemon] Stopped gracefully.');
|
|
255
|
+
return { ok: true };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function buildDaemonPrompt(task, agentFile) {
|
|
259
|
+
return [
|
|
260
|
+
'You are operating in autonomous headless mode. Complete the following task independently.',
|
|
261
|
+
`Agent role: read ${agentFile} for your operating instructions.`,
|
|
262
|
+
'',
|
|
263
|
+
`Task: ${task}`,
|
|
264
|
+
'',
|
|
265
|
+
'When the task is complete, write TASK_COMPLETE on a new line as the final output.',
|
|
266
|
+
'If you cannot complete the task, write TASK_FAILED: [reason].'
|
|
267
|
+
].join('\n');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function sleep(ms) {
|
|
271
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
module.exports = { runRunnerDaemon };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
5
|
+
const { ensureRunnerQueue, addTask, listTasks } = require('../runner/queue-store');
|
|
6
|
+
const { importFromPlan } = require('../runner/plan-importer');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* aioson runner:plan — importa phases de um implementation-plan.md para a queue do runner.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* aioson runner:plan . --slug=checkout --agent=dev
|
|
13
|
+
* aioson runner:plan . --slug=checkout (usa agent=dev por padrão)
|
|
14
|
+
*/
|
|
15
|
+
async function runRunnerPlan({ args, options = {}, logger }) {
|
|
16
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
17
|
+
const { slug, agent = 'dev' } = options;
|
|
18
|
+
|
|
19
|
+
if (!slug) {
|
|
20
|
+
logger.error('--slug is required. Example: aioson runner:plan . --slug=checkout');
|
|
21
|
+
return { ok: false };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let importResult;
|
|
25
|
+
try {
|
|
26
|
+
importResult = await importFromPlan(projectDir, slug, { agent });
|
|
27
|
+
} catch (err) {
|
|
28
|
+
logger.error(`[runner:plan] ${err.message}`);
|
|
29
|
+
return { ok: false, error: err.message };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const { tasks, planPath } = importResult;
|
|
33
|
+
|
|
34
|
+
if (tasks.length === 0) {
|
|
35
|
+
logger.error(
|
|
36
|
+
`[runner:plan] No phases found in implementation-plan-${slug}.md.\n` +
|
|
37
|
+
' Expected sections like: ## Phase 1 — Create migration\n' +
|
|
38
|
+
' Add phase headings to the plan and try again.'
|
|
39
|
+
);
|
|
40
|
+
return { ok: false, error: 'no_phases_found' };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const handle = await openRuntimeDb(projectDir, {});
|
|
44
|
+
if (!handle) {
|
|
45
|
+
logger.error('Could not open runtime database.');
|
|
46
|
+
return { ok: false };
|
|
47
|
+
}
|
|
48
|
+
const { db } = handle;
|
|
49
|
+
ensureRunnerQueue(db);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
for (const t of tasks) {
|
|
53
|
+
addTask(db, { task: t.task, agent: t.agent });
|
|
54
|
+
}
|
|
55
|
+
} finally {
|
|
56
|
+
try { db.close(); } catch { /* noop */ }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const relPath = path.relative(projectDir, planPath);
|
|
60
|
+
logger.log(`[runner:plan] Imported ${tasks.length} task(s) from ${relPath}:`);
|
|
61
|
+
for (const t of tasks) {
|
|
62
|
+
logger.log(` ○ @${t.agent} ${t.task}`);
|
|
63
|
+
}
|
|
64
|
+
logger.log('');
|
|
65
|
+
logger.log('Run with: aioson runner:queue run .');
|
|
66
|
+
|
|
67
|
+
return { ok: true, tasks, planPath };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { runRunnerPlan };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson runner:queue:from-plan — import phases from an implementation plan into the runner queue.
|
|
5
|
+
*
|
|
6
|
+
* Reads an implementation-plan-{slug}.md, extracts phases, and creates runner queue
|
|
7
|
+
* tasks with dependency ordering. No LLM calls.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson runner:queue:from-plan . --plan=.aioson/context/implementation-plan-checkout.md
|
|
11
|
+
* aioson runner:queue:from-plan . --feature=checkout
|
|
12
|
+
* aioson runner:queue:from-plan . --feature=checkout --agent=dev --dry-run
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const { readFileSafe, contextDir } = require('../preflight-engine');
|
|
17
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
18
|
+
const { ensureRunnerQueue, addTask } = require('../runner/queue-store');
|
|
19
|
+
|
|
20
|
+
// Phase extraction patterns
|
|
21
|
+
const PHASE_PATTERNS = [
|
|
22
|
+
// "## Phase 1: Create migration" or "## Phase 1 — Create migration"
|
|
23
|
+
/^#{2,3}\s+[Pp]hase\s+(\d+)[:\s—-]+(.+)$/m,
|
|
24
|
+
// "### 1. Create migration"
|
|
25
|
+
/^#{2,3}\s+(\d+)\.\s+(.+)$/m,
|
|
26
|
+
// "**Phase 1:** Create migration"
|
|
27
|
+
/^\*\*[Pp]hase\s+(\d+)[:\s—-]+\*\*\s*(.+)$/m
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function extractPhases(content) {
|
|
31
|
+
const phases = [];
|
|
32
|
+
const lines = content.split(/\r?\n/);
|
|
33
|
+
let currentPhase = null;
|
|
34
|
+
let currentDescription = [];
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
const line = lines[i];
|
|
38
|
+
|
|
39
|
+
// Try all phase header patterns
|
|
40
|
+
let matched = false;
|
|
41
|
+
for (const pattern of PHASE_PATTERNS) {
|
|
42
|
+
const m = line.match(pattern);
|
|
43
|
+
if (m) {
|
|
44
|
+
// Save previous phase
|
|
45
|
+
if (currentPhase) {
|
|
46
|
+
currentPhase.detail = currentDescription.join(' ').trim().slice(0, 200);
|
|
47
|
+
phases.push(currentPhase);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const num = parseInt(m[1]);
|
|
51
|
+
const title = m[2].trim().replace(/\*+/g, '');
|
|
52
|
+
currentPhase = { num, title, detail: '', lines: [line] };
|
|
53
|
+
currentDescription = [];
|
|
54
|
+
matched = true;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!matched && currentPhase) {
|
|
60
|
+
// Collect phase description from bullet points or short lines
|
|
61
|
+
const bullet = line.match(/^[-*]\s+(.+)$/);
|
|
62
|
+
if (bullet) currentDescription.push(bullet[1]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Save last phase
|
|
67
|
+
if (currentPhase) {
|
|
68
|
+
currentPhase.detail = currentDescription.join(' ').trim().slice(0, 200);
|
|
69
|
+
phases.push(currentPhase);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Fallback: try H3 headings as phases if nothing found
|
|
73
|
+
if (phases.length === 0) {
|
|
74
|
+
const h3Re = /^###\s+(.+)$/gm;
|
|
75
|
+
let m, num = 1;
|
|
76
|
+
while ((m = h3Re.exec(content)) !== null) {
|
|
77
|
+
phases.push({ num: num++, title: m[1].trim(), detail: '' });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return phases;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function runRunnerQueueFromPlan({ args, options = {}, logger }) {
|
|
85
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
86
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
87
|
+
const agent = options.agent ? String(options.agent) : 'dev';
|
|
88
|
+
const dryRun = Boolean(options['dry-run'] || options.dry);
|
|
89
|
+
|
|
90
|
+
// Resolve plan file
|
|
91
|
+
let planPath = options.plan ? path.resolve(targetDir, options.plan) : null;
|
|
92
|
+
if (!planPath && slug) {
|
|
93
|
+
planPath = path.join(contextDir(targetDir), `implementation-plan-${slug}.md`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!planPath) {
|
|
97
|
+
if (options.json) return { ok: false, reason: 'no_plan', message: 'Provide --plan=<path> or --feature=<slug>' };
|
|
98
|
+
logger.log('Provide --plan=<path> or --feature=<slug>.');
|
|
99
|
+
return { ok: false };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const content = await readFileSafe(planPath);
|
|
103
|
+
if (!content) {
|
|
104
|
+
if (options.json) return { ok: false, reason: 'file_not_found', path: planPath };
|
|
105
|
+
logger.log(`Plan file not found: ${path.relative(targetDir, planPath)}`);
|
|
106
|
+
return { ok: false };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const phases = extractPhases(content);
|
|
110
|
+
|
|
111
|
+
if (phases.length === 0) {
|
|
112
|
+
if (options.json) return { ok: false, reason: 'no_phases', message: 'No phases found in plan file' };
|
|
113
|
+
logger.log('No phases found in plan file. Expected "## Phase N: title" headings.');
|
|
114
|
+
return { ok: false };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
logger.log(`Importing ${phases.length} phases from ${path.relative(targetDir, planPath)}:`);
|
|
118
|
+
|
|
119
|
+
if (dryRun) {
|
|
120
|
+
for (const phase of phases) {
|
|
121
|
+
const dep = phase.num > 1 ? ` (depends: Phase ${phase.num - 1})` : '';
|
|
122
|
+
logger.log(` Phase ${phase.num}: "${phase.title}"${dep} → would queue (priority: ${phase.num})`);
|
|
123
|
+
}
|
|
124
|
+
logger.log(`\n[dry-run] ${phases.length} tasks would be queued for @${agent}`);
|
|
125
|
+
return { ok: true, dry_run: true, phases, agent };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Open runtime DB and queue tasks
|
|
129
|
+
const handle = await openRuntimeDb(targetDir, {});
|
|
130
|
+
if (!handle) {
|
|
131
|
+
if (options.json) return { ok: false, reason: 'no_runtime' };
|
|
132
|
+
logger.log('Could not open runtime database.');
|
|
133
|
+
return { ok: false };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const { db } = handle;
|
|
137
|
+
ensureRunnerQueue(db);
|
|
138
|
+
|
|
139
|
+
const queued = [];
|
|
140
|
+
try {
|
|
141
|
+
for (const phase of phases) {
|
|
142
|
+
const taskDesc = phase.detail
|
|
143
|
+
? `Phase ${phase.num}: ${phase.title} — ${phase.detail}`
|
|
144
|
+
: `Phase ${phase.num}: ${phase.title}`;
|
|
145
|
+
|
|
146
|
+
const id = addTask(db, {
|
|
147
|
+
task: taskDesc,
|
|
148
|
+
agent,
|
|
149
|
+
cascade: options.cascade || null,
|
|
150
|
+
priority: phase.num
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
queued.push({ id, phase: phase.num, title: phase.title });
|
|
154
|
+
const dep = phase.num > 1 ? ` (depends: Phase ${phase.num - 1})` : '';
|
|
155
|
+
logger.log(` Phase ${phase.num}: "${phase.title}"${dep} → queued (id: ${id}, priority: ${phase.num})`);
|
|
156
|
+
}
|
|
157
|
+
} finally {
|
|
158
|
+
try { db.close(); } catch { /* noop */ }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
logger.log(`\n${queued.length} tasks queued. Run: aioson runner:queue list`);
|
|
162
|
+
|
|
163
|
+
return { ok: true, plan_path: path.relative(targetDir, planPath), agent, queued };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
module.exports = { runRunnerQueueFromPlan };
|