@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,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* validate-fidelity-output.cjs — validador estático de FORMA + ARITMÉTICA do output
|
|
5
|
+
* do comando `*fidelity-score` (e do bloco `trindade:` de `*extract`/`*validate`) do
|
|
6
|
+
* mind-extractor (squad-forge). ADR-008 Decisão 2/4.
|
|
7
|
+
*
|
|
8
|
+
* FRONTEIRA (ADR-002/ADR-008): prova o que é MECANIZÁVEL — a aritmética de agregação
|
|
9
|
+
* e a coerência estrutural do bloco — e NUNCA julga CONTEÚDO. Ele não decide se o "4"
|
|
10
|
+
* é o score certo, nem se a citação sustenta o score, nem se um Playbook de fato existe
|
|
11
|
+
* no corpus: isso é JULGAMENTO do agente, revisado por QA/humano. Deixar a aritmética à
|
|
12
|
+
* LLM é o vetor real de fake-green do Risco 1 (score "premium" com denominador inflado,
|
|
13
|
+
* peso trocado ou threshold arredondado através de uma banda) — é isso que este script fecha.
|
|
14
|
+
*
|
|
15
|
+
* Verifica (fidelity_score): (i) 8 camadas presentes, cada uma `scored` (int 1-5 +
|
|
16
|
+
* `evidence` não-vazia) OU `insufficient_data`; (ii) `insufficient_data` FORA do
|
|
17
|
+
* denominador; (iii) peso de cada camada bate com o tipo (Observable 0.8 / Cognitive-Deep
|
|
18
|
+
* 1.0); (iv) média ponderada RECOMPUTADA casa com a reportada; (v) threshold/maturidade
|
|
19
|
+
* consistente com a média computada. Verifica (trindade): 3 componentes nomeados, cada um
|
|
20
|
+
* present|missing, e `verdict: blocked` SSE algum componente `missing` (coerência
|
|
21
|
+
* veredito<->status — nunca a presença real do componente no corpus).
|
|
22
|
+
*
|
|
23
|
+
* Uso: node scripts/validate-fidelity-output.cjs <output.yaml> [<output.yaml> ...]
|
|
24
|
+
* Exit 0 = bloco bem-formado e aritmética honesta; exit 1 = primeira violação nomeada.
|
|
25
|
+
*
|
|
26
|
+
* Fonte única do formato: template/pods/squad-forge/knowledge/fidelity-rubric.yaml
|
|
27
|
+
* (seção output_contract:) — mudar o formato exige tocar rubrica + este validador (dívida
|
|
28
|
+
* de acoplamento declarada no ADR-008 Consequências).
|
|
29
|
+
*
|
|
30
|
+
* Node >= 18, sem dependências externas (reusa o parser YAML-lite do validador de workflow).
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const fs = require('node:fs');
|
|
34
|
+
const path = require('node:path');
|
|
35
|
+
const { parseYaml, Fail } = require('./validate-pod-workflow.cjs');
|
|
36
|
+
|
|
37
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
38
|
+
|
|
39
|
+
// Espelho do knowledge/fidelity-rubric.yaml (threshold_bands + camadas). Acoplamento
|
|
40
|
+
// declarado no ADR-008; a fixture da rubrica (validate-fidelity-output.test.cjs) confere
|
|
41
|
+
// que a rubrica em disco carrega os mesmos 8 pesos/tipos, guardando contra drift.
|
|
42
|
+
const LAYERS = [
|
|
43
|
+
{ layer: 1, type: 'Observable', weight: 0.8 },
|
|
44
|
+
{ layer: 2, type: 'Observable', weight: 0.8 },
|
|
45
|
+
{ layer: 3, type: 'Observable', weight: 0.8 },
|
|
46
|
+
{ layer: 4, type: 'Observable', weight: 0.8 },
|
|
47
|
+
{ layer: 5, type: 'Cognitive', weight: 1.0 },
|
|
48
|
+
{ layer: 6, type: 'Deep Identity', weight: 1.0 },
|
|
49
|
+
{ layer: 7, type: 'Deep Identity', weight: 1.0 },
|
|
50
|
+
{ layer: 8, type: 'Deep Identity', weight: 1.0 },
|
|
51
|
+
];
|
|
52
|
+
const CANON = new Map(LAYERS.map((l) => [l.layer, l]));
|
|
53
|
+
const THRESHOLD_BANDS = {
|
|
54
|
+
below_basic: { min: 1.0, max: 3.0, maturity: 'v0' },
|
|
55
|
+
basic: { min: 3.0, max: 3.75, maturity: '1.0' },
|
|
56
|
+
intermediate: { min: 3.75, max: 4.25, maturity: '2.0' },
|
|
57
|
+
premium: { min: 4.25, max: 4.85, maturity: '3.0+' },
|
|
58
|
+
elite: { min: 4.65, max: 5.0, maturity: '3.0+' },
|
|
59
|
+
};
|
|
60
|
+
const EPS = 0.01; // folga na checagem de pertencimento à banda de threshold
|
|
61
|
+
const AVG_TOL = 0.01; // tolerância de arredondamento da média ponderada (2 casas)
|
|
62
|
+
const TRINDADE_COMPONENTS = ['playbook', 'framework', 'swipe_file'];
|
|
63
|
+
|
|
64
|
+
function fail(msg) {
|
|
65
|
+
throw new Fail(msg);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isPlainMap(v) {
|
|
69
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Bloco fidelity_score — FORMA + ARITMÉTICA.
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
function validateFidelityBlock(fsb) {
|
|
77
|
+
if (!isPlainMap(fsb)) fail('fidelity_score não é um mapa');
|
|
78
|
+
const layers = fsb.layers;
|
|
79
|
+
if (!Array.isArray(layers)) fail('fidelity_score.layers ausente ou não é lista');
|
|
80
|
+
if (layers.length !== 8) fail(`fidelity_score.layers deve ter as 8 camadas — tem ${layers.length}`);
|
|
81
|
+
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
let sumWeighted = 0;
|
|
84
|
+
let sumWeights = 0;
|
|
85
|
+
let scored = 0;
|
|
86
|
+
for (const L of layers) {
|
|
87
|
+
if (!isPlainMap(L)) fail('camada não é um mapa');
|
|
88
|
+
const n = L.layer;
|
|
89
|
+
if (!CANON.has(n)) fail(`camada com número inválido: ${JSON.stringify(n)} (esperado 1-8)`);
|
|
90
|
+
if (seen.has(n)) fail(`camada duplicada: ${n}`);
|
|
91
|
+
seen.add(n);
|
|
92
|
+
const canon = CANON.get(n);
|
|
93
|
+
if (L.type !== canon.type) {
|
|
94
|
+
fail(`camada ${n}: type "${L.type}" != "${canon.type}" da rubrica`);
|
|
95
|
+
}
|
|
96
|
+
if (L.weight !== canon.weight) {
|
|
97
|
+
fail(`camada ${n}: weight ${JSON.stringify(L.weight)} != ${canon.weight} (peso da rubrica para type ${canon.type})`);
|
|
98
|
+
}
|
|
99
|
+
if (L.status === 'scored') {
|
|
100
|
+
if (!Number.isInteger(L.score) || L.score < 1 || L.score > 5) {
|
|
101
|
+
fail(`camada ${n} scored: score deve ser inteiro 1-5 — recebeu ${JSON.stringify(L.score)}`);
|
|
102
|
+
}
|
|
103
|
+
if (typeof L.evidence !== 'string' || L.evidence.trim() === '') {
|
|
104
|
+
fail(`camada ${n} scored: evidence obrigatória e não-vazia (No Invention — score sem evidência citável é ficção)`);
|
|
105
|
+
}
|
|
106
|
+
sumWeighted += L.score * canon.weight;
|
|
107
|
+
sumWeights += canon.weight;
|
|
108
|
+
scored++;
|
|
109
|
+
} else if (L.status === 'insufficient_data') {
|
|
110
|
+
// Fora do denominador — não soma peso nem score (invariante ii).
|
|
111
|
+
} else {
|
|
112
|
+
fail(`camada ${n}: status inválido "${L.status}" (esperado scored | insufficient_data)`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
for (let i = 1; i <= 8; i++) if (!seen.has(i)) fail(`camada ${i} ausente`);
|
|
116
|
+
|
|
117
|
+
const insufficient = 8 - scored;
|
|
118
|
+
if (fsb.scored_count !== scored) {
|
|
119
|
+
fail(`scored_count reportado ${JSON.stringify(fsb.scored_count)} != ${scored} camadas scored reais`);
|
|
120
|
+
}
|
|
121
|
+
if (fsb.insufficient_count !== insufficient) {
|
|
122
|
+
fail(`insufficient_count reportado ${JSON.stringify(fsb.insufficient_count)} != ${insufficient} reais`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (scored === 0) {
|
|
126
|
+
// Nada pontuável: sem média, sem maturidade; threshold só pode ser insufficient_data.
|
|
127
|
+
if (fsb.weighted_average !== null && fsb.weighted_average !== undefined) {
|
|
128
|
+
fail('scored_count=0: weighted_average deve ser null (nenhuma camada sustenta média)');
|
|
129
|
+
}
|
|
130
|
+
if (fsb.threshold !== 'insufficient_data') {
|
|
131
|
+
fail(`scored_count=0: threshold deve ser "insufficient_data" — recebeu ${JSON.stringify(fsb.threshold)}`);
|
|
132
|
+
}
|
|
133
|
+
if (fsb.maturity !== null && fsb.maturity !== undefined) {
|
|
134
|
+
fail('scored_count=0: maturity deve ser ausente/null');
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const computed = sumWeighted / sumWeights;
|
|
140
|
+
if (typeof fsb.weighted_average !== 'number') {
|
|
141
|
+
fail(`weighted_average ausente ou não numérico: ${JSON.stringify(fsb.weighted_average)}`);
|
|
142
|
+
}
|
|
143
|
+
if (Math.abs(fsb.weighted_average - computed) > AVG_TOL) {
|
|
144
|
+
fail(`weighted_average reportado ${fsb.weighted_average} != ${computed.toFixed(4)} recomputado ` +
|
|
145
|
+
`(soma ${sumWeighted.toFixed(3)} / pesos ${sumWeights.toFixed(3)} sobre ${scored} camadas scored) — ` +
|
|
146
|
+
`fake-green aritmético (denominador inflado por insufficient_data, peso trocado ou média forjada)`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const band = THRESHOLD_BANDS[fsb.threshold];
|
|
150
|
+
if (!band) {
|
|
151
|
+
fail(`threshold inválido "${fsb.threshold}" (esperado ${Object.keys(THRESHOLD_BANDS).join('|')})`);
|
|
152
|
+
}
|
|
153
|
+
if (computed < band.min - EPS || computed > band.max + EPS) {
|
|
154
|
+
fail(`threshold "${fsb.threshold}" (banda ${band.min}-${band.max}) inconsistente com a média computada ` +
|
|
155
|
+
`${computed.toFixed(3)} — threshold inflado/deflacionado (rótulo fora da própria banda)`);
|
|
156
|
+
}
|
|
157
|
+
if (fsb.maturity !== band.maturity) {
|
|
158
|
+
fail(`maturity "${fsb.maturity}" != "${band.maturity}" esperada para threshold "${fsb.threshold}"`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
// Bloco trindade — COERÊNCIA veredito<->status (nunca a presença real no corpus).
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
function validateTrindadeBlock(tr) {
|
|
167
|
+
if (!isPlainMap(tr)) fail('trindade não é um mapa');
|
|
168
|
+
const computedMissing = [];
|
|
169
|
+
for (const c of TRINDADE_COMPONENTS) {
|
|
170
|
+
const comp = tr[c];
|
|
171
|
+
if (!isPlainMap(comp)) fail(`trindade.${c} ausente ou não é um mapa {status, evidence}`);
|
|
172
|
+
if (comp.status === 'present') {
|
|
173
|
+
if (typeof comp.evidence !== 'string' || comp.evidence.trim() === '') {
|
|
174
|
+
fail(`trindade.${c} present: evidence obrigatória e não-vazia`);
|
|
175
|
+
}
|
|
176
|
+
} else if (comp.status === 'missing') {
|
|
177
|
+
computedMissing.push(c);
|
|
178
|
+
} else {
|
|
179
|
+
fail(`trindade.${c}: status inválido "${comp.status}" (esperado present | missing)`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (tr.verdict !== 'complete' && tr.verdict !== 'blocked') {
|
|
183
|
+
fail(`trindade.verdict inválido "${tr.verdict}" (esperado complete | blocked)`);
|
|
184
|
+
}
|
|
185
|
+
const reported = Array.isArray(tr.missing) ? tr.missing.slice().sort() : null;
|
|
186
|
+
if (reported === null) fail('trindade.missing ausente (use [] quando completo)');
|
|
187
|
+
const expected = computedMissing.slice().sort();
|
|
188
|
+
if (reported.join(',') !== expected.join(',')) {
|
|
189
|
+
fail(`trindade.missing reportado [${reported.join(', ')}] != [${expected.join(', ')}] (componentes com status missing)`);
|
|
190
|
+
}
|
|
191
|
+
// Coerência bloqueante: verdict=blocked SSE há componente missing (ADR-008 Decisão 4).
|
|
192
|
+
if (computedMissing.length > 0 && tr.verdict !== 'blocked') {
|
|
193
|
+
fail(`trindade.verdict deve ser "blocked" com componente(s) missing [${expected.join(', ')}] — ` +
|
|
194
|
+
`PROIBIDO aprovar com Trindade incompleta (AN003; ADR-008 Decisão 4)`);
|
|
195
|
+
}
|
|
196
|
+
if (computedMissing.length === 0 && tr.verdict !== 'complete') {
|
|
197
|
+
fail('trindade.verdict deve ser "complete" quando nenhum componente está missing');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// Documento (aceita fidelity_score e/ou trindade; exige ao menos um).
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
function validateFidelityOutput(doc) {
|
|
206
|
+
if (!isPlainMap(doc)) fail('raiz do output não é um mapa YAML');
|
|
207
|
+
const hasFs = 'fidelity_score' in doc;
|
|
208
|
+
const hasTr = 'trindade' in doc;
|
|
209
|
+
if (!hasFs && !hasTr) {
|
|
210
|
+
fail('nenhum bloco reconhecido — esperado fidelity_score e/ou trindade (output_contract da rubrica)');
|
|
211
|
+
}
|
|
212
|
+
if (hasFs) validateFidelityBlock(doc.fidelity_score);
|
|
213
|
+
if (hasTr) validateTrindadeBlock(doc.trindade);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function validateFile(filePath) {
|
|
217
|
+
let doc;
|
|
218
|
+
try {
|
|
219
|
+
doc = parseYaml(fs.readFileSync(filePath, 'utf8'));
|
|
220
|
+
} catch (e) {
|
|
221
|
+
fail(`YAML malformado: ${e.message}`);
|
|
222
|
+
}
|
|
223
|
+
validateFidelityOutput(doc);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function main() {
|
|
227
|
+
const targets = process.argv.slice(2);
|
|
228
|
+
if (targets.length === 0) {
|
|
229
|
+
console.error('Uso: node scripts/validate-fidelity-output.cjs <output.yaml> [...]');
|
|
230
|
+
process.exit(2);
|
|
231
|
+
}
|
|
232
|
+
let ok = 0;
|
|
233
|
+
for (const t of targets) {
|
|
234
|
+
const rel = path.relative(REPO_ROOT, path.resolve(t));
|
|
235
|
+
if (!fs.existsSync(t)) {
|
|
236
|
+
console.error(`[FALHA] ${rel}: arquivo não encontrado`);
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
validateFile(t);
|
|
241
|
+
console.log(`[OK ] ${rel}`);
|
|
242
|
+
ok++;
|
|
243
|
+
} catch (e) {
|
|
244
|
+
if (e instanceof Fail) {
|
|
245
|
+
console.error(`[FALHA] ${rel}: ${e.message}`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
}
|
|
248
|
+
throw e;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
console.log(`\n${ok} output(s) de fidelidade validado(s). Forma + aritmética honestas.`);
|
|
252
|
+
process.exit(0);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (require.main === module) {
|
|
256
|
+
main();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = {
|
|
260
|
+
validateFidelityOutput,
|
|
261
|
+
validateFidelityBlock,
|
|
262
|
+
validateTrindadeBlock,
|
|
263
|
+
LAYERS,
|
|
264
|
+
THRESHOLD_BANDS,
|
|
265
|
+
TRINDADE_COMPONENTS,
|
|
266
|
+
Fail,
|
|
267
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* validate-fidelity-output.test.cjs — suíte do validador de FORMA+ARITMÉTICA do
|
|
5
|
+
* *fidelity-score (Story SF7.1, AC5; ADR-008 Decisão 2/4). Prova:
|
|
6
|
+
* (1) o output golden (7 scored + 1 insufficient + trindade completa) PASSA;
|
|
7
|
+
* (2) cada fake-green FALHA (média forjada, insufficient no denominador, evidência
|
|
8
|
+
* ausente, threshold inflado, peso adulterado, Trindade incoerente);
|
|
9
|
+
* (3) a rubrica em disco carrega a FORMA exigida (8 camadas, weight numérico, Fonte:,
|
|
10
|
+
* thresholds, 3 componentes da Trindade, output_contract) — AC5 fixture estrutural;
|
|
11
|
+
* (4) SEM DRIFT: pesos/tipos da rubrica == constantes do validador.
|
|
12
|
+
*
|
|
13
|
+
* Node >= 18.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
const {
|
|
19
|
+
validateFidelityOutput, validateTrindadeBlock, LAYERS, THRESHOLD_BANDS, Fail,
|
|
20
|
+
} = require('./validate-fidelity-output.cjs');
|
|
21
|
+
const { parseYaml } = require('./validate-pod-workflow.cjs');
|
|
22
|
+
|
|
23
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
24
|
+
const FIX = path.join(__dirname, '__fixtures__', 'fidelity');
|
|
25
|
+
const RUBRIC = path.join(REPO_ROOT, 'template', 'pods', 'squad-forge', 'knowledge', 'fidelity-rubric.yaml');
|
|
26
|
+
|
|
27
|
+
let passed = 0;
|
|
28
|
+
const failures = [];
|
|
29
|
+
function ok(cond, label) {
|
|
30
|
+
if (cond) { passed++; console.log(`[OK ] ${label}`); }
|
|
31
|
+
else { failures.push(label); console.error(`[FALHA] ${label}`); }
|
|
32
|
+
}
|
|
33
|
+
function parseFix(name) {
|
|
34
|
+
return parseYaml(fs.readFileSync(path.join(FIX, name), 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
/** True se validateFidelityOutput lançou Fail sobre o doc. */
|
|
37
|
+
function throwsFail(doc) {
|
|
38
|
+
try { validateFidelityOutput(doc); return false; }
|
|
39
|
+
catch (e) { if (e instanceof Fail) return true; throw e; }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// --- (1) Golden PASSA (fidelity_score + trindade) ---
|
|
43
|
+
let goldenOk = true;
|
|
44
|
+
try { validateFidelityOutput(parseFix('golden.yaml')); } catch (e) { goldenOk = false; console.error(e.message); }
|
|
45
|
+
ok(goldenOk, 'AC5 (1) golden (7 scored + 1 insufficient + trindade completa) PASSA');
|
|
46
|
+
|
|
47
|
+
// --- (2) Fake-greens FALHAM, cada um pelo seu vetor ---
|
|
48
|
+
// NOTA de redação (CONCERNS-1): fake-green-average (avg 4.60/premium) e fake-green-denominator
|
|
49
|
+
// (avg 3.47/basic) reportam um threshold INCONSISTENTE com a média recomputada, então quem os
|
|
50
|
+
// pega PRIMEIRO é o threshold-check — não isolam o average-recompute. O isolamento do
|
|
51
|
+
// average-recompute é provado por fake-green-average-in-band (abaixo), único fixture que só ele pega.
|
|
52
|
+
ok(throwsFail(parseFix('fake-green-average.yaml')), 'AC5 (2) média + threshold forjados (4.60/premium) FALHA (pego pelo threshold-check)');
|
|
53
|
+
ok(throwsFail(parseFix('fake-green-denominator.yaml')), 'AC5 (2) insufficient_data no denominador (3.47/basic) FALHA (pego pelo threshold-check)');
|
|
54
|
+
ok(throwsFail(parseFix('fake-green-average-in-band.yaml')),'AC5 (2) ISOLA o average-recompute: média forjada 4.20 DENTRO da banda intermediate (threshold consistente) — só o recompute pega, FALHA');
|
|
55
|
+
ok(throwsFail(parseFix('fake-green-missing-evidence.yaml')),'AC5 (2) score sem evidência FALHA');
|
|
56
|
+
ok(throwsFail(parseFix('fake-green-threshold.yaml')), 'AC5 (2) threshold inflado (premium sobre 4.03) FALHA');
|
|
57
|
+
ok(throwsFail(parseFix('fake-green-weight.yaml')), 'AC5 (2) peso adulterado (Cognitive 0.8) FALHA');
|
|
58
|
+
ok(throwsFail(parseFix('trindade-incoherent.yaml')), 'AC5 (2) Trindade: verdict complete com componente missing FALHA');
|
|
59
|
+
|
|
60
|
+
// --- Sanidade inline: coerência da Trindade nos dois sentidos ---
|
|
61
|
+
ok(!throwsFail({ trindade: {
|
|
62
|
+
playbook: { status: 'present', evidence: 'x' }, framework: { status: 'present', evidence: 'x' },
|
|
63
|
+
swipe_file: { status: 'present', evidence: 'x' }, verdict: 'complete', missing: [] } }),
|
|
64
|
+
'sanidade: trindade completa (todos present + verdict complete) PASSA');
|
|
65
|
+
ok(throwsFail({ trindade: {
|
|
66
|
+
playbook: { status: 'missing', evidence: '' }, framework: { status: 'present', evidence: 'x' },
|
|
67
|
+
swipe_file: { status: 'present', evidence: 'x' }, verdict: 'blocked', missing: [] } }),
|
|
68
|
+
'sanidade: verdict blocked mas missing:[] (lista incoerente) FALHA');
|
|
69
|
+
ok(throwsFail({}), 'sanidade: doc sem fidelity_score nem trindade FALHA');
|
|
70
|
+
|
|
71
|
+
// --- (3) Rubrica em disco: FORMA estrutural (AC5 fixture) ---
|
|
72
|
+
const rubricText = fs.readFileSync(RUBRIC, 'utf8');
|
|
73
|
+
const rubric = parseYaml(rubricText);
|
|
74
|
+
ok(Array.isArray(rubric.layers) && rubric.layers.length === 8, 'AC5 (3) rubrica tem 8 camadas');
|
|
75
|
+
ok(rubric.layers.every((l) => typeof l.weight === 'number'), 'AC5 (3) toda camada tem weight numérico');
|
|
76
|
+
ok(/^\s*#?\s*Fonte:/im.test(rubricText), 'AC5 (3) rubrica tem cabeçalho Fonte:');
|
|
77
|
+
ok(rubric.scoring && rubric.scoring.thresholds && rubric.threshold_bands, 'AC5 (3) thresholds presentes');
|
|
78
|
+
ok(rubric.trindade && rubric.trindade.components
|
|
79
|
+
&& ['playbook', 'framework', 'swipe_file'].every((c) => c in rubric.trindade.components),
|
|
80
|
+
'AC5 (3) 3 componentes da Trindade nomeados');
|
|
81
|
+
ok(!!rubric.output_contract, 'AC5 (3) output_contract presente');
|
|
82
|
+
|
|
83
|
+
// --- (4) Sem drift: rubrica == constantes do validador ---
|
|
84
|
+
const noDrift = LAYERS.every((canon) => {
|
|
85
|
+
const r = rubric.layers.find((l) => l.layer === canon.layer);
|
|
86
|
+
return r && r.type === canon.type && r.weight === canon.weight;
|
|
87
|
+
});
|
|
88
|
+
ok(noDrift, 'AC5 (4) pesos/tipos da rubrica == constantes LAYERS do validador (sem drift)');
|
|
89
|
+
const bandsMatch = Object.keys(THRESHOLD_BANDS).every((k) => {
|
|
90
|
+
const r = rubric.threshold_bands[k];
|
|
91
|
+
return r && r.min === THRESHOLD_BANDS[k].min && r.max === THRESHOLD_BANDS[k].max
|
|
92
|
+
&& r.maturity === THRESHOLD_BANDS[k].maturity;
|
|
93
|
+
});
|
|
94
|
+
ok(bandsMatch, 'AC5 (4) threshold_bands da rubrica == constantes do validador (sem drift)');
|
|
95
|
+
|
|
96
|
+
if (failures.length > 0) {
|
|
97
|
+
console.error(`\nSuíte do validador de fidelidade FALHOU: ${failures.length} de ${passed + failures.length}.`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
console.log(`\n${passed} asserções verdes. Validador de fidelidade provado.`);
|
|
101
|
+
process.exit(0);
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/**
|
|
4
|
+
* validate-install.js — teste E2E do instalador POWER CLAUDE.
|
|
5
|
+
*
|
|
6
|
+
* Cria um tmpdir, roda `node bin/cli.js install --yes` com cwd no tmpdir e
|
|
7
|
+
* verifica o resultado. Exit 0/1 com relatório.
|
|
8
|
+
*
|
|
9
|
+
* Node >= 18, sem dependências externas.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('node:fs');
|
|
13
|
+
const os = require('node:os');
|
|
14
|
+
const path = require('node:path');
|
|
15
|
+
const { spawnSync } = require('node:child_process');
|
|
16
|
+
|
|
17
|
+
const { motorEntries } = require('../installer/motor-scripts');
|
|
18
|
+
const { sha256OfFile } = require('../installer/manifest');
|
|
19
|
+
|
|
20
|
+
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
21
|
+
const CLI = path.join(REPO_ROOT, 'bin', 'cli.js');
|
|
22
|
+
const TEMPLATE_DIR = path.join(REPO_ROOT, 'template');
|
|
23
|
+
|
|
24
|
+
const results = [];
|
|
25
|
+
function check(label, ok, detail) {
|
|
26
|
+
results.push({ label, ok, detail });
|
|
27
|
+
console.log(`[${ok ? 'OK ' : 'FALHA'}] ${label}${detail ? ` — ${detail}` : ''}`);
|
|
28
|
+
return ok;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function countTemplateFiles(dir) {
|
|
32
|
+
let n = 0;
|
|
33
|
+
const stack = [dir];
|
|
34
|
+
while (stack.length > 0) {
|
|
35
|
+
const d = stack.pop();
|
|
36
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
37
|
+
const p = path.join(d, entry.name);
|
|
38
|
+
if (entry.isDirectory()) stack.push(p);
|
|
39
|
+
else if (entry.isFile()) n++;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return n;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function listPodDirs(dir) {
|
|
46
|
+
const podsDir = path.join(dir, 'pods');
|
|
47
|
+
if (!fs.existsSync(podsDir)) return [];
|
|
48
|
+
return fs
|
|
49
|
+
.readdirSync(podsDir, { withFileTypes: true })
|
|
50
|
+
.filter((e) => e.isDirectory())
|
|
51
|
+
.map((e) => e.name)
|
|
52
|
+
.sort();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function main() {
|
|
56
|
+
console.log('POWER CLAUDE — validate-install (E2E)\n');
|
|
57
|
+
|
|
58
|
+
const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), 'power-claude-e2e-'));
|
|
59
|
+
console.log(`Diretório de teste: ${tmpdir}\n`);
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
// 1. Instalação não-interativa
|
|
63
|
+
const install = spawnSync(process.execPath, [CLI, 'install', '--yes'], {
|
|
64
|
+
cwd: tmpdir,
|
|
65
|
+
encoding: 'utf8',
|
|
66
|
+
timeout: 120000,
|
|
67
|
+
});
|
|
68
|
+
const installed = check('install --yes termina com exit 0', install.status === 0, `exit ${install.status}`);
|
|
69
|
+
if (!installed) {
|
|
70
|
+
console.error('\n--- stdout ---\n' + (install.stdout || ''));
|
|
71
|
+
console.error('\n--- stderr ---\n' + (install.stderr || ''));
|
|
72
|
+
finish(tmpdir);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 2. Arquivos essenciais
|
|
77
|
+
check('.claude/CLAUDE.md existe', fs.existsSync(path.join(tmpdir, '.claude', 'CLAUDE.md')));
|
|
78
|
+
|
|
79
|
+
const settingsPath = path.join(tmpdir, '.claude', 'settings.json');
|
|
80
|
+
let settings = null;
|
|
81
|
+
let settingsOk = false;
|
|
82
|
+
try {
|
|
83
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
84
|
+
settingsOk = true;
|
|
85
|
+
} catch {
|
|
86
|
+
settingsOk = false;
|
|
87
|
+
}
|
|
88
|
+
check('.claude/settings.json parseia', settingsOk);
|
|
89
|
+
check(
|
|
90
|
+
'.claude/settings.json tem hooks',
|
|
91
|
+
Boolean(settings && settings.hooks && typeof settings.hooks === 'object' && Object.keys(settings.hooks).length > 0)
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
check(
|
|
95
|
+
'.claude/hooks/enforce-git-push-authority.cjs existe',
|
|
96
|
+
fs.existsSync(path.join(tmpdir, '.claude', 'hooks', 'enforce-git-push-authority.cjs'))
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// 3. Pods e knowledge
|
|
100
|
+
check('pods/README.md existe', fs.existsSync(path.join(tmpdir, 'pods', 'README.md')));
|
|
101
|
+
|
|
102
|
+
const expectedPods = listPodDirs(TEMPLATE_DIR);
|
|
103
|
+
const installedPods = listPodDirs(tmpdir);
|
|
104
|
+
const allPodsPresent = expectedPods.every((p) => installedPods.includes(p));
|
|
105
|
+
check(
|
|
106
|
+
`5 diretórios de pods instalados (${expectedPods.length} esperados)`,
|
|
107
|
+
expectedPods.length >= 5 && allPodsPresent,
|
|
108
|
+
`instalados: ${installedPods.join(', ') || 'nenhum'}`
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
check('knowledge/voice-dna/ existe', fs.existsSync(path.join(tmpdir, 'knowledge', 'voice-dna')));
|
|
112
|
+
|
|
113
|
+
// 4. Manifest
|
|
114
|
+
const manifestPath = path.join(tmpdir, '.power-claude', 'manifest.json');
|
|
115
|
+
let manifest = null;
|
|
116
|
+
try {
|
|
117
|
+
manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
118
|
+
} catch {
|
|
119
|
+
manifest = null;
|
|
120
|
+
}
|
|
121
|
+
check('.power-claude/manifest.json parseia', manifest !== null);
|
|
122
|
+
if (manifest) {
|
|
123
|
+
const expectedMin = countTemplateFiles(TEMPLATE_DIR);
|
|
124
|
+
check(
|
|
125
|
+
`manifest cobre >= ${expectedMin} arquivos (todos do template)`,
|
|
126
|
+
Array.isArray(manifest.files) && manifest.files.length >= expectedMin,
|
|
127
|
+
`manifest tem ${Array.isArray(manifest.files) ? manifest.files.length : 0}`
|
|
128
|
+
);
|
|
129
|
+
check('manifest tem version e installedAt', Boolean(manifest.version && manifest.installedAt));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// 5. .gitignore cobre .env
|
|
133
|
+
const gitignorePath = path.join(tmpdir, '.gitignore');
|
|
134
|
+
let coversEnv = false;
|
|
135
|
+
if (fs.existsSync(gitignorePath)) {
|
|
136
|
+
const lines = fs.readFileSync(gitignorePath, 'utf8').split(/\r?\n/).map((l) => l.trim());
|
|
137
|
+
coversEnv = lines.includes('.env');
|
|
138
|
+
}
|
|
139
|
+
check('.gitignore contém ".env"', coversEnv);
|
|
140
|
+
|
|
141
|
+
// 6. doctor passa no projeto recém-instalado
|
|
142
|
+
const doctor = spawnSync(process.execPath, [CLI, 'doctor'], { cwd: tmpdir, encoding: 'utf8', timeout: 120000 });
|
|
143
|
+
if (!check('doctor termina com exit 0 no projeto recém-instalado', doctor.status === 0, `exit ${doctor.status}`)) {
|
|
144
|
+
console.error('\n--- doctor stdout ---\n' + (doctor.stdout || ''));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 7. Scripts do motor (ADR-007): os 14 presentes e byte-idênticos ao pacote.
|
|
148
|
+
const entries = motorEntries();
|
|
149
|
+
let allMotorPresent = true;
|
|
150
|
+
let allByteIdentical = true;
|
|
151
|
+
for (const { path: rel } of entries) {
|
|
152
|
+
const destPath = path.join(tmpdir, ...rel.split('/'));
|
|
153
|
+
const srcPath = path.join(REPO_ROOT, ...rel.split('/'));
|
|
154
|
+
if (!fs.existsSync(destPath)) {
|
|
155
|
+
allMotorPresent = false;
|
|
156
|
+
console.error(` ausente: ${rel}`);
|
|
157
|
+
} else if (fs.existsSync(srcPath) && sha256OfFile(destPath) !== sha256OfFile(srcPath)) {
|
|
158
|
+
allByteIdentical = false;
|
|
159
|
+
console.error(` difere do pacote: ${rel}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
check(`${entries.length} scripts do motor presentes em scripts/<nome>`, allMotorPresent);
|
|
163
|
+
check('scripts do motor byte-idênticos ao pacote', allByteIdentical);
|
|
164
|
+
|
|
165
|
+
// 7b. Fixture negativa: scripts de teste/E2E NÃO vazam para o projeto.
|
|
166
|
+
const forbidden = [
|
|
167
|
+
'scripts/validate-install.js',
|
|
168
|
+
'scripts/validate-adopt.js',
|
|
169
|
+
'scripts/pc-run-pod.test.cjs',
|
|
170
|
+
'scripts/forge.test.cjs',
|
|
171
|
+
'scripts/__tests__/motor-scripts.test.cjs',
|
|
172
|
+
];
|
|
173
|
+
const leaked = forbidden.filter((rel) => fs.existsSync(path.join(tmpdir, ...rel.split('/'))));
|
|
174
|
+
check('scripts de teste/E2E NÃO foram copiados (fixture negativa)', leaked.length === 0, leaked.length ? `vazaram: ${leaked.join(', ')}` : undefined);
|
|
175
|
+
check('diretório scripts/__tests__ NÃO foi copiado', !fs.existsSync(path.join(tmpdir, 'scripts', '__tests__')));
|
|
176
|
+
check('diretório scripts/__fixtures__ NÃO foi copiado', !fs.existsSync(path.join(tmpdir, 'scripts', '__fixtures__')));
|
|
177
|
+
|
|
178
|
+
// 8. update preserva script do motor modificado pelo usuário; intacto atualiza.
|
|
179
|
+
const MOD_REL = 'scripts/watcher-audit.cjs';
|
|
180
|
+
const INTACT_REL = 'scripts/pod-memory.cjs';
|
|
181
|
+
const modPath = path.join(tmpdir, ...MOD_REL.split('/'));
|
|
182
|
+
const userContent = fs.readFileSync(modPath, 'utf8') + '\n// edição do usuário — não sobrescrever\n';
|
|
183
|
+
fs.writeFileSync(modPath, userContent, 'utf8');
|
|
184
|
+
const userHash = sha256OfFile(modPath);
|
|
185
|
+
const update = spawnSync(process.execPath, [CLI, 'update', '--yes'], { cwd: tmpdir, encoding: 'utf8', timeout: 120000 });
|
|
186
|
+
check('update --yes termina com exit 0', update.status === 0, `exit ${update.status}`);
|
|
187
|
+
check('update PRESERVOU o script do motor modificado', sha256OfFile(modPath) === userHash);
|
|
188
|
+
check(
|
|
189
|
+
'update manteve script do motor intacto (byte-idêntico ao pacote)',
|
|
190
|
+
sha256OfFile(path.join(tmpdir, ...INTACT_REL.split('/'))) === sha256OfFile(path.join(REPO_ROOT, ...INTACT_REL.split('/')))
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// 9. doctor: script do motor ausente com owner presente → FALHA (exit 1);
|
|
194
|
+
// sem o owner → check pulado (doctor não falha por causa dele).
|
|
195
|
+
const DEL_REL = 'scripts/forge-generate.cjs'; // owner pod:squad-forge
|
|
196
|
+
fs.rmSync(path.join(tmpdir, ...DEL_REL.split('/')), { force: true });
|
|
197
|
+
const doctorMissing = spawnSync(process.execPath, [CLI, 'doctor'], { cwd: tmpdir, encoding: 'utf8', timeout: 120000 });
|
|
198
|
+
check('doctor FALHA (exit 1) com script do motor ausente e owner presente', doctorMissing.status === 1, `exit ${doctorMissing.status}`);
|
|
199
|
+
check('doctor aponta o script ausente', /forge-generate\.cjs/.test(doctorMissing.stdout || ''));
|
|
200
|
+
// Remove o owner (pod squad-forge) → o check do script ausente é pulado.
|
|
201
|
+
fs.rmSync(path.join(tmpdir, 'pods', 'squad-forge'), { recursive: true, force: true });
|
|
202
|
+
const doctorSkipped = spawnSync(process.execPath, [CLI, 'doctor'], { cwd: tmpdir, encoding: 'utf8', timeout: 120000 });
|
|
203
|
+
check(
|
|
204
|
+
'doctor PULA (warn) o script do motor quando o owner não está instalado',
|
|
205
|
+
/Motor: scripts\/forge-generate\.cjs.*pulada/i.test(doctorSkipped.stdout || ''),
|
|
206
|
+
undefined
|
|
207
|
+
);
|
|
208
|
+
} finally {
|
|
209
|
+
finish(tmpdir);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function finish(tmpdir) {
|
|
214
|
+
try {
|
|
215
|
+
fs.rmSync(tmpdir, { recursive: true, force: true });
|
|
216
|
+
} catch (error) {
|
|
217
|
+
console.warn(`Aviso: falha ao limpar tmpdir ${tmpdir}: ${error.message}`);
|
|
218
|
+
}
|
|
219
|
+
const failed = results.filter((r) => !r.ok);
|
|
220
|
+
console.log(`\n${results.length - failed.length}/${results.length} checagens passaram.`);
|
|
221
|
+
if (failed.length > 0) {
|
|
222
|
+
console.error('E2E FALHOU:');
|
|
223
|
+
for (const f of failed) console.error(` - ${f.label}${f.detail ? ` (${f.detail})` : ''}`);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
console.log('E2E verde.');
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
main();
|