@daniellins/power-claude 0.16.3
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.
Potentially problematic release.
This version of @daniellins/power-claude might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/bin/cli.js +124 -0
- package/installer/__tests__/doctor-ready-oracles.test.cjs +140 -0
- package/installer/__tests__/merge-settings.test.cjs +330 -0
- package/installer/adopt.js +161 -0
- package/installer/copy.js +203 -0
- package/installer/doctor.js +266 -0
- package/installer/install.js +155 -0
- package/installer/manifest.js +102 -0
- package/installer/motor-scripts.js +50 -0
- package/installer/motor-scripts.json +39 -0
- package/installer/uninstall.js +99 -0
- package/installer/update.js +376 -0
- package/installer/util.js +113 -0
- package/installer/wizard.js +64 -0
- package/package.json +26 -0
- package/scripts/__fixtures__/anti-path-demo/agents/ap-writer.md +13 -0
- package/scripts/__fixtures__/anti-path-demo/templates/write-tmpl.md +7 -0
- package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.smoke.json +10 -0
- package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.yaml +25 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/agents/content-chief.md +1 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/workflows/wf-criacao-redteam.yaml +3 -0
- package/scripts/__fixtures__/assess-tier/retrofit-leve/pod-spec.json +13 -0
- package/scripts/__fixtures__/fidelity/fake-green-average-in-band.yaml +21 -0
- package/scripts/__fixtures__/fidelity/fake-green-average.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-denominator.yaml +19 -0
- package/scripts/__fixtures__/fidelity/fake-green-missing-evidence.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-threshold.yaml +18 -0
- package/scripts/__fixtures__/fidelity/fake-green-weight.yaml +18 -0
- package/scripts/__fixtures__/fidelity/golden.yaml +31 -0
- package/scripts/__fixtures__/fidelity/trindade-incoherent.yaml +15 -0
- package/scripts/__fixtures__/forge-canonical/pod-spec-example.json +37 -0
- package/scripts/__fixtures__/migrate-squad/authored/agents/offer-engineer.md +17 -0
- package/scripts/__fixtures__/migrate-squad/authored/knowledge/no-source.md +7 -0
- package/scripts/__fixtures__/migrate-squad/authored/knowledge/value-stack-method.md +8 -0
- package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.smoke.json +24 -0
- package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.spec.json +45 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/HEADLINE.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/README.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/agents/hormozi-offer.md +14 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/dead-redundant.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/method-guide.md +6 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/veto-screen.md +4 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/config/config.yaml +2 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/data/case-library.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/scripts/validate-mvn.py +16 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/sops/sop-sample.md +3 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/squad-io.yaml +14 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/tasks/gather-context.md +7 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/templates/output-tmpl.md +5 -0
- package/scripts/__fixtures__/migrate-squad/legacy-squad/workflows/wf-sample.yaml +24 -0
- package/scripts/__fixtures__/pipeline/pipelines/pipeline-checkpoint.yaml +21 -0
- package/scripts/__fixtures__/pipeline/pipelines/pipeline-demo.yaml +22 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/agents/maker.md +13 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.consolidated.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.jsonl +83 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/templates/make-tmpl.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-a/workflows/wf-a.yaml +16 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/agents/user.md +13 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.consolidated.md +8 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.jsonl +14 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/templates/use-tmpl.md +6 -0
- package/scripts/__fixtures__/pipeline/pods/pipe-b/workflows/wf-b.yaml +16 -0
- package/scripts/__fixtures__/pod-run/agents/forge-chief.md +13 -0
- package/scripts/__fixtures__/pod-run/agents/pod-critic.md +13 -0
- package/scripts/__fixtures__/pod-run/templates/build-tmpl.md +8 -0
- package/scripts/__fixtures__/pod-run/templates/gate-tmpl.md +6 -0
- package/scripts/__fixtures__/pod-run/workflows/wf-min.yaml +43 -0
- package/scripts/__fixtures__/pod-run/workflows/wf-skip-modes.yaml +50 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-all-skippable.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-criteria-escalar-de-bloco.yaml +40 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-skip-mode-desconhecido.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-unknown-key.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-cycle.yaml +26 -0
- package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-backedge.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-forward.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/invalid-handoff-open.yaml +27 -0
- package/scripts/__fixtures__/pod-workflow/invalid-knowledge-shape.yaml +18 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-agent.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-outputs.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-template.yaml +15 -0
- package/scripts/__fixtures__/pod-workflow/invalid-missing-veto.yaml +13 -0
- package/scripts/__fixtures__/pod-workflow/invalid-template-not-on-disk.yaml +16 -0
- package/scripts/__fixtures__/pod-workflow/invalid-veto-prose.yaml +17 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/a.md +4 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/b.md +4 -0
- package/scripts/__fixtures__/pod-workflow/knowledge/c.md +4 -0
- package/scripts/__fixtures__/pod-workflow/templates/step-tmpl.md +7 -0
- package/scripts/__fixtures__/pod-workflow/valid-checkpoint-skip-modes.yaml +29 -0
- package/scripts/__fixtures__/pod-workflow/valid-fix-loop.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/valid-knowledge.yaml +30 -0
- package/scripts/__fixtures__/pod-workflow/valid-veto-always-true.yaml +20 -0
- package/scripts/__fixtures__/pod-workflow/valid.yaml +27 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-reporter.md +13 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-researcher.md +13 -0
- package/scripts/__fixtures__/smoke-canary/agents/canary-synth.md +13 -0
- package/scripts/__fixtures__/smoke-canary/memory/learnings.consolidated.md +10 -0
- package/scripts/__fixtures__/smoke-canary/memory/learnings.jsonl +448 -0
- package/scripts/__fixtures__/smoke-canary/templates/report-tmpl.md +9 -0
- package/scripts/__fixtures__/smoke-canary/templates/research-tmpl.md +7 -0
- package/scripts/__fixtures__/smoke-canary/templates/synth-tmpl.md +9 -0
- package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.smoke.json +11 -0
- package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.yaml +53 -0
- package/scripts/__fixtures__/source-audit/fake-green-bronze-unsignaled.yaml +10 -0
- package/scripts/__fixtures__/source-audit/fake-green-counts.yaml +9 -0
- package/scripts/__fixtures__/source-audit/fake-green-missing-evidence.yaml +9 -0
- package/scripts/__fixtures__/source-audit/fake-green-unclassified.yaml +10 -0
- package/scripts/__fixtures__/source-audit/fake-green-verdict.yaml +10 -0
- package/scripts/__fixtures__/source-audit/golden-blocked.yaml +10 -0
- package/scripts/__fixtures__/source-audit/golden.yaml +11 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-count.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-field.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-fileref.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-json.md +13 -0
- package/scripts/__fixtures__/sweep-forms/agents/forms-section.md +13 -0
- package/scripts/__fixtures__/sweep-forms/specs/wf-forms.spec.json +5 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_count.md +5 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_field.md +3 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_fileref.md +3 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_json.md +0 -0
- package/scripts/__fixtures__/sweep-forms/templates/t_section.md +3 -0
- package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.smoke.json +13 -0
- package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.yaml +67 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-1-noop-state-json.fixture.md +18 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-2-crash-buildworkflowyaml.fixture.md +26 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-3-nasce-verde-skip-modes.fixture.md +29 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-4-guarda-sem-irmao.fixture.md +17 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5a-diff-stat-sem-guarda.fixture.md +17 -0
- package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5b-test-f-sobre-diretorio.fixture.md +20 -0
- package/scripts/__fixtures__/veto-checks/copy-clean.md +4 -0
- package/scripts/__fixtures__/veto-checks/copy-dashes.md +4 -0
- package/scripts/__fixtures__/veto-checks/n8n-bad.md +18 -0
- package/scripts/__fixtures__/veto-checks/n8n-ok.md +22 -0
- package/scripts/__fixtures__/veto-checks/page-bad.html +7 -0
- package/scripts/__fixtures__/veto-checks/phash/copy.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/distinct.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/distinct2.png +0 -0
- package/scripts/__fixtures__/veto-checks/phash/make-fixtures.cjs +203 -0
- package/scripts/__fixtures__/veto-checks/phash/ref.png +0 -0
- package/scripts/__fixtures__/veto-checks/slide-ok.html +15 -0
- package/scripts/__fixtures__/veto-checks/slide-overflow.html +14 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/agents/vc-checker.md +13 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/templates/check-tmpl.md +6 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.smoke.json +10 -0
- package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.yaml +19 -0
- package/scripts/__fixtures__/voz-do-dono/README.md +23 -0
- package/scripts/__fixtures__/voz-do-dono/dono-escalar.yaml +9 -0
- package/scripts/__fixtures__/voz-do-dono/dono-guia.yaml +10 -0
- package/scripts/__fixtures__/voz-do-dono/peca-3a-pessoa.md +6 -0
- package/scripts/__fixtures__/voz-do-dono/peca-com-lexico-proibido.md +6 -0
- package/scripts/__fixtures__/voz-do-dono/peca-limpa-1a-pessoa.md +6 -0
- package/scripts/__tests__/derive-ready-transitions.test.cjs +269 -0
- package/scripts/__tests__/enforce-cycle-authority.test.cjs +869 -0
- package/scripts/__tests__/enforce-git-push-authority.test.cjs +701 -0
- package/scripts/__tests__/enforce-ready-oracles.test.cjs +745 -0
- package/scripts/__tests__/motor-scripts.test.cjs +339 -0
- package/scripts/__tests__/pc-run-pod-counter.test.cjs +58 -0
- package/scripts/__tests__/pc-run-pod.test.cjs +578 -0
- package/scripts/__tests__/validate-pod-workflow.test.cjs +90 -0
- package/scripts/__tests__/validate-story-acs.test.cjs +607 -0
- package/scripts/anti-path.test.cjs +163 -0
- package/scripts/arena.cjs +514 -0
- package/scripts/arena.test.cjs +213 -0
- package/scripts/brief-leitura-obrigatoria.test.cjs +364 -0
- package/scripts/consolidate-knowledge-runner.test.cjs +249 -0
- package/scripts/default-funcional.test.cjs +153 -0
- package/scripts/derive-ready-transitions.cjs +325 -0
- package/scripts/forge-additive.test.cjs +158 -0
- package/scripts/forge-assess-tier.cjs +205 -0
- package/scripts/forge-assess-tier.test.cjs +114 -0
- package/scripts/forge-canonical.test.cjs +624 -0
- package/scripts/forge-generate.cjs +1303 -0
- package/scripts/forge-harden-learning.cjs +921 -0
- package/scripts/forge-harden-learning.test.cjs +242 -0
- package/scripts/forge-ingest-memory.cjs +136 -0
- package/scripts/forge-upgrade-pod.cjs +368 -0
- package/scripts/forge.test.cjs +609 -0
- package/scripts/harden-knowledge.test.cjs +612 -0
- package/scripts/harness-g5-lite.cjs +243 -0
- package/scripts/harness-g5-lite.test.cjs +134 -0
- package/scripts/hn-carousel-contrato-entrada.test.cjs +96 -0
- package/scripts/migrate-squad-orchestration.test.cjs +146 -0
- package/scripts/migration-manifest-sf3.2.test.cjs +382 -0
- package/scripts/migration-manifest-sf3.3.test.cjs +170 -0
- package/scripts/migration-manifest-sf5.5.test.cjs +189 -0
- package/scripts/migration-manifest.cjs +1146 -0
- package/scripts/migration-manifest.test.cjs +186 -0
- package/scripts/npm-scope-invocation.test.cjs +194 -0
- package/scripts/owner-layer.cjs +442 -0
- package/scripts/owner-layer.test.cjs +358 -0
- package/scripts/pc-run-pipeline.cjs +289 -0
- package/scripts/pc-run-pipeline.test.cjs +256 -0
- package/scripts/pc-run-pod-countgte.test.cjs +66 -0
- package/scripts/pc-run-pod.cjs +1355 -0
- package/scripts/phash-gate.test.cjs +433 -0
- package/scripts/pod-export-compile.cjs +487 -0
- package/scripts/pod-export-compile.test.cjs +312 -0
- package/scripts/pod-export-executor.cjs +678 -0
- package/scripts/pod-export-executor.test.cjs +1341 -0
- package/scripts/pod-export-hardening.test.cjs +531 -0
- package/scripts/pod-export-postprocess.cjs +427 -0
- package/scripts/pod-export-postprocess.test.cjs +558 -0
- package/scripts/pod-export-queue-race.test.cjs +865 -0
- package/scripts/pod-export-release.cjs +473 -0
- package/scripts/pod-export-release.test.cjs +267 -0
- package/scripts/pod-export-service.cjs +1297 -0
- package/scripts/pod-export-service.test.cjs +489 -0
- package/scripts/pod-export-tools.cjs +470 -0
- package/scripts/pod-export-ui.cjs +805 -0
- package/scripts/pod-export-ui.test.cjs +301 -0
- package/scripts/pod-memory-budget.test.cjs +309 -0
- package/scripts/pod-memory-note.cjs +357 -0
- package/scripts/pod-memory-note.test.cjs +452 -0
- package/scripts/pod-memory.cjs +1252 -0
- package/scripts/pod-memory.test.cjs +951 -0
- package/scripts/render-png.test.cjs +307 -0
- package/scripts/smoke-isolation.test.cjs +100 -0
- package/scripts/smoke-pod-workflow.cjs +755 -0
- package/scripts/smoke-sweep.test.cjs +170 -0
- package/scripts/validate-adopt.js +235 -0
- package/scripts/validate-branding.js +84 -0
- package/scripts/validate-budgets.js +140 -0
- package/scripts/validate-fidelity-output.cjs +267 -0
- package/scripts/validate-fidelity-output.test.cjs +101 -0
- package/scripts/validate-install.js +230 -0
- package/scripts/validate-no-clone.cjs +220 -0
- package/scripts/validate-no-clone.test.cjs +77 -0
- package/scripts/validate-pipeline.cjs +145 -0
- package/scripts/validate-pod-workflow.cjs +878 -0
- package/scripts/validate-source-audit.cjs +170 -0
- package/scripts/validate-source-audit.test.cjs +90 -0
- package/scripts/validate-story-acs.cjs +862 -0
- package/scripts/validate-update-scope-motor.js +421 -0
- package/scripts/veto-checks/html-valid.cjs +92 -0
- package/scripts/veto-checks/lexical-check.cjs +62 -0
- package/scripts/veto-checks/phash-gate.cjs +589 -0
- package/scripts/veto-checks/render-gate.cjs +165 -0
- package/scripts/veto-checks/render-png.cjs +358 -0
- package/scripts/veto-checks.test.cjs +219 -0
- package/scripts/watcher-audit.cjs +178 -0
- package/template/.claude/CLAUDE.md +103 -0
- package/template/.claude/agents/pc-analyst.md +100 -0
- package/template/.claude/agents/pc-architect.md +32 -0
- package/template/.claude/agents/pc-dev.md +27 -0
- package/template/.claude/agents/pc-devops.md +45 -0
- package/template/.claude/agents/pc-planner.md +32 -0
- package/template/.claude/agents/pc-po.md +25 -0
- package/template/.claude/agents/pc-qa.md +25 -0
- package/template/.claude/commands/power/academy.md +9 -0
- package/template/.claude/commands/power/automation.md +9 -0
- package/template/.claude/commands/power/content-carousel.md +267 -0
- package/template/.claude/commands/power/content.md +9 -0
- package/template/.claude/commands/power/dev.md +9 -0
- package/template/.claude/commands/power/forge.md +224 -0
- package/template/.claude/commands/power/hormozi.md +221 -0
- package/template/.claude/commands/power/modo.md +57 -0
- package/template/.claude/hooks/README.md +114 -0
- package/template/.claude/hooks/context-budget.cjs +64 -0
- package/template/.claude/hooks/enforce-cycle-authority.cjs +457 -0
- package/template/.claude/hooks/enforce-git-push-authority.cjs +925 -0
- package/template/.claude/hooks/enforce-ready-oracles.cjs +502 -0
- package/template/.claude/rules/authority.md +76 -0
- package/template/.claude/rules/curadoria-de-conhecimento.md +30 -0
- package/template/.claude/rules/model-matrix.md +34 -0
- package/template/.claude/rules/orchestration.md +133 -0
- package/template/.claude/settings.json +50 -0
- package/template/.claude/skills/pc-apply-qa-fixes/SKILL.md +108 -0
- package/template/.claude/skills/pc-apply-qa-fixes/references/fix-loop.md +40 -0
- package/template/.claude/skills/pc-apply-qa-fixes/references/fix-request-template.md +70 -0
- package/template/.claude/skills/pc-arena/SKILL.md +96 -0
- package/template/.claude/skills/pc-close-story/SKILL.md +105 -0
- package/template/.claude/skills/pc-commit/SKILL.md +108 -0
- package/template/.claude/skills/pc-develop-story/SKILL.md +116 -0
- package/template/.claude/skills/pc-full-cycle/SKILL.md +150 -0
- package/template/.claude/skills/pc-pipeline/SKILL.md +63 -0
- package/template/.claude/skills/pc-pipeline/references/gate-templates.md +46 -0
- package/template/.claude/skills/pc-review-story/SKILL.md +129 -0
- package/template/.claude/skills/pc-review-story/references/false-positive-detection.md +50 -0
- package/template/.claude/skills/pc-review-story/references/nfr-assess.md +47 -0
- package/template/.claude/skills/pc-review-story/references/risk-profile.md +75 -0
- package/template/.claude/skills/pc-review-story/references/security-checklist.md +69 -0
- package/template/.claude/skills/pc-review-story/references/test-design.md +37 -0
- package/template/.claude/skills/pc-review-story/references/trace-requirements.md +46 -0
- package/template/.claude/skills/pc-run-pod/SKILL.md +123 -0
- package/template/.claude/skills/pc-validate-story/SKILL.md +114 -0
- package/template/.claude/skills/pc-wave/SKILL.md +133 -0
- package/template/.env.example +10 -0
- package/template/knowledge/analyst/brainstorming.md +40 -0
- package/template/knowledge/analyst/brief-skeleton.md +32 -0
- package/template/knowledge/analyst/competitor-skeleton.md +39 -0
- package/template/knowledge/analyst/elicitation-menu.md +49 -0
- package/template/knowledge/analyst/market-research-skeleton.md +36 -0
- package/template/knowledge/analyst/research-prompt-structure.md +48 -0
- package/template/knowledge/analyst/roi-skeleton.md +51 -0
- package/template/knowledge/voice-dna/README.md +99 -0
- package/template/knowledge/voice-dna/voice-dna.example.yaml +157 -0
- package/template/pods/README.md +64 -0
- package/template/pods/academy/README.md +37 -0
- package/template/pods/academy/agents/academy-chief.md +27 -0
- package/template/pods/academy/examples/palestra.example.md +142 -0
- package/template/pods/academy/pod-spec.json +44 -0
- package/template/pods/academy/templates/materiais-tmpl.md +17 -0
- package/template/pods/academy/templates/revisao-didatica-tmpl.md +20 -0
- package/template/pods/academy/workflows/wf-materiais-revisao.yaml +30 -0
- package/template/pods/authority-content/README.md +43 -0
- package/template/pods/authority-content/agents/content-chief.md +28 -0
- package/template/pods/authority-content/pod-spec.json +45 -0
- package/template/pods/authority-content/templates/criacao-na-voz-tmpl.md +17 -0
- package/template/pods/authority-content/templates/red-team-factual-tmpl.md +23 -0
- package/template/pods/authority-content/workflows/wf-criacao-redteam.yaml +30 -0
- package/template/pods/automation/README.md +37 -0
- package/template/pods/automation/agents/langgraph-architect.md +30 -0
- package/template/pods/automation/agents/n8n-architect.md +30 -0
- package/template/pods/automation/examples/README.md +46 -0
- package/template/pods/automation/examples/n8n-content-radar.example.json +380 -0
- package/template/pods/automation/knowledge/langgraph-patterns.md +126 -0
- package/template/pods/automation/knowledge/n8n-patterns.md +131 -0
- package/template/pods/automation/memory/README.md +16 -0
- package/template/pods/automation/memory/learnings.consolidated.md +8 -0
- package/template/pods/automation/memory/learnings.jsonl +0 -0
- package/template/pods/automation/pod-spec.json +109 -0
- package/template/pods/automation/specs/wf-langgraph-build.spec.json +107 -0
- package/template/pods/automation/squad-io.yaml +28 -0
- package/template/pods/automation/templates/lg-build-tmpl.md +17 -0
- package/template/pods/automation/templates/lg-design-tmpl.md +23 -0
- package/template/pods/automation/templates/lg-discover-tmpl.md +20 -0
- package/template/pods/automation/templates/lg-handoff-tmpl.md +20 -0
- package/template/pods/automation/templates/lg-test-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-build-tmpl.md +14 -0
- package/template/pods/automation/templates/n8n-design-tmpl.md +23 -0
- package/template/pods/automation/templates/n8n-discover-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-handoff-tmpl.md +20 -0
- package/template/pods/automation/templates/n8n-test-tmpl.md +20 -0
- package/template/pods/automation/workflows/wf-langgraph-build.smoke.json +11 -0
- package/template/pods/automation/workflows/wf-langgraph-build.yaml +64 -0
- package/template/pods/automation/workflows/wf-n8n-build.smoke.json +11 -0
- package/template/pods/automation/workflows/wf-n8n-build.yaml +65 -0
- package/template/pods/content-carousel/README.md +91 -0
- package/template/pods/content-carousel/agents/carousel-builder.md +28 -0
- package/template/pods/content-carousel/agents/carousel-visual.md +24 -0
- package/template/pods/content-carousel/agents/hn-curator.md +74 -0
- package/template/pods/content-carousel/config/heuristic-watcher-rubric.yaml +59 -0
- package/template/pods/content-carousel/knowledge/aquisicao-ancora.md +443 -0
- package/template/pods/content-carousel/knowledge/cta-brief.md +25 -0
- package/template/pods/content-carousel/knowledge/dono.example.yaml +45 -0
- package/template/pods/content-carousel/knowledge/identidade-visual-mascote.md +62 -0
- package/template/pods/content-carousel/knowledge/image-generation.md +62 -0
- package/template/pods/content-carousel/knowledge/selecao-de-ancora.md +60 -0
- package/template/pods/content-carousel/knowledge/slides-html.md +56 -0
- package/template/pods/content-carousel/memory/README.md +18 -0
- package/template/pods/content-carousel/memory/learnings.consolidated.md +6 -0
- package/template/pods/content-carousel/memory/learnings.jsonl +0 -0
- package/template/pods/content-carousel/pod-spec.json +100 -0
- package/template/pods/content-carousel/squad-io.yaml +10 -0
- package/template/pods/content-carousel/templates/assembly-tmpl.md +23 -0
- package/template/pods/content-carousel/templates/digest-tmpl.md +29 -0
- package/template/pods/content-carousel/templates/visuals-tmpl.md +20 -0
- package/template/pods/content-carousel/workflows/wf-content-carousel.smoke.json +23 -0
- package/template/pods/content-carousel/workflows/wf-content-carousel.yaml +80 -0
- package/template/pods/dev-ia/README.md +45 -0
- package/template/pods/dev-ia/agents/db-architect.md +33 -0
- package/template/pods/dev-ia/agents/ux-architect.md +29 -0
- package/template/pods/dev-ia/knowledge/db/migration-protocol.md +95 -0
- package/template/pods/dev-ia/knowledge/db/rls-patterns.md +101 -0
- package/template/pods/dev-ia/knowledge/db/schema-review-checklist.md +76 -0
- package/template/pods/dev-ia/memory/README.md +16 -0
- package/template/pods/dev-ia/memory/learnings.consolidated.md +8 -0
- package/template/pods/dev-ia/memory/learnings.jsonl +0 -0
- package/template/pods/dev-ia/pod-spec.json +34 -0
- package/template/pods/dev-ia/templates/schema-review-tmpl.md +23 -0
- package/template/pods/dev-ia/templates/ux-flow-review-tmpl.md +23 -0
- package/template/pods/dev-ia/tools/db-ops/backup-manager.sh +321 -0
- package/template/pods/dev-ia/tools/db-ops/best-practices-auditor.sh +534 -0
- package/template/pods/dev-ia/tools/db-ops/bootstrap-runner.sh +255 -0
- package/template/pods/dev-ia/tools/db-ops/data-loader.sh +616 -0
- package/template/pods/dev-ia/tools/db-ops/detect-database.sh +113 -0
- package/template/pods/dev-ia/tools/db-ops/explain-analyzer.sh +285 -0
- package/template/pods/dev-ia/tools/db-ops/health-checker.sh +323 -0
- package/template/pods/dev-ia/tools/db-ops/migration-runner.sh +308 -0
- package/template/pods/dev-ia/tools/db-ops/postgresql-schema-loader.sh +334 -0
- package/template/pods/dev-ia/tools/db-ops/query-runner.sh +171 -0
- package/template/pods/dev-ia/tools/db-ops/rls-policy-installer.sh +480 -0
- package/template/pods/dev-ia/tools/db-ops/rls-test-suite.sh +172 -0
- package/template/pods/dev-ia/tools/db-ops/schema-context-loader.sh +176 -0
- package/template/pods/hormozi-method/README.md +52 -0
- package/template/pods/hormozi-method/agents/acquisition-strategist.md +33 -0
- package/template/pods/hormozi-method/agents/conversion-copywriter.md +34 -0
- package/template/pods/hormozi-method/agents/monetization-architect.md +35 -0
- package/template/pods/hormozi-method/agents/offer-engineer.md +37 -0
- package/template/pods/hormozi-method/knowledge/core-four-leads.md +51 -0
- package/template/pods/hormozi-method/knowledge/grand-slam-offer.md +66 -0
- package/template/pods/hormozi-method/knowledge/growth-decision.md +38 -0
- package/template/pods/hormozi-method/knowledge/hooks-and-ads.md +56 -0
- package/template/pods/hormozi-method/knowledge/launch-email.md +31 -0
- package/template/pods/hormozi-method/knowledge/money-model.md +46 -0
- package/template/pods/hormozi-method/knowledge/opportunity-screening.md +44 -0
- package/template/pods/hormozi-method/knowledge/pages.md +25 -0
- package/template/pods/hormozi-method/knowledge/pos-lancamento-leads.md +56 -0
- package/template/pods/hormozi-method/knowledge/pricing.md +36 -0
- package/template/pods/hormozi-method/knowledge/retention-ltv.md +37 -0
- package/template/pods/hormozi-method/knowledge/scale-roadmap.md +35 -0
- package/template/pods/hormozi-method/knowledge/swipefiles-curados.md +44 -0
- package/template/pods/hormozi-method/knowledge/value-equation-diagnostic.md +77 -0
- package/template/pods/hormozi-method/memory/README.md +16 -0
- package/template/pods/hormozi-method/memory/learnings.consolidated.md +6 -0
- package/template/pods/hormozi-method/memory/learnings.jsonl +0 -0
- package/template/pods/hormozi-method/pod-spec.json +50 -0
- package/template/pods/hormozi-method/specs/wf-full-launch-sequence.spec.json +149 -0
- package/template/pods/hormozi-method/specs/wf-lead-magnet-pipeline.spec.json +125 -0
- package/template/pods/hormozi-method/specs/wf-money-model-design.spec.json +117 -0
- package/template/pods/hormozi-method/specs/wf-paid-ads-campaign.spec.json +132 -0
- package/template/pods/hormozi-method/specs/wf-scaling-diagnostic.spec.json +121 -0
- package/template/pods/hormozi-method/squad-io.yaml +43 -0
- package/template/pods/hormozi-method/templates/conversion-copywriter-tmpl.md +20 -0
- package/template/pods/hormozi-method/templates/launch-execucao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-fechamento-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-pos-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/launch-preparacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/lm-copy-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/lm-distribuicao-tmpl.md +18 -0
- package/template/pods/hormozi-method/templates/lm-estrategia-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/mm-arquitetura-tmpl.md +18 -0
- package/template/pods/hormozi-method/templates/mm-copy-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/mm-diagnostico-tmpl.md +14 -0
- package/template/pods/hormozi-method/templates/monetization-architect-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/offer-engineer-tmpl.md +20 -0
- package/template/pods/hormozi-method/templates/paid-criativos-tmpl.md +19 -0
- package/template/pods/hormozi-method/templates/paid-fundacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/paid-teste-escala-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-diagnostico-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-priorizacao-tmpl.md +17 -0
- package/template/pods/hormozi-method/templates/scaling-roadmap-tmpl.md +17 -0
- package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.smoke.json +12 -0
- package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.yaml +56 -0
- package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.smoke.json +9 -0
- package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-money-model-design.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-money-model-design.yaml +45 -0
- package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.smoke.json +9 -0
- package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.yaml +46 -0
- package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.smoke.json +11 -0
- package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.yaml +44 -0
- package/template/pods/squad-forge/README.md +53 -0
- package/template/pods/squad-forge/agents/forge-chief.md +31 -0
- package/template/pods/squad-forge/agents/mind-extractor.md +29 -0
- package/template/pods/squad-forge/agents/pod-critic.md +26 -0
- package/template/pods/squad-forge/config/heuristic-watcher-rubric.yaml +74 -0
- package/template/pods/squad-forge/knowledge/fidelity-rubric.yaml +176 -0
- package/template/pods/squad-forge/knowledge/g6-memory-check.md +17 -0
- package/template/pods/squad-forge/knowledge/memory-ingest.md +16 -0
- package/template/pods/squad-forge/knowledge/source-audit-rubric.yaml +60 -0
- package/template/pods/squad-forge/memory/README.md +16 -0
- package/template/pods/squad-forge/memory/learnings.consolidated.md +8 -0
- package/template/pods/squad-forge/memory/learnings.jsonl +0 -0
- package/template/pods/squad-forge/pod-spec.json +166 -0
- package/template/pods/squad-forge/squad-io.yaml +13 -0
- package/template/pods/squad-forge/tasks/pipeline.md +158 -0
- package/template/pods/squad-forge/templates/discovery-tmpl.md +40 -0
- package/template/pods/squad-forge/templates/generation-tmpl.md +18 -0
- package/template/pods/squad-forge/templates/red-team-tmpl.md +17 -0
- package/template/pods/squad-forge/templates/register-tmpl.md +17 -0
- package/template/pods/squad-forge/templates/workflow-tmpl.yaml +101 -0
- package/template/pods/squad-forge/workflows/wf-forge.smoke.json +12 -0
- package/template/pods/squad-forge/workflows/wf-forge.yaml +60 -0
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* forge.test.cjs — harness de auto-verificação da fábrica v0.3 (Story SF1.4).
|
|
5
|
+
*
|
|
6
|
+
* Cobre, com pods sintéticos em diretório temporário, os ACs verificáveis sem o
|
|
7
|
+
* runner/smoke (SF1.2/SF1.3):
|
|
8
|
+
* AC1 gate de proporcionalidade classifica SIMPLE vs STANDARD/COMPLEX (2 casos).
|
|
9
|
+
* AC2 SIMPLE não recebe aparato completo (sem squad-io/memória).
|
|
10
|
+
* AC3 STANDARD/COMPLEX recebe wf-*.yaml + template/etapa + squad-io + memória.
|
|
11
|
+
* AC4 wf-*.yaml gerado passa validate-pod-workflow.cjs (exit 0) sem ajuste.
|
|
12
|
+
* AC5 persistência disco-first (artefatos existem em disco após a geração).
|
|
13
|
+
* AC6 *upgrade-pod preserva os arquivos de agente (não deleta/sobrescreve).
|
|
14
|
+
* AC7 *upgrade-pod gera artefatos ausentes proporcionais ao tier.
|
|
15
|
+
* AC8 reconciliação bounded remove auto-sequenciamento; excesso ⇒ recomenda *new.
|
|
16
|
+
* AC10 scaffold de memória sem lifecycle (vazio/cabeçalho, sem código).
|
|
17
|
+
*
|
|
18
|
+
* AC9/AC11 (gate G6 real + smoke 4/4) dependem de SF1.2/SF1.3 — verificados no
|
|
19
|
+
* gate do @qa quando prontos; aqui, fora de escopo executável.
|
|
20
|
+
*
|
|
21
|
+
* Node >= 18, sem dependências externas.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const fs = require('node:fs');
|
|
25
|
+
const os = require('node:os');
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
const { spawnSync } = require('node:child_process');
|
|
28
|
+
|
|
29
|
+
const SCRIPTS = __dirname;
|
|
30
|
+
const { classifyTier } = require('./forge-assess-tier.cjs');
|
|
31
|
+
const { generatePod } = require('./forge-generate.cjs');
|
|
32
|
+
const { upgradePod, reconcileAgent } = require('./forge-upgrade-pod.cjs');
|
|
33
|
+
// SF2.3 — fábrica gera memória OPERANTE + watcher + ingest M1.
|
|
34
|
+
const { getConsolidatedForBrief } = require('./pod-memory.cjs');
|
|
35
|
+
const { auditAdherence } = require('./watcher-audit.cjs');
|
|
36
|
+
const { ingestExternal } = require('./forge-ingest-memory.cjs');
|
|
37
|
+
|
|
38
|
+
const results = [];
|
|
39
|
+
function check(label, cond, detail) {
|
|
40
|
+
results.push({ label, ok: Boolean(cond), detail: detail || '' });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function tmpPod(name) {
|
|
44
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), `forge-${name}-`));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// SF12.4a/ADR-030 Bloco O/AC53b — `generatePod` agora exige `opts.specOrigin`. Todo
|
|
48
|
+
// call site direto deste arquivo é geração FRESCA (equivalente ao CLI de `*new`) ⇒
|
|
49
|
+
// 'authored', que por sua vez exige os 3 campos canônicos (Bloco C) declarados ou
|
|
50
|
+
// recusados. Estes testes não modelam ritmo/entrada/entregável — RECUSAM os 3.
|
|
51
|
+
const CANON_REFUSED = {
|
|
52
|
+
nao_se_aplica: true,
|
|
53
|
+
razao: 'fixture de forge.test.cjs não modela ritmo/entrada parametrizada/entregável',
|
|
54
|
+
respondido_por: 'forge.test.cjs',
|
|
55
|
+
};
|
|
56
|
+
function withCanon(spec) {
|
|
57
|
+
return {
|
|
58
|
+
ritmo: CANON_REFUSED, contrato_entrada: CANON_REFUSED, entregavel: CANON_REFUSED,
|
|
59
|
+
...spec,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const AUTHORED = { specOrigin: 'authored' };
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// AC1 — gate de proporcionalidade: 2 casos sintéticos, um de cada lado.
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
const simpleSpec = { pod: 'ac1-simple', agents: ['solo', 'helper'], workflows: 1, handoffs: 1, dna: false, critical: false };
|
|
68
|
+
const complexSpec = { pod: 'ac1-complex', agents: ['a', 'b', 'c'], workflows: 1, handoffs: 2, dna: false, critical: false };
|
|
69
|
+
check('AC1 SIMPLE (≤2 ag/≤1 wf/≤1 handoff/sem dna/não-crítico)', classifyTier(simpleSpec).tier === 'SIMPLE', classifyTier(simpleSpec).tier);
|
|
70
|
+
check('AC1 STANDARD/COMPLEX (3 agentes cruza o limiar)', classifyTier(complexSpec).tier === 'STANDARD/COMPLEX', classifyTier(complexSpec).tier);
|
|
71
|
+
// Cada gatilho oposto isolado força o superior:
|
|
72
|
+
check('AC1 gatilho DNA força STANDARD/COMPLEX', classifyTier({ agents: ['x'], workflows: 1, handoffs: 0, dna: true }).tier === 'STANDARD/COMPLEX');
|
|
73
|
+
check('AC1 gatilho crítico força STANDARD/COMPLEX', classifyTier({ agents: ['x'], workflows: 1, handoffs: 0, critical: true }).tier === 'STANDARD/COMPLEX');
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// AC2 — SIMPLE não recebe aparato completo.
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
{
|
|
79
|
+
const dir = tmpPod('simple');
|
|
80
|
+
const r = generatePod(withCanon({ pod: 'ac2', agents: ['solo', 'helper'], workflows: 1, handoffs: 1 }), dir, AUTHORED);
|
|
81
|
+
check('AC2 tier SIMPLE', r.tier === 'SIMPLE', r.tier);
|
|
82
|
+
check('AC2 sem squad-io.yaml', !fs.existsSync(path.join(dir, 'squad-io.yaml')));
|
|
83
|
+
check('AC2 sem memory/', !fs.existsSync(path.join(dir, 'memory')));
|
|
84
|
+
const wfDir = path.join(dir, 'workflows');
|
|
85
|
+
// SF12.4a/ADR-030 Bloco I: workflows/ agora também pode conter o sidecar `.smoke.json`
|
|
86
|
+
// sintetizado — o regex mede só o(s) `wf-*.yaml` (o mínimo que a AC2 verifica).
|
|
87
|
+
const wfCount = fs.existsSync(wfDir) ? fs.readdirSync(wfDir).filter((f) => /^wf-.*\.ya?ml$/.test(f)).length : 0;
|
|
88
|
+
check('AC2 no máximo 1 workflow mínimo', wfCount <= 1, `${wfCount} workflow(s)`);
|
|
89
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// AC3/AC4/AC5/AC10 — pod STANDARD/COMPLEX completo, validado, disco-first.
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
{
|
|
96
|
+
const dir = tmpPod('complex');
|
|
97
|
+
const spec = { pod: 'ac3', agents: ['discovery', 'build', 'red-team'], handoffs: 2 };
|
|
98
|
+
const r = generatePod(withCanon(spec), dir, AUTHORED);
|
|
99
|
+
check('AC3 tier STANDARD/COMPLEX', r.tier === 'STANDARD/COMPLEX', r.tier);
|
|
100
|
+
|
|
101
|
+
const wfDir = path.join(dir, 'workflows');
|
|
102
|
+
const wfs = fs.existsSync(wfDir) ? fs.readdirSync(wfDir).filter((f) => /^wf-.*\.ya?ml$/.test(f)) : [];
|
|
103
|
+
check('AC3 wf-*.yaml gerado', wfs.length === 1, wfs.join(','));
|
|
104
|
+
|
|
105
|
+
const tplDir = path.join(dir, 'templates');
|
|
106
|
+
const tpls = fs.existsSync(tplDir) ? fs.readdirSync(tplDir).filter((f) => f.endsWith('-tmpl.md')) : [];
|
|
107
|
+
check('AC3 1 template por etapa (3 etapas)', tpls.length === 3, `${tpls.length} templates`);
|
|
108
|
+
check('AC3 squad-io.yaml com handoffs', fs.existsSync(path.join(dir, 'squad-io.yaml')) &&
|
|
109
|
+
fs.readFileSync(path.join(dir, 'squad-io.yaml'), 'utf8').includes('handoffs:'));
|
|
110
|
+
|
|
111
|
+
// AC5 disco-first: todos os artefatos existem em disco imediatamente após gerar.
|
|
112
|
+
check('AC5 disco-first (todos os artefatos em disco)', r.written.every((w) => fs.existsSync(w)));
|
|
113
|
+
|
|
114
|
+
// AC10 scaffold de memória sem lifecycle.
|
|
115
|
+
const jsonl = path.join(dir, 'memory', 'learnings.jsonl');
|
|
116
|
+
const consolidated = path.join(dir, 'memory', 'learnings.consolidated.md');
|
|
117
|
+
check('AC10 learnings.jsonl vazio', fs.existsSync(jsonl) && fs.readFileSync(jsonl, 'utf8').trim() === '');
|
|
118
|
+
const consTxt = fs.existsSync(consolidated) ? fs.readFileSync(consolidated, 'utf8') : '';
|
|
119
|
+
check('AC10 consolidated só cabeçalho (sem heurística)', consTxt.includes('Nenhuma heurística consolidada'));
|
|
120
|
+
// Sem lógica executável de lifecycle (só prosa de scaffold; menção a "Fase 2" é ok).
|
|
121
|
+
check('AC10 memória sem código de lifecycle', !/function\s|=>|require\(|module\.exports|for\s*\(|while\s*\(/.test(consTxt));
|
|
122
|
+
|
|
123
|
+
// AC4 — validador estático da SF1.1 sobre o wf gerado, exit 0 na primeira.
|
|
124
|
+
const wfPath = path.join(wfDir, wfs[0]);
|
|
125
|
+
const val = spawnSync(process.execPath, [path.join(SCRIPTS, 'validate-pod-workflow.cjs'), wfPath], { encoding: 'utf8' });
|
|
126
|
+
check('AC4 wf gerado passa validate-pod-workflow.cjs (exit 0)', val.status === 0, `exit ${val.status} :: ${(val.stdout || '') + (val.stderr || '')}`.slice(0, 200));
|
|
127
|
+
|
|
128
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// AC6/AC7/AC8 — *upgrade-pod sobre pod sintético existente.
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
{
|
|
135
|
+
const dir = tmpPod('upgrade');
|
|
136
|
+
const agentsDir = path.join(dir, 'agents');
|
|
137
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
138
|
+
// 3 agentes pré-existentes ⇒ STANDARD/COMPLEX. Um com auto-sequenciamento;
|
|
139
|
+
// um limpo; um que EXCEDE o bound (decide sozinho entre caminhos).
|
|
140
|
+
const agentAutoSeq = `---\nname: alpha\n---\n# alpha\nGere o rascunho X.\nDepois disso, chame o agente beta para revisar.\n`;
|
|
141
|
+
const agentClean = `---\nname: beta\n---\n# beta\nRevise o rascunho e emita o parecer.\n`;
|
|
142
|
+
const agentOOB = `---\nname: gamma\n---\n# gamma\nVocê decide sozinho entre os 3 caminhos possíveis do processo e orquestra as etapas.\n`;
|
|
143
|
+
fs.writeFileSync(path.join(agentsDir, 'alpha.md'), agentAutoSeq);
|
|
144
|
+
fs.writeFileSync(path.join(agentsDir, 'beta.md'), agentClean);
|
|
145
|
+
fs.writeFileSync(path.join(agentsDir, 'gamma.md'), agentOOB);
|
|
146
|
+
|
|
147
|
+
const beforeAlpha = fs.readFileSync(path.join(agentsDir, 'alpha.md'), 'utf8');
|
|
148
|
+
const beforeGamma = fs.readFileSync(path.join(agentsDir, 'gamma.md'), 'utf8');
|
|
149
|
+
|
|
150
|
+
// ADR-005: a ordem do DAG é dado declarado; upgradePod exige pod-spec.json/--spec.
|
|
151
|
+
fs.writeFileSync(path.join(dir, 'pod-spec.json'), JSON.stringify(
|
|
152
|
+
{ pod: 'upgrade', workflowId: 'up', agents: ['alpha', 'beta', 'gamma'], handoffs: 2 }, null, 2));
|
|
153
|
+
const r = upgradePod(dir, { apply: true, handoffs: 2 });
|
|
154
|
+
|
|
155
|
+
// AC6 — arquivos de agente preservados (existem; gamma intocado por exceder bound).
|
|
156
|
+
check('AC6 agentes preservados (arquivos ainda existem)',
|
|
157
|
+
['alpha.md', 'beta.md', 'gamma.md'].every((f) => fs.existsSync(path.join(agentsDir, f))));
|
|
158
|
+
check('AC6 gamma (fora do bound) NÃO sobrescrito', fs.readFileSync(path.join(agentsDir, 'gamma.md'), 'utf8') === beforeGamma);
|
|
159
|
+
const afterBeta = fs.readFileSync(path.join(agentsDir, 'beta.md'), 'utf8');
|
|
160
|
+
check('AC6 beta (limpo) NÃO alterado', afterBeta === agentClean);
|
|
161
|
+
|
|
162
|
+
// AC7 — artefatos ausentes gerados proporcionais ao tier (STANDARD/COMPLEX).
|
|
163
|
+
check('AC7 tier STANDARD/COMPLEX', r.tier === 'STANDARD/COMPLEX', r.tier);
|
|
164
|
+
const wfDir = path.join(dir, 'workflows');
|
|
165
|
+
check('AC7 workflows/wf-*.yaml gerado', fs.existsSync(wfDir) && fs.readdirSync(wfDir).some((f) => /^wf-.*\.ya?ml$/.test(f)));
|
|
166
|
+
check('AC7 templates gerados', fs.existsSync(path.join(dir, 'templates')));
|
|
167
|
+
check('AC7 squad-io.yaml gerado (STANDARD/COMPLEX)', fs.existsSync(path.join(dir, 'squad-io.yaml')));
|
|
168
|
+
|
|
169
|
+
// AC8 — reconciliação bounded.
|
|
170
|
+
const afterAlpha = fs.readFileSync(path.join(agentsDir, 'alpha.md'), 'utf8');
|
|
171
|
+
check('AC8 auto-sequenciamento removido do alpha',
|
|
172
|
+
beforeAlpha.includes('chame o agente beta') && !afterAlpha.includes('chame o agente beta'));
|
|
173
|
+
check('AC8 alpha ganhou nota workflow-aware (output escopado)', afterAlpha.includes('[reconciliação v0.3]'));
|
|
174
|
+
const gammaRec = r.reconciliation.find((x) => x.agent === 'gamma');
|
|
175
|
+
check('AC8 gamma detectado como excesso de bound ⇒ recomenda *new',
|
|
176
|
+
gammaRec && gammaRec.status === 'recommend-new' && r.recommendNew.includes('gamma'), gammaRec && gammaRec.status);
|
|
177
|
+
|
|
178
|
+
// Reconciliação unitária pura (função):
|
|
179
|
+
const pure = reconcileAgent('Gere X. Depois disso, invoque o agente Y.');
|
|
180
|
+
check('AC8 reconcileAgent remove auto-chamada (unit)', pure.status === 'reconciled' && pure.removed.length === 1);
|
|
181
|
+
const pureOOB = reconcileAgent('Você escolhe o caminho do fluxo conforme o caso.');
|
|
182
|
+
check('AC8 reconcileAgent detecta out-of-bound (unit)', pureOOB.status === 'recommend-new');
|
|
183
|
+
|
|
184
|
+
// [SF6.1 fix round — CONCERNS-1] FALSO-POSITIVO do `[^.]*` guloso: papel-de-domínio
|
|
185
|
+
// "Orquestra a criação de ... agentes" (agentes = OBJETO DA CRIAÇÃO) NÃO pode flagrar.
|
|
186
|
+
// Fixture = a description REAL do forge-chief (o gatilho reproduzido pelo QA).
|
|
187
|
+
const forgeChiefDesc = '---\nname: forge-chief\ndescription: "Orquestra a criação de novos pods, agentes e skills no padrão POWER CLAUDE. Use para: criar um agente para um problema de negócio."\n---\n# forge-chief\nVocê conduz o pipeline que transforma um pedido em artefato. Você orquestra; a extração de DNA é do mind-extractor.\n';
|
|
188
|
+
const fpRec = reconcileAgent(forgeChiefDesc);
|
|
189
|
+
check('AC8 FP: papel-de-domínio "orquestra a criação de agentes" NÃO flagra (clean)',
|
|
190
|
+
fpRec.status === 'clean', fpRec.status);
|
|
191
|
+
|
|
192
|
+
// SEM AFROUXAR: orquestração REAL de fluxo/dispatch continua flagrando (objeto direto).
|
|
193
|
+
check('AC8 pos: "orquestra as etapas do pipeline" → recommend-new',
|
|
194
|
+
reconcileAgent('Você orquestra as etapas do pipeline.').status === 'recommend-new');
|
|
195
|
+
check('AC8 pos: "orquestra os agentes" (dispatch) → recommend-new',
|
|
196
|
+
reconcileAgent('Você orquestra os agentes conforme a fase.').status === 'recommend-new');
|
|
197
|
+
check('AC8 pos: "orquestra o fluxo" → recommend-new',
|
|
198
|
+
reconcileAgent('O agente orquestra o fluxo do processo.').status === 'recommend-new');
|
|
199
|
+
// Domínio inverso: geração/criação como objeto → clean (não é orquestração de fluxo).
|
|
200
|
+
check('AC8 FP: "orquestra a geração dos agentes" (domínio) NÃO flagra (clean)',
|
|
201
|
+
reconcileAgent('Ele orquestra a geração dos agentes finais.').status === 'clean');
|
|
202
|
+
|
|
203
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ===========================================================================
|
|
207
|
+
// ADR-005 — veto ortogonal + ordem do DAG declarada (7 casos que provam o fix).
|
|
208
|
+
// ===========================================================================
|
|
209
|
+
const { parseYaml } = require('./validate-pod-workflow.cjs');
|
|
210
|
+
const { checkTemplateConformance, evalVeto } = require('./pc-run-pod.cjs');
|
|
211
|
+
const VALIDATOR = path.join(SCRIPTS, 'validate-pod-workflow.cjs');
|
|
212
|
+
const SMOKE = path.join(SCRIPTS, 'smoke-pod-workflow.cjs');
|
|
213
|
+
|
|
214
|
+
// --- Caso 1 — wf gerado por default: sem section_exists; veto = field_matches confianca;
|
|
215
|
+
// template tem linha `confianca:` NÃO-heading.
|
|
216
|
+
{
|
|
217
|
+
const dir = tmpPod('adr005-c1');
|
|
218
|
+
generatePod(withCanon({ pod: 'c1', workflowId: 'c1', agents: ['x1', 'x2', 'x3'], handoffs: 2 }), dir, AUTHORED);
|
|
219
|
+
const wf = fs.readFileSync(path.join(dir, 'workflows', 'wf-c1.yaml'), 'utf8');
|
|
220
|
+
check('C1 wf default NÃO usa section_exists', !wf.includes('section_exists'));
|
|
221
|
+
check('C1 wf default usa field_matches confianca', /type:\s*field_matches/.test(wf) && /field:\s*confianca/.test(wf));
|
|
222
|
+
const tpl = fs.readFileSync(path.join(dir, 'templates', 'x2-tmpl.md'), 'utf8');
|
|
223
|
+
const confLine = tpl.split(/\r?\n/).find((l) => /^confianca\s*:/.test(l.trim()));
|
|
224
|
+
check('C1 template tem linha confianca:', Boolean(confLine), confLine || '(ausente)');
|
|
225
|
+
check('C1 linha confianca NÃO é heading', confLine && !/^#{2,6}\s/.test(confLine.trim()));
|
|
226
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// --- Caso 2 — validador REPROVA section_exists que duplica heading do template; e
|
|
230
|
+
// PASSA section_exists de seção AUSENTE do template.
|
|
231
|
+
{
|
|
232
|
+
const dir = tmpPod('adr005-c2');
|
|
233
|
+
fs.mkdirSync(path.join(dir, 'templates'), { recursive: true });
|
|
234
|
+
fs.mkdirSync(path.join(dir, 'workflows'), { recursive: true });
|
|
235
|
+
fs.writeFileSync(path.join(dir, 'templates', 's-tmpl.md'), '# T\n\n## Contexto\nx\n\n## Output\ny\n');
|
|
236
|
+
const wfHead = 'state_machine:\n states: [init, running, complete, failed]\n initial: init\n terminal: [complete, failed]\nsteps:\n';
|
|
237
|
+
const stepFor = (assertion) =>
|
|
238
|
+
` - id: s\n agent: a\n template: templates/s-tmpl.md\n inputs: [brief]\n outputs: [o]\n depends_on: []\n checkpoint: null\n veto:\n assertions:\n - ${assertion}\n`;
|
|
239
|
+
// (a) degenerado: section_exists de "## Output" (heading do template) → FALHA.
|
|
240
|
+
fs.writeFileSync(path.join(dir, 'workflows', 'wf-degen.yaml'), wfHead + stepFor('{ type: section_exists, section: "## Output" }'));
|
|
241
|
+
const degen = spawnSync(process.execPath, [VALIDATOR, path.join(dir, 'workflows', 'wf-degen.yaml')], { encoding: 'utf8' });
|
|
242
|
+
check('C2 validador REPROVA veto não-ortogonal (exit != 0)', degen.status !== 0, `exit ${degen.status}`);
|
|
243
|
+
check('C2 mensagem cita "não-ortogonal"', /não-ortogonal/.test((degen.stdout || '') + (degen.stderr || '')));
|
|
244
|
+
// (b) section_exists de seção AUSENTE do template ("## Anexo") → PASSA (adiciona info).
|
|
245
|
+
fs.writeFileSync(path.join(dir, 'workflows', 'wf-ok.yaml'), wfHead + stepFor('{ type: section_exists, section: "## Anexo" }'));
|
|
246
|
+
const okv = spawnSync(process.execPath, [VALIDATOR, path.join(dir, 'workflows', 'wf-ok.yaml')], { encoding: 'utf8' });
|
|
247
|
+
check('C2 section_exists de seção AUSENTE do template PASSA (exit 0)', okv.status === 0, `exit ${okv.status}`);
|
|
248
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// --- Caso 3 — isolamento das classes com o motor real (checkTemplateConformance vs evalVeto):
|
|
252
|
+
// artefato com todas as seções + confianca inválida → falha SÓ veto [3b];
|
|
253
|
+
// artefato sem uma seção + confianca válida → falha SÓ template [3a].
|
|
254
|
+
{
|
|
255
|
+
const dir = tmpPod('adr005-c3');
|
|
256
|
+
fs.mkdirSync(path.join(dir, 'templates'), { recursive: true });
|
|
257
|
+
fs.writeFileSync(path.join(dir, 'templates', 'syn-tmpl.md'), '# T\n\n## Contexto\nx\n\n## Output\ny\n\nconfianca: <alta|media|baixa>\n');
|
|
258
|
+
const ctx = { podRoot: dir };
|
|
259
|
+
const step = { template: 'templates/syn-tmpl.md' };
|
|
260
|
+
const vetoAssertion = { type: 'field_matches', field: 'confianca', pattern: '^(alta|media|baixa)$' };
|
|
261
|
+
// [3b] todas as seções, confianca: talvez → forma OK, veto FALHA.
|
|
262
|
+
const art3b = '## Contexto\nx\n\n## Output\ny\n\nconfianca: talvez\n';
|
|
263
|
+
const t3b = checkTemplateConformance(ctx, step, art3b);
|
|
264
|
+
const v3b = evalVeto(vetoAssertion, art3b, path.join(dir, 'a.md'), ctx);
|
|
265
|
+
check('C3 [3b] forma OK e veto FALHA (isolado)', t3b.ok === true && v3b.ok === false, `tconf=${t3b.ok} veto=${v3b.ok}`);
|
|
266
|
+
// [3a] falta "## Output", confianca: alta → forma FALHA, veto OK.
|
|
267
|
+
const art3a = '## Contexto\nx\n\nconfianca: alta\n';
|
|
268
|
+
const t3a = checkTemplateConformance(ctx, step, art3a);
|
|
269
|
+
const v3a = evalVeto(vetoAssertion, art3a, path.join(dir, 'a.md'), ctx);
|
|
270
|
+
check('C3 [3a] forma FALHA e veto OK (isolado)', t3a.ok === false && v3a.ok === true, `tconf=${t3a.ok} veto=${v3a.ok}`);
|
|
271
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// --- Caso 4 — upgradePod sem spec → erro ruidoso citando fontes candidatas; NENHUM artefato escrito.
|
|
275
|
+
{
|
|
276
|
+
const dir = tmpPod('adr005-c4');
|
|
277
|
+
fs.mkdirSync(path.join(dir, 'agents'), { recursive: true });
|
|
278
|
+
fs.writeFileSync(path.join(dir, 'agents', 'a.md'), '---\nname: a\n---\n# a\nFaz X.\n');
|
|
279
|
+
fs.writeFileSync(path.join(dir, 'agents', 'b.md'), '---\nname: b\n---\n# b\nFaz Y.\n');
|
|
280
|
+
fs.writeFileSync(path.join(dir, 'agents', 'c.md'), '---\nname: c\n---\n# c\nFaz Z.\n');
|
|
281
|
+
fs.writeFileSync(path.join(dir, 'README.md'), '# pod\nFluxo.\n');
|
|
282
|
+
let threw = null;
|
|
283
|
+
try { upgradePod(dir, { apply: true }); } catch (e) { threw = e; }
|
|
284
|
+
check('C4 upgradePod sem spec LANÇA erro', Boolean(threw), threw ? threw.name : 'não lançou');
|
|
285
|
+
check('C4 erro é fail-loud exit 2', threw && threw.exitCode === 2);
|
|
286
|
+
check('C4 mensagem cita fontes candidatas (README)', threw && /candidatas/.test(threw.message) && /README\.md/.test(threw.message));
|
|
287
|
+
check('C4 NENHUM artefato escrito', !fs.existsSync(path.join(dir, 'workflows')) && !fs.existsSync(path.join(dir, 'templates')) && !fs.existsSync(path.join(dir, 'squad-io.yaml')));
|
|
288
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// --- Caso 5 — spec ordenada [zeta, alfa, media] → steps NESSA ordem (readdir não manda);
|
|
292
|
+
// depends_on/inputs encadeados na ordem da spec.
|
|
293
|
+
{
|
|
294
|
+
const dir = tmpPod('adr005-c5');
|
|
295
|
+
fs.mkdirSync(path.join(dir, 'agents'), { recursive: true });
|
|
296
|
+
// Escritos em ordem alfabética; a spec impõe zeta→alfa→media (readdir daria alfa,media,zeta).
|
|
297
|
+
for (const n of ['alfa', 'media', 'zeta']) fs.writeFileSync(path.join(dir, 'agents', `${n}.md`), `---\nname: ${n}\n---\n# ${n}\nProduz artefato.\n`);
|
|
298
|
+
fs.writeFileSync(path.join(dir, 'pod-spec.json'), JSON.stringify({ pod: 'c5', workflowId: 'ord', agents: ['zeta', 'alfa', 'media'], handoffs: 2 }, null, 2));
|
|
299
|
+
upgradePod(dir, { apply: true });
|
|
300
|
+
const wf = parseYaml(fs.readFileSync(path.join(dir, 'workflows', 'wf-ord.yaml'), 'utf8'));
|
|
301
|
+
const ids = wf.steps.map((s) => s.id);
|
|
302
|
+
check('C5 steps na ordem da spec (zeta, alfa, media)', JSON.stringify(ids) === JSON.stringify(['zeta', 'alfa', 'media']), ids.join(','));
|
|
303
|
+
check('C5 depends_on encadeado na ordem da spec', JSON.stringify(wf.steps[1].depends_on) === '["zeta"]' && JSON.stringify(wf.steps[2].depends_on) === '["alfa"]', JSON.stringify(wf.steps.map((s) => s.depends_on)));
|
|
304
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// --- Caso 6 — agente na spec sem arquivo → erro; agente em disco fora da spec →
|
|
308
|
+
// not-in-workflow no relatório, ausente dos steps, arquivo intocado.
|
|
309
|
+
{
|
|
310
|
+
const dir = tmpPod('adr005-c6');
|
|
311
|
+
fs.mkdirSync(path.join(dir, 'agents'), { recursive: true });
|
|
312
|
+
for (const n of ['a', 'b', 'extra']) fs.writeFileSync(path.join(dir, 'agents', `${n}.md`), `---\nname: ${n}\n---\n# ${n}\nProduz artefato.\n`);
|
|
313
|
+
const extraBefore = fs.readFileSync(path.join(dir, 'agents', 'extra.md'), 'utf8');
|
|
314
|
+
// (a) spec com agente inexistente em disco → erro.
|
|
315
|
+
fs.writeFileSync(path.join(dir, 'pod-spec.json'), JSON.stringify({ pod: 'c6', workflowId: 'w', agents: ['a', 'ghost'], handoffs: 1 }, null, 2));
|
|
316
|
+
let threw = null;
|
|
317
|
+
try { upgradePod(dir, {}); } catch (e) { threw = e; }
|
|
318
|
+
check('C6 agente na spec sem arquivo → erro', Boolean(threw) && /ghost/.test(threw.message));
|
|
319
|
+
// (b) spec [a, b] com 'extra' em disco fora da spec → not-in-workflow, ausente dos steps, intocado.
|
|
320
|
+
fs.writeFileSync(path.join(dir, 'pod-spec.json'), JSON.stringify({ pod: 'c6', workflowId: 'w', agents: ['a', 'b'], handoffs: 1 }, null, 2));
|
|
321
|
+
const r = upgradePod(dir, { apply: true });
|
|
322
|
+
check('C6 extra reportado not-in-workflow', r.notInWorkflow.includes('extra'), r.notInWorkflow.join(','));
|
|
323
|
+
const wf = parseYaml(fs.readFileSync(path.join(dir, 'workflows', 'wf-w.yaml'), 'utf8'));
|
|
324
|
+
check('C6 extra ausente dos steps', !wf.steps.map((s) => s.id).includes('extra'), wf.steps.map((s) => s.id).join(','));
|
|
325
|
+
check('C6 arquivo de extra intocado', fs.readFileSync(path.join(dir, 'agents', 'extra.md'), 'utf8') === extraBefore);
|
|
326
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// --- Caso 7 (equivalente sintético do hormozi) — pod gerado via spec com veto de domínio
|
|
330
|
+
// (count_gte) + confianca: validador exit 0 (incl. ortogonalidade) e smoke 4/4 exit 0,
|
|
331
|
+
// provando a 3b agora construível. O hormozi REAL é regenerado/provado no second-brain.
|
|
332
|
+
{
|
|
333
|
+
const dir = tmpPod('adr005-c7');
|
|
334
|
+
fs.mkdirSync(path.join(dir, 'agents'), { recursive: true });
|
|
335
|
+
for (const n of ['builder', 'checker', 'writer']) fs.writeFileSync(path.join(dir, 'agents', `${n}.md`), `---\nname: ${n}\n---\n# ${n}\nProduz o artefato da etapa.\n`);
|
|
336
|
+
const spec = {
|
|
337
|
+
pod: 'c7', workflowId: 'demo', handoffs: 2,
|
|
338
|
+
agents: [
|
|
339
|
+
{ name: 'builder', output: 'pkg', sections: ['## Contexto', '## Value Stack', '## Output'], veto: [{ type: 'count_gte', field: 'Value Stack', n: 5 }, { type: 'field_matches', field: 'confianca', pattern: '^(alta|media|baixa)$' }] },
|
|
340
|
+
{ name: 'checker', output: 'review' },
|
|
341
|
+
{ name: 'writer', output: 'copy' },
|
|
342
|
+
],
|
|
343
|
+
};
|
|
344
|
+
fs.writeFileSync(path.join(dir, 'pod-spec.json'), JSON.stringify(spec, null, 2));
|
|
345
|
+
upgradePod(dir, { apply: true });
|
|
346
|
+
const wfPath = path.join(dir, 'workflows', 'wf-demo.yaml');
|
|
347
|
+
const val = spawnSync(process.execPath, [VALIDATOR, wfPath], { encoding: 'utf8' });
|
|
348
|
+
check('C7 validador exit 0 (com ortogonalidade)', val.status === 0, `exit ${val.status} :: ${((val.stdout || '') + (val.stderr || '')).slice(0, 160)}`);
|
|
349
|
+
// Sidecar: target_step = checker (default confianca). 3a = falta seção + confianca válida;
|
|
350
|
+
// 3b = todas as seções + confianca inválida.
|
|
351
|
+
const sidecar = {
|
|
352
|
+
target_step: 'checker',
|
|
353
|
+
artifacts: {
|
|
354
|
+
builder: '## Contexto\nc\n\n## Value Stack\n- 1\n- 2\n- 3\n- 4\n- 5\n\n## Output\no\n\nconfianca: alta\n',
|
|
355
|
+
checker: '## Contexto\nc\n\n## Output\no\n\nconfianca: alta\n',
|
|
356
|
+
writer: '## Contexto\nc\n\n## Output\no\n\nconfianca: media\n',
|
|
357
|
+
},
|
|
358
|
+
template_violation: '## Output\no\n\nconfianca: alta\n',
|
|
359
|
+
veto_violation: '## Contexto\nc\n\n## Output\no\n\nconfianca: talvez\n',
|
|
360
|
+
};
|
|
361
|
+
fs.writeFileSync(path.join(dir, 'workflows', 'wf-demo.smoke.json'), JSON.stringify(sidecar, null, 2));
|
|
362
|
+
const sm = spawnSync(process.execPath, [SMOKE, wfPath], { encoding: 'utf8' });
|
|
363
|
+
check('C7 smoke 4/4 exit 0 (3b agora construível)', sm.status === 0, `exit ${sm.status} :: ${((sm.stdout || '') + (sm.stderr || '')).split('\n').filter((l) => /Prova|provas/.test(l)).join(' | ')}`);
|
|
364
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ===========================================================================
|
|
368
|
+
// SF2.3 — memória OPERANTE proporcional ao tier, watcher de aderência, ingest M1.
|
|
369
|
+
// ===========================================================================
|
|
370
|
+
|
|
371
|
+
// AC1 — STANDARD/COMPLEX: memória OPERANTE (instalada pelo motor real, não morta).
|
|
372
|
+
{
|
|
373
|
+
const dir = tmpPod('sf23-operante');
|
|
374
|
+
const spec = { pod: 'op', agents: ['a', 'b', 'c'], handoffs: 2 };
|
|
375
|
+
generatePod(withCanon(spec), dir, AUTHORED);
|
|
376
|
+
const consTxt = fs.readFileSync(path.join(dir, 'memory', 'learnings.consolidated.md'), 'utf8');
|
|
377
|
+
check('SF2.3 AC1 consolidado no formato do MOTOR (pod-memory.cjs), não scaffold morto',
|
|
378
|
+
consTxt.includes('Curado por pod-memory.cjs'), consTxt.split('\n')[2] || '');
|
|
379
|
+
check('SF2.3 AC1 getConsolidatedForBrief lê o path canônico (pod cabeado ao runner)',
|
|
380
|
+
getConsolidatedForBrief('op', { podDir: dir }).length > 0);
|
|
381
|
+
check('SF2.3 AC1 marcador de cabeamento (memory/README.md) presente',
|
|
382
|
+
fs.existsSync(path.join(dir, 'memory', 'README.md')));
|
|
383
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// AC2 — SIMPLE: memória OPCIONAL (default não gera; flag gera; sem virar obrigatória).
|
|
387
|
+
{
|
|
388
|
+
const spec = { pod: 'simp', agents: ['solo', 'helper'], workflows: 1, handoffs: 1 };
|
|
389
|
+
const dirOff = tmpPod('sf23-simple-off');
|
|
390
|
+
generatePod(withCanon(spec), dirOff, AUTHORED);
|
|
391
|
+
check('SF2.3 AC2 SIMPLE sem flag → sem memory/', !fs.existsSync(path.join(dirOff, 'memory')));
|
|
392
|
+
fs.rmSync(dirOff, { recursive: true, force: true });
|
|
393
|
+
|
|
394
|
+
const dirOn = tmpPod('sf23-simple-on');
|
|
395
|
+
const r = generatePod(withCanon(spec), dirOn, { withMemory: true, specOrigin: 'authored' });
|
|
396
|
+
check('SF2.3 AC2 SIMPLE continua SIMPLE (flag não muda o tier)', r.tier === 'SIMPLE', r.tier);
|
|
397
|
+
check('SF2.3 AC2 SIMPLE --with-memory → memória gerada (opcional, sob pedido)',
|
|
398
|
+
fs.existsSync(path.join(dirOn, 'memory', 'learnings.consolidated.md')));
|
|
399
|
+
check('SF2.3 AC2 caminho spec.memoryOpt também habilita',
|
|
400
|
+
(() => { const d = tmpPod('sf23-simple-opt'); generatePod(withCanon({ ...spec, memoryOpt: true }), d, AUTHORED);
|
|
401
|
+
const ok = fs.existsSync(path.join(d, 'memory')); fs.rmSync(d, { recursive: true, force: true }); return ok; })());
|
|
402
|
+
fs.rmSync(dirOn, { recursive: true, force: true });
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// AC6 — débito #1: template gerado documenta a forma contável do count_gte.
|
|
406
|
+
{
|
|
407
|
+
const dir = tmpPod('sf23-countgte');
|
|
408
|
+
const spec = { pod: 'cg', handoffs: 2, dna: true, agents: [
|
|
409
|
+
{ name: 'builder', output: 'pkg', sections: ['## Contexto', '## Value Stack', '## Output'],
|
|
410
|
+
veto: [{ type: 'count_gte', field: 'Value Stack', n: 5 }, { type: 'field_matches', field: 'confianca', pattern: '^(alta|media|baixa)$' }] },
|
|
411
|
+
{ name: 'checker', output: 'rev' },
|
|
412
|
+
] };
|
|
413
|
+
generatePod(withCanon(spec), dir, AUTHORED);
|
|
414
|
+
const tpl = fs.readFileSync(path.join(dir, 'templates', 'builder-tmpl.md'), 'utf8');
|
|
415
|
+
check('SF2.3 AC6 nota count_gte presente junto à seção-alvo', /count_gte "Value Stack"/.test(tpl));
|
|
416
|
+
check('SF2.3 AC6 nota prescreve as 3 formas + prosa não conta',
|
|
417
|
+
/bullets/.test(tpl) && /numeradas/.test(tpl) && /tabela/.test(tpl) && /[Pp]rosa/.test(tpl));
|
|
418
|
+
check('SF2.3 AC6 seção SEM count_gte não recebe a nota (só a seção contável)',
|
|
419
|
+
!/## Contexto\n<!-- count_gte/.test(tpl));
|
|
420
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// AC3 — watcher-rubric audita ADERÊNCIA real (não resumo), 3 status determinísticos.
|
|
424
|
+
{
|
|
425
|
+
check('SF2.3 AC3 heuristic-watcher-rubric.yaml existe no pod squad-forge',
|
|
426
|
+
fs.existsSync(path.resolve(SCRIPTS, '..', 'template', 'pods', 'squad-forge', 'config', 'heuristic-watcher-rubric.yaml')));
|
|
427
|
+
const cons = '# Memória\n- **[oferta fraca]** ancore o preço no valor percebido do cliente\n- **[copy generica]** use provas concretas e numeros especificos\n';
|
|
428
|
+
const applied = auditAdherence(cons, '## Oferta\nreescrevi a oferta fraca: ancore o preço no valor percebido do cliente, não no custo\n## Copy\nadicionei provas concretas e numeros especificos de resultado');
|
|
429
|
+
check('SF2.3 AC3 heurística com padrão materializado → applied', applied.appliedCount === 2 && applied.notAppliedCount === 0, JSON.stringify(applied.results.map((r) => r.status)));
|
|
430
|
+
// ANTI-RESUMO: artefato que só MENCIONA o consolidado sem materializar → not-applied.
|
|
431
|
+
const mention = auditAdherence(cons, '## Oferta\nrevisei a oferta e consultei o learnings.consolidated.md, segui as heurísticas');
|
|
432
|
+
const ofertaRes = mention.results.find((r) => r.trigger === 'oferta fraca');
|
|
433
|
+
check('SF2.3 AC3 ANTI-RESUMO: mencionar o consolidado NÃO conta como aplicar → not-applied',
|
|
434
|
+
ofertaRes.status === 'not-applied', ofertaRes.status);
|
|
435
|
+
// not-applicable: contexto ausente não vira falha.
|
|
436
|
+
const na = auditAdherence(cons, '## Introdução\ntexto sobre um assunto totalmente distinto e sem relação');
|
|
437
|
+
check('SF2.3 AC3 contexto ausente → not-applicable (não é falha do agente)',
|
|
438
|
+
na.notApplicableCount === 2 && na.notAppliedCount === 0, JSON.stringify(na));
|
|
439
|
+
check('SF2.3 AC3 aderência = aplicadas/aplicáveis (não conta as não-aplicáveis)', applied.adherenceScore === 1);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// AC4 — *ingest-memory opt-in com dedup M1 (hash+fonte; colisão → merge, não duplica).
|
|
443
|
+
{
|
|
444
|
+
const dir = tmpPod('sf23-ingest');
|
|
445
|
+
const e = { trigger: 'oferta fraca', recommendation: 'adicione garantia de risco reverso', source: '$100M Offers p.120', content: 'garantia reverte o risco' };
|
|
446
|
+
const r1 = ingestExternal(dir, e);
|
|
447
|
+
const r2 = ingestExternal(dir, e); // mesmo conteúdo + mesma fonte
|
|
448
|
+
const r3 = ingestExternal(dir, { ...e, source: 'outra fonte' }); // fonte diferente
|
|
449
|
+
check('SF2.3 AC4 1a ingestão → appended', r1.action === 'appended');
|
|
450
|
+
check('SF2.3 AC4 colisão hash+fonte → MERGE (incrementa ocorrência)', r2.action === 'merged' && r2.occurrences === 2);
|
|
451
|
+
check('SF2.3 AC4 fonte diferente com mesmo conteúdo → entrada distinta (proveniência)', r3.action === 'appended');
|
|
452
|
+
const raw = fs.readFileSync(path.join(dir, 'memory', 'learnings.jsonl'), 'utf8').trim().split('\n');
|
|
453
|
+
check('SF2.3 AC4 merge NÃO duplica linha (2 entradas: 1 merge x2 + 1 nova)', raw.length === 2, `${raw.length} linhas`);
|
|
454
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
// SF3.4 finding F2 — buildWorkflowYaml PROPAGA checkpoint por-etapa da spec (mid ou
|
|
459
|
+
// final), não só o `final` genérico. Regressão: mid-checkpoint autorado → wf sem ele.
|
|
460
|
+
// ---------------------------------------------------------------------------
|
|
461
|
+
{
|
|
462
|
+
const { stepsFromSpec, buildWorkflowYaml } = require('./forge-generate.cjs');
|
|
463
|
+
const { computeFeatureSet } = require('./migration-manifest.cjs');
|
|
464
|
+
const { parseYaml } = require('./validate-pod-workflow.cjs');
|
|
465
|
+
const spec = {
|
|
466
|
+
pod: 'cp', agents: [
|
|
467
|
+
{ name: 'intake', step: 'a', output: 'o1' },
|
|
468
|
+
{ name: 'arquiteto', step: 'mm-arquitetura', output: 'o2', checkpoint: { blocking: true, criteria: 'CP_PHASE_2 arquitetura de monetização aprovada' } },
|
|
469
|
+
{ name: 'fechamento', step: 'c', output: 'o3' },
|
|
470
|
+
],
|
|
471
|
+
};
|
|
472
|
+
const wf = buildWorkflowYaml('cp', stepsFromSpec(spec));
|
|
473
|
+
const lines = wf.split('\n');
|
|
474
|
+
const cpOf = (id) => {
|
|
475
|
+
const idx = lines.findIndex((l) => l.trim() === `- id: ${id}`);
|
|
476
|
+
return idx < 0 ? '' : (lines.slice(idx).find((l) => l.trim().startsWith('checkpoint:')) || '');
|
|
477
|
+
};
|
|
478
|
+
const cpMid = cpOf('mm-arquitetura');
|
|
479
|
+
check('SF3.4 F2 checkpoint mid-DAG da spec é PROPAGADO ao wf (não dropado)', /blocking: true/.test(cpMid) && /CP_PHASE_2/.test(cpMid), cpMid);
|
|
480
|
+
// A REGRESSÃO que o gate pegou: mid-checkpoint declarado NUNCA pode sair null.
|
|
481
|
+
check('SF3.4 F2 REGRESSÃO — etapa mid com checkpoint declarado NÃO sai null', !/checkpoint:\s*null/.test(cpMid), cpMid);
|
|
482
|
+
check('SF3.4 F2 etapa sem checkpoint declarado mantém default (null em não-final)', /checkpoint:\s*null/.test(cpOf('a')), cpOf('a'));
|
|
483
|
+
check('SF3.4 F2 última etapa sem declaração mantém default final bloqueante', /blocking: true/.test(cpOf('c')) && /revisão da etapa final/.test(cpOf('c')), cpOf('c'));
|
|
484
|
+
const feat = computeFeatureSet(parseYaml(wf));
|
|
485
|
+
check('SF3.4 F2 computeFeatureSet enxerga checkpoint:mid (gatilho do feature-diff não mais mascarado)', feat.checkpoint_positions.includes('mid'), JSON.stringify(feat.checkpoint_positions));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// ===========================================================================
|
|
489
|
+
// SF6.2 / ADR-004 adendo 2026-07-25 — forma STANDARD-interface + dry-run zero-write.
|
|
490
|
+
// Diretiva de fix (3 fixtures): (a) dev-ia real → STANDARD sem wf/squad-io COM memória
|
|
491
|
+
// e templates; (b) interface:true + handoffs:1 → recusa exit 2; (c) dry-run byte-idêntico.
|
|
492
|
+
// ===========================================================================
|
|
493
|
+
const { InterfaceContractError } = require('./forge-generate.cjs');
|
|
494
|
+
|
|
495
|
+
// Snapshot recursivo (relpath → conteúdo) de uma árvore, para provar byte-identidade.
|
|
496
|
+
function snapshotTree(root) {
|
|
497
|
+
const out = {};
|
|
498
|
+
const walk = (dir) => {
|
|
499
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
500
|
+
const abs = path.join(dir, ent.name);
|
|
501
|
+
if (ent.isDirectory()) walk(abs);
|
|
502
|
+
else out[path.relative(root, abs)] = fs.readFileSync(abs, 'utf8');
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
if (fs.existsSync(root)) walk(root);
|
|
506
|
+
return out;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// --- Fixture (a) — dev-ia REAL: 2 agentes, critical:true, interface:true →
|
|
510
|
+
// tier STANDARD/COMPLEX, SEM wf/squad-io, COM memória e templates. Via generatePod
|
|
511
|
+
// (unit) e via upgradePod (integração, com agents/ + pod-spec.json em disco).
|
|
512
|
+
{
|
|
513
|
+
// (a.1) generatePod unit
|
|
514
|
+
const dir = tmpPod('sf62-iface-gen');
|
|
515
|
+
const spec = { pod: 'dev-ia', agents: ['db-architect', 'ux-architect'], handoffs: 0, critical: true, interface: true };
|
|
516
|
+
const r = generatePod(withCanon(spec), dir, AUTHORED);
|
|
517
|
+
check('SF6.2 (a) tier STANDARD/COMPLEX (critical, interface não rebaixa)', r.tier === 'STANDARD/COMPLEX', r.tier);
|
|
518
|
+
check('SF6.2 (a) SEM workflows/ fabricado', !fs.existsSync(path.join(dir, 'workflows')));
|
|
519
|
+
check('SF6.2 (a) SEM squad-io.yaml fabricado', !fs.existsSync(path.join(dir, 'squad-io.yaml')));
|
|
520
|
+
check('SF6.2 (a) skipped combinado wf/squad-io registrado', r.skipped.some((s) => /pod-interface: zero handoff interno/.test(s)), r.skipped.join(' | '));
|
|
521
|
+
check('SF6.2 (a) COM memória operante (é por POD, agnóstica de workflow)', fs.existsSync(path.join(dir, 'memory', 'learnings.consolidated.md')));
|
|
522
|
+
const tpls = fs.existsSync(path.join(dir, 'templates')) ? fs.readdirSync(path.join(dir, 'templates')).filter((f) => f.endsWith('-tmpl.md')) : [];
|
|
523
|
+
check('SF6.2 (a) COM 1 template por especialista (2)', tpls.length === 2, `${tpls.length} templates`);
|
|
524
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
525
|
+
|
|
526
|
+
// (a.2) upgradePod integração — pod real em disco.
|
|
527
|
+
const pd = tmpPod('sf62-iface-up');
|
|
528
|
+
fs.mkdirSync(path.join(pd, 'agents'), { recursive: true });
|
|
529
|
+
fs.writeFileSync(path.join(pd, 'agents', 'db-architect.md'), '---\nname: db-architect\n---\n# db-architect\nModela schema, migrations e RLS.\n');
|
|
530
|
+
fs.writeFileSync(path.join(pd, 'agents', 'ux-architect.md'), '---\nname: ux-architect\n---\n# ux-architect\nDesenha fluxo e revisa UX.\n');
|
|
531
|
+
fs.writeFileSync(path.join(pd, 'pod-spec.json'), JSON.stringify(
|
|
532
|
+
{ pod: 'dev-ia', agents: ['db-architect', 'ux-architect'], handoffs: 0, critical: true, interface: true }, null, 2));
|
|
533
|
+
const ru = upgradePod(pd, { apply: true });
|
|
534
|
+
check('SF6.2 (a) upgradePod tier STANDARD/COMPLEX', ru.tier === 'STANDARD/COMPLEX', ru.tier);
|
|
535
|
+
check('SF6.2 (a) upgradePod NÃO cria workflows/', !fs.existsSync(path.join(pd, 'workflows')));
|
|
536
|
+
check('SF6.2 (a) upgradePod NÃO cria squad-io.yaml', !fs.existsSync(path.join(pd, 'squad-io.yaml')));
|
|
537
|
+
check('SF6.2 (a) upgradePod cria memory/ + templates/', fs.existsSync(path.join(pd, 'memory')) && fs.existsSync(path.join(pd, 'templates')));
|
|
538
|
+
fs.rmSync(pd, { recursive: true, force: true });
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// --- Fixture (b) — interface:true com handoffs:1 → InterfaceContractError exit 2.
|
|
542
|
+
// Fabricar processo onde há acoplamento real é justamente o que a forma proíbe.
|
|
543
|
+
{
|
|
544
|
+
let threw = null;
|
|
545
|
+
try { generatePod({ pod: 'bad', agents: ['a', 'b'], handoffs: 1, interface: true }, tmpPod('sf62-bad'), AUTHORED); }
|
|
546
|
+
catch (e) { threw = e; }
|
|
547
|
+
check('SF6.2 (b) generatePod interface+handoffs:1 LANÇA', Boolean(threw), threw ? threw.name : 'não lançou');
|
|
548
|
+
check('SF6.2 (b) é InterfaceContractError exit 2', threw instanceof InterfaceContractError && threw.exitCode === 2, threw && `${threw.name}/${threw.exitCode}`);
|
|
549
|
+
// Via upgradePod (spec em disco) — o gate vale no caminho de retrofit também.
|
|
550
|
+
const pd = tmpPod('sf62-bad-up');
|
|
551
|
+
fs.mkdirSync(path.join(pd, 'agents'), { recursive: true });
|
|
552
|
+
fs.writeFileSync(path.join(pd, 'agents', 'a.md'), '---\nname: a\n---\n# a\nX.\n');
|
|
553
|
+
fs.writeFileSync(path.join(pd, 'agents', 'b.md'), '---\nname: b\n---\n# b\nY.\n');
|
|
554
|
+
fs.writeFileSync(path.join(pd, 'pod-spec.json'), JSON.stringify({ pod: 'bad', agents: ['a', 'b'], handoffs: 1, interface: true }, null, 2));
|
|
555
|
+
let threw2 = null;
|
|
556
|
+
try { upgradePod(pd, { apply: true }); } catch (e) { threw2 = e; }
|
|
557
|
+
check('SF6.2 (b) upgradePod interface+handoffs:1 recusa exit 2', threw2 && threw2.exitCode === 2, threw2 && `${threw2.name}/${threw2.exitCode}`);
|
|
558
|
+
fs.rmSync(pd, { recursive: true, force: true });
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// --- Fixture (c) — dry-run do upgradePod = ZERO escrita (árvore byte-idêntica antes/depois).
|
|
562
|
+
// Prova o bug real do ADR-004 §2 (generatePod chamado incondicionalmente escrevia até em dry-run).
|
|
563
|
+
// Dois casos: pod-interface e pod STANDARD comum (o fix é geral, não só do caminho interface).
|
|
564
|
+
for (const kind of ['interface', 'standard']) {
|
|
565
|
+
const pd = tmpPod(`sf62-dryrun-${kind}`);
|
|
566
|
+
fs.mkdirSync(path.join(pd, 'agents'), { recursive: true });
|
|
567
|
+
if (kind === 'interface') {
|
|
568
|
+
fs.writeFileSync(path.join(pd, 'agents', 'db-architect.md'), '---\nname: db-architect\n---\n# db-architect\nSchema/RLS.\n');
|
|
569
|
+
fs.writeFileSync(path.join(pd, 'agents', 'ux-architect.md'), '---\nname: ux-architect\n---\n# ux-architect\nUX.\n');
|
|
570
|
+
fs.writeFileSync(path.join(pd, 'pod-spec.json'), JSON.stringify({ pod: 'dev-ia', agents: ['db-architect', 'ux-architect'], handoffs: 0, critical: true, interface: true }, null, 2));
|
|
571
|
+
} else {
|
|
572
|
+
// pod STANDARD comum COM auto-sequenciamento — a reconciliação TAMBÉM não pode escrever em dry-run.
|
|
573
|
+
fs.writeFileSync(path.join(pd, 'agents', 'a.md'), '---\nname: a\n---\n# a\nGere X. Depois disso, chame o agente b.\n');
|
|
574
|
+
fs.writeFileSync(path.join(pd, 'agents', 'b.md'), '---\nname: b\n---\n# b\nRevise.\n');
|
|
575
|
+
fs.writeFileSync(path.join(pd, 'agents', 'c.md'), '---\nname: c\n---\n# c\nFecha.\n');
|
|
576
|
+
fs.writeFileSync(path.join(pd, 'pod-spec.json'), JSON.stringify({ pod: 'std', workflowId: 'w', agents: ['a', 'b', 'c'], handoffs: 2 }, null, 2));
|
|
577
|
+
}
|
|
578
|
+
const before = snapshotTree(pd);
|
|
579
|
+
const rd = upgradePod(pd, { apply: false }); // DRY-RUN
|
|
580
|
+
const after = snapshotTree(pd);
|
|
581
|
+
check(`SF6.2 (c/${kind}) dry-run árvore byte-idêntica (zero escrita)`,
|
|
582
|
+
JSON.stringify(before) === JSON.stringify(after),
|
|
583
|
+
`antes=${Object.keys(before).length} arq, depois=${Object.keys(after).length} arq`);
|
|
584
|
+
check(`SF6.2 (c/${kind}) dry-run ainda reporta o PLANO (generated[] preenchido)`,
|
|
585
|
+
Array.isArray(rd.generated) && rd.generated.length > 0, `${rd.generated.length} no plano`);
|
|
586
|
+
// E o --apply DEPOIS realmente escreve (não quebramos o caminho de escrita).
|
|
587
|
+
const ra = upgradePod(pd, { apply: true });
|
|
588
|
+
const applied = snapshotTree(pd);
|
|
589
|
+
check(`SF6.2 (c/${kind}) --apply após dry-run efetivamente escreve`,
|
|
590
|
+
Object.keys(applied).length > Object.keys(before).length,
|
|
591
|
+
`antes=${Object.keys(before).length} → apply=${Object.keys(applied).length}`);
|
|
592
|
+
void ra;
|
|
593
|
+
fs.rmSync(pd, { recursive: true, force: true });
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ---------------------------------------------------------------------------
|
|
597
|
+
// Relatório.
|
|
598
|
+
// ---------------------------------------------------------------------------
|
|
599
|
+
console.log('POWER CLAUDE — forge v0.3 (harness SF1.4 + ADR-005 + SF6.2 interface)\n');
|
|
600
|
+
const failures = results.filter((r) => !r.ok);
|
|
601
|
+
for (const r of results) {
|
|
602
|
+
console.log(`[${r.ok ? 'OK ' : 'FALHA'}] ${r.label}${r.ok ? '' : ` — ${r.detail}`}`);
|
|
603
|
+
}
|
|
604
|
+
console.log(`\n${results.length - failures.length}/${results.length} verificações passaram.`);
|
|
605
|
+
if (failures.length > 0) {
|
|
606
|
+
console.error('\nHARNESS FALHOU.');
|
|
607
|
+
process.exit(1);
|
|
608
|
+
}
|
|
609
|
+
process.exit(0);
|