@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,154 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { execFile } = require('node:child_process');
|
|
6
|
+
const { promisify } = require('node:util');
|
|
7
|
+
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
|
|
10
|
+
const CONTEXT_DIR = path.join('.aioson', 'context');
|
|
11
|
+
const RECOVERY_FILE = 'recovery-context.md';
|
|
12
|
+
const MAX_TOKENS = 2000;
|
|
13
|
+
|
|
14
|
+
function estimateTokens(str) {
|
|
15
|
+
return Math.ceil(str.length / 4);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function readRecentGitLog(cwd, limit = 10) {
|
|
19
|
+
try {
|
|
20
|
+
const { stdout } = await execFileAsync('git', [
|
|
21
|
+
'log', `--max-count=${limit}`, '--oneline', '--no-merges'
|
|
22
|
+
], { cwd });
|
|
23
|
+
return stdout.trim().split('\n').filter(Boolean);
|
|
24
|
+
} catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function readModifiedFiles(cwd) {
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await execFileAsync('git', [
|
|
32
|
+
'diff', '--name-only', 'HEAD'
|
|
33
|
+
], { cwd });
|
|
34
|
+
return stdout.trim().split('\n').filter(Boolean);
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildSessionRecoveryMarkdown(sessionState, gitLog, modifiedFiles) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
|
|
43
|
+
lines.push('# Recovery Context — Direct Session');
|
|
44
|
+
lines.push(`> Generated: ${new Date().toISOString()}`);
|
|
45
|
+
lines.push('');
|
|
46
|
+
|
|
47
|
+
// Session goal/task
|
|
48
|
+
if (sessionState.goal) {
|
|
49
|
+
lines.push('## Current Goal');
|
|
50
|
+
lines.push(sessionState.goal);
|
|
51
|
+
lines.push('');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Active agent
|
|
55
|
+
if (sessionState.agent) {
|
|
56
|
+
lines.push('## Active Agent');
|
|
57
|
+
lines.push(sessionState.agent);
|
|
58
|
+
lines.push('');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Tasks
|
|
62
|
+
const tasks = Array.isArray(sessionState.tasks) ? sessionState.tasks : [];
|
|
63
|
+
if (tasks.length > 0) {
|
|
64
|
+
lines.push('## Tasks');
|
|
65
|
+
for (const t of tasks.slice(-5)) {
|
|
66
|
+
const status = t.status || 'unknown';
|
|
67
|
+
const title = t.title || t.id || '(untitled)';
|
|
68
|
+
lines.push(`- [${status}] ${title}`);
|
|
69
|
+
}
|
|
70
|
+
lines.push('');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Notes
|
|
74
|
+
const notes = Array.isArray(sessionState.notes) ? sessionState.notes : [];
|
|
75
|
+
if (notes.length > 0) {
|
|
76
|
+
lines.push('## Notes');
|
|
77
|
+
for (const note of notes.slice(-5)) {
|
|
78
|
+
lines.push(`- ${note}`);
|
|
79
|
+
}
|
|
80
|
+
lines.push('');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Modified files
|
|
84
|
+
if (modifiedFiles.length > 0) {
|
|
85
|
+
lines.push('## Modified Files');
|
|
86
|
+
for (const f of modifiedFiles.slice(0, 10)) {
|
|
87
|
+
lines.push(`- ${f}`);
|
|
88
|
+
}
|
|
89
|
+
lines.push('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Recent git commits
|
|
93
|
+
if (gitLog.length > 0) {
|
|
94
|
+
lines.push('## Recent Commits');
|
|
95
|
+
for (const entry of gitLog.slice(0, 5)) {
|
|
96
|
+
lines.push(`- ${entry}`);
|
|
97
|
+
}
|
|
98
|
+
lines.push('');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
lines.push('---');
|
|
102
|
+
lines.push('*Inject this file at the top of your next session to restore context after a compact.*');
|
|
103
|
+
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Generate and write recovery-context.md for a direct session (no squad).
|
|
109
|
+
* @param {string} cwd — project root directory
|
|
110
|
+
* @param {object} sessionState — { goal?, agent?, tasks?, notes? }
|
|
111
|
+
* @returns {{ ok: boolean, path: string, tokens: number }}
|
|
112
|
+
*/
|
|
113
|
+
async function generateSessionRecovery(cwd, sessionState = {}) {
|
|
114
|
+
const [gitLog, modifiedFiles] = await Promise.all([
|
|
115
|
+
readRecentGitLog(cwd),
|
|
116
|
+
readModifiedFiles(cwd)
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
let content = buildSessionRecoveryMarkdown(sessionState, gitLog, modifiedFiles);
|
|
120
|
+
|
|
121
|
+
// Enforce token budget
|
|
122
|
+
if (estimateTokens(content) > MAX_TOKENS) {
|
|
123
|
+
content = buildSessionRecoveryMarkdown(sessionState, gitLog.slice(0, 3), modifiedFiles.slice(0, 5));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const tokens = estimateTokens(content);
|
|
127
|
+
const outDir = path.join(cwd, CONTEXT_DIR);
|
|
128
|
+
const outPath = path.join(outDir, RECOVERY_FILE);
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
await fs.mkdir(outDir, { recursive: true });
|
|
132
|
+
await fs.writeFile(outPath, content, 'utf8');
|
|
133
|
+
} catch (err) {
|
|
134
|
+
return { ok: false, error: err.message, path: outPath, tokens };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return { ok: true, path: outPath, tokens };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Read the current session recovery-context.md (returns null if missing).
|
|
142
|
+
* @param {string} cwd
|
|
143
|
+
* @returns {string|null}
|
|
144
|
+
*/
|
|
145
|
+
async function readSessionRecovery(cwd) {
|
|
146
|
+
const p = path.join(cwd, CONTEXT_DIR, RECOVERY_FILE);
|
|
147
|
+
try {
|
|
148
|
+
return await fs.readFile(p, 'utf8');
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
module.exports = { generateSessionRecovery, readSessionRecovery };
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { launchCLI } = require('./cli-launcher');
|
|
4
|
+
|
|
5
|
+
const DEFAULT_ATTEMPTS = { haiku: 3, sonnet: 2, opus: 1 };
|
|
6
|
+
|
|
7
|
+
// Model IDs por alias. Injetados via ANTHROPIC_MODEL env var para Claude Code.
|
|
8
|
+
const MODEL_MAP = {
|
|
9
|
+
haiku: 'claude-haiku-4-5-20251001',
|
|
10
|
+
sonnet: 'claude-sonnet-4-6',
|
|
11
|
+
opus: 'claude-opus-4-6'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Executa uma task com cascade de modelos.
|
|
16
|
+
*
|
|
17
|
+
* Para cada modelo na cadeia:
|
|
18
|
+
* 1. Tenta até N vezes (DEFAULT_ATTEMPTS ou customizado)
|
|
19
|
+
* 2. Se result.ok: verifica via gateConfig (opcional)
|
|
20
|
+
* 3. Se aprovado: retorna resultado imediatamente
|
|
21
|
+
* 4. Se reprovado ou falha: tenta próximo modelo
|
|
22
|
+
*
|
|
23
|
+
* @param {string} projectDir
|
|
24
|
+
* @param {string} prompt
|
|
25
|
+
* @param {string[]} modelChain ex: ['haiku', 'sonnet', 'opus']
|
|
26
|
+
* @param {object} options
|
|
27
|
+
* @param {string} [options.tool] CLI a usar (padrão: auto-detectado)
|
|
28
|
+
* @param {Function} [options.gateCheck] fn(output: string) → {passed: boolean, reason?: string}
|
|
29
|
+
* @param {Function} [options.onProgress] fn({model, attempt, maxAttempts, status, reason?})
|
|
30
|
+
* @param {number} [options.timeout] Timeout em ms por tentativa
|
|
31
|
+
* @returns {Promise<{ok: boolean, result?, modelUsed?: string, attempts?: number, error?: string}>}
|
|
32
|
+
*/
|
|
33
|
+
async function runWithCascade(projectDir, prompt, modelChain, options = {}) {
|
|
34
|
+
const { tool, gateCheck, onProgress, timeout } = options;
|
|
35
|
+
|
|
36
|
+
for (const modelAlias of modelChain) {
|
|
37
|
+
const maxAttempts = DEFAULT_ATTEMPTS[modelAlias] ?? 1;
|
|
38
|
+
const modelId = MODEL_MAP[modelAlias];
|
|
39
|
+
|
|
40
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
41
|
+
if (onProgress) {
|
|
42
|
+
onProgress({ model: modelAlias, attempt, maxAttempts, status: 'running' });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Injeta o modelo via ANTHROPIC_MODEL (compatível com Claude Code)
|
|
46
|
+
const extraEnv = modelId ? { ANTHROPIC_MODEL: modelId } : {};
|
|
47
|
+
|
|
48
|
+
const result = await launchCLI(projectDir, prompt, {
|
|
49
|
+
tool,
|
|
50
|
+
timeout,
|
|
51
|
+
env: extraEnv
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!result.ok) {
|
|
55
|
+
if (onProgress) {
|
|
56
|
+
onProgress({ model: modelAlias, attempt, maxAttempts, status: 'cli_failed' });
|
|
57
|
+
}
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Verifica qualidade se gate configurado
|
|
62
|
+
if (gateCheck) {
|
|
63
|
+
const gateResult = gateCheck(result.output);
|
|
64
|
+
if (gateResult.passed) {
|
|
65
|
+
return { ok: true, result, modelUsed: modelAlias, attempts: attempt };
|
|
66
|
+
}
|
|
67
|
+
if (onProgress) {
|
|
68
|
+
onProgress({
|
|
69
|
+
model: modelAlias,
|
|
70
|
+
attempt,
|
|
71
|
+
maxAttempts,
|
|
72
|
+
status: 'gate_failed',
|
|
73
|
+
reason: gateResult.reason || 'quality gate failed'
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Não retorna — tenta próxima tentativa ou próximo modelo
|
|
77
|
+
} else {
|
|
78
|
+
// Sem gate: aceita o resultado
|
|
79
|
+
return { ok: true, result, modelUsed: modelAlias, attempts: attempt };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { ok: false, error: 'All cascade models exhausted without passing quality gate' };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Parseia uma string de cascade como "haiku,sonnet,opus" para um array.
|
|
89
|
+
* @param {string} cascadeStr
|
|
90
|
+
* @returns {string[]}
|
|
91
|
+
*/
|
|
92
|
+
function parseCascadeChain(cascadeStr) {
|
|
93
|
+
if (!cascadeStr) return [];
|
|
94
|
+
return cascadeStr.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = { runWithCascade, parseCascadeChain, MODEL_MAP, DEFAULT_ATTEMPTS };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('node:child_process');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detecta qual CLI de AI está disponível no sistema.
|
|
7
|
+
* Usa AIOSON_RUNNER_TOOL env var se definida, depois tenta
|
|
8
|
+
* claude, codex, gemini, opencode em sequência.
|
|
9
|
+
*/
|
|
10
|
+
async function detectCLI() {
|
|
11
|
+
const envTool = process.env.AIOSON_RUNNER_TOOL;
|
|
12
|
+
if (envTool) return envTool;
|
|
13
|
+
|
|
14
|
+
for (const cli of ['claude', 'codex', 'gemini', 'opencode']) {
|
|
15
|
+
const found = await new Promise((resolve) => {
|
|
16
|
+
const child = spawn('which', [cli], { stdio: 'pipe' });
|
|
17
|
+
child.on('close', (code) => resolve(code === 0));
|
|
18
|
+
child.on('error', () => resolve(false));
|
|
19
|
+
});
|
|
20
|
+
if (found) return cli;
|
|
21
|
+
}
|
|
22
|
+
throw new Error('No AI CLI found. Install claude, codex, gemini, or opencode.');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Monta os argumentos de headless para cada CLI.
|
|
27
|
+
*/
|
|
28
|
+
function buildArgs(cli, prompt, options = {}) {
|
|
29
|
+
const { allowedTools, outputFormat } = options;
|
|
30
|
+
|
|
31
|
+
switch (cli) {
|
|
32
|
+
case 'claude':
|
|
33
|
+
return [
|
|
34
|
+
'-p', prompt,
|
|
35
|
+
'--output-format', outputFormat || 'stream-json',
|
|
36
|
+
'--dangerously-skip-permissions',
|
|
37
|
+
...(allowedTools ? ['--allowedTools', allowedTools] : [])
|
|
38
|
+
];
|
|
39
|
+
case 'codex':
|
|
40
|
+
return ['-p', prompt, '--quiet', '--no-interactive'];
|
|
41
|
+
case 'gemini':
|
|
42
|
+
return ['-p', prompt, '--quiet'];
|
|
43
|
+
default:
|
|
44
|
+
return ['-p', prompt];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Spawna o CLI de AI com o prompt headless e retorna o output.
|
|
50
|
+
* Detecta TASK_COMPLETE no stream para sinalizar conclusão.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} projectDir
|
|
53
|
+
* @param {string} prompt
|
|
54
|
+
* @param {object} options
|
|
55
|
+
* @returns {Promise<{ok: boolean, output: string, stderr: string, completionMarker: boolean, exitCode: number}>}
|
|
56
|
+
*/
|
|
57
|
+
async function launchCLI(projectDir, prompt, options = {}) {
|
|
58
|
+
const { tool, timeout = 120000, onData, env: extraEnv } = options;
|
|
59
|
+
const cli = tool || await detectCLI();
|
|
60
|
+
const args = buildArgs(cli, prompt, options);
|
|
61
|
+
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
const child = spawn(cli, args, {
|
|
64
|
+
cwd: projectDir,
|
|
65
|
+
env: { ...process.env, ...(extraEnv || {}) },
|
|
66
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let stdout = '';
|
|
70
|
+
let stderr = '';
|
|
71
|
+
let completionMarker = false;
|
|
72
|
+
let settled = false;
|
|
73
|
+
|
|
74
|
+
const timer = timeout > 0
|
|
75
|
+
? setTimeout(() => {
|
|
76
|
+
if (!settled) child.kill('SIGTERM');
|
|
77
|
+
}, timeout)
|
|
78
|
+
: null;
|
|
79
|
+
|
|
80
|
+
child.stdout.on('data', (chunk) => {
|
|
81
|
+
const text = chunk.toString();
|
|
82
|
+
stdout += text;
|
|
83
|
+
if (onData) onData(text);
|
|
84
|
+
if (text.includes('TASK_COMPLETE')) completionMarker = true;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
|
|
88
|
+
|
|
89
|
+
child.on('close', (code) => {
|
|
90
|
+
settled = true;
|
|
91
|
+
if (timer) clearTimeout(timer);
|
|
92
|
+
resolve({
|
|
93
|
+
ok: code === 0,
|
|
94
|
+
output: stdout.trim(),
|
|
95
|
+
stderr: stderr.trim(),
|
|
96
|
+
completionMarker,
|
|
97
|
+
exitCode: code ?? -1
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
child.on('error', (err) => {
|
|
102
|
+
settled = true;
|
|
103
|
+
if (timer) clearTimeout(timer);
|
|
104
|
+
resolve({ ok: false, output: '', stderr: err.message, completionMarker: false, exitCode: -1 });
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = { launchCLI, detectCLI, buildArgs };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs/promises');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parseia um implementation-plan-{slug}.md e extrai as phases como tasks.
|
|
8
|
+
*
|
|
9
|
+
* Formatos suportados:
|
|
10
|
+
* ## Phase 1 — Title
|
|
11
|
+
* ## Phase 1 - Title
|
|
12
|
+
* ## Phase 1: Title
|
|
13
|
+
*
|
|
14
|
+
* @param {string} projectDir
|
|
15
|
+
* @param {string} slug
|
|
16
|
+
* @param {{ agent?: string }} options
|
|
17
|
+
* @returns {Promise<Array<{task: string, agent: string, status: string}>>}
|
|
18
|
+
*/
|
|
19
|
+
async function importFromPlan(projectDir, slug, options = {}) {
|
|
20
|
+
const { agent = 'dev' } = options;
|
|
21
|
+
|
|
22
|
+
const candidates = [
|
|
23
|
+
path.join(projectDir, '.aioson', 'context', `implementation-plan-${slug}.md`),
|
|
24
|
+
path.join(projectDir, '.aioson', 'plans', `implementation-plan-${slug}.md`),
|
|
25
|
+
path.join(projectDir, `implementation-plan-${slug}.md`)
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
let content = null;
|
|
29
|
+
let foundPath = null;
|
|
30
|
+
for (const candidate of candidates) {
|
|
31
|
+
try {
|
|
32
|
+
content = await fs.readFile(candidate, 'utf8');
|
|
33
|
+
foundPath = candidate;
|
|
34
|
+
break;
|
|
35
|
+
} catch { /* try next */ }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!content) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`implementation-plan-${slug}.md not found. Tried:\n` +
|
|
41
|
+
candidates.map((c) => ` ${c}`).join('\n') +
|
|
42
|
+
'\n\nRun `aioson plan . --slug=' + slug + '` to create one.'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const tasks = [];
|
|
47
|
+
|
|
48
|
+
// Captura ## Phase N seguido de separador (—, -, :) e título
|
|
49
|
+
// Exemplos: "## Phase 1 — Create migration" "## Phase 1 - Foo" "## Phase 1: Bar"
|
|
50
|
+
const phaseRegex = /^##\s+Phase\s+\d+\s*(?:[—\-:])\s*(.+)$/gim;
|
|
51
|
+
let match;
|
|
52
|
+
|
|
53
|
+
while ((match = phaseRegex.exec(content)) !== null) {
|
|
54
|
+
const title = match[1].trim().replace(/\s*\(.*?\)\s*$/, '').trim(); // remove sufixos como "(2-3 days)"
|
|
55
|
+
if (title) {
|
|
56
|
+
tasks.push({ task: title, agent, status: 'pending' });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { tasks, planPath: foundPath };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = { importFromPlan };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CRUD para a tabela runner_queue no SQLite existente.
|
|
5
|
+
* A tabela é criada automaticamente via openRuntimeDb — este módulo
|
|
6
|
+
* apenas lida com a DDL adicional e os queries da fila do runner.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const RUNNER_QUEUE_DDL = `
|
|
10
|
+
CREATE TABLE IF NOT EXISTS runner_queue (
|
|
11
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
12
|
+
task TEXT NOT NULL,
|
|
13
|
+
agent TEXT NOT NULL DEFAULT 'dev',
|
|
14
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
15
|
+
cascade TEXT,
|
|
16
|
+
priority INTEGER NOT NULL DEFAULT 0,
|
|
17
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
18
|
+
started_at TEXT,
|
|
19
|
+
finished_at TEXT,
|
|
20
|
+
result_ok INTEGER,
|
|
21
|
+
error_msg TEXT,
|
|
22
|
+
session_id TEXT
|
|
23
|
+
);
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Garante que a tabela runner_queue existe no DB aberto.
|
|
28
|
+
* @param {import('better-sqlite3').Database} db
|
|
29
|
+
*/
|
|
30
|
+
function ensureRunnerQueue(db) {
|
|
31
|
+
db.exec(RUNNER_QUEUE_DDL);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Adiciona uma task à fila.
|
|
36
|
+
* @param {import('better-sqlite3').Database} db
|
|
37
|
+
* @param {{ task: string, agent?: string, cascade?: string, priority?: number }} options
|
|
38
|
+
* @returns {number} id da task inserida
|
|
39
|
+
*/
|
|
40
|
+
function addTask(db, options) {
|
|
41
|
+
ensureRunnerQueue(db);
|
|
42
|
+
const { task, agent = 'dev', cascade = null, priority = 0 } = options;
|
|
43
|
+
const result = db.prepare(`
|
|
44
|
+
INSERT INTO runner_queue (task, agent, cascade, priority)
|
|
45
|
+
VALUES (?, ?, ?, ?)
|
|
46
|
+
`).run(task, agent, cascade, priority);
|
|
47
|
+
return result.lastInsertRowid;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Lista todas as tasks da fila, ordenadas por prioridade DESC, criação ASC.
|
|
52
|
+
* @param {import('better-sqlite3').Database} db
|
|
53
|
+
* @param {{ status?: string }} options
|
|
54
|
+
*/
|
|
55
|
+
function listTasks(db, options = {}) {
|
|
56
|
+
ensureRunnerQueue(db);
|
|
57
|
+
if (options.status) {
|
|
58
|
+
return db.prepare(`
|
|
59
|
+
SELECT * FROM runner_queue WHERE status = ? ORDER BY priority DESC, id ASC
|
|
60
|
+
`).all(options.status);
|
|
61
|
+
}
|
|
62
|
+
return db.prepare(`
|
|
63
|
+
SELECT * FROM runner_queue ORDER BY priority DESC, id ASC
|
|
64
|
+
`).all();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Busca a próxima task com status pending.
|
|
69
|
+
* @param {import('better-sqlite3').Database} db
|
|
70
|
+
*/
|
|
71
|
+
function nextPending(db) {
|
|
72
|
+
ensureRunnerQueue(db);
|
|
73
|
+
return db.prepare(`
|
|
74
|
+
SELECT * FROM runner_queue WHERE status = 'pending' ORDER BY priority DESC, id ASC LIMIT 1
|
|
75
|
+
`).get();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Atualiza o status de uma task.
|
|
80
|
+
* @param {import('better-sqlite3').Database} db
|
|
81
|
+
* @param {number} id
|
|
82
|
+
* @param {{ status: string, resultOk?: boolean, errorMsg?: string, sessionId?: string }} options
|
|
83
|
+
*/
|
|
84
|
+
function updateTaskStatus(db, id, options) {
|
|
85
|
+
ensureRunnerQueue(db);
|
|
86
|
+
const now = new Date().toISOString();
|
|
87
|
+
const status = options.status;
|
|
88
|
+
const isFinished = status === 'completed' || status === 'failed' || status === 'skipped';
|
|
89
|
+
const isStarted = status === 'running';
|
|
90
|
+
|
|
91
|
+
db.prepare(`
|
|
92
|
+
UPDATE runner_queue
|
|
93
|
+
SET status = ?,
|
|
94
|
+
result_ok = COALESCE(?, result_ok),
|
|
95
|
+
error_msg = COALESCE(?, error_msg),
|
|
96
|
+
session_id = COALESCE(?, session_id),
|
|
97
|
+
started_at = CASE WHEN ? = 1 THEN ? ELSE started_at END,
|
|
98
|
+
finished_at = CASE WHEN ? = 1 THEN ? ELSE finished_at END
|
|
99
|
+
WHERE id = ?
|
|
100
|
+
`).run(
|
|
101
|
+
status,
|
|
102
|
+
options.resultOk != null ? (options.resultOk ? 1 : 0) : null,
|
|
103
|
+
options.errorMsg ?? null,
|
|
104
|
+
options.sessionId ?? null,
|
|
105
|
+
isStarted ? 1 : 0, now,
|
|
106
|
+
isFinished ? 1 : 0, now,
|
|
107
|
+
id
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove todas as tasks da fila (clear).
|
|
113
|
+
* @param {import('better-sqlite3').Database} db
|
|
114
|
+
*/
|
|
115
|
+
function clearQueue(db) {
|
|
116
|
+
ensureRunnerQueue(db);
|
|
117
|
+
db.prepare('DELETE FROM runner_queue').run();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Exporta todas as tasks como Markdown.
|
|
122
|
+
* @param {import('better-sqlite3').Database} db
|
|
123
|
+
*/
|
|
124
|
+
function exportQueueMarkdown(db) {
|
|
125
|
+
const tasks = listTasks(db);
|
|
126
|
+
if (tasks.length === 0) return '# Runner Queue\n\n_Queue is empty._\n';
|
|
127
|
+
|
|
128
|
+
const STATUS_ICON = {
|
|
129
|
+
pending: '○',
|
|
130
|
+
running: '▶',
|
|
131
|
+
completed: '✓',
|
|
132
|
+
failed: '✗',
|
|
133
|
+
skipped: '—'
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const lines = ['# Runner Queue', ''];
|
|
137
|
+
for (const t of tasks) {
|
|
138
|
+
const icon = STATUS_ICON[t.status] || '?';
|
|
139
|
+
const cascade = t.cascade ? ` [cascade: ${t.cascade}]` : '';
|
|
140
|
+
lines.push(`- ${icon} **${t.id}** \`@${t.agent}\`${cascade} — ${t.task}`);
|
|
141
|
+
if (t.status !== 'pending') {
|
|
142
|
+
lines.push(` - Status: ${t.status} | Created: ${t.created_at}`);
|
|
143
|
+
if (t.finished_at) lines.push(` - Finished: ${t.finished_at}`);
|
|
144
|
+
if (t.error_msg) lines.push(` - Error: ${t.error_msg}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
lines.push('');
|
|
148
|
+
return lines.join('\n');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
ensureRunnerQueue,
|
|
153
|
+
addTask,
|
|
154
|
+
listTasks,
|
|
155
|
+
nextPending,
|
|
156
|
+
updateTaskStatus,
|
|
157
|
+
clearQueue,
|
|
158
|
+
exportQueueMarkdown
|
|
159
|
+
};
|