@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,925 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* POWER CLAUDE — PreToolUse hook: autoridade de publicação remota (git/GitHub).
|
|
6
|
+
*
|
|
7
|
+
* Regras (D4, 3 níveis de autoridade — story SF12.3, Bloco M):
|
|
8
|
+
* 1. Force-push é SEMPRE negado, para qualquer agente, incondicionalmente
|
|
9
|
+
* (guardrail do ambiente — a única operação irreversível deste hook).
|
|
10
|
+
* 2. `git push` (sem `--force`) / `gh pr create`:
|
|
11
|
+
* - permitidos, sem output, se `input.agent_type === "pc-devops"`;
|
|
12
|
+
* - caso contrário, exigem aprovação humana explícita ("ask").
|
|
13
|
+
* 3. `gh pr merge`: **`ask` sempre, para TODO agente, sem exceção — inclusive
|
|
14
|
+
* devops.** Merge em `main` espera aprovação humana explícita como regra
|
|
15
|
+
* permanente (decisão do dono, D4); isto NÃO muda com este hook.
|
|
16
|
+
* 4. Identidade: `input.agent_type`, o `subagent_type` literal do despacho
|
|
17
|
+
* (ex. "pc-devops") — MEDIDO (não deduzido), ver AC41 da story SF12.3.
|
|
18
|
+
* SEM fallback a variáveis de ambiente: `PC_ACTIVE_AGENT` /
|
|
19
|
+
* `CLAUDE_AGENT_NAME` / `CLAUDE_CODE_AGENT` não existem no produto (0
|
|
20
|
+
* ocorrências no binário da plataforma) e `.claude/settings.json` tem
|
|
21
|
+
* chave `env` que alcança subprocessos — mantê-las como fonte
|
|
22
|
+
* reabriria a autoproclamação que este hook existe para fechar (o
|
|
23
|
+
* `@dev` que edita `settings.json` poderia se autoproclamar devops).
|
|
24
|
+
* `agent_type` não é escrevível pelo agente. `input.agent_id` ausente
|
|
25
|
+
* (não vazio) identifica o main thread — tratado como identidade
|
|
26
|
+
* ambígua, nunca como devops.
|
|
27
|
+
* 5. Input malformado bloqueia apenas comandos que aparentem ser de push,
|
|
28
|
+
* não qualquer Bash (fail-closed proporcional).
|
|
29
|
+
* 6. Robustez: `input.agent_type` pode estar AUSENTE (main thread) — nenhum
|
|
30
|
+
* método de string é chamado sobre ele sem checar presença antes; um
|
|
31
|
+
* `TypeError` faria o hook não emitir decisão nenhuma (fail-open
|
|
32
|
+
* silencioso, pior que qualquer `ask`).
|
|
33
|
+
*
|
|
34
|
+
* Reconhecimento de comando (fix round F1, story SF12.3 — gate FAIL do
|
|
35
|
+
* `pc-qa` em 2026-08-06): o desenho ANTERIOR enumerava sintaxe por regex de
|
|
36
|
+
* contiguidade textual (`\bgit\s+push\b[^|;&]*\s--force\b` etc.) — bypassável
|
|
37
|
+
* por sintaxe de shell corriqueira e não-adversarial: flags curtas
|
|
38
|
+
* combinadas (`-uf`) e opções globais do git antes do subcomando
|
|
39
|
+
* (`git -c user.name=x push`). Enumeração de sintaxe shell não converge (
|
|
40
|
+
* sempre existe uma variante a mais). Este arquivo RECONHECE A OPERAÇÃO em
|
|
41
|
+
* vez de enumerar formas perigosas: tokeniza o comando (respeitando aspas),
|
|
42
|
+
* separa comandos encadeados (`;`, `&&`, `||`, `|`, quebra de linha) em
|
|
43
|
+
* segmentos independentes, localiza o token `git`/`gh` (ou `.../git`,
|
|
44
|
+
* `.../gh` — caminho absoluto/relativo), pula as opções GLOBAIS conhecidas
|
|
45
|
+
* do git (`-c`, `-C`, `--git-dir[=]`, `--work-tree[=]`, `--namespace[=]`,
|
|
46
|
+
* `--exec-path[=]`, `--super-prefix[=]`, `--config-env[=]`, e flags globais
|
|
47
|
+
* sem argumento) até achar o SUBCOMANDO real, e só então classifica as
|
|
48
|
+
* flags do subcomando. Para força: `--force`/`--force-with-lease`/
|
|
49
|
+
* `--force-if-includes` (com ou sem `=valor`) OU qualquer flag curta em
|
|
50
|
+
* CLUSTER que contenha `f` isolado (`-uf`, `-fu`, `-f`, ...) — a única
|
|
51
|
+
* forma de errar para o lado seguro é tratar cedo demais como força, nunca
|
|
52
|
+
* tarde demais.
|
|
53
|
+
*
|
|
54
|
+
* ALIAS de git (fix round F3, story SF12.3 — gate FAIL do `pc-qa` em
|
|
55
|
+
* 2026-08-06): um subcomando de git pode ser um ALIAS configurado — o texto
|
|
56
|
+
* do comando sozinho não denuncia isso (`git z origin main` não parece push
|
|
57
|
+
* nenhum se `alias.z = push` estiver na config do repo, estado EXTERNO ao
|
|
58
|
+
* comando). Quando o subcomando encontrado não é um subcomando conhecido do
|
|
59
|
+
* git (`KNOWN_GIT_SUBCOMMANDS`), este hook tenta resolvê-lo como alias, em
|
|
60
|
+
* 3 fontes, da mais barata para a mais cara: (1) `-c alias.<nome>=<valor>`
|
|
61
|
+
* no PRÓPRIO comando; (2) `git config alias.<nome> <valor>` num segmento
|
|
62
|
+
* ANTERIOR do mesmo comando encadeado; (3) `git config --get alias.<nome>`
|
|
63
|
+
* consultando a config real do repositório (`input.cwd`), via subprocesso
|
|
64
|
+
* síncrono com timeout curto — só chamado quando as 2 fontes baratas não
|
|
65
|
+
* resolveram, e nunca para subcomandos já reconhecidos (custo comum ~0).
|
|
66
|
+
* O valor resolvido é reexpandido e reanalisado (alias de alias tem um
|
|
67
|
+
* limite de profundidade). Alias de shell (`!git push --force`) é resolvido
|
|
68
|
+
* antes de classificar. **Se a consulta em si falhar** (não confundir com
|
|
69
|
+
* "não é alias" — `git config --get` retorna exit 1 quando a chave não
|
|
70
|
+
* existe, e isto É uma resposta conclusiva, não uma falha) — timeout,
|
|
71
|
+
* `git` ausente, erro inesperado — o resultado é `ask`, nunca silêncio.
|
|
72
|
+
*
|
|
73
|
+
* Limitação DECLARADA, não implícita (mesma régua do AC10/AC12/AC15 —
|
|
74
|
+
* "um AC nunca promete mais do que o instrumento entrega", D7 do dono):
|
|
75
|
+
* este hook é guard-rail contra ERRO, não barreira contra evasão
|
|
76
|
+
* deliberada. Ele NÃO resolve substituição de comando (`$(...)`, crase),
|
|
77
|
+
* expansão de variável cujo valor contém o comando (`$CMD` onde
|
|
78
|
+
* `CMD="git push --force"`), nem indireção por `sh -c`/`bash -c`/
|
|
79
|
+
* `eval`/`npm run`/`node -e`/scripts externos (`./deploy.sh`) que por sua
|
|
80
|
+
* vez rodem git — qualquer um desses contorna o hook por desenho, decisão
|
|
81
|
+
* do dono (perseguir essas variantes não converge e não é o problema que
|
|
82
|
+
* este hook resolve). Comandos encadeados por `;`/`&&`/`||`/`|` OU por
|
|
83
|
+
* quebra de linha SÃO tratados (cada segmento é analisado de forma
|
|
84
|
+
* independente). Dentro do que este hook SE PROPÕE a cobrir (a forma
|
|
85
|
+
* direta de `git`/`gh`, incluindo alias), na dúvida ele nunca decide por
|
|
86
|
+
* silêncio: ou reconhece a operação (e classifica), ou não reconhece nada
|
|
87
|
+
* (silêncio é aceitável SÓ quando não há `git`/`gh` reconhecível no
|
|
88
|
+
* comando, ou quando um subcomando desconhecido foi CONCLUSIVAMENTE
|
|
89
|
+
* resolvido como "não é alias").
|
|
90
|
+
*
|
|
91
|
+
* Fix round F4 (story SF12.3 — 3º gate FAIL do `pc-qa`, mesmo dia do F3):
|
|
92
|
+
* o guarda de profundidade da resolução de alias (`ALIAS_MAX_DEPTH`)
|
|
93
|
+
* retornava `null` (silêncio) ao estourar o limite — "não consegui
|
|
94
|
+
* resolver a cadeia" tratado como se fosse "sei que não é push", a MESMA
|
|
95
|
+
* classe de defeito de F1 (regex não cobria sintaxe) e da falha de
|
|
96
|
+
* identidade que motivou o design deste hook: confiança indevida
|
|
97
|
+
* disfarçada de resposta conclusiva. Corrigido para `{kind:
|
|
98
|
+
* 'unresolved-alias'}` → `ask`. Nesta rodada, TODO caminho de saída
|
|
99
|
+
* silenciosa do arquivo foi varrido e classificado (ver Dev Agent Record
|
|
100
|
+
* da story para a lista completa); 2 outros achados da MESMA família
|
|
101
|
+
* foram corrigidos no mesmo round: (1) o fallback de JSON malformado
|
|
102
|
+
* (`rawTextSuspectsGovernedOperation`) reusava o parser tokenizado, que
|
|
103
|
+
* colapsa um JSON compacto (sem espaço fora de strings) num único token —
|
|
104
|
+
* o fallback NUNCA detectava nada, mesmo com "git push --force" literal
|
|
105
|
+
* no texto; corrigido para regex de substring sobre o texto bruto; (2)
|
|
106
|
+
* `main()` não tinha rede de segurança de topo — uma exceção não prevista
|
|
107
|
+
* em qualquer ponto do fluxo terminava o processo sem emitir
|
|
108
|
+
* `hookSpecificOutput` nenhum, que a plataforma trata como fail-open
|
|
109
|
+
* (pior que `ask`); adicionado `try/catch` em `main()` que converte
|
|
110
|
+
* QUALQUER exceção não tratada em `ask`. `readStdin()` deixou de engolir
|
|
111
|
+
* sua própria exceção (antes disfarçava falha de leitura como "comando
|
|
112
|
+
* vazio" = silêncio) — agora propaga para essa rede de segurança.
|
|
113
|
+
*
|
|
114
|
+
* ALIAS de `gh` (fix round F5, story SF12.3 — 4º gate FAIL do `pc-qa`,
|
|
115
|
+
* mesmo dia): assimetria entre os 2 branches — o `git` ganhou resolução de
|
|
116
|
+
* alias em 3 fontes no F3/F4, o `gh` continuou casando `pr create`/
|
|
117
|
+
* `pr merge` de forma literal, mesmo o `gh` tendo alias NATIVO (`gh alias
|
|
118
|
+
* set`) tão real quanto o do git (medido: `gh alias set qm 'pr merge
|
|
119
|
+
* --auto'` faz `gh qm` executar `pr merge --auto`; `gh alias set --shell`
|
|
120
|
+
* embute shell da mesma forma que o `!` do git). O branch `gh` agora usa a
|
|
121
|
+
* MESMA disciplina do `git`, com a lógica de expansão/recursão/guarda de
|
|
122
|
+
* profundidade COMPARTILHADA entre os 2 branches (`expandResolvedAliasAndRecurse`)
|
|
123
|
+
* — só a forma de CONSULTAR alias difere, porque as ferramentas diferem:
|
|
124
|
+
* o `git` tem consulta por nome exata (`git config --get alias.<nome>`,
|
|
125
|
+
* exit 1 = "não existe", resposta conclusiva por chave); o `gh` só expõe
|
|
126
|
+
* `gh alias list` (lista tudo, sem consulta por nome) — este hook chama
|
|
127
|
+
* essa lista NO MÁXIMO 1 VEZ por invocação (cacheada em `ctx.ghAliasCache`,
|
|
128
|
+
* mesmo com múltiplos subcomandos desconhecidos na mesma cadeia) e procura
|
|
129
|
+
* o nome no resultado; qualquer código de saída ≠ 0 (config corrompida,
|
|
130
|
+
* `gh` ausente, timeout) é tratado como "não deu para confirmar" → `ask` —
|
|
131
|
+
* a lista de `gh` não tem o mesmo sinal limpo de "exit 1 = não existe" que
|
|
132
|
+
* o `git config --get` tem (medido: config corrompida também sai com
|
|
133
|
+
* exit 1), então SÓ exit 0 com saída parseável conta como resposta
|
|
134
|
+
* conclusiva. 2 fontes (não 3): não existe equivalente do `-c
|
|
135
|
+
* alias.X=valor` inline do git para `gh` (a ferramenta não tem esse
|
|
136
|
+
* mecanismo — assimetria INERENTE, declarada, não uma lacuna) — mas
|
|
137
|
+
* `gh alias set <nome> <valor> [--shell]` num segmento ANTERIOR da mesma
|
|
138
|
+
* cadeia é capturado (fonte barata), e a consulta real via `gh alias list`
|
|
139
|
+
* fecha o resto. Verificado empiricamente e DESCARTADO como risco: `gh`
|
|
140
|
+
* recusa criar alias com nome de comando real ("already a gh command or
|
|
141
|
+
* extension") — não há como um alias sombrear `pr`/`issue`/etc., mesma
|
|
142
|
+
* garantia já confirmada para o `git`.
|
|
143
|
+
*
|
|
144
|
+
* Sem dependências externas além do próprio `git`/`gh` (só chamados para
|
|
145
|
+
* resolver alias — roda em qualquer instalação limpa mesmo sem `git`/`gh`
|
|
146
|
+
* no PATH: nesse caso a consulta falha e o resultado é `ask`, não crash).
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
const fs = require('fs');
|
|
150
|
+
const { spawnSync } = require('child_process');
|
|
151
|
+
|
|
152
|
+
const DEVOPS_AGENT_TYPE = 'pc-devops';
|
|
153
|
+
|
|
154
|
+
// Opções GLOBAIS do git que tomam um valor em token SEPARADO (quando não
|
|
155
|
+
// usadas na forma `--opcao=valor`). Fonte: `git help` (seção OPTIONS).
|
|
156
|
+
const GIT_GLOBAL_OPTS_WITH_ARG = new Set([
|
|
157
|
+
'-c',
|
|
158
|
+
'-C',
|
|
159
|
+
'--exec-path',
|
|
160
|
+
'--git-dir',
|
|
161
|
+
'--work-tree',
|
|
162
|
+
'--namespace',
|
|
163
|
+
'--super-prefix',
|
|
164
|
+
'--config-env',
|
|
165
|
+
'--html-path',
|
|
166
|
+
'--man-path',
|
|
167
|
+
'--info-path',
|
|
168
|
+
]);
|
|
169
|
+
|
|
170
|
+
// gh: opções globais mais comuns que tomam valor em token separado.
|
|
171
|
+
const GH_GLOBAL_OPTS_WITH_ARG = new Set(['-R', '--repo', '--hostname']);
|
|
172
|
+
|
|
173
|
+
// Subcomandos REAIS do git (porcelana + os plumbing mais comuns) — lista de
|
|
174
|
+
// custo, não de correção: um subcomando fora desta lista dispara a
|
|
175
|
+
// resolução de alias (barata primeiro, subprocesso só se preciso); um
|
|
176
|
+
// subcomando real que falte aqui só custa 1 consulta extra de config (que
|
|
177
|
+
// resolve "não é alias" e segue em silêncio), nunca um resultado errado.
|
|
178
|
+
const KNOWN_GIT_SUBCOMMANDS = new Set([
|
|
179
|
+
'add', 'am', 'apply', 'archive', 'bisect', 'blame', 'branch', 'bundle',
|
|
180
|
+
'cat-file', 'checkout', 'cherry-pick', 'citool', 'clean', 'clone', 'commit',
|
|
181
|
+
'config', 'count-objects', 'describe', 'diff', 'difftool', 'fetch',
|
|
182
|
+
'filter-branch', 'format-patch', 'fsck', 'gc', 'grep', 'gui', 'help',
|
|
183
|
+
'init', 'instaweb', 'log', 'ls-files', 'ls-remote', 'ls-tree',
|
|
184
|
+
'maintenance', 'merge', 'mergetool', 'mv', 'notes', 'pull', 'push',
|
|
185
|
+
'range-diff', 'rebase', 'reflog', 'remote', 'repack', 'replace',
|
|
186
|
+
'request-pull', 'reset', 'restore', 'rev-list', 'rev-parse', 'revert',
|
|
187
|
+
'rm', 'send-email', 'shortlog', 'show', 'sparse-checkout', 'stash',
|
|
188
|
+
'status', 'submodule', 'switch', 'tag', 'update-index', 'var',
|
|
189
|
+
'verify-commit', 'verify-tag', 'version', 'whatchanged', 'worktree',
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
// Subcomandos REAIS do `gh` (fonte: `gh --help`, seções CORE/GITHUB
|
|
193
|
+
// ACTIONS/ADDITIONAL COMMANDS + `help`) — mesma régua de custo do
|
|
194
|
+
// `KNOWN_GIT_SUBCOMMANDS`: um subcomando fora desta lista dispara a
|
|
195
|
+
// resolução de alias; um subcomando real que falte aqui só custa 1
|
|
196
|
+
// consulta extra a `gh alias list` (que resolve "não é alias" e segue em
|
|
197
|
+
// silêncio), nunca um resultado errado. `co` (o alias nativo que o `gh`
|
|
198
|
+
// já vem com por padrão) NÃO entra aqui de propósito — é um alias, não um
|
|
199
|
+
// subcomando, e precisa cair no caminho de resolução.
|
|
200
|
+
const KNOWN_GH_SUBCOMMANDS = new Set([
|
|
201
|
+
'auth', 'browse', 'codespace', 'discussion', 'gist', 'issue', 'org', 'pr',
|
|
202
|
+
'project', 'release', 'repo', 'skill', 'cache', 'run', 'workflow',
|
|
203
|
+
'agent-task', 'alias', 'api', 'attestation', 'completion', 'config',
|
|
204
|
+
'copilot', 'extension', 'gpg-key', 'label', 'licenses', 'preview',
|
|
205
|
+
'ruleset', 'search', 'secret', 'ssh-key', 'status', 'variable', 'help',
|
|
206
|
+
]);
|
|
207
|
+
|
|
208
|
+
// Sem try/catch aqui de propósito (fix round F4): se a leitura de stdin
|
|
209
|
+
// falhar, isso é "não sei o que o comando é", não "não há comando" — a
|
|
210
|
+
// exceção propaga e é pega pelo catch-all de `main()`, que emite `ask`.
|
|
211
|
+
// Engolir o erro aqui e devolver '' faria `parseInput` produzir `{}`
|
|
212
|
+
// (JSON válido, vazio) em vez de sinalizar falha — silêncio disfarçado de
|
|
213
|
+
// "não há operação", exatamente o padrão que este round existe para fechar.
|
|
214
|
+
function readStdin() {
|
|
215
|
+
return fs.readFileSync(0, 'utf8');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function parseInput(rawInput) {
|
|
219
|
+
try {
|
|
220
|
+
const parsed = JSON.parse(rawInput || '{}');
|
|
221
|
+
return parsed && typeof parsed === 'object' ? parsed : null;
|
|
222
|
+
} catch {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Separa comandos encadeados por `;`, `&&`, `||`, `|` e quebra de linha,
|
|
228
|
+
// respeitando aspas (não separa dentro de uma string entre aspas).
|
|
229
|
+
function splitSegments(command) {
|
|
230
|
+
const segments = [];
|
|
231
|
+
let current = '';
|
|
232
|
+
let quote = null;
|
|
233
|
+
const str = String(command || '');
|
|
234
|
+
for (let i = 0; i < str.length; i++) {
|
|
235
|
+
const ch = str[i];
|
|
236
|
+
const next = str[i + 1];
|
|
237
|
+
if (quote) {
|
|
238
|
+
current += ch;
|
|
239
|
+
if (ch === quote) quote = null;
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (ch === '"' || ch === "'") {
|
|
243
|
+
quote = ch;
|
|
244
|
+
current += ch;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (ch === '\n' || ch === '\r') {
|
|
248
|
+
segments.push(current);
|
|
249
|
+
current = '';
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (ch === ';') {
|
|
253
|
+
segments.push(current);
|
|
254
|
+
current = '';
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (ch === '&' && next === '&') {
|
|
258
|
+
segments.push(current);
|
|
259
|
+
current = '';
|
|
260
|
+
i++;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (ch === '|' && next === '|') {
|
|
264
|
+
segments.push(current);
|
|
265
|
+
current = '';
|
|
266
|
+
i++;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (ch === '|') {
|
|
270
|
+
segments.push(current);
|
|
271
|
+
current = '';
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
current += ch;
|
|
275
|
+
}
|
|
276
|
+
segments.push(current);
|
|
277
|
+
return segments;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Tokeniza um segmento por espaço em branco, respeitando aspas (o conteúdo
|
|
281
|
+
// entre aspas vira 1 token, sem as aspas em si). Não expande `\` como
|
|
282
|
+
// escape — suficiente para localizar subcomando e flags, não para executar.
|
|
283
|
+
function tokenize(segment) {
|
|
284
|
+
const tokens = [];
|
|
285
|
+
let current = '';
|
|
286
|
+
let quote = null;
|
|
287
|
+
let has = false;
|
|
288
|
+
const str = String(segment || '');
|
|
289
|
+
for (let i = 0; i < str.length; i++) {
|
|
290
|
+
const ch = str[i];
|
|
291
|
+
if (quote) {
|
|
292
|
+
if (ch === quote) {
|
|
293
|
+
quote = null;
|
|
294
|
+
} else {
|
|
295
|
+
current += ch;
|
|
296
|
+
}
|
|
297
|
+
has = true;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (ch === '"' || ch === "'") {
|
|
301
|
+
quote = ch;
|
|
302
|
+
has = true;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (/\s/.test(ch)) {
|
|
306
|
+
if (has) {
|
|
307
|
+
tokens.push(current);
|
|
308
|
+
current = '';
|
|
309
|
+
has = false;
|
|
310
|
+
}
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
current += ch;
|
|
314
|
+
has = true;
|
|
315
|
+
}
|
|
316
|
+
if (has) tokens.push(current);
|
|
317
|
+
return tokens;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function isGitToken(tok) {
|
|
321
|
+
return tok === 'git' || tok.endsWith('/git');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function isGhToken(tok) {
|
|
325
|
+
return tok === 'gh' || tok.endsWith('/gh');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// A partir do índice do token "git", pula as opções GLOBAIS conhecidas e
|
|
329
|
+
// retorna { subcommand, index } do primeiro token que não é uma opção
|
|
330
|
+
// global — ou null se só houver opções/nada depois de "git". Se
|
|
331
|
+
// `inlineAliases` (Map) for passado, toda opção `-c alias.<nome>=<valor>`
|
|
332
|
+
// encontrada no caminho é registrada nele — fonte MAIS BARATA de resolução
|
|
333
|
+
// de alias, o próprio comando já carrega a definição.
|
|
334
|
+
function findGitSubcommand(tokens, gitIndex, inlineAliases) {
|
|
335
|
+
let i = gitIndex + 1;
|
|
336
|
+
while (i < tokens.length) {
|
|
337
|
+
const tok = tokens[i];
|
|
338
|
+
if (!tok.startsWith('-')) {
|
|
339
|
+
return { subcommand: tok, index: i };
|
|
340
|
+
}
|
|
341
|
+
const eqIdx = tok.indexOf('=');
|
|
342
|
+
const base = eqIdx === -1 ? tok : tok.slice(0, eqIdx);
|
|
343
|
+
if (GIT_GLOBAL_OPTS_WITH_ARG.has(base)) {
|
|
344
|
+
// `--opcao=valor` consome só este token; `-c valor`/`-C valor` (forma
|
|
345
|
+
// separada) consome este token + o próximo.
|
|
346
|
+
let value;
|
|
347
|
+
if (eqIdx === -1) {
|
|
348
|
+
value = tokens[i + 1];
|
|
349
|
+
i += 2;
|
|
350
|
+
} else {
|
|
351
|
+
value = tok.slice(eqIdx + 1);
|
|
352
|
+
i += 1;
|
|
353
|
+
}
|
|
354
|
+
if (base === '-c' && inlineAliases && typeof value === 'string') {
|
|
355
|
+
const aliasMatch = /^alias\.([^=\s]+)=([\s\S]*)$/.exec(value);
|
|
356
|
+
if (aliasMatch) inlineAliases.set(aliasMatch[1], aliasMatch[2]);
|
|
357
|
+
}
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
// Qualquer outra flag (global conhecida sem argumento, ou desconhecida)
|
|
361
|
+
// é tratada como flag isolada — nunca interrompe a busca do subcomando.
|
|
362
|
+
i += 1;
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Ache o PRÓXIMO token não-flag em `tokens` a partir de `fromIndex`
|
|
368
|
+
// (exclusivo), pulando as opções GLOBAIS conhecidas do `gh`
|
|
369
|
+
// (`GH_GLOBAL_OPTS_WITH_ARG`) — espelha `findGitSubcommand`, mas devolve
|
|
370
|
+
// só 1 token por vez (chamado 2x em sequência p/ achar "pr" + o verbo, ou
|
|
371
|
+
// 2x p/ achar "alias" + "set" — ver `analyzeSegment`/`collectGhSessionAliases`).
|
|
372
|
+
function findNextGhToken(tokens, fromIndex) {
|
|
373
|
+
let i = fromIndex + 1;
|
|
374
|
+
while (i < tokens.length) {
|
|
375
|
+
const tok = tokens[i];
|
|
376
|
+
if (!tok.startsWith('-')) {
|
|
377
|
+
return { token: tok, index: i };
|
|
378
|
+
}
|
|
379
|
+
const eqIdx = tok.indexOf('=');
|
|
380
|
+
const base = eqIdx === -1 ? tok : tok.slice(0, eqIdx);
|
|
381
|
+
if (GH_GLOBAL_OPTS_WITH_ARG.has(base)) {
|
|
382
|
+
i += eqIdx === -1 ? 2 : 1;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
i += 1;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const FORCE_LONG_FLAGS = new Set(['--force', '--force-with-lease', '--force-if-includes']);
|
|
391
|
+
|
|
392
|
+
// Token de flag do subcomando `push` que representa força — forma longa
|
|
393
|
+
// (com ou sem `=valor`) ou cluster de flags curtas contendo `f` isolado
|
|
394
|
+
// (`-uf`, `-fu`, `-f`; nunca `-4`/`--foo`, que não são clusters de letras).
|
|
395
|
+
function isForceFlagToken(tok) {
|
|
396
|
+
if (!tok.startsWith('-')) return false;
|
|
397
|
+
if (tok.startsWith('--')) {
|
|
398
|
+
const eqIdx = tok.indexOf('=');
|
|
399
|
+
const base = eqIdx === -1 ? tok : tok.slice(0, eqIdx);
|
|
400
|
+
return FORCE_LONG_FLAGS.has(base);
|
|
401
|
+
}
|
|
402
|
+
const rest = tok.slice(1);
|
|
403
|
+
if (rest.length > 0 && /^[a-zA-Z]+$/.test(rest)) {
|
|
404
|
+
return rest.includes('f');
|
|
405
|
+
}
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Consulta `git config --get alias.<nome>` no repositório de `cwd` — a
|
|
410
|
+
// fonte MAIS CARA de resolução de alias do `git` (subprocesso síncrono),
|
|
411
|
+
// só chamada quando as 2 fontes baratas (inline `-c`, `git config alias.X`
|
|
412
|
+
// num segmento anterior) não resolveram. Timeout curto, sem stdin aberto.
|
|
413
|
+
//
|
|
414
|
+
// Retorna:
|
|
415
|
+
// { status: 'found', value } — alias existe, `value` é o corpo (pode
|
|
416
|
+
// começar com "!" — alias de shell).
|
|
417
|
+
// { status: 'not-alias' } — CONCLUSIVO: `git config --get` rodou e
|
|
418
|
+
// respondeu "chave não existe" (exit 1).
|
|
419
|
+
// Isto não é falha de consulta, é resposta.
|
|
420
|
+
// { status: 'error' } — a consulta em si não pôde ser feita com
|
|
421
|
+
// segurança (git ausente, timeout, exit
|
|
422
|
+
// code inesperado) — NÃO É "não é alias".
|
|
423
|
+
function resolveGitAliasFromDisk(name, cwd) {
|
|
424
|
+
try {
|
|
425
|
+
const result = spawnSync('git', ['config', '--get', `alias.${name}`], {
|
|
426
|
+
cwd: cwd || process.cwd(),
|
|
427
|
+
encoding: 'utf8',
|
|
428
|
+
timeout: 800,
|
|
429
|
+
input: '',
|
|
430
|
+
});
|
|
431
|
+
if (result.error) {
|
|
432
|
+
return { status: 'error' };
|
|
433
|
+
}
|
|
434
|
+
if (result.status === 0) {
|
|
435
|
+
const value = (result.stdout || '').replace(/\r?\n$/, '');
|
|
436
|
+
return value ? { status: 'found', value } : { status: 'not-alias' };
|
|
437
|
+
}
|
|
438
|
+
if (result.status === 1) {
|
|
439
|
+
// `git config --get` retorna 1 quando a chave não existe — resolvido
|
|
440
|
+
// COM SEGURANÇA que NÃO é alias, mesmo fora de um repositório git
|
|
441
|
+
// (medido: mesmo comportamento dentro/fora de repo, sem stderr).
|
|
442
|
+
return { status: 'not-alias' };
|
|
443
|
+
}
|
|
444
|
+
// Qualquer outro código de saída (config corrompida, permissão etc.) —
|
|
445
|
+
// não deu para confirmar com segurança.
|
|
446
|
+
return { status: 'error' };
|
|
447
|
+
} catch {
|
|
448
|
+
return { status: 'error' };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Varre TODOS os segmentos do comando encadeado procurando
|
|
453
|
+
// `git config alias.<nome> <valor...>` (ou `--global`/`--local`/etc. antes
|
|
454
|
+
// da chave) — a 2ª fonte barata: o comando pode definir o alias num
|
|
455
|
+
// segmento e usá-lo no seguinte (`git config alias.z push; git z origin
|
|
456
|
+
// main`), sem que a config real do disco precise ser consultada.
|
|
457
|
+
function collectSessionAliases(segments) {
|
|
458
|
+
const aliases = new Map();
|
|
459
|
+
for (const segment of segments) {
|
|
460
|
+
const tokens = tokenize(segment);
|
|
461
|
+
const gitIndex = tokens.findIndex(isGitToken);
|
|
462
|
+
if (gitIndex === -1) continue;
|
|
463
|
+
const found = findGitSubcommand(tokens, gitIndex, aliases /* também captura -c alias.* */);
|
|
464
|
+
if (!found || found.subcommand !== 'config') continue;
|
|
465
|
+
const rest = tokens.slice(found.index + 1);
|
|
466
|
+
let idx = 0;
|
|
467
|
+
while (idx < rest.length && rest[idx].startsWith('-')) idx++;
|
|
468
|
+
const keyTok = rest[idx];
|
|
469
|
+
if (!keyTok) continue;
|
|
470
|
+
const eqIdx = keyTok.indexOf('=');
|
|
471
|
+
const keyBase = eqIdx === -1 ? keyTok : keyTok.slice(0, eqIdx);
|
|
472
|
+
const aliasMatch = /^alias\.([^\s]+)$/.exec(keyBase);
|
|
473
|
+
if (!aliasMatch) continue;
|
|
474
|
+
const aliasName = aliasMatch[1];
|
|
475
|
+
const value = eqIdx !== -1 ? keyTok.slice(eqIdx + 1) : rest.slice(idx + 1).join(' ');
|
|
476
|
+
if (aliasName && value) aliases.set(aliasName, value);
|
|
477
|
+
}
|
|
478
|
+
return aliases;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Parseia a saída de `gh alias list` (`<nome>: <valor>\n`, um por linha;
|
|
482
|
+
// valores de alias de shell vêm entre aspas simples, ex.: `x: '!gh pr
|
|
483
|
+
// merge'` — medido em `gh version 2.96.0`). Desembrulha as aspas só quando
|
|
484
|
+
// o conteúdo interno começa com `!` (o único caso em que o `gh` as usa).
|
|
485
|
+
function parseGhAliasListOutput(text) {
|
|
486
|
+
const map = new Map();
|
|
487
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
488
|
+
for (const line of lines) {
|
|
489
|
+
if (!line.trim()) continue;
|
|
490
|
+
const idx = line.indexOf(': ');
|
|
491
|
+
if (idx === -1) continue;
|
|
492
|
+
const name = line.slice(0, idx);
|
|
493
|
+
let value = line.slice(idx + 2);
|
|
494
|
+
if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) {
|
|
495
|
+
const inner = value.slice(1, -1);
|
|
496
|
+
if (inner.startsWith('!')) value = inner;
|
|
497
|
+
}
|
|
498
|
+
if (name) map.set(name, value);
|
|
499
|
+
}
|
|
500
|
+
return map;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Consulta `gh alias list` — a fonte MAIS CARA de resolução de alias do
|
|
504
|
+
// `gh` (subprocesso síncrono). Diferente do `git config --get` (consulta
|
|
505
|
+
// por CHAVE exata, com exit 1 = "não existe" como sinal limpo), o `gh` só
|
|
506
|
+
// expõe "listar tudo" — então este hook lista 1 VEZ por invocação inteira
|
|
507
|
+
// (cacheada em `cache`, um objeto `{ loaded, map, failed }` que vive em
|
|
508
|
+
// `ctx` e é reaproveitado por QUALQUER subcomando desconhecido encontrado
|
|
509
|
+
// na mesma cadeia, mesmo através de recursão de alias) e procura o nome no
|
|
510
|
+
// resultado. Medido: config corrompida do `gh` também sai com exit ≠ 0 —
|
|
511
|
+
// sem o sinal limpo do git, então aqui SÓ exit 0 com saída parseável conta
|
|
512
|
+
// como resposta conclusiva; qualquer outro desfecho é "não deu para
|
|
513
|
+
// confirmar", nunca "não é alias".
|
|
514
|
+
function resolveGhAliasFromDisk(name, cwd, cache) {
|
|
515
|
+
if (!cache.loaded) {
|
|
516
|
+
cache.loaded = true;
|
|
517
|
+
try {
|
|
518
|
+
const result = spawnSync('gh', ['alias', 'list'], {
|
|
519
|
+
cwd: cwd || process.cwd(),
|
|
520
|
+
encoding: 'utf8',
|
|
521
|
+
timeout: 800,
|
|
522
|
+
input: '',
|
|
523
|
+
});
|
|
524
|
+
if (result.error || result.status !== 0) {
|
|
525
|
+
cache.failed = true;
|
|
526
|
+
} else {
|
|
527
|
+
cache.map = parseGhAliasListOutput(result.stdout);
|
|
528
|
+
}
|
|
529
|
+
} catch {
|
|
530
|
+
cache.failed = true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (cache.failed || !cache.map) {
|
|
534
|
+
return { status: 'error' };
|
|
535
|
+
}
|
|
536
|
+
return cache.map.has(name) ? { status: 'found', value: cache.map.get(name) } : { status: 'not-alias' };
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
// Varre TODOS os segmentos do comando encadeado procurando `gh alias set
|
|
540
|
+
// <nome> <valor...> [--shell|-s]` — a única fonte barata do `gh` (não há
|
|
541
|
+
// equivalente do `-c alias.X=valor` inline do git; a ferramenta não tem
|
|
542
|
+
// esse mecanismo — assimetria INERENTE entre as 2 ferramentas, não uma
|
|
543
|
+
// lacuna deste hook). `--shell`/`-s` sem `!` explícito no valor é
|
|
544
|
+
// normalizado para `!<valor>` — o próprio `gh` faz essa normalização ao
|
|
545
|
+
// gravar (medido: `gh alias set --shell x 'gh pr merge'` grava `x: '!gh pr
|
|
546
|
+
// merge'`), então replicamos aqui para a fonte de sessão bater com a fonte
|
|
547
|
+
// de disco.
|
|
548
|
+
function collectGhSessionAliases(segments) {
|
|
549
|
+
const aliases = new Map();
|
|
550
|
+
for (const segment of segments) {
|
|
551
|
+
const tokens = tokenize(segment);
|
|
552
|
+
const ghIndex = tokens.findIndex(isGhToken);
|
|
553
|
+
if (ghIndex === -1) continue;
|
|
554
|
+
const first = findNextGhToken(tokens, ghIndex);
|
|
555
|
+
if (!first || first.token !== 'alias') continue;
|
|
556
|
+
const second = findNextGhToken(tokens, first.index);
|
|
557
|
+
if (!second || second.token !== 'set') continue;
|
|
558
|
+
const rest = tokens.slice(second.index + 1);
|
|
559
|
+
let nameIdx = -1;
|
|
560
|
+
for (let i = 0; i < rest.length; i++) {
|
|
561
|
+
if (!rest[i].startsWith('-')) {
|
|
562
|
+
nameIdx = i;
|
|
563
|
+
break;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (nameIdx === -1) continue;
|
|
567
|
+
const aliasName = rest[nameIdx];
|
|
568
|
+
let isShell = false;
|
|
569
|
+
const valueParts = [];
|
|
570
|
+
for (const tok of rest.slice(nameIdx + 1)) {
|
|
571
|
+
if (tok === '--shell' || tok === '-s') {
|
|
572
|
+
isShell = true;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (tok.startsWith('-')) continue; // outras flags (ex.: --clobber) ignoradas
|
|
576
|
+
valueParts.push(tok);
|
|
577
|
+
}
|
|
578
|
+
let value = valueParts.join(' ').trim();
|
|
579
|
+
if (!value) continue;
|
|
580
|
+
if (isShell && !value.startsWith('!')) value = `!${value}`;
|
|
581
|
+
if (aliasName) aliases.set(aliasName, value);
|
|
582
|
+
}
|
|
583
|
+
return aliases;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Limite de profundidade de resolução de alias (alias que resolve para
|
|
587
|
+
// outro alias, encadeado). NÃO é uma medida de segurança — é um limite de
|
|
588
|
+
// CUSTO (cada nível não resolvido por fonte barata paga 1 subprocesso). Uma
|
|
589
|
+
// cadeia real de aliases encadeados raramente passa de 2-3 níveis; 8 é
|
|
590
|
+
// generoso o bastante para nunca incomodar uso legítimo, e qualquer cadeia
|
|
591
|
+
// que o exceda é tratada como "não sei", nunca como "não é" (fix round F4
|
|
592
|
+
// — ver `analyzeSegment`).
|
|
593
|
+
const ALIAS_MAX_DEPTH = 8;
|
|
594
|
+
|
|
595
|
+
// Expande um alias RESOLVIDO (`resolvedValue`, o corpo — pode começar com
|
|
596
|
+
// "!" para alias de shell) + os tokens que seguiam o nome do alias no
|
|
597
|
+
// comando original (`trailingTokens`), e reanalisa recursivamente —
|
|
598
|
+
// COMPARTILHADO entre o branch `git` e o branch `gh` (fix round F5: antes
|
|
599
|
+
// desta unificação, só o `git` tinha esta lógica, e o `gh` não tinha
|
|
600
|
+
// NENHUMA resolução de alias — a assimetria que o F5 corrige). `tool` é
|
|
601
|
+
// `'git'` ou `'gh'`, usado só para reconstruir o prefixo do comando quando
|
|
602
|
+
// o alias NÃO é de shell (`git <corpo> <trailing>` / `gh <corpo>
|
|
603
|
+
// <trailing>`); alias de shell já é um comando completo, sem prefixo.
|
|
604
|
+
function expandResolvedAliasAndRecurse(tool, resolvedValue, trailingTokens, ctx, currentDepth) {
|
|
605
|
+
const body = String(resolvedValue).trim();
|
|
606
|
+
const expandedCommand = body.startsWith('!')
|
|
607
|
+
? `${body.slice(1)} ${trailingTokens.join(' ')}`
|
|
608
|
+
: `${tool} ${body} ${trailingTokens.join(' ')}`;
|
|
609
|
+
return analyzeSegment(expandedCommand, ctx, currentDepth + 1);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Analisa um único segmento (já sem `;`/`&&`/`||`/`|`) e retorna a operação
|
|
613
|
+
// reconhecida, ou null se nenhuma operação governada for encontrada.
|
|
614
|
+
// `ctx` = { cwd, gitSessionAliases, ghSessionAliases, ghAliasCache } —
|
|
615
|
+
// construído 1x por `findGovernedOperation` e reaproveitado por TODOS os
|
|
616
|
+
// segmentos e níveis de recursão da mesma invocação (é isto que garante
|
|
617
|
+
// que `gh alias list` seja chamado no máximo 1 vez por invocação inteira,
|
|
618
|
+
// não 1x por subcomando desconhecido encontrado).
|
|
619
|
+
// { kind: 'force-push' }
|
|
620
|
+
// { kind: 'git-push' }
|
|
621
|
+
// { kind: 'gh-pr-create' }
|
|
622
|
+
// { kind: 'gh-pr-merge' }
|
|
623
|
+
// { kind: 'unresolved-alias' } — subcomando (git OU gh) desconhecido, e a
|
|
624
|
+
// tentativa de resolvê-lo como alias não
|
|
625
|
+
// pôde ser concluída com segurança (ver
|
|
626
|
+
// AC/D6), OU a cadeia de alias excedeu o
|
|
627
|
+
// limite de profundidade (fix round F4 —
|
|
628
|
+
// "não sei o que isto resolve" também é
|
|
629
|
+
// `unresolved-alias`, NUNCA silêncio).
|
|
630
|
+
function analyzeSegment(segment, ctx, depth) {
|
|
631
|
+
const currentDepth = depth || 0;
|
|
632
|
+
if (currentDepth > ALIAS_MAX_DEPTH) {
|
|
633
|
+
// Fix round F4 (gate FAIL do `pc-qa`): ANTES retornava `null` aqui —
|
|
634
|
+
// silêncio, ou seja, allow. Estourar o limite de profundidade é "não
|
|
635
|
+
// sei o que a cadeia de alias resolve", não "sei que não é push" — as
|
|
636
|
+
// 2 únicas categorias em que silêncio é aceitável (comando sem
|
|
637
|
+
// `git`/`gh`, ou subcomando CONCLUSIVAMENTE resolvido como "não é
|
|
638
|
+
// alias"). Isto não é nenhuma das duas. Vale para os 2 branches.
|
|
639
|
+
return { kind: 'unresolved-alias' };
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const tokens = tokenize(segment);
|
|
643
|
+
|
|
644
|
+
const gitIndex = tokens.findIndex(isGitToken);
|
|
645
|
+
if (gitIndex !== -1) {
|
|
646
|
+
const inlineAliases = new Map();
|
|
647
|
+
const found = findGitSubcommand(tokens, gitIndex, inlineAliases);
|
|
648
|
+
if (found) {
|
|
649
|
+
if (found.subcommand === 'push') {
|
|
650
|
+
const isForce = tokens.slice(found.index + 1).some(isForceFlagToken);
|
|
651
|
+
return { kind: isForce ? 'force-push' : 'git-push' };
|
|
652
|
+
}
|
|
653
|
+
if (!KNOWN_GIT_SUBCOMMANDS.has(found.subcommand)) {
|
|
654
|
+
const trailing = tokens.slice(found.index + 1);
|
|
655
|
+
let resolved = inlineAliases.has(found.subcommand)
|
|
656
|
+
? inlineAliases.get(found.subcommand)
|
|
657
|
+
: ctx.gitSessionAliases.get(found.subcommand);
|
|
658
|
+
|
|
659
|
+
if (resolved === undefined) {
|
|
660
|
+
const lookup = resolveGitAliasFromDisk(found.subcommand, ctx.cwd);
|
|
661
|
+
if (lookup.status === 'found') {
|
|
662
|
+
resolved = lookup.value;
|
|
663
|
+
} else if (lookup.status === 'not-alias') {
|
|
664
|
+
return null; // resolvido com segurança: não é alias, não é push
|
|
665
|
+
} else {
|
|
666
|
+
return { kind: 'unresolved-alias' }; // não deu para confirmar
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return expandResolvedAliasAndRecurse('git', resolved, trailing, ctx, currentDepth);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const ghIndex = tokens.findIndex(isGhToken);
|
|
676
|
+
if (ghIndex !== -1) {
|
|
677
|
+
const first = findNextGhToken(tokens, ghIndex);
|
|
678
|
+
if (first) {
|
|
679
|
+
if (first.token === 'pr') {
|
|
680
|
+
const second = findNextGhToken(tokens, first.index);
|
|
681
|
+
if (second && second.token === 'create') return { kind: 'gh-pr-create' };
|
|
682
|
+
if (second && second.token === 'merge') return { kind: 'gh-pr-merge' };
|
|
683
|
+
// "pr" seguido de outro verbo conhecido (checkout, view, ...) —
|
|
684
|
+
// não governado; cai para o `return null` no fim da função.
|
|
685
|
+
} else if (!KNOWN_GH_SUBCOMMANDS.has(first.token)) {
|
|
686
|
+
// Fix round F5: mesma disciplina do branch `git` — subcomando de
|
|
687
|
+
// `gh` desconhecido pode ser alias nativo (`gh alias set`).
|
|
688
|
+
const trailing = tokens.slice(first.index + 1);
|
|
689
|
+
let resolved = ctx.ghSessionAliases.get(first.token);
|
|
690
|
+
|
|
691
|
+
if (resolved === undefined) {
|
|
692
|
+
const lookup = resolveGhAliasFromDisk(first.token, ctx.cwd, ctx.ghAliasCache);
|
|
693
|
+
if (lookup.status === 'found') {
|
|
694
|
+
resolved = lookup.value;
|
|
695
|
+
} else if (lookup.status === 'not-alias') {
|
|
696
|
+
return null; // resolvido com segurança: não é alias
|
|
697
|
+
} else {
|
|
698
|
+
return { kind: 'unresolved-alias' }; // não deu para confirmar
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
return expandResolvedAliasAndRecurse('gh', resolved, trailing, ctx, currentDepth);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Analisa o comando inteiro (podendo ter vários comandos encadeados) e
|
|
711
|
+
// retorna a operação de MAIOR severidade encontrada em qualquer segmento
|
|
712
|
+
// (force-push > merge > alias não resolvido > push/pr create), para não
|
|
713
|
+
// deixar passar em silêncio um comando composto que contenha uma operação
|
|
714
|
+
// governada em qualquer posição da cadeia.
|
|
715
|
+
const SEVERITY = {
|
|
716
|
+
'force-push': 4,
|
|
717
|
+
'gh-pr-merge': 3,
|
|
718
|
+
'unresolved-alias': 2,
|
|
719
|
+
'git-push': 1,
|
|
720
|
+
'gh-pr-create': 1,
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
function findGovernedOperation(command, cwd) {
|
|
724
|
+
const segments = splitSegments(command);
|
|
725
|
+
const ctx = {
|
|
726
|
+
cwd,
|
|
727
|
+
gitSessionAliases: collectSessionAliases(segments),
|
|
728
|
+
ghSessionAliases: collectGhSessionAliases(segments),
|
|
729
|
+
ghAliasCache: { loaded: false, map: null, failed: false },
|
|
730
|
+
};
|
|
731
|
+
let best = null;
|
|
732
|
+
for (const segment of segments) {
|
|
733
|
+
const found = analyzeSegment(segment, ctx, 0);
|
|
734
|
+
if (!found) continue;
|
|
735
|
+
if (!best || SEVERITY[found.kind] > SEVERITY[best.kind]) {
|
|
736
|
+
best = found;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return best;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Identidade lida EXCLUSIVAMENTE de `input.agent_type` (payload do
|
|
743
|
+
// PreToolUse) — nunca do ambiente do processo, nunca do texto do comando.
|
|
744
|
+
// Guarda explícita: `agent_type` ausente (main thread) não é string vazia,
|
|
745
|
+
// é `undefined` — não chame método de string sobre ele sem checar antes.
|
|
746
|
+
function isDevOpsAgent(input) {
|
|
747
|
+
return typeof input?.agent_type === 'string' && input.agent_type === DEVOPS_AGENT_TYPE;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function agentLabel(input) {
|
|
751
|
+
return typeof input?.agent_type === 'string' && input.agent_type
|
|
752
|
+
? input.agent_type
|
|
753
|
+
: 'desconhecido (main thread ou identidade ausente)';
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
function emitDecision(permissionDecision, permissionDecisionReason) {
|
|
757
|
+
process.stdout.write(JSON.stringify({
|
|
758
|
+
hookSpecificOutput: {
|
|
759
|
+
hookEventName: 'PreToolUse',
|
|
760
|
+
permissionDecision,
|
|
761
|
+
permissionDecisionReason,
|
|
762
|
+
},
|
|
763
|
+
}));
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const OPERATION_LABEL = {
|
|
767
|
+
'git-push': 'git push',
|
|
768
|
+
'gh-pr-create': 'gh pr create',
|
|
769
|
+
'gh-pr-merge': 'gh pr merge',
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
function decideAndEmit(operation, input) {
|
|
773
|
+
if (operation.kind === 'force-push') {
|
|
774
|
+
emitDecision(
|
|
775
|
+
'deny',
|
|
776
|
+
'Force-push é proibido neste ambiente para qualquer agente, inclusive devops (regra de ouro: push somente fast-forward). Use push fast-forward.',
|
|
777
|
+
);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (operation.kind === 'unresolved-alias') {
|
|
782
|
+
// Subcomando de git OU gh desconhecido que PODE ser alias — ou a
|
|
783
|
+
// consulta (`git config --get`/`gh alias list`) não pôde ser concluída
|
|
784
|
+
// com segurança, ou a cadeia de alias (alias que resolve para outro
|
|
785
|
+
// alias) excedeu o limite de profundidade (fix round F4/F5). Nunca
|
|
786
|
+
// silêncio aqui: ask sempre, mesmo identidade conhecida — não sabemos
|
|
787
|
+
// se isto é force-push, push/PR comum, `pr merge`, ou nada.
|
|
788
|
+
emitDecision(
|
|
789
|
+
'ask',
|
|
790
|
+
`O comando usa um subcomando de git/gh não reconhecido, que pode ser um alias, e não foi possível confirmar com segurança o que ele resolve (consulta à config malsucedida, ou cadeia de alias longa demais para resolver com segurança). Aprovação humana necessária. Agente atual: ${agentLabel(input)}.`,
|
|
791
|
+
);
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (operation.kind === 'gh-pr-merge') {
|
|
796
|
+
// gh pr merge: ask SEMPRE, mesmo para devops — D4, decisão do dono.
|
|
797
|
+
emitDecision(
|
|
798
|
+
'ask',
|
|
799
|
+
`gh pr merge exige aprovação humana explícita, sempre — inclusive para o papel devops (regra permanente do dono sobre merge em main). Agente atual: ${agentLabel(input)}.`,
|
|
800
|
+
);
|
|
801
|
+
return;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// git-push / gh-pr-create
|
|
805
|
+
if (isDevOpsAgent(input)) {
|
|
806
|
+
return; // allow, sem output
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
emitDecision(
|
|
810
|
+
'ask',
|
|
811
|
+
`${OPERATION_LABEL[operation.kind]} é exclusivo do papel devops. Agente atual: ${agentLabel(input)}. Aprovação humana necessária para prosseguir.`,
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
// Fallback de texto bruto para JSON ilegível — achado do sweep do fix
|
|
816
|
+
// round F4 (mesma família de defeito: confiança indevida disfarçada de
|
|
817
|
+
// "não é"). O `tokenize()` usado pelo parser principal separa tokens por
|
|
818
|
+
// ESPAÇO EM BRANCO fora de aspas — mas um JSON compacto típico (o formato
|
|
819
|
+
// real que a plataforma envia, sem indentação) só tem espaço em branco
|
|
820
|
+
// DENTRO dos valores de string; fora deles, `{`/`"`/`:`/`}` ficam colados
|
|
821
|
+
// sem separador. Resultado medido: `tokenize()` sobre
|
|
822
|
+
// `{"tool_input":{"command":"git push --force"}}` produz **1 token só**
|
|
823
|
+
// (todo o JSON vira uma string colada, incluindo o espaço de "git push"
|
|
824
|
+
// preservado ilesamente DENTRO da aspas aberta), e `isGitToken`/`isGhToken`
|
|
825
|
+
// (que comparam o token inteiro a `"git"`/`"gh"`) NUNCA bate — ou seja,
|
|
826
|
+
// reusar `findGovernedOperation` aqui (tokenizado) fazia este fallback
|
|
827
|
+
// retornar "não suspeito" (silêncio) para TODO JSON malformado, mesmo com
|
|
828
|
+
// "git push --force" literalmente no texto. Corrigido para regex de
|
|
829
|
+
// SUBSTRING sobre o texto bruto (não sobre tokens) — aqui a imprecisão é
|
|
830
|
+
// aceitável e desejada: falso positivo custa 1 `deny` a mais num caso já
|
|
831
|
+
// raro (JSON ilegível); falso negativo custa silêncio numa operação que
|
|
832
|
+
// podia ser força. `\bgit\s+push\b` etc. acham a substring onde quer que
|
|
833
|
+
// ela esteja no blob, independente de chaves/aspas/dois-pontos ao redor.
|
|
834
|
+
const RAW_TEXT_GOVERNED_PATTERNS = [
|
|
835
|
+
/\bgit\s+push\b/i,
|
|
836
|
+
/\bgh\s+pr\s+create\b/i,
|
|
837
|
+
/\bgh\s+pr\s+merge\b/i,
|
|
838
|
+
/\bgit\s+config\b[\s\S]{0,80}\balias\b/i,
|
|
839
|
+
// Fix round F5: mesma régua de paranoia do padrão acima, agora para o
|
|
840
|
+
// rastro textual de definição de alias do `gh` (`gh alias set ...`).
|
|
841
|
+
/\bgh\s+alias\b/i,
|
|
842
|
+
];
|
|
843
|
+
|
|
844
|
+
function rawTextSuspectsGovernedOperation(rawText) {
|
|
845
|
+
const text = String(rawText || '');
|
|
846
|
+
return RAW_TEXT_GOVERNED_PATTERNS.some((pattern) => pattern.test(text));
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function runMain() {
|
|
850
|
+
const rawInput = readStdin();
|
|
851
|
+
const input = parseInput(rawInput);
|
|
852
|
+
|
|
853
|
+
if (!input) {
|
|
854
|
+
// Fail-closed proporcional: sem JSON válido, só bloqueia se o texto bruto
|
|
855
|
+
// aparentar conter uma operação remota governada.
|
|
856
|
+
if (rawTextSuspectsGovernedOperation(rawInput)) {
|
|
857
|
+
emitDecision(
|
|
858
|
+
'deny',
|
|
859
|
+
'O hook não conseguiu interpretar o input do PreToolUse e o comando aparenta ser uma operação remota. Bloqueado por segurança.',
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
const command = input?.tool_input?.command || '';
|
|
866
|
+
const cwd = typeof input?.cwd === 'string' && input.cwd ? input.cwd : undefined;
|
|
867
|
+
const operation = findGovernedOperation(command, cwd);
|
|
868
|
+
if (!operation) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
decideAndEmit(operation, input);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Rede de segurança de topo (fix round F4, sweep): qualquer exceção NÃO
|
|
876
|
+
// prevista em qualquer ponto do fluxo acima — inclusive `readStdin()` sem
|
|
877
|
+
// try/catch próprio agora (decisão deliberada, ver comentário da função) —
|
|
878
|
+
// é, por definição, um caso "não sei", nunca "sei que não". Um hook que
|
|
879
|
+
// lança sem emitir `hookSpecificOutput` não é silêncio-como-decisão: é
|
|
880
|
+
// ausência de decisão nenhuma, que a plataforma trata como fail-open (sem
|
|
881
|
+
// restrição) — pior do que qualquer `ask`. Este catch garante que ISSO
|
|
882
|
+
// NUNCA acontece: toda saída do processo, mesmo diante do inesperado, emite
|
|
883
|
+
// uma decisão explícita.
|
|
884
|
+
function main() {
|
|
885
|
+
try {
|
|
886
|
+
runMain();
|
|
887
|
+
} catch (err) {
|
|
888
|
+
emitDecision(
|
|
889
|
+
'ask',
|
|
890
|
+
`Erro interno inesperado no hook de autoridade de push/PR (${err && err.message ? err.message : 'erro desconhecido'}). Aprovação humana necessária — o hook não pôde concluir a análise do comando.`,
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
if (require.main === module) {
|
|
896
|
+
main();
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
module.exports = {
|
|
900
|
+
DEVOPS_AGENT_TYPE,
|
|
901
|
+
KNOWN_GIT_SUBCOMMANDS,
|
|
902
|
+
KNOWN_GH_SUBCOMMANDS,
|
|
903
|
+
ALIAS_MAX_DEPTH,
|
|
904
|
+
tokenize,
|
|
905
|
+
splitSegments,
|
|
906
|
+
isGitToken,
|
|
907
|
+
isGhToken,
|
|
908
|
+
findGitSubcommand,
|
|
909
|
+
findNextGhToken,
|
|
910
|
+
isForceFlagToken,
|
|
911
|
+
resolveGitAliasFromDisk,
|
|
912
|
+
resolveGhAliasFromDisk,
|
|
913
|
+
parseGhAliasListOutput,
|
|
914
|
+
collectSessionAliases,
|
|
915
|
+
collectGhSessionAliases,
|
|
916
|
+
expandResolvedAliasAndRecurse,
|
|
917
|
+
analyzeSegment,
|
|
918
|
+
findGovernedOperation,
|
|
919
|
+
rawTextSuspectsGovernedOperation,
|
|
920
|
+
isDevOpsAgent,
|
|
921
|
+
agentLabel,
|
|
922
|
+
readStdin,
|
|
923
|
+
runMain,
|
|
924
|
+
main,
|
|
925
|
+
};
|