@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,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson learning:rollback [projectDir] --evolution=<uuid> [--squad=<slug>]
|
|
5
|
+
*
|
|
6
|
+
* Reverts a specific evolution delta from evolution-log.jsonl.
|
|
7
|
+
*
|
|
8
|
+
* Steps:
|
|
9
|
+
* 1. Find the evolution entry by UUID in .aioson/evolution/evolution-log.jsonl
|
|
10
|
+
* 2. Revert the appended content from the target file
|
|
11
|
+
* 3. Mark the entry as rolled_back in the log
|
|
12
|
+
* 4. Mark source learnings as stale in SQLite
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* aioson learning:rollback . --evolution=<uuid>
|
|
16
|
+
* aioson learning:rollback . --evolution=<uuid> --dry-run
|
|
17
|
+
* aioson learning:rollback . --list (show applied evolutions)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('node:fs/promises');
|
|
21
|
+
const path = require('node:path');
|
|
22
|
+
const { openRuntimeDb } = require('../runtime-store');
|
|
23
|
+
|
|
24
|
+
const EVOLUTION_LOG = path.join('.aioson', 'evolution', 'evolution-log.jsonl');
|
|
25
|
+
|
|
26
|
+
async function readEvolutionLog(projectDir) {
|
|
27
|
+
const logPath = path.resolve(projectDir, EVOLUTION_LOG);
|
|
28
|
+
try {
|
|
29
|
+
const content = await fs.readFile(logPath, 'utf8');
|
|
30
|
+
return content.trim().split('\n')
|
|
31
|
+
.filter(Boolean)
|
|
32
|
+
.map((line) => {
|
|
33
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
34
|
+
})
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function writeEvolutionLog(projectDir, entries) {
|
|
42
|
+
const logPath = path.resolve(projectDir, EVOLUTION_LOG);
|
|
43
|
+
await fs.mkdir(path.dirname(logPath), { recursive: true });
|
|
44
|
+
await fs.writeFile(logPath, entries.map((e) => JSON.stringify(e)).join('\n') + '\n', 'utf8');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function runLearningRollback({ args = [], options = {}, logger = console } = {}) {
|
|
48
|
+
const projectDir = path.resolve(process.cwd(), args[0] || '.');
|
|
49
|
+
const dryRun = Boolean(options['dry-run'] || options.dry);
|
|
50
|
+
|
|
51
|
+
// ── List mode ──────────────────────────────────────────────────────────────
|
|
52
|
+
if (options.list) {
|
|
53
|
+
const entries = await readEvolutionLog(projectDir);
|
|
54
|
+
const applied = entries.filter((e) => e.status === 'applied');
|
|
55
|
+
|
|
56
|
+
if (applied.length === 0) {
|
|
57
|
+
logger.log('No applied evolutions found in evolution-log.jsonl');
|
|
58
|
+
return { ok: true, entries: [] };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
logger.log(`Applied evolutions (${applied.length}):`);
|
|
62
|
+
for (const e of applied) {
|
|
63
|
+
logger.log(` ${e.id.slice(0, 8)}... ${e.ts.slice(0, 16)} → ${e.file}`);
|
|
64
|
+
logger.log(` ${e.learning_ids?.length || 0} learning(s) applied`);
|
|
65
|
+
if (e.squad) logger.log(` Squad: ${e.squad}`);
|
|
66
|
+
}
|
|
67
|
+
logger.log('');
|
|
68
|
+
logger.log('Rollback: aioson learning:rollback . --evolution=<id>');
|
|
69
|
+
|
|
70
|
+
return { ok: true, entries: applied };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ── Rollback mode ──────────────────────────────────────────────────────────
|
|
74
|
+
const evolutionId = String(options.evolution || '').trim();
|
|
75
|
+
if (!evolutionId) {
|
|
76
|
+
logger.error('Error: --evolution <uuid> is required (or --list to see applied evolutions)');
|
|
77
|
+
return { ok: false, error: 'missing_evolution_id' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const entries = await readEvolutionLog(projectDir);
|
|
81
|
+
const entryIndex = entries.findIndex(
|
|
82
|
+
(e) => e.id === evolutionId || e.id.startsWith(evolutionId)
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (entryIndex === -1) {
|
|
86
|
+
logger.error(`Evolution "${evolutionId}" not found in evolution-log.jsonl`);
|
|
87
|
+
logger.log('Run: aioson learning:rollback . --list');
|
|
88
|
+
return { ok: false, error: 'evolution_not_found' };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const entry = entries[entryIndex];
|
|
92
|
+
|
|
93
|
+
if (entry.status === 'rolled_back') {
|
|
94
|
+
logger.log(`Evolution "${entry.id.slice(0, 8)}..." is already rolled back.`);
|
|
95
|
+
return { ok: true, alreadyRolledBack: true };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (entry.status !== 'applied') {
|
|
99
|
+
logger.error(`Evolution "${entry.id.slice(0, 8)}..." has unexpected status: ${entry.status}`);
|
|
100
|
+
return { ok: false, error: 'unexpected_status' };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
logger.log(`Rolling back evolution: ${entry.id}`);
|
|
104
|
+
logger.log(` File: ${entry.file}`);
|
|
105
|
+
logger.log(` Content to remove (${entry.content?.length || 0} chars)`);
|
|
106
|
+
|
|
107
|
+
if (dryRun) {
|
|
108
|
+
logger.log('[dry-run] No changes applied.');
|
|
109
|
+
return { ok: true, dryRun: true, entry };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ── Revert file content ────────────────────────────────────────────────────
|
|
113
|
+
if (entry.content && entry.file) {
|
|
114
|
+
const filePath = path.isAbsolute(entry.file)
|
|
115
|
+
? entry.file
|
|
116
|
+
: path.resolve(projectDir, entry.file);
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const current = await fs.readFile(filePath, 'utf8');
|
|
120
|
+
// Remove the exact content that was appended
|
|
121
|
+
const reverted = current.replace(entry.content, '').replace(/\n{3,}/g, '\n\n');
|
|
122
|
+
await fs.writeFile(filePath, reverted, 'utf8');
|
|
123
|
+
logger.log(` ✓ Reverted: ${entry.file}`);
|
|
124
|
+
} catch (err) {
|
|
125
|
+
logger.error(` ✗ Failed to revert ${entry.file}: ${err.message}`);
|
|
126
|
+
return { ok: false, error: 'file_revert_failed', detail: err.message };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── Mark entry as rolled_back ──────────────────────────────────────────────
|
|
131
|
+
entries[entryIndex] = {
|
|
132
|
+
...entry,
|
|
133
|
+
status: 'rolled_back',
|
|
134
|
+
rollback_ts: new Date().toISOString(),
|
|
135
|
+
rollback_reason: options.reason || 'user request'
|
|
136
|
+
};
|
|
137
|
+
await writeEvolutionLog(projectDir, entries);
|
|
138
|
+
|
|
139
|
+
// ── Mark learnings as stale in SQLite ─────────────────────────────────────
|
|
140
|
+
const learningIds = entry.learning_ids || [];
|
|
141
|
+
if (learningIds.length > 0) {
|
|
142
|
+
const handle = await openRuntimeDb(projectDir, { mustExist: true });
|
|
143
|
+
if (handle) {
|
|
144
|
+
const { db } = handle;
|
|
145
|
+
try {
|
|
146
|
+
for (const id of learningIds) {
|
|
147
|
+
db.prepare(
|
|
148
|
+
`UPDATE squad_learnings SET status = 'stale', updated_at = datetime('now') WHERE learning_id = ?`
|
|
149
|
+
).run(id);
|
|
150
|
+
}
|
|
151
|
+
logger.log(` ✓ ${learningIds.length} learning(s) marked as stale`);
|
|
152
|
+
} finally {
|
|
153
|
+
db.close();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
logger.log('');
|
|
159
|
+
logger.log(`✓ Evolution rolled back: ${entry.id}`);
|
|
160
|
+
|
|
161
|
+
return { ok: true, entry: entries[entryIndex] };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = { runLearningRollback };
|
package/src/commands/live.js
CHANGED
|
@@ -860,6 +860,20 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
860
860
|
throw new Error(t('live.json_requires_no_launch'));
|
|
861
861
|
}
|
|
862
862
|
|
|
863
|
+
// ── 5.3 Ambient Intelligence health check alert ────────────────────────────
|
|
864
|
+
if (!options.json && !options['no-health-check']) {
|
|
865
|
+
try {
|
|
866
|
+
const { runHealthCheck, formatHealthAlert } = require('../lib/health-check');
|
|
867
|
+
const health = await runHealthCheck(targetDir);
|
|
868
|
+
const alert = formatHealthAlert(health.items);
|
|
869
|
+
if (alert) {
|
|
870
|
+
logger.log('');
|
|
871
|
+
logger.log(alert);
|
|
872
|
+
logger.log('');
|
|
873
|
+
}
|
|
874
|
+
} catch { /* health check is non-fatal */ }
|
|
875
|
+
}
|
|
876
|
+
|
|
863
877
|
const toolBinary = String(options['tool-bin'] || tool).trim();
|
|
864
878
|
const binaryPath = await resolveExecutablePath(toolBinary);
|
|
865
879
|
if (!binaryPath) {
|
|
@@ -1062,6 +1076,23 @@ async function runLiveStart({ args, options = {}, logger, t }) {
|
|
|
1062
1076
|
logger.log(t('live.session_started', { agent: agentName, tool, session: sessionKey, dbPath }));
|
|
1063
1077
|
}
|
|
1064
1078
|
|
|
1079
|
+
// Ambient Intelligence: exibe digest de saúde ao iniciar sessão
|
|
1080
|
+
if (!options.json && !options['no-health']) {
|
|
1081
|
+
try {
|
|
1082
|
+
const { getHealthDigest } = require('./health');
|
|
1083
|
+
const items = await getHealthDigest(targetDir);
|
|
1084
|
+
if (items && items.length > 0) {
|
|
1085
|
+
logger.log('');
|
|
1086
|
+
logger.log('AIOSON Health — itens pendentes:');
|
|
1087
|
+
for (const item of items) {
|
|
1088
|
+
logger.log(` ● ${item}`);
|
|
1089
|
+
}
|
|
1090
|
+
logger.log(' → aioson health . para detalhes');
|
|
1091
|
+
logger.log('');
|
|
1092
|
+
}
|
|
1093
|
+
} catch { /* não bloqueia o start */ }
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1065
1096
|
if (child) {
|
|
1066
1097
|
childResult = await waitForChild(child);
|
|
1067
1098
|
}
|
|
@@ -1190,6 +1221,11 @@ async function runRuntimeEmit({ args, options = {}, logger, t }) {
|
|
|
1190
1221
|
}
|
|
1191
1222
|
}
|
|
1192
1223
|
|
|
1224
|
+
const workerStatus = options['worker-status'] ? String(options['worker-status']).trim() : null;
|
|
1225
|
+
const verdict = options.verdict ? String(options.verdict).trim().toUpperCase() : null;
|
|
1226
|
+
const tokenCount = options['token-count'] != null ? Number(options['token-count']) || null : null;
|
|
1227
|
+
const progressPct = options['progress-pct'] != null ? Number(options['progress-pct']) || null : null;
|
|
1228
|
+
|
|
1193
1229
|
appendRunEvent(db, {
|
|
1194
1230
|
runKey: context.run.run_key,
|
|
1195
1231
|
eventType,
|
|
@@ -1197,7 +1233,12 @@ async function runRuntimeEmit({ args, options = {}, logger, t }) {
|
|
|
1197
1233
|
status: context.run.status || 'running',
|
|
1198
1234
|
message: summary,
|
|
1199
1235
|
payload: Object.keys(payload).length > 0 ? payload : null,
|
|
1200
|
-
createdAt: now
|
|
1236
|
+
createdAt: now,
|
|
1237
|
+
planStepId: planStep || null,
|
|
1238
|
+
workerStatus,
|
|
1239
|
+
verdict,
|
|
1240
|
+
tokenCount,
|
|
1241
|
+
progressPct
|
|
1201
1242
|
});
|
|
1202
1243
|
|
|
1203
1244
|
const eventRecord = createLiveEventRecord(context, {
|
|
@@ -1508,6 +1549,23 @@ async function runLiveClose({ args, options = {}, logger, t }) {
|
|
|
1508
1549
|
logger.log(t('live.session_closed', { agent: context.agentName, session: context.sessionKey, dbPath }));
|
|
1509
1550
|
}
|
|
1510
1551
|
|
|
1552
|
+
// Ambient Intelligence: sugere evolução se há learnings acumulados
|
|
1553
|
+
if (!options.json && !options['no-health']) {
|
|
1554
|
+
try {
|
|
1555
|
+
const { getHealthDigest } = require('./health');
|
|
1556
|
+
const items = await getHealthDigest(targetDir);
|
|
1557
|
+
if (items && items.length > 0) {
|
|
1558
|
+
logger.log('');
|
|
1559
|
+
logger.log('AIOSON Health — itens após sessão:');
|
|
1560
|
+
for (const item of items) {
|
|
1561
|
+
logger.log(` ● ${item}`);
|
|
1562
|
+
}
|
|
1563
|
+
logger.log(' → aioson health . para detalhes e ações');
|
|
1564
|
+
logger.log('');
|
|
1565
|
+
}
|
|
1566
|
+
} catch { /* não bloqueia o close */ }
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1511
1569
|
return {
|
|
1512
1570
|
ok: true,
|
|
1513
1571
|
targetDir,
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson pattern:detect — Detect automation candidates from squad learnings
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aioson pattern:detect . --squad=content-team
|
|
8
|
+
* aioson pattern:detect . --squad=content-team --min-occurrences=2
|
|
9
|
+
* aioson pattern:detect . --squad=content-team --json
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const path = require('node:path');
|
|
13
|
+
const { detectPatterns, formatPatternReport } = require('../squad/pattern-detector');
|
|
14
|
+
|
|
15
|
+
async function runPatternDetect({ args, options = {}, logger }) {
|
|
16
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
17
|
+
const squadSlug = String(options.squad || options.s || '').trim();
|
|
18
|
+
|
|
19
|
+
if (!squadSlug) {
|
|
20
|
+
logger.error('Error: --squad is required');
|
|
21
|
+
return { ok: false, error: 'missing_squad' };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const minOccurrences = Number(options['min-occurrences'] || options.min || 3);
|
|
25
|
+
const result = await detectPatterns(targetDir, squadSlug, { minOccurrences });
|
|
26
|
+
|
|
27
|
+
if (options.json) return result;
|
|
28
|
+
|
|
29
|
+
logger.log(formatPatternReport(result));
|
|
30
|
+
return { ok: true, ...result };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { runPatternDetect };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson preflight:context — Estimate context budget before a session
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aioson preflight:context . --agent=dev
|
|
8
|
+
* aioson preflight:context . --agent=orchestrator --squad=content-team
|
|
9
|
+
* aioson preflight:context . --agent=dev --verbose
|
|
10
|
+
* aioson preflight:context . --agent=dev --json
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const path = require('node:path');
|
|
14
|
+
const { estimateContext, formatReport } = require('../squad/preflight-context');
|
|
15
|
+
|
|
16
|
+
async function runPreflightContext({ args, options = {}, logger }) {
|
|
17
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
18
|
+
const agent = String(options.agent || options.a || 'dev').trim();
|
|
19
|
+
const squad = options.squad ? String(options.squad).trim() : undefined;
|
|
20
|
+
const verbose = Boolean(options.verbose || options.v);
|
|
21
|
+
|
|
22
|
+
const result = await estimateContext(targetDir, { agent, squad, verbose });
|
|
23
|
+
|
|
24
|
+
if (options.json) return result;
|
|
25
|
+
|
|
26
|
+
logger.log(formatReport(result));
|
|
27
|
+
return { ok: result.exitCode === 0, ...result };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { runPreflightContext };
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson preflight — consolidated pre-flight analysis for any agent session.
|
|
5
|
+
*
|
|
6
|
+
* Replaces 10+ manual file checks with one command. Returns mode, context package,
|
|
7
|
+
* readiness, phase gates, and next step — deterministically, with no LLM calls.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson preflight . --agent=dev --feature=checkout
|
|
11
|
+
* aioson preflight . --agent=qa --feature=checkout --json
|
|
12
|
+
* aioson preflight . (project-level, no feature)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('node:path');
|
|
16
|
+
const {
|
|
17
|
+
loadProjectContext,
|
|
18
|
+
scanArtifacts,
|
|
19
|
+
readPhaseGates,
|
|
20
|
+
readDevState,
|
|
21
|
+
readProjectPulse,
|
|
22
|
+
detectClassification,
|
|
23
|
+
detectFramework,
|
|
24
|
+
detectTestRunner,
|
|
25
|
+
discoverRules,
|
|
26
|
+
buildContextPackage,
|
|
27
|
+
evaluateReadiness,
|
|
28
|
+
extractSpecVersion,
|
|
29
|
+
extractLastCheckpoint,
|
|
30
|
+
GATE_NAMES
|
|
31
|
+
} = require('../preflight-engine');
|
|
32
|
+
|
|
33
|
+
const BAR = '━'.repeat(55);
|
|
34
|
+
|
|
35
|
+
function gateIcon(status) {
|
|
36
|
+
if (!status) return '○';
|
|
37
|
+
if (status === 'approved') return '✓';
|
|
38
|
+
if (status === 'pending') return '○';
|
|
39
|
+
return '✗';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function runPreflight({ args, options = {}, logger }) {
|
|
43
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
44
|
+
const agent = options.agent ? String(options.agent) : null;
|
|
45
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
46
|
+
|
|
47
|
+
// --- Gather all data ---
|
|
48
|
+
const ctx = await loadProjectContext(targetDir);
|
|
49
|
+
const artifacts = await scanArtifacts(targetDir, slug);
|
|
50
|
+
const phaseGates = await readPhaseGates(targetDir, slug);
|
|
51
|
+
const devState = await readDevState(targetDir);
|
|
52
|
+
const pulse = await readProjectPulse(targetDir);
|
|
53
|
+
|
|
54
|
+
let classification = await detectClassification(targetDir, slug);
|
|
55
|
+
const framework = ctx.data.framework || ctx.data.stack || await detectFramework(targetDir);
|
|
56
|
+
const testRunnerInfo = await detectTestRunner(targetDir);
|
|
57
|
+
const testRunner = testRunnerInfo ? testRunnerInfo.name : (ctx.data.test_runner || null);
|
|
58
|
+
const rules = agent ? await discoverRules(targetDir, agent) : [];
|
|
59
|
+
const contextPackage = buildContextPackage(agent || 'dev', slug, classification, artifacts, devState);
|
|
60
|
+
const readiness = evaluateReadiness(artifacts, phaseGates, classification, agent);
|
|
61
|
+
|
|
62
|
+
// Determine mode
|
|
63
|
+
const mode = slug
|
|
64
|
+
? (artifacts.prd.exists ? 'feature' : 'continuation')
|
|
65
|
+
: (artifacts.project_context.exists ? 'project' : 'greenfield');
|
|
66
|
+
|
|
67
|
+
// Spec version + checkpoint
|
|
68
|
+
const specVersion = extractSpecVersion(artifacts.spec);
|
|
69
|
+
const lastCheckpoint = extractLastCheckpoint(artifacts.spec);
|
|
70
|
+
|
|
71
|
+
const result = {
|
|
72
|
+
ok: true,
|
|
73
|
+
mode,
|
|
74
|
+
feature_slug: slug,
|
|
75
|
+
agent,
|
|
76
|
+
classification,
|
|
77
|
+
framework: framework || null,
|
|
78
|
+
test_runner: testRunner,
|
|
79
|
+
artifacts: {
|
|
80
|
+
project_context: { exists: artifacts.project_context.exists, path: artifacts.project_context.path || null },
|
|
81
|
+
prd: { exists: artifacts.prd.exists, path: artifacts.prd.path || null },
|
|
82
|
+
sheldon_enrichment: { exists: artifacts.sheldon_enrichment.exists },
|
|
83
|
+
requirements: { exists: artifacts.requirements.exists, path: artifacts.requirements.path || null },
|
|
84
|
+
spec: {
|
|
85
|
+
exists: artifacts.spec.exists,
|
|
86
|
+
path: artifacts.spec.path || null,
|
|
87
|
+
version: specVersion,
|
|
88
|
+
last_checkpoint: lastCheckpoint
|
|
89
|
+
},
|
|
90
|
+
architecture: { exists: artifacts.architecture.exists },
|
|
91
|
+
implementation_plan: {
|
|
92
|
+
exists: artifacts.implementation_plan.exists,
|
|
93
|
+
path: artifacts.implementation_plan.path || null,
|
|
94
|
+
status: artifacts.implementation_plan.exists ? (artifacts.implementation_plan.frontmatter.status || null) : null
|
|
95
|
+
},
|
|
96
|
+
conformance: { exists: artifacts.conformance.exists },
|
|
97
|
+
dev_state: {
|
|
98
|
+
exists: devState.exists,
|
|
99
|
+
next_step: devState.next_step || null
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
phase_gates: {
|
|
103
|
+
requirements: phaseGates.requirements || 'pending',
|
|
104
|
+
design: phaseGates.design || 'pending',
|
|
105
|
+
plan: phaseGates.plan || 'pending',
|
|
106
|
+
execution: phaseGates.execution || 'pending'
|
|
107
|
+
},
|
|
108
|
+
context_package: contextPackage,
|
|
109
|
+
rules,
|
|
110
|
+
readiness: readiness.status,
|
|
111
|
+
readiness_blockers: readiness.blockers,
|
|
112
|
+
pulse: {
|
|
113
|
+
last_agent: pulse.last_agent || null,
|
|
114
|
+
last_gate: pulse.last_gate || null,
|
|
115
|
+
blockers: pulse.blockers || 'none'
|
|
116
|
+
},
|
|
117
|
+
dev_state: {
|
|
118
|
+
active_feature: devState.active_feature || null,
|
|
119
|
+
active_phase: devState.active_phase || null,
|
|
120
|
+
next_step: devState.next_step || null,
|
|
121
|
+
last_spec_version: devState.last_spec_version || null
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
if (options.json) return result;
|
|
126
|
+
|
|
127
|
+
// --- Human output ---
|
|
128
|
+
const header = agent && slug
|
|
129
|
+
? `AIOSON Pre-flight — @${agent} / ${slug}`
|
|
130
|
+
: agent
|
|
131
|
+
? `AIOSON Pre-flight — @${agent}`
|
|
132
|
+
: 'AIOSON Pre-flight';
|
|
133
|
+
|
|
134
|
+
logger.log('');
|
|
135
|
+
logger.log(header);
|
|
136
|
+
logger.log(BAR);
|
|
137
|
+
logger.log('');
|
|
138
|
+
logger.log(`Mode: ${mode}${classification ? ' | Classification: ' + classification : ''}${framework ? ' | Framework: ' + framework : ''}${testRunner ? ' | Test runner: ' + testRunner : ''}`);
|
|
139
|
+
logger.log('');
|
|
140
|
+
|
|
141
|
+
logger.log('Artifacts:');
|
|
142
|
+
const checks = [
|
|
143
|
+
['project.context.md', artifacts.project_context.exists, null],
|
|
144
|
+
slug ? [`prd-${slug}.md`, artifacts.prd.exists, null] : null,
|
|
145
|
+
slug ? [`sheldon-enrichment-${slug}.md`, artifacts.sheldon_enrichment.exists, 'optional'] : null,
|
|
146
|
+
slug ? [`requirements-${slug}.md`, artifacts.requirements.exists, null] : null,
|
|
147
|
+
slug
|
|
148
|
+
? [`spec-${slug}.md`, artifacts.spec.exists, specVersion ? `version: ${specVersion}${lastCheckpoint ? ', last: "' + lastCheckpoint + '"' : ''}` : null]
|
|
149
|
+
: null,
|
|
150
|
+
['architecture.md', artifacts.architecture.exists, null],
|
|
151
|
+
slug ? [`implementation-plan-${slug}.md`, artifacts.implementation_plan.exists, artifacts.implementation_plan.exists ? `status: ${artifacts.implementation_plan.frontmatter.status || 'unknown'}` : null] : null,
|
|
152
|
+
slug ? [`conformance-${slug}.yaml`, artifacts.conformance.exists, classification === 'SMALL' || classification === 'MICRO' ? 'MEDIUM only — not required' : null] : null
|
|
153
|
+
].filter(Boolean);
|
|
154
|
+
|
|
155
|
+
for (const [name, exists, note] of checks) {
|
|
156
|
+
const icon = exists ? ' ✓' : ' ✗';
|
|
157
|
+
const suffix = note ? ` (${note})` : '';
|
|
158
|
+
logger.log(`${icon} ${name}${suffix}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
logger.log('');
|
|
162
|
+
logger.log('Phase gates:');
|
|
163
|
+
for (const [letter, name] of Object.entries(GATE_NAMES)) {
|
|
164
|
+
const status = phaseGates[name] || 'pending';
|
|
165
|
+
logger.log(` ${gateIcon(status)} Gate ${letter} (${name}): ${status}`);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (devState.exists && devState.next_step) {
|
|
169
|
+
logger.log('');
|
|
170
|
+
logger.log('Dev state:');
|
|
171
|
+
if (devState.active_feature) logger.log(` active_feature: ${devState.active_feature}`);
|
|
172
|
+
if (devState.active_phase) logger.log(` active_phase: ${devState.active_phase}`);
|
|
173
|
+
logger.log(` next_step: "${devState.next_step}"`);
|
|
174
|
+
if (devState.last_spec_version) logger.log(` last_spec_version: ${devState.last_spec_version}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (contextPackage.length > 0) {
|
|
178
|
+
logger.log('');
|
|
179
|
+
logger.log('Context package (load these):');
|
|
180
|
+
contextPackage.forEach((p, i) => logger.log(` ${i + 1}. ${p}`));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (rules.length > 0) {
|
|
184
|
+
logger.log('');
|
|
185
|
+
logger.log(`Rules loaded: ${rules.join(', ')}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (pulse.last_agent) {
|
|
189
|
+
logger.log('');
|
|
190
|
+
logger.log('Project pulse:');
|
|
191
|
+
if (pulse.last_agent) logger.log(` last_agent: @${pulse.last_agent}`);
|
|
192
|
+
if (pulse.last_gate) logger.log(` last_gate: ${pulse.last_gate}`);
|
|
193
|
+
logger.log(` blockers: ${pulse.blockers || 'none'}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
logger.log('');
|
|
197
|
+
if (readiness.status === 'READY') {
|
|
198
|
+
logger.log(`Readiness: READY — proceed`);
|
|
199
|
+
} else {
|
|
200
|
+
logger.log(`Readiness: BLOCKED`);
|
|
201
|
+
for (const b of readiness.blockers) logger.log(` ✗ ${b}`);
|
|
202
|
+
}
|
|
203
|
+
logger.log('');
|
|
204
|
+
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
module.exports = { runPreflight };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* aioson pulse:update — update project-pulse.md at session end.
|
|
5
|
+
*
|
|
6
|
+
* Replaces the manual project-pulse.md editing block in 7+ agents.
|
|
7
|
+
* Keeps last 3 recent activity entries.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* aioson pulse:update . --agent=dev --feature=checkout --gate="Gate C: approved" \
|
|
11
|
+
* --action="Implemented payment webhook handler" --next="Continue with phase 4"
|
|
12
|
+
* aioson pulse:update . --agent=qa --verdict=PASS --feature=checkout
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('node:fs/promises');
|
|
16
|
+
const path = require('node:path');
|
|
17
|
+
const { contextDir, readFileSafe, parseFrontmatter } = require('../preflight-engine');
|
|
18
|
+
|
|
19
|
+
function nowDate() {
|
|
20
|
+
return new Date().toISOString().slice(0, 10);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function runPulseUpdate({ args, options = {}, logger }) {
|
|
24
|
+
const targetDir = path.resolve(process.cwd(), args[0] || '.');
|
|
25
|
+
const agent = options.agent ? String(options.agent) : null;
|
|
26
|
+
const slug = options.feature ? String(options.feature) : null;
|
|
27
|
+
const gate = options.gate ? String(options.gate) : null;
|
|
28
|
+
const action = options.action ? String(options.action) : null;
|
|
29
|
+
const next = options.next ? String(options.next) : null;
|
|
30
|
+
const phase = options.phase ? String(options.phase) : null;
|
|
31
|
+
const verdict = options.verdict ? String(options.verdict).toUpperCase() : null;
|
|
32
|
+
|
|
33
|
+
if (!agent) {
|
|
34
|
+
if (options.json) return { ok: false, reason: 'missing_agent' };
|
|
35
|
+
logger.log('--agent is required. Example: aioson pulse:update . --agent=dev --feature=checkout');
|
|
36
|
+
return { ok: false };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const pulsePath = path.join(contextDir(targetDir), 'project-pulse.md');
|
|
40
|
+
const existing = await readFileSafe(pulsePath);
|
|
41
|
+
|
|
42
|
+
// Parse existing frontmatter
|
|
43
|
+
const fm = existing ? parseFrontmatter(existing) : {};
|
|
44
|
+
|
|
45
|
+
// Extract existing recent_activity lines (keep last 2 to add 1 new = 3 total)
|
|
46
|
+
const existingActivities = [];
|
|
47
|
+
if (existing) {
|
|
48
|
+
const activityMatch = existing.match(/## Recent Activity\n([\s\S]*?)(?=\n##|\s*$)/);
|
|
49
|
+
if (activityMatch) {
|
|
50
|
+
const lines = activityMatch[1].split('\n').filter((l) => l.trim().startsWith('-'));
|
|
51
|
+
existingActivities.push(...lines.slice(-2));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Build new activity line
|
|
56
|
+
const today = nowDate();
|
|
57
|
+
let activityLine = `- ${today} @${agent}`;
|
|
58
|
+
if (slug) activityLine += ` → ${slug}`;
|
|
59
|
+
if (phase) activityLine += ` phase ${phase}`;
|
|
60
|
+
if (gate) activityLine += ` (${gate})`;
|
|
61
|
+
if (verdict) activityLine += ` VERDICT: ${verdict}`;
|
|
62
|
+
if (action) activityLine += `: ${action}`;
|
|
63
|
+
|
|
64
|
+
const recentActivities = [...existingActivities, activityLine];
|
|
65
|
+
|
|
66
|
+
// Build active work entry
|
|
67
|
+
let activeWork = fm.active_work || '';
|
|
68
|
+
if (slug) {
|
|
69
|
+
const phaseStr = phase ? ` → phase ${phase}` : '';
|
|
70
|
+
const statusStr = verdict ? (verdict === 'PASS' ? 'done' : 'in_progress') : 'in_progress';
|
|
71
|
+
activeWork = `${slug}${phaseStr} → @${agent} → ${statusStr}`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Build next recommendation
|
|
75
|
+
const nextRec = next || fm.next_recommendation || '';
|
|
76
|
+
|
|
77
|
+
// Write pulse file
|
|
78
|
+
const lines = [
|
|
79
|
+
'---',
|
|
80
|
+
`last_updated: ${today}`,
|
|
81
|
+
`last_agent: ${agent}`,
|
|
82
|
+
gate ? `last_gate: ${gate}` : (fm.last_gate ? `last_gate: ${fm.last_gate}` : null),
|
|
83
|
+
slug ? `active_feature: ${slug}` : (fm.active_feature ? `active_feature: ${fm.active_feature}` : null),
|
|
84
|
+
activeWork ? `active_work: "${activeWork}"` : null,
|
|
85
|
+
'blockers: none',
|
|
86
|
+
nextRec ? `next_recommendation: "${nextRec}"` : null,
|
|
87
|
+
'---',
|
|
88
|
+
'',
|
|
89
|
+
'# Project Pulse',
|
|
90
|
+
'',
|
|
91
|
+
'## Status',
|
|
92
|
+
'',
|
|
93
|
+
`- **Last agent:** @${agent}`,
|
|
94
|
+
gate ? `- **Last gate:** ${gate}` : null,
|
|
95
|
+
slug ? `- **Active feature:** ${slug}` : null,
|
|
96
|
+
activeWork ? `- **Active work:** ${activeWork}` : null,
|
|
97
|
+
nextRec ? `- **Next:** ${nextRec}` : null,
|
|
98
|
+
'',
|
|
99
|
+
'## Recent Activity',
|
|
100
|
+
'',
|
|
101
|
+
...recentActivities,
|
|
102
|
+
''
|
|
103
|
+
].filter((l) => l !== null);
|
|
104
|
+
|
|
105
|
+
await fs.mkdir(path.dirname(pulsePath), { recursive: true });
|
|
106
|
+
await fs.writeFile(pulsePath, lines.join('\n'), 'utf8');
|
|
107
|
+
|
|
108
|
+
const result = {
|
|
109
|
+
ok: true,
|
|
110
|
+
path: path.relative(targetDir, pulsePath),
|
|
111
|
+
last_agent: agent,
|
|
112
|
+
last_gate: gate,
|
|
113
|
+
active_feature: slug,
|
|
114
|
+
active_work: activeWork,
|
|
115
|
+
next_recommendation: nextRec
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (options.json) return result;
|
|
119
|
+
|
|
120
|
+
logger.log('Project pulse updated:');
|
|
121
|
+
logger.log(` last_agent: ${agent}`);
|
|
122
|
+
if (gate) logger.log(` last_gate: ${gate}`);
|
|
123
|
+
if (slug) logger.log(` active_work: ${activeWork}`);
|
|
124
|
+
logger.log(` Recent activity: +1 entry (kept last 3)`);
|
|
125
|
+
if (next) logger.log(` Next: ${next}`);
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = { runPulseUpdate };
|