@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,189 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
5
|
+
const {
|
|
6
|
+
ensureRunnerQueue,
|
|
7
|
+
addTask,
|
|
8
|
+
listTasks,
|
|
9
|
+
nextPending,
|
|
10
|
+
updateTaskStatus,
|
|
11
|
+
clearQueue,
|
|
12
|
+
exportQueueMarkdown
|
|
13
|
+
} = require('../runner/queue-store');
|
|
14
|
+
const { launchCLI } = require('../runner/cli-launcher');
|
|
15
|
+
const { runWithCascade, parseCascadeChain } = require('../runner/cascade');
|
|
16
|
+
|
|
17
|
+
const STATUS_ICON = {
|
|
18
|
+
pending: '○',
|
|
19
|
+
running: '▶',
|
|
20
|
+
completed: '✓',
|
|
21
|
+
failed: '✗',
|
|
22
|
+
skipped: '—'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* aioson runner:queue — gerencia e executa a fila de tasks do runner.
|
|
27
|
+
*
|
|
28
|
+
* Subcomandos:
|
|
29
|
+
* add <path> "task description" [--agent=dev] [--cascade=haiku,sonnet]
|
|
30
|
+
* list <path>
|
|
31
|
+
* run <path> [--agent=dev] [--timeout=120]
|
|
32
|
+
* export <path>
|
|
33
|
+
* clear <path>
|
|
34
|
+
*/
|
|
35
|
+
async function runRunnerQueue({ args, options = {}, logger }) {
|
|
36
|
+
const sub = options.sub || args[1] || 'list';
|
|
37
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
38
|
+
|
|
39
|
+
const handle = await openRuntimeDb(projectDir, {});
|
|
40
|
+
if (!handle) {
|
|
41
|
+
logger.error('Could not open runtime database.');
|
|
42
|
+
return { ok: false };
|
|
43
|
+
}
|
|
44
|
+
const { db } = handle;
|
|
45
|
+
ensureRunnerQueue(db);
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
switch (sub) {
|
|
49
|
+
case 'add': return await handleAdd(db, args, options, logger);
|
|
50
|
+
case 'list': return handleList(db, logger);
|
|
51
|
+
case 'run': return await handleRun(db, projectDir, options, logger);
|
|
52
|
+
case 'export': return handleExport(db, logger);
|
|
53
|
+
case 'clear': return handleClear(db, logger);
|
|
54
|
+
default:
|
|
55
|
+
logger.error(`Unknown subcommand: ${sub}. Use add, list, run, export, or clear.`);
|
|
56
|
+
return { ok: false };
|
|
57
|
+
}
|
|
58
|
+
} finally {
|
|
59
|
+
try { db.close(); } catch { /* noop */ }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function handleAdd(db, args, options, logger) {
|
|
64
|
+
// Task pode vir de args[2] ou --task
|
|
65
|
+
const task = options.task || args[2];
|
|
66
|
+
if (!task) {
|
|
67
|
+
logger.error('Task description required. Usage: aioson runner:queue add . "task description"');
|
|
68
|
+
return { ok: false };
|
|
69
|
+
}
|
|
70
|
+
const agent = options.agent || 'dev';
|
|
71
|
+
const cascade = options.cascade || null;
|
|
72
|
+
const priority = options.priority ? Number(options.priority) : 0;
|
|
73
|
+
|
|
74
|
+
const id = addTask(db, { task, agent, cascade, priority });
|
|
75
|
+
logger.log(`[runner:queue] Added task #${id}: ${task}`);
|
|
76
|
+
logger.log(` Agent: @${agent}${cascade ? ' | Cascade: ' + cascade : ''}`);
|
|
77
|
+
return { ok: true, id };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function handleList(db, logger) {
|
|
81
|
+
const tasks = listTasks(db);
|
|
82
|
+
if (tasks.length === 0) {
|
|
83
|
+
logger.log('[runner:queue] Queue is empty. Use `runner:queue add` to add tasks.');
|
|
84
|
+
return { ok: true, tasks: [] };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
logger.log(`[runner:queue] ${tasks.length} task(s):`);
|
|
88
|
+
for (const t of tasks) {
|
|
89
|
+
const icon = STATUS_ICON[t.status] || '?';
|
|
90
|
+
const cascade = t.cascade ? ` [cascade: ${t.cascade}]` : '';
|
|
91
|
+
logger.log(` ${icon} ${t.id} @${t.agent}${cascade} ${t.task}`);
|
|
92
|
+
}
|
|
93
|
+
return { ok: true, tasks };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function handleRun(db, projectDir, options, logger) {
|
|
97
|
+
const defaultAgent = options.agent || 'dev';
|
|
98
|
+
const timeout = options.timeout ? Number(options.timeout) * 1000 : 120000;
|
|
99
|
+
|
|
100
|
+
let processed = 0;
|
|
101
|
+
let failed = 0;
|
|
102
|
+
|
|
103
|
+
logger.log('[runner:queue] Starting queue execution...');
|
|
104
|
+
|
|
105
|
+
// eslint-disable-next-line no-constant-condition
|
|
106
|
+
while (true) {
|
|
107
|
+
const task = nextPending(db);
|
|
108
|
+
if (!task) {
|
|
109
|
+
logger.log(`[runner:queue] Queue exhausted. ${processed} completed, ${failed} failed.`);
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const agent = task.agent || defaultAgent;
|
|
114
|
+
const agentFile = path.join(projectDir, '.aioson', 'agents', `${agent}.md`);
|
|
115
|
+
const prompt = buildQueuePrompt(task.task, agentFile);
|
|
116
|
+
|
|
117
|
+
logger.log(`\n[runner:queue] Running task #${task.id}: ${task.task}`);
|
|
118
|
+
logger.log(` Agent: @${agent}`);
|
|
119
|
+
|
|
120
|
+
updateTaskStatus(db, task.id, { status: 'running' });
|
|
121
|
+
|
|
122
|
+
let result;
|
|
123
|
+
const cascadeChain = parseCascadeChain(task.cascade);
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
if (cascadeChain.length > 0) {
|
|
127
|
+
const cascadeResult = await runWithCascade(projectDir, prompt, cascadeChain, {
|
|
128
|
+
timeout,
|
|
129
|
+
onProgress: ({ model, attempt, maxAttempts, status, reason }) => {
|
|
130
|
+
if (status === 'running') {
|
|
131
|
+
logger.log(` [cascade] ${model} attempt ${attempt}/${maxAttempts}...`);
|
|
132
|
+
} else if (status === 'gate_failed') {
|
|
133
|
+
logger.log(` [cascade] ${model} attempt ${attempt} — gate failed${reason ? ': ' + reason : ''}, escalating...`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
result = cascadeResult.ok
|
|
138
|
+
? cascadeResult.result
|
|
139
|
+
: { ok: false, output: '', error: cascadeResult.error };
|
|
140
|
+
} else {
|
|
141
|
+
result = await launchCLI(projectDir, prompt, {
|
|
142
|
+
timeout,
|
|
143
|
+
onData: (chunk) => process.stdout.write(chunk)
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
} catch (err) {
|
|
147
|
+
result = { ok: false, output: '', error: err.message };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (result.ok) {
|
|
151
|
+
updateTaskStatus(db, task.id, { status: 'completed', resultOk: true });
|
|
152
|
+
logger.log(` [runner:queue] Task #${task.id} completed`);
|
|
153
|
+
processed++;
|
|
154
|
+
} else {
|
|
155
|
+
const errorMsg = result.error || result.stderr || 'unknown error';
|
|
156
|
+
updateTaskStatus(db, task.id, { status: 'failed', resultOk: false, errorMsg });
|
|
157
|
+
logger.error(` [runner:queue] Task #${task.id} failed: ${errorMsg}`);
|
|
158
|
+
failed++;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return { ok: true, processed, failed };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function handleExport(db, logger) {
|
|
166
|
+
const markdown = exportQueueMarkdown(db);
|
|
167
|
+
process.stdout.write(markdown);
|
|
168
|
+
return { ok: true };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function handleClear(db, logger) {
|
|
172
|
+
clearQueue(db);
|
|
173
|
+
logger.log('[runner:queue] Queue cleared.');
|
|
174
|
+
return { ok: true };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function buildQueuePrompt(task, agentFile) {
|
|
178
|
+
return [
|
|
179
|
+
'You are operating in autonomous headless mode. Complete the following task independently.',
|
|
180
|
+
`Agent role: read ${agentFile} for your operating instructions.`,
|
|
181
|
+
'',
|
|
182
|
+
`Task: ${task}`,
|
|
183
|
+
'',
|
|
184
|
+
'When the task is complete, write TASK_COMPLETE on a new line as the final output.',
|
|
185
|
+
'If you cannot complete the task, write TASK_FAILED: [reason].'
|
|
186
|
+
].join('\n');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = { runRunnerQueue };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { launchCLI, detectCLI } = require('../runner/cli-launcher');
|
|
5
|
+
const { runWithCascade, parseCascadeChain } = require('../runner/cascade');
|
|
6
|
+
const { openRuntimeDb, startRun, updateRun, createRunKey } = require('../runtime-store');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* aioson runner:run — executa uma única task headless usando o CLI de AI ativo.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* aioson runner:run . --task="Fix the auth modal" --agent=dev
|
|
13
|
+
* aioson runner:run . --task="..." --agent=qa --timeout=300
|
|
14
|
+
* aioson runner:run . --task="..." --agent=dev --cascade=haiku,sonnet
|
|
15
|
+
* aioson runner:run . --task="..." --dry-run
|
|
16
|
+
*/
|
|
17
|
+
async function runRunnerRun({ args, options = {}, logger }) {
|
|
18
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
19
|
+
const { task, agent = 'dev', dryRun, cascade: cascadeStr } = options;
|
|
20
|
+
const timeout = options.timeout ? Number(options.timeout) * 1000 : 120000;
|
|
21
|
+
|
|
22
|
+
if (!task) {
|
|
23
|
+
logger.error('--task is required. Example: aioson runner:run . --task="Fix the login modal"');
|
|
24
|
+
return { ok: false };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const agentFile = path.join(projectDir, '.aioson', 'agents', `${agent}.md`);
|
|
28
|
+
const prompt = buildRunnerPrompt(task, agentFile);
|
|
29
|
+
|
|
30
|
+
if (dryRun) {
|
|
31
|
+
let cli;
|
|
32
|
+
try { cli = await detectCLI(); } catch { cli = 'claude'; }
|
|
33
|
+
logger.log(`[dry-run] Would run: ${cli} -p "${prompt.slice(0, 120)}..."`);
|
|
34
|
+
logger.log(`[dry-run] Agent: @${agent} | Timeout: ${timeout / 1000}s`);
|
|
35
|
+
if (cascadeStr) logger.log(`[dry-run] Cascade: ${cascadeStr}`);
|
|
36
|
+
return { ok: true, dryRun: true };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
logger.log(`[runner] Task: ${task}`);
|
|
40
|
+
logger.log(`[runner] Agent: @${agent} | Timeout: ${timeout / 1000}s`);
|
|
41
|
+
if (cascadeStr) logger.log(`[runner] Cascade: ${cascadeStr}`);
|
|
42
|
+
|
|
43
|
+
const start = Date.now();
|
|
44
|
+
|
|
45
|
+
// Abre DB para registrar evento (melhor esforço — não bloqueia se não existir)
|
|
46
|
+
let db = null;
|
|
47
|
+
let runKey = null;
|
|
48
|
+
try {
|
|
49
|
+
const handle = await openRuntimeDb(projectDir, {});
|
|
50
|
+
if (handle) {
|
|
51
|
+
db = handle.db;
|
|
52
|
+
runKey = createRunKey(agent);
|
|
53
|
+
startRun(db, {
|
|
54
|
+
runKey,
|
|
55
|
+
agentName: agent,
|
|
56
|
+
agentKind: 'runner',
|
|
57
|
+
source: 'runner',
|
|
58
|
+
title: task.slice(0, 80),
|
|
59
|
+
status: 'running',
|
|
60
|
+
message: `Runner task started: ${task.slice(0, 80)}`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} catch { /* dashboard logging is best-effort */ }
|
|
64
|
+
|
|
65
|
+
let result;
|
|
66
|
+
const cascadeChain = parseCascadeChain(cascadeStr);
|
|
67
|
+
|
|
68
|
+
if (cascadeChain.length > 0) {
|
|
69
|
+
const cascadeResult = await runWithCascade(projectDir, prompt, cascadeChain, {
|
|
70
|
+
timeout,
|
|
71
|
+
onProgress: ({ model, attempt, maxAttempts, status, reason }) => {
|
|
72
|
+
if (status === 'running') {
|
|
73
|
+
logger.log(`[cascade] ${model} attempt ${attempt}/${maxAttempts}...`);
|
|
74
|
+
} else if (status === 'gate_failed') {
|
|
75
|
+
logger.log(`[cascade] ${model} attempt ${attempt} — gate failed${reason ? ': ' + reason : ''}, escalating...`);
|
|
76
|
+
} else if (status === 'cli_failed') {
|
|
77
|
+
logger.log(`[cascade] ${model} attempt ${attempt} — CLI failed, retrying...`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (cascadeResult.ok) {
|
|
82
|
+
result = cascadeResult.result;
|
|
83
|
+
logger.log(`[runner] Completed via ${cascadeResult.modelUsed} (attempt ${cascadeResult.attempts})`);
|
|
84
|
+
} else {
|
|
85
|
+
result = { ok: false, output: '', completionMarker: false };
|
|
86
|
+
logger.error(`[runner] ${cascadeResult.error}`);
|
|
87
|
+
}
|
|
88
|
+
} else {
|
|
89
|
+
result = await launchCLI(projectDir, prompt, {
|
|
90
|
+
timeout,
|
|
91
|
+
onData: (chunk) => process.stdout.write(chunk)
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
96
|
+
const status = result.ok ? 'completed' : 'failed';
|
|
97
|
+
|
|
98
|
+
logger.log(`\n[runner] Task ${status} in ${elapsed}s`);
|
|
99
|
+
if (result.completionMarker) logger.log('[runner] TASK_COMPLETE marker detected');
|
|
100
|
+
|
|
101
|
+
// Atualiza run no dashboard
|
|
102
|
+
if (db && runKey) {
|
|
103
|
+
try {
|
|
104
|
+
updateRun(db, {
|
|
105
|
+
runKey,
|
|
106
|
+
status,
|
|
107
|
+
message: `Runner task ${status}: ${task.slice(0, 80)}`,
|
|
108
|
+
payload: { task, agent, elapsed, ok: result.ok, completionMarker: result.completionMarker }
|
|
109
|
+
});
|
|
110
|
+
} catch { /* best-effort */ }
|
|
111
|
+
try { db.close(); } catch { /* noop */ }
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { ok: result.ok, output: result.output, elapsed, completionMarker: result.completionMarker };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function buildRunnerPrompt(task, agentFile) {
|
|
118
|
+
return [
|
|
119
|
+
'You are operating in autonomous headless mode. Complete the following task independently.',
|
|
120
|
+
`Agent role: read ${agentFile} for your operating instructions.`,
|
|
121
|
+
'',
|
|
122
|
+
`Task: ${task}`,
|
|
123
|
+
'',
|
|
124
|
+
'When the task is complete, write TASK_COMPLETE on a new line as the final output.',
|
|
125
|
+
'If you cannot complete the task, write TASK_FAILED: [reason].'
|
|
126
|
+
].join('\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = { runRunnerRun };
|
package/src/commands/runtime.js
CHANGED
|
@@ -1179,6 +1179,11 @@ async function runAgentDone({ args, options = {}, logger, t }) {
|
|
|
1179
1179
|
const summary = String(options.summary || options.message || `${normalizedAgent} session completed`).trim();
|
|
1180
1180
|
const title = options.title ? String(options.title).trim() : null;
|
|
1181
1181
|
const status = options.status || 'completed';
|
|
1182
|
+
const verdict = options.verdict ? String(options.verdict).trim().toUpperCase() : null;
|
|
1183
|
+
const planStepId = options['plan-step'] ? String(options['plan-step']).trim() : null;
|
|
1184
|
+
const artifactPaths = options.artifacts
|
|
1185
|
+
? String(options.artifacts).split(',').map((p) => p.trim()).filter(Boolean)
|
|
1186
|
+
: [];
|
|
1182
1187
|
|
|
1183
1188
|
const { db, dbPath, runtimeDir } = await openRuntimeDb(targetDir);
|
|
1184
1189
|
|
|
@@ -1194,9 +1199,24 @@ async function runAgentDone({ args, options = {}, logger, t }) {
|
|
|
1194
1199
|
eventType: 'agent_done',
|
|
1195
1200
|
phase: 'live',
|
|
1196
1201
|
status: 'running',
|
|
1197
|
-
message: summary
|
|
1202
|
+
message: summary,
|
|
1203
|
+
verdict,
|
|
1204
|
+
planStepId
|
|
1198
1205
|
});
|
|
1199
1206
|
|
|
1207
|
+
if (artifactPaths.length > 0) {
|
|
1208
|
+
for (const filePath of artifactPaths) {
|
|
1209
|
+
try {
|
|
1210
|
+
attachArtifact(db, {
|
|
1211
|
+
runKey: session.runKey,
|
|
1212
|
+
agentName: normalizedAgent,
|
|
1213
|
+
kind: 'output',
|
|
1214
|
+
filePath
|
|
1215
|
+
});
|
|
1216
|
+
} catch { /* non-fatal */ }
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1200
1220
|
if (!options.json) {
|
|
1201
1221
|
logger.log(`agent:done — ${normalizedAgent} | live session active, event logged | run: ${session.runKey} (${dbPath})`);
|
|
1202
1222
|
}
|
|
@@ -1219,6 +1239,32 @@ async function runAgentDone({ args, options = {}, logger, t }) {
|
|
|
1219
1239
|
summary
|
|
1220
1240
|
});
|
|
1221
1241
|
|
|
1242
|
+
if (verdict || planStepId) {
|
|
1243
|
+
appendRunEvent(db, {
|
|
1244
|
+
runKey,
|
|
1245
|
+
eventType: 'agent_done',
|
|
1246
|
+
phase: 'direct',
|
|
1247
|
+
status: 'completed',
|
|
1248
|
+
message: summary,
|
|
1249
|
+
verdict,
|
|
1250
|
+
planStepId
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
if (artifactPaths.length > 0) {
|
|
1255
|
+
for (const filePath of artifactPaths) {
|
|
1256
|
+
try {
|
|
1257
|
+
attachArtifact(db, {
|
|
1258
|
+
runKey,
|
|
1259
|
+
taskKey,
|
|
1260
|
+
agentName: normalizedAgent,
|
|
1261
|
+
kind: 'output',
|
|
1262
|
+
filePath
|
|
1263
|
+
});
|
|
1264
|
+
} catch { /* non-fatal */ }
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1222
1268
|
if (!options.json) {
|
|
1223
1269
|
logger.log(`agent:done — ${normalizedAgent} | task: ${taskKey} | run: ${runKey} (${dbPath})`);
|
|
1224
1270
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { executeInSandbox } = require('../sandbox');
|
|
5
|
+
|
|
6
|
+
async function runSandboxExec({ args, options, logger }) {
|
|
7
|
+
const command = args[0] || options.command || '';
|
|
8
|
+
const cwd = path.resolve(process.cwd(), options.cwd || '.');
|
|
9
|
+
const timeout = Number(options.timeout) || 30_000;
|
|
10
|
+
const intent = options.intent || undefined;
|
|
11
|
+
|
|
12
|
+
if (!command) {
|
|
13
|
+
logger.error('Usage: aioson sandbox:exec "<command>" [--timeout=30000] [--cwd=.]');
|
|
14
|
+
return { ok: false, error: 'missing_command' };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const result = await executeInSandbox(command, { cwd, timeout, intent });
|
|
18
|
+
|
|
19
|
+
if (options.json) {
|
|
20
|
+
return { ok: result.ok, ...result };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (result.stdout) {
|
|
24
|
+
logger.log(result.stdout);
|
|
25
|
+
}
|
|
26
|
+
if (result.stderr) {
|
|
27
|
+
logger.error(result.stderr);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (result.timedOut) {
|
|
31
|
+
logger.error(`Command timed out after ${timeout}ms`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return { ok: result.ok, ...result };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = { runSandboxExec };
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson self:loop — Autonomous implement + verify loop
|
|
5
|
+
*
|
|
6
|
+
* Runs an agent task, verifies with verify-gate in a fresh context,
|
|
7
|
+
* and retries with feedback injection on failure.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson self:loop . --agent=dev --task="implement stripe webhook handler" --max-iterations=3
|
|
11
|
+
* aioson self:loop . --agent=dev --task="..." --verification-criteria="all tests pass"
|
|
12
|
+
* aioson self:loop . --agent=dev --task="..." --spec=briefs/phase-1.md --artifact=src/
|
|
13
|
+
*
|
|
14
|
+
* Integrates with:
|
|
15
|
+
* - verify-gate.js for tiered verification (tiers 1–4)
|
|
16
|
+
* - intra-bus.js for recording attempts
|
|
17
|
+
* - state-manager.js for recording final result
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const path = require('node:path');
|
|
21
|
+
const { execSync, execFileSync } = require('node:child_process');
|
|
22
|
+
const { randomUUID } = require('node:crypto');
|
|
23
|
+
const fs = require('node:fs/promises');
|
|
24
|
+
|
|
25
|
+
const bus = require('../squad/intra-bus');
|
|
26
|
+
const stateManager = require('../squad/state-manager');
|
|
27
|
+
|
|
28
|
+
// ─── Agent execution ─────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute an agent task via the aioson CLI.
|
|
32
|
+
* Returns { ok, output, error }.
|
|
33
|
+
*/
|
|
34
|
+
function executeAgent(projectDir, agent, task, feedbackContext, timeoutMs) {
|
|
35
|
+
const prompt = feedbackContext
|
|
36
|
+
? `${task}\n\n---\nPrevious attempt feedback:\n${feedbackContext}`
|
|
37
|
+
: task;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const output = execSync(
|
|
41
|
+
`aioson agent:prompt ${agent} . --tool=claude`,
|
|
42
|
+
{
|
|
43
|
+
cwd: projectDir,
|
|
44
|
+
input: prompt,
|
|
45
|
+
timeout: timeoutMs,
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
maxBuffer: 1024 * 1024 * 5,
|
|
48
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
return { ok: true, output: output.trim() };
|
|
52
|
+
} catch (err) {
|
|
53
|
+
return { ok: false, output: '', error: err.message.slice(0, 500) };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Run verify-gate on the result.
|
|
59
|
+
* Returns { ok, verdict, issues }.
|
|
60
|
+
*/
|
|
61
|
+
async function runVerification(projectDir, spec, artifact, criteria) {
|
|
62
|
+
if (!spec || !artifact) {
|
|
63
|
+
// Fallback: criteria-only verification
|
|
64
|
+
return criteriaOnlyVerify(projectDir, artifact, criteria);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const output = execSync(
|
|
69
|
+
`aioson verify:gate . --spec="${spec}" --artifact="${artifact}" --json`,
|
|
70
|
+
{
|
|
71
|
+
cwd: projectDir,
|
|
72
|
+
timeout: 30_000,
|
|
73
|
+
encoding: 'utf8',
|
|
74
|
+
maxBuffer: 1024 * 1024
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
const result = JSON.parse(output);
|
|
78
|
+
return {
|
|
79
|
+
ok: result.verdict === 'PASS' || result.verdict === 'PASS_WITH_NOTES',
|
|
80
|
+
verdict: result.verdict,
|
|
81
|
+
issues: result.issues || []
|
|
82
|
+
};
|
|
83
|
+
} catch (err) {
|
|
84
|
+
return { ok: false, verdict: 'BLOCKED', issues: [{ message: err.message.slice(0, 200) }] };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Simple criteria-based verification when no spec/artifact is given.
|
|
90
|
+
* Checks if verification criteria strings are present in the output directory.
|
|
91
|
+
*/
|
|
92
|
+
async function criteriaOnlyVerify(projectDir, artifactPath, criteria) {
|
|
93
|
+
if (!criteria) {
|
|
94
|
+
return { ok: true, verdict: 'PASS', issues: [] };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const issues = [];
|
|
98
|
+
const criteriaList = criteria.split(',').map((c) => c.trim());
|
|
99
|
+
|
|
100
|
+
for (const criterion of criteriaList) {
|
|
101
|
+
if (/test/i.test(criterion)) {
|
|
102
|
+
// Check if tests pass
|
|
103
|
+
try {
|
|
104
|
+
execSync('npm test --if-present 2>&1', {
|
|
105
|
+
cwd: projectDir,
|
|
106
|
+
timeout: 60_000,
|
|
107
|
+
encoding: 'utf8'
|
|
108
|
+
});
|
|
109
|
+
} catch {
|
|
110
|
+
issues.push({ message: `Test criterion failed: "${criterion}"` });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
ok: issues.length === 0,
|
|
117
|
+
verdict: issues.length === 0 ? 'PASS' : 'FAIL_WITH_ISSUES',
|
|
118
|
+
issues
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Run the self-implement loop.
|
|
126
|
+
*
|
|
127
|
+
* @param {object} params
|
|
128
|
+
* @returns {Promise<object>} — { ok, iterations, verdict, feedback[] }
|
|
129
|
+
*/
|
|
130
|
+
async function runSelfLoop({ args, options = {}, logger }) {
|
|
131
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
132
|
+
const agent = String(options.agent || options.a || 'dev').trim();
|
|
133
|
+
const task = String(options.task || options.t || '').trim();
|
|
134
|
+
const maxIterations = Math.min(Math.max(Number(options['max-iterations'] || 3), 1), 5);
|
|
135
|
+
const spec = options.spec ? String(options.spec).trim() : null;
|
|
136
|
+
const artifact = options.artifact ? String(options.artifact).trim() : null;
|
|
137
|
+
const criteria = options['verification-criteria'] || options.criteria || '';
|
|
138
|
+
const squad = options.squad ? String(options.squad).trim() : null;
|
|
139
|
+
const timeoutMs = (Number(options.timeout) || 300) * 1000;
|
|
140
|
+
|
|
141
|
+
if (!task) {
|
|
142
|
+
logger.error('Error: --task is required');
|
|
143
|
+
return { ok: false, error: 'missing_task' };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const sessionId = randomUUID();
|
|
147
|
+
const feedbackHistory = [];
|
|
148
|
+
|
|
149
|
+
logger.log(`Self-implement loop: @${agent} — "${task.slice(0, 60)}${task.length > 60 ? '...' : ''}"`);
|
|
150
|
+
logger.log(`Max iterations: ${maxIterations}`);
|
|
151
|
+
if (spec) logger.log(`Spec: ${spec}`);
|
|
152
|
+
if (artifact) logger.log(`Artifact: ${artifact}`);
|
|
153
|
+
logger.log('');
|
|
154
|
+
|
|
155
|
+
for (let iteration = 1; iteration <= maxIterations; iteration++) {
|
|
156
|
+
logger.log(`── Iteration ${iteration}/${maxIterations} ──────────────────────────`);
|
|
157
|
+
|
|
158
|
+
// Step 1: Execute agent
|
|
159
|
+
const feedbackContext = feedbackHistory.length > 0
|
|
160
|
+
? feedbackHistory.map((f) => `[Iteration ${f.iteration}] ${f.verdict}: ${f.issues.map((i) => i.message).join('; ')}`).join('\n')
|
|
161
|
+
: null;
|
|
162
|
+
|
|
163
|
+
logger.log(` Running @${agent}...`);
|
|
164
|
+
const agentResult = executeAgent(targetDir, agent, task, feedbackContext, timeoutMs);
|
|
165
|
+
|
|
166
|
+
if (!agentResult.ok) {
|
|
167
|
+
logger.log(` ✗ Agent execution failed: ${agentResult.error?.slice(0, 100)}`);
|
|
168
|
+
// Record on bus if squad context
|
|
169
|
+
if (squad) {
|
|
170
|
+
await bus.post(targetDir, squad, sessionId, {
|
|
171
|
+
from: 'self-loop',
|
|
172
|
+
type: 'status',
|
|
173
|
+
content: `Iteration ${iteration} — agent failed: ${agentResult.error?.slice(0, 200)}`
|
|
174
|
+
}).catch(() => {});
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Step 2: Verify (fresh context)
|
|
180
|
+
logger.log(' Verifying...');
|
|
181
|
+
const verifyResult = await runVerification(targetDir, spec, artifact, criteria);
|
|
182
|
+
|
|
183
|
+
// Record on bus
|
|
184
|
+
if (squad) {
|
|
185
|
+
await bus.post(targetDir, squad, sessionId, {
|
|
186
|
+
from: 'self-loop',
|
|
187
|
+
type: verifyResult.ok ? 'result' : 'gap_closure_attempt',
|
|
188
|
+
content: `Iteration ${iteration}: ${verifyResult.verdict}`,
|
|
189
|
+
metadata: {
|
|
190
|
+
iteration,
|
|
191
|
+
verdict: verifyResult.verdict,
|
|
192
|
+
issues_count: verifyResult.issues.length
|
|
193
|
+
}
|
|
194
|
+
}).catch(() => {});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Step 3: Check result
|
|
198
|
+
if (verifyResult.ok) {
|
|
199
|
+
logger.log(` ✓ PASS${iteration > 1 ? ` (after ${iteration} iteration${iteration > 1 ? 's' : ''})` : ''}`);
|
|
200
|
+
|
|
201
|
+
// Record success in state
|
|
202
|
+
if (squad) {
|
|
203
|
+
await stateManager.updateState(targetDir, squad, {
|
|
204
|
+
addDecision: [`self-loop: "${task.slice(0, 50)}" completed in ${iteration} iteration(s)`]
|
|
205
|
+
}).catch(() => {});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (options.json) {
|
|
209
|
+
return { ok: true, iterations: iteration, verdict: verifyResult.verdict, feedback: feedbackHistory };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return { ok: true, iterations: iteration, verdict: verifyResult.verdict };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Step 4: Collect feedback for next iteration
|
|
216
|
+
logger.log(` ✗ ${verifyResult.verdict} — ${verifyResult.issues.length} issue(s)`);
|
|
217
|
+
for (const issue of verifyResult.issues.slice(0, 5)) {
|
|
218
|
+
logger.log(` - ${issue.message}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
feedbackHistory.push({
|
|
222
|
+
iteration,
|
|
223
|
+
verdict: verifyResult.verdict,
|
|
224
|
+
issues: verifyResult.issues
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Step 5: Exhausted — escalate
|
|
229
|
+
logger.log('');
|
|
230
|
+
logger.log(`✗ Max iterations (${maxIterations}) exhausted — escalating to user`);
|
|
231
|
+
|
|
232
|
+
if (squad) {
|
|
233
|
+
await bus.post(targetDir, squad, sessionId, {
|
|
234
|
+
from: 'self-loop',
|
|
235
|
+
type: 'block',
|
|
236
|
+
content: `Self-implement loop exhausted ${maxIterations} iterations for: "${task.slice(0, 100)}"`,
|
|
237
|
+
metadata: { exhausted: true, iterations: maxIterations }
|
|
238
|
+
}).catch(() => {});
|
|
239
|
+
|
|
240
|
+
await stateManager.updateState(targetDir, squad, {
|
|
241
|
+
addBlocker: [`self-loop exhausted: "${task.slice(0, 50)}" (${maxIterations} iterations)`]
|
|
242
|
+
}).catch(() => {});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const result = {
|
|
246
|
+
ok: false,
|
|
247
|
+
iterations: maxIterations,
|
|
248
|
+
verdict: 'EXHAUSTED',
|
|
249
|
+
feedback: feedbackHistory
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (options.json) return result;
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = { runSelfLoop };
|