@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.

Files changed (467) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +121 -0
  3. package/bin/cli.js +124 -0
  4. package/installer/__tests__/doctor-ready-oracles.test.cjs +140 -0
  5. package/installer/__tests__/merge-settings.test.cjs +330 -0
  6. package/installer/adopt.js +161 -0
  7. package/installer/copy.js +203 -0
  8. package/installer/doctor.js +266 -0
  9. package/installer/install.js +155 -0
  10. package/installer/manifest.js +102 -0
  11. package/installer/motor-scripts.js +50 -0
  12. package/installer/motor-scripts.json +39 -0
  13. package/installer/uninstall.js +99 -0
  14. package/installer/update.js +376 -0
  15. package/installer/util.js +113 -0
  16. package/installer/wizard.js +64 -0
  17. package/package.json +26 -0
  18. package/scripts/__fixtures__/anti-path-demo/agents/ap-writer.md +13 -0
  19. package/scripts/__fixtures__/anti-path-demo/templates/write-tmpl.md +7 -0
  20. package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.smoke.json +10 -0
  21. package/scripts/__fixtures__/anti-path-demo/workflows/wf-ap.yaml +25 -0
  22. package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/agents/content-chief.md +1 -0
  23. package/scripts/__fixtures__/assess-tier/retrofit-leve/pod/workflows/wf-criacao-redteam.yaml +3 -0
  24. package/scripts/__fixtures__/assess-tier/retrofit-leve/pod-spec.json +13 -0
  25. package/scripts/__fixtures__/fidelity/fake-green-average-in-band.yaml +21 -0
  26. package/scripts/__fixtures__/fidelity/fake-green-average.yaml +18 -0
  27. package/scripts/__fixtures__/fidelity/fake-green-denominator.yaml +19 -0
  28. package/scripts/__fixtures__/fidelity/fake-green-missing-evidence.yaml +18 -0
  29. package/scripts/__fixtures__/fidelity/fake-green-threshold.yaml +18 -0
  30. package/scripts/__fixtures__/fidelity/fake-green-weight.yaml +18 -0
  31. package/scripts/__fixtures__/fidelity/golden.yaml +31 -0
  32. package/scripts/__fixtures__/fidelity/trindade-incoherent.yaml +15 -0
  33. package/scripts/__fixtures__/forge-canonical/pod-spec-example.json +37 -0
  34. package/scripts/__fixtures__/migrate-squad/authored/agents/offer-engineer.md +17 -0
  35. package/scripts/__fixtures__/migrate-squad/authored/knowledge/no-source.md +7 -0
  36. package/scripts/__fixtures__/migrate-squad/authored/knowledge/value-stack-method.md +8 -0
  37. package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.smoke.json +24 -0
  38. package/scripts/__fixtures__/migrate-squad/authored/specs/wf-sample.spec.json +45 -0
  39. package/scripts/__fixtures__/migrate-squad/legacy-squad/HEADLINE.md +3 -0
  40. package/scripts/__fixtures__/migrate-squad/legacy-squad/README.md +4 -0
  41. package/scripts/__fixtures__/migrate-squad/legacy-squad/agents/hormozi-offer.md +14 -0
  42. package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/dead-redundant.md +4 -0
  43. package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/method-guide.md +6 -0
  44. package/scripts/__fixtures__/migrate-squad/legacy-squad/checklists/veto-screen.md +4 -0
  45. package/scripts/__fixtures__/migrate-squad/legacy-squad/config/config.yaml +2 -0
  46. package/scripts/__fixtures__/migrate-squad/legacy-squad/data/case-library.md +3 -0
  47. package/scripts/__fixtures__/migrate-squad/legacy-squad/scripts/validate-mvn.py +16 -0
  48. package/scripts/__fixtures__/migrate-squad/legacy-squad/sops/sop-sample.md +3 -0
  49. package/scripts/__fixtures__/migrate-squad/legacy-squad/squad-io.yaml +14 -0
  50. package/scripts/__fixtures__/migrate-squad/legacy-squad/tasks/gather-context.md +7 -0
  51. package/scripts/__fixtures__/migrate-squad/legacy-squad/templates/output-tmpl.md +5 -0
  52. package/scripts/__fixtures__/migrate-squad/legacy-squad/workflows/wf-sample.yaml +24 -0
  53. package/scripts/__fixtures__/pipeline/pipelines/pipeline-checkpoint.yaml +21 -0
  54. package/scripts/__fixtures__/pipeline/pipelines/pipeline-demo.yaml +22 -0
  55. package/scripts/__fixtures__/pipeline/pods/pipe-a/agents/maker.md +13 -0
  56. package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.consolidated.md +8 -0
  57. package/scripts/__fixtures__/pipeline/pods/pipe-a/memory/learnings.jsonl +83 -0
  58. package/scripts/__fixtures__/pipeline/pods/pipe-a/templates/make-tmpl.md +8 -0
  59. package/scripts/__fixtures__/pipeline/pods/pipe-a/workflows/wf-a.yaml +16 -0
  60. package/scripts/__fixtures__/pipeline/pods/pipe-b/agents/user.md +13 -0
  61. package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.consolidated.md +8 -0
  62. package/scripts/__fixtures__/pipeline/pods/pipe-b/memory/learnings.jsonl +14 -0
  63. package/scripts/__fixtures__/pipeline/pods/pipe-b/templates/use-tmpl.md +6 -0
  64. package/scripts/__fixtures__/pipeline/pods/pipe-b/workflows/wf-b.yaml +16 -0
  65. package/scripts/__fixtures__/pod-run/agents/forge-chief.md +13 -0
  66. package/scripts/__fixtures__/pod-run/agents/pod-critic.md +13 -0
  67. package/scripts/__fixtures__/pod-run/templates/build-tmpl.md +8 -0
  68. package/scripts/__fixtures__/pod-run/templates/gate-tmpl.md +6 -0
  69. package/scripts/__fixtures__/pod-run/workflows/wf-min.yaml +43 -0
  70. package/scripts/__fixtures__/pod-run/workflows/wf-skip-modes.yaml +50 -0
  71. package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-all-skippable.yaml +30 -0
  72. package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-criteria-escalar-de-bloco.yaml +40 -0
  73. package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-skip-mode-desconhecido.yaml +30 -0
  74. package/scripts/__fixtures__/pod-workflow/invalid-checkpoint-unknown-key.yaml +29 -0
  75. package/scripts/__fixtures__/pod-workflow/invalid-cycle.yaml +26 -0
  76. package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-backedge.yaml +29 -0
  77. package/scripts/__fixtures__/pod-workflow/invalid-fix-loop-forward.yaml +29 -0
  78. package/scripts/__fixtures__/pod-workflow/invalid-handoff-open.yaml +27 -0
  79. package/scripts/__fixtures__/pod-workflow/invalid-knowledge-shape.yaml +18 -0
  80. package/scripts/__fixtures__/pod-workflow/invalid-missing-agent.yaml +15 -0
  81. package/scripts/__fixtures__/pod-workflow/invalid-missing-outputs.yaml +15 -0
  82. package/scripts/__fixtures__/pod-workflow/invalid-missing-template.yaml +15 -0
  83. package/scripts/__fixtures__/pod-workflow/invalid-missing-veto.yaml +13 -0
  84. package/scripts/__fixtures__/pod-workflow/invalid-template-not-on-disk.yaml +16 -0
  85. package/scripts/__fixtures__/pod-workflow/invalid-veto-prose.yaml +17 -0
  86. package/scripts/__fixtures__/pod-workflow/knowledge/a.md +4 -0
  87. package/scripts/__fixtures__/pod-workflow/knowledge/b.md +4 -0
  88. package/scripts/__fixtures__/pod-workflow/knowledge/c.md +4 -0
  89. package/scripts/__fixtures__/pod-workflow/templates/step-tmpl.md +7 -0
  90. package/scripts/__fixtures__/pod-workflow/valid-checkpoint-skip-modes.yaml +29 -0
  91. package/scripts/__fixtures__/pod-workflow/valid-fix-loop.yaml +30 -0
  92. package/scripts/__fixtures__/pod-workflow/valid-knowledge.yaml +30 -0
  93. package/scripts/__fixtures__/pod-workflow/valid-veto-always-true.yaml +20 -0
  94. package/scripts/__fixtures__/pod-workflow/valid.yaml +27 -0
  95. package/scripts/__fixtures__/smoke-canary/agents/canary-reporter.md +13 -0
  96. package/scripts/__fixtures__/smoke-canary/agents/canary-researcher.md +13 -0
  97. package/scripts/__fixtures__/smoke-canary/agents/canary-synth.md +13 -0
  98. package/scripts/__fixtures__/smoke-canary/memory/learnings.consolidated.md +10 -0
  99. package/scripts/__fixtures__/smoke-canary/memory/learnings.jsonl +448 -0
  100. package/scripts/__fixtures__/smoke-canary/templates/report-tmpl.md +9 -0
  101. package/scripts/__fixtures__/smoke-canary/templates/research-tmpl.md +7 -0
  102. package/scripts/__fixtures__/smoke-canary/templates/synth-tmpl.md +9 -0
  103. package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.smoke.json +11 -0
  104. package/scripts/__fixtures__/smoke-canary/workflows/wf-canary.yaml +53 -0
  105. package/scripts/__fixtures__/source-audit/fake-green-bronze-unsignaled.yaml +10 -0
  106. package/scripts/__fixtures__/source-audit/fake-green-counts.yaml +9 -0
  107. package/scripts/__fixtures__/source-audit/fake-green-missing-evidence.yaml +9 -0
  108. package/scripts/__fixtures__/source-audit/fake-green-unclassified.yaml +10 -0
  109. package/scripts/__fixtures__/source-audit/fake-green-verdict.yaml +10 -0
  110. package/scripts/__fixtures__/source-audit/golden-blocked.yaml +10 -0
  111. package/scripts/__fixtures__/source-audit/golden.yaml +11 -0
  112. package/scripts/__fixtures__/sweep-forms/agents/forms-count.md +13 -0
  113. package/scripts/__fixtures__/sweep-forms/agents/forms-field.md +13 -0
  114. package/scripts/__fixtures__/sweep-forms/agents/forms-fileref.md +13 -0
  115. package/scripts/__fixtures__/sweep-forms/agents/forms-json.md +13 -0
  116. package/scripts/__fixtures__/sweep-forms/agents/forms-section.md +13 -0
  117. package/scripts/__fixtures__/sweep-forms/specs/wf-forms.spec.json +5 -0
  118. package/scripts/__fixtures__/sweep-forms/templates/t_count.md +5 -0
  119. package/scripts/__fixtures__/sweep-forms/templates/t_field.md +3 -0
  120. package/scripts/__fixtures__/sweep-forms/templates/t_fileref.md +3 -0
  121. package/scripts/__fixtures__/sweep-forms/templates/t_json.md +0 -0
  122. package/scripts/__fixtures__/sweep-forms/templates/t_section.md +3 -0
  123. package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.smoke.json +13 -0
  124. package/scripts/__fixtures__/sweep-forms/workflows/wf-forms.yaml +67 -0
  125. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-1-noop-state-json.fixture.md +18 -0
  126. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-2-crash-buildworkflowyaml.fixture.md +26 -0
  127. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-3-nasce-verde-skip-modes.fixture.md +29 -0
  128. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-4-guarda-sem-irmao.fixture.md +17 -0
  129. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5a-diff-stat-sem-guarda.fixture.md +17 -0
  130. package/scripts/__fixtures__/validate-story-acs-corpus/corpus-5b-test-f-sobre-diretorio.fixture.md +20 -0
  131. package/scripts/__fixtures__/veto-checks/copy-clean.md +4 -0
  132. package/scripts/__fixtures__/veto-checks/copy-dashes.md +4 -0
  133. package/scripts/__fixtures__/veto-checks/n8n-bad.md +18 -0
  134. package/scripts/__fixtures__/veto-checks/n8n-ok.md +22 -0
  135. package/scripts/__fixtures__/veto-checks/page-bad.html +7 -0
  136. package/scripts/__fixtures__/veto-checks/phash/copy.png +0 -0
  137. package/scripts/__fixtures__/veto-checks/phash/distinct.png +0 -0
  138. package/scripts/__fixtures__/veto-checks/phash/distinct2.png +0 -0
  139. package/scripts/__fixtures__/veto-checks/phash/make-fixtures.cjs +203 -0
  140. package/scripts/__fixtures__/veto-checks/phash/ref.png +0 -0
  141. package/scripts/__fixtures__/veto-checks/slide-ok.html +15 -0
  142. package/scripts/__fixtures__/veto-checks/slide-overflow.html +14 -0
  143. package/scripts/__fixtures__/veto-checks/sweep-pod/agents/vc-checker.md +13 -0
  144. package/scripts/__fixtures__/veto-checks/sweep-pod/templates/check-tmpl.md +6 -0
  145. package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.smoke.json +10 -0
  146. package/scripts/__fixtures__/veto-checks/sweep-pod/workflows/wf-vc.yaml +19 -0
  147. package/scripts/__fixtures__/voz-do-dono/README.md +23 -0
  148. package/scripts/__fixtures__/voz-do-dono/dono-escalar.yaml +9 -0
  149. package/scripts/__fixtures__/voz-do-dono/dono-guia.yaml +10 -0
  150. package/scripts/__fixtures__/voz-do-dono/peca-3a-pessoa.md +6 -0
  151. package/scripts/__fixtures__/voz-do-dono/peca-com-lexico-proibido.md +6 -0
  152. package/scripts/__fixtures__/voz-do-dono/peca-limpa-1a-pessoa.md +6 -0
  153. package/scripts/__tests__/derive-ready-transitions.test.cjs +269 -0
  154. package/scripts/__tests__/enforce-cycle-authority.test.cjs +869 -0
  155. package/scripts/__tests__/enforce-git-push-authority.test.cjs +701 -0
  156. package/scripts/__tests__/enforce-ready-oracles.test.cjs +745 -0
  157. package/scripts/__tests__/motor-scripts.test.cjs +339 -0
  158. package/scripts/__tests__/pc-run-pod-counter.test.cjs +58 -0
  159. package/scripts/__tests__/pc-run-pod.test.cjs +578 -0
  160. package/scripts/__tests__/validate-pod-workflow.test.cjs +90 -0
  161. package/scripts/__tests__/validate-story-acs.test.cjs +607 -0
  162. package/scripts/anti-path.test.cjs +163 -0
  163. package/scripts/arena.cjs +514 -0
  164. package/scripts/arena.test.cjs +213 -0
  165. package/scripts/brief-leitura-obrigatoria.test.cjs +364 -0
  166. package/scripts/consolidate-knowledge-runner.test.cjs +249 -0
  167. package/scripts/default-funcional.test.cjs +153 -0
  168. package/scripts/derive-ready-transitions.cjs +325 -0
  169. package/scripts/forge-additive.test.cjs +158 -0
  170. package/scripts/forge-assess-tier.cjs +205 -0
  171. package/scripts/forge-assess-tier.test.cjs +114 -0
  172. package/scripts/forge-canonical.test.cjs +624 -0
  173. package/scripts/forge-generate.cjs +1303 -0
  174. package/scripts/forge-harden-learning.cjs +921 -0
  175. package/scripts/forge-harden-learning.test.cjs +242 -0
  176. package/scripts/forge-ingest-memory.cjs +136 -0
  177. package/scripts/forge-upgrade-pod.cjs +368 -0
  178. package/scripts/forge.test.cjs +609 -0
  179. package/scripts/harden-knowledge.test.cjs +612 -0
  180. package/scripts/harness-g5-lite.cjs +243 -0
  181. package/scripts/harness-g5-lite.test.cjs +134 -0
  182. package/scripts/hn-carousel-contrato-entrada.test.cjs +96 -0
  183. package/scripts/migrate-squad-orchestration.test.cjs +146 -0
  184. package/scripts/migration-manifest-sf3.2.test.cjs +382 -0
  185. package/scripts/migration-manifest-sf3.3.test.cjs +170 -0
  186. package/scripts/migration-manifest-sf5.5.test.cjs +189 -0
  187. package/scripts/migration-manifest.cjs +1146 -0
  188. package/scripts/migration-manifest.test.cjs +186 -0
  189. package/scripts/npm-scope-invocation.test.cjs +194 -0
  190. package/scripts/owner-layer.cjs +442 -0
  191. package/scripts/owner-layer.test.cjs +358 -0
  192. package/scripts/pc-run-pipeline.cjs +289 -0
  193. package/scripts/pc-run-pipeline.test.cjs +256 -0
  194. package/scripts/pc-run-pod-countgte.test.cjs +66 -0
  195. package/scripts/pc-run-pod.cjs +1355 -0
  196. package/scripts/phash-gate.test.cjs +433 -0
  197. package/scripts/pod-export-compile.cjs +487 -0
  198. package/scripts/pod-export-compile.test.cjs +312 -0
  199. package/scripts/pod-export-executor.cjs +678 -0
  200. package/scripts/pod-export-executor.test.cjs +1341 -0
  201. package/scripts/pod-export-hardening.test.cjs +531 -0
  202. package/scripts/pod-export-postprocess.cjs +427 -0
  203. package/scripts/pod-export-postprocess.test.cjs +558 -0
  204. package/scripts/pod-export-queue-race.test.cjs +865 -0
  205. package/scripts/pod-export-release.cjs +473 -0
  206. package/scripts/pod-export-release.test.cjs +267 -0
  207. package/scripts/pod-export-service.cjs +1297 -0
  208. package/scripts/pod-export-service.test.cjs +489 -0
  209. package/scripts/pod-export-tools.cjs +470 -0
  210. package/scripts/pod-export-ui.cjs +805 -0
  211. package/scripts/pod-export-ui.test.cjs +301 -0
  212. package/scripts/pod-memory-budget.test.cjs +309 -0
  213. package/scripts/pod-memory-note.cjs +357 -0
  214. package/scripts/pod-memory-note.test.cjs +452 -0
  215. package/scripts/pod-memory.cjs +1252 -0
  216. package/scripts/pod-memory.test.cjs +951 -0
  217. package/scripts/render-png.test.cjs +307 -0
  218. package/scripts/smoke-isolation.test.cjs +100 -0
  219. package/scripts/smoke-pod-workflow.cjs +755 -0
  220. package/scripts/smoke-sweep.test.cjs +170 -0
  221. package/scripts/validate-adopt.js +235 -0
  222. package/scripts/validate-branding.js +84 -0
  223. package/scripts/validate-budgets.js +140 -0
  224. package/scripts/validate-fidelity-output.cjs +267 -0
  225. package/scripts/validate-fidelity-output.test.cjs +101 -0
  226. package/scripts/validate-install.js +230 -0
  227. package/scripts/validate-no-clone.cjs +220 -0
  228. package/scripts/validate-no-clone.test.cjs +77 -0
  229. package/scripts/validate-pipeline.cjs +145 -0
  230. package/scripts/validate-pod-workflow.cjs +878 -0
  231. package/scripts/validate-source-audit.cjs +170 -0
  232. package/scripts/validate-source-audit.test.cjs +90 -0
  233. package/scripts/validate-story-acs.cjs +862 -0
  234. package/scripts/validate-update-scope-motor.js +421 -0
  235. package/scripts/veto-checks/html-valid.cjs +92 -0
  236. package/scripts/veto-checks/lexical-check.cjs +62 -0
  237. package/scripts/veto-checks/phash-gate.cjs +589 -0
  238. package/scripts/veto-checks/render-gate.cjs +165 -0
  239. package/scripts/veto-checks/render-png.cjs +358 -0
  240. package/scripts/veto-checks.test.cjs +219 -0
  241. package/scripts/watcher-audit.cjs +178 -0
  242. package/template/.claude/CLAUDE.md +103 -0
  243. package/template/.claude/agents/pc-analyst.md +100 -0
  244. package/template/.claude/agents/pc-architect.md +32 -0
  245. package/template/.claude/agents/pc-dev.md +27 -0
  246. package/template/.claude/agents/pc-devops.md +45 -0
  247. package/template/.claude/agents/pc-planner.md +32 -0
  248. package/template/.claude/agents/pc-po.md +25 -0
  249. package/template/.claude/agents/pc-qa.md +25 -0
  250. package/template/.claude/commands/power/academy.md +9 -0
  251. package/template/.claude/commands/power/automation.md +9 -0
  252. package/template/.claude/commands/power/content-carousel.md +267 -0
  253. package/template/.claude/commands/power/content.md +9 -0
  254. package/template/.claude/commands/power/dev.md +9 -0
  255. package/template/.claude/commands/power/forge.md +224 -0
  256. package/template/.claude/commands/power/hormozi.md +221 -0
  257. package/template/.claude/commands/power/modo.md +57 -0
  258. package/template/.claude/hooks/README.md +114 -0
  259. package/template/.claude/hooks/context-budget.cjs +64 -0
  260. package/template/.claude/hooks/enforce-cycle-authority.cjs +457 -0
  261. package/template/.claude/hooks/enforce-git-push-authority.cjs +925 -0
  262. package/template/.claude/hooks/enforce-ready-oracles.cjs +502 -0
  263. package/template/.claude/rules/authority.md +76 -0
  264. package/template/.claude/rules/curadoria-de-conhecimento.md +30 -0
  265. package/template/.claude/rules/model-matrix.md +34 -0
  266. package/template/.claude/rules/orchestration.md +133 -0
  267. package/template/.claude/settings.json +50 -0
  268. package/template/.claude/skills/pc-apply-qa-fixes/SKILL.md +108 -0
  269. package/template/.claude/skills/pc-apply-qa-fixes/references/fix-loop.md +40 -0
  270. package/template/.claude/skills/pc-apply-qa-fixes/references/fix-request-template.md +70 -0
  271. package/template/.claude/skills/pc-arena/SKILL.md +96 -0
  272. package/template/.claude/skills/pc-close-story/SKILL.md +105 -0
  273. package/template/.claude/skills/pc-commit/SKILL.md +108 -0
  274. package/template/.claude/skills/pc-develop-story/SKILL.md +116 -0
  275. package/template/.claude/skills/pc-full-cycle/SKILL.md +150 -0
  276. package/template/.claude/skills/pc-pipeline/SKILL.md +63 -0
  277. package/template/.claude/skills/pc-pipeline/references/gate-templates.md +46 -0
  278. package/template/.claude/skills/pc-review-story/SKILL.md +129 -0
  279. package/template/.claude/skills/pc-review-story/references/false-positive-detection.md +50 -0
  280. package/template/.claude/skills/pc-review-story/references/nfr-assess.md +47 -0
  281. package/template/.claude/skills/pc-review-story/references/risk-profile.md +75 -0
  282. package/template/.claude/skills/pc-review-story/references/security-checklist.md +69 -0
  283. package/template/.claude/skills/pc-review-story/references/test-design.md +37 -0
  284. package/template/.claude/skills/pc-review-story/references/trace-requirements.md +46 -0
  285. package/template/.claude/skills/pc-run-pod/SKILL.md +123 -0
  286. package/template/.claude/skills/pc-validate-story/SKILL.md +114 -0
  287. package/template/.claude/skills/pc-wave/SKILL.md +133 -0
  288. package/template/.env.example +10 -0
  289. package/template/knowledge/analyst/brainstorming.md +40 -0
  290. package/template/knowledge/analyst/brief-skeleton.md +32 -0
  291. package/template/knowledge/analyst/competitor-skeleton.md +39 -0
  292. package/template/knowledge/analyst/elicitation-menu.md +49 -0
  293. package/template/knowledge/analyst/market-research-skeleton.md +36 -0
  294. package/template/knowledge/analyst/research-prompt-structure.md +48 -0
  295. package/template/knowledge/analyst/roi-skeleton.md +51 -0
  296. package/template/knowledge/voice-dna/README.md +99 -0
  297. package/template/knowledge/voice-dna/voice-dna.example.yaml +157 -0
  298. package/template/pods/README.md +64 -0
  299. package/template/pods/academy/README.md +37 -0
  300. package/template/pods/academy/agents/academy-chief.md +27 -0
  301. package/template/pods/academy/examples/palestra.example.md +142 -0
  302. package/template/pods/academy/pod-spec.json +44 -0
  303. package/template/pods/academy/templates/materiais-tmpl.md +17 -0
  304. package/template/pods/academy/templates/revisao-didatica-tmpl.md +20 -0
  305. package/template/pods/academy/workflows/wf-materiais-revisao.yaml +30 -0
  306. package/template/pods/authority-content/README.md +43 -0
  307. package/template/pods/authority-content/agents/content-chief.md +28 -0
  308. package/template/pods/authority-content/pod-spec.json +45 -0
  309. package/template/pods/authority-content/templates/criacao-na-voz-tmpl.md +17 -0
  310. package/template/pods/authority-content/templates/red-team-factual-tmpl.md +23 -0
  311. package/template/pods/authority-content/workflows/wf-criacao-redteam.yaml +30 -0
  312. package/template/pods/automation/README.md +37 -0
  313. package/template/pods/automation/agents/langgraph-architect.md +30 -0
  314. package/template/pods/automation/agents/n8n-architect.md +30 -0
  315. package/template/pods/automation/examples/README.md +46 -0
  316. package/template/pods/automation/examples/n8n-content-radar.example.json +380 -0
  317. package/template/pods/automation/knowledge/langgraph-patterns.md +126 -0
  318. package/template/pods/automation/knowledge/n8n-patterns.md +131 -0
  319. package/template/pods/automation/memory/README.md +16 -0
  320. package/template/pods/automation/memory/learnings.consolidated.md +8 -0
  321. package/template/pods/automation/memory/learnings.jsonl +0 -0
  322. package/template/pods/automation/pod-spec.json +109 -0
  323. package/template/pods/automation/specs/wf-langgraph-build.spec.json +107 -0
  324. package/template/pods/automation/squad-io.yaml +28 -0
  325. package/template/pods/automation/templates/lg-build-tmpl.md +17 -0
  326. package/template/pods/automation/templates/lg-design-tmpl.md +23 -0
  327. package/template/pods/automation/templates/lg-discover-tmpl.md +20 -0
  328. package/template/pods/automation/templates/lg-handoff-tmpl.md +20 -0
  329. package/template/pods/automation/templates/lg-test-tmpl.md +20 -0
  330. package/template/pods/automation/templates/n8n-build-tmpl.md +14 -0
  331. package/template/pods/automation/templates/n8n-design-tmpl.md +23 -0
  332. package/template/pods/automation/templates/n8n-discover-tmpl.md +20 -0
  333. package/template/pods/automation/templates/n8n-handoff-tmpl.md +20 -0
  334. package/template/pods/automation/templates/n8n-test-tmpl.md +20 -0
  335. package/template/pods/automation/workflows/wf-langgraph-build.smoke.json +11 -0
  336. package/template/pods/automation/workflows/wf-langgraph-build.yaml +64 -0
  337. package/template/pods/automation/workflows/wf-n8n-build.smoke.json +11 -0
  338. package/template/pods/automation/workflows/wf-n8n-build.yaml +65 -0
  339. package/template/pods/content-carousel/README.md +91 -0
  340. package/template/pods/content-carousel/agents/carousel-builder.md +28 -0
  341. package/template/pods/content-carousel/agents/carousel-visual.md +24 -0
  342. package/template/pods/content-carousel/agents/hn-curator.md +74 -0
  343. package/template/pods/content-carousel/config/heuristic-watcher-rubric.yaml +59 -0
  344. package/template/pods/content-carousel/knowledge/aquisicao-ancora.md +443 -0
  345. package/template/pods/content-carousel/knowledge/cta-brief.md +25 -0
  346. package/template/pods/content-carousel/knowledge/dono.example.yaml +45 -0
  347. package/template/pods/content-carousel/knowledge/identidade-visual-mascote.md +62 -0
  348. package/template/pods/content-carousel/knowledge/image-generation.md +62 -0
  349. package/template/pods/content-carousel/knowledge/selecao-de-ancora.md +60 -0
  350. package/template/pods/content-carousel/knowledge/slides-html.md +56 -0
  351. package/template/pods/content-carousel/memory/README.md +18 -0
  352. package/template/pods/content-carousel/memory/learnings.consolidated.md +6 -0
  353. package/template/pods/content-carousel/memory/learnings.jsonl +0 -0
  354. package/template/pods/content-carousel/pod-spec.json +100 -0
  355. package/template/pods/content-carousel/squad-io.yaml +10 -0
  356. package/template/pods/content-carousel/templates/assembly-tmpl.md +23 -0
  357. package/template/pods/content-carousel/templates/digest-tmpl.md +29 -0
  358. package/template/pods/content-carousel/templates/visuals-tmpl.md +20 -0
  359. package/template/pods/content-carousel/workflows/wf-content-carousel.smoke.json +23 -0
  360. package/template/pods/content-carousel/workflows/wf-content-carousel.yaml +80 -0
  361. package/template/pods/dev-ia/README.md +45 -0
  362. package/template/pods/dev-ia/agents/db-architect.md +33 -0
  363. package/template/pods/dev-ia/agents/ux-architect.md +29 -0
  364. package/template/pods/dev-ia/knowledge/db/migration-protocol.md +95 -0
  365. package/template/pods/dev-ia/knowledge/db/rls-patterns.md +101 -0
  366. package/template/pods/dev-ia/knowledge/db/schema-review-checklist.md +76 -0
  367. package/template/pods/dev-ia/memory/README.md +16 -0
  368. package/template/pods/dev-ia/memory/learnings.consolidated.md +8 -0
  369. package/template/pods/dev-ia/memory/learnings.jsonl +0 -0
  370. package/template/pods/dev-ia/pod-spec.json +34 -0
  371. package/template/pods/dev-ia/templates/schema-review-tmpl.md +23 -0
  372. package/template/pods/dev-ia/templates/ux-flow-review-tmpl.md +23 -0
  373. package/template/pods/dev-ia/tools/db-ops/backup-manager.sh +321 -0
  374. package/template/pods/dev-ia/tools/db-ops/best-practices-auditor.sh +534 -0
  375. package/template/pods/dev-ia/tools/db-ops/bootstrap-runner.sh +255 -0
  376. package/template/pods/dev-ia/tools/db-ops/data-loader.sh +616 -0
  377. package/template/pods/dev-ia/tools/db-ops/detect-database.sh +113 -0
  378. package/template/pods/dev-ia/tools/db-ops/explain-analyzer.sh +285 -0
  379. package/template/pods/dev-ia/tools/db-ops/health-checker.sh +323 -0
  380. package/template/pods/dev-ia/tools/db-ops/migration-runner.sh +308 -0
  381. package/template/pods/dev-ia/tools/db-ops/postgresql-schema-loader.sh +334 -0
  382. package/template/pods/dev-ia/tools/db-ops/query-runner.sh +171 -0
  383. package/template/pods/dev-ia/tools/db-ops/rls-policy-installer.sh +480 -0
  384. package/template/pods/dev-ia/tools/db-ops/rls-test-suite.sh +172 -0
  385. package/template/pods/dev-ia/tools/db-ops/schema-context-loader.sh +176 -0
  386. package/template/pods/hormozi-method/README.md +52 -0
  387. package/template/pods/hormozi-method/agents/acquisition-strategist.md +33 -0
  388. package/template/pods/hormozi-method/agents/conversion-copywriter.md +34 -0
  389. package/template/pods/hormozi-method/agents/monetization-architect.md +35 -0
  390. package/template/pods/hormozi-method/agents/offer-engineer.md +37 -0
  391. package/template/pods/hormozi-method/knowledge/core-four-leads.md +51 -0
  392. package/template/pods/hormozi-method/knowledge/grand-slam-offer.md +66 -0
  393. package/template/pods/hormozi-method/knowledge/growth-decision.md +38 -0
  394. package/template/pods/hormozi-method/knowledge/hooks-and-ads.md +56 -0
  395. package/template/pods/hormozi-method/knowledge/launch-email.md +31 -0
  396. package/template/pods/hormozi-method/knowledge/money-model.md +46 -0
  397. package/template/pods/hormozi-method/knowledge/opportunity-screening.md +44 -0
  398. package/template/pods/hormozi-method/knowledge/pages.md +25 -0
  399. package/template/pods/hormozi-method/knowledge/pos-lancamento-leads.md +56 -0
  400. package/template/pods/hormozi-method/knowledge/pricing.md +36 -0
  401. package/template/pods/hormozi-method/knowledge/retention-ltv.md +37 -0
  402. package/template/pods/hormozi-method/knowledge/scale-roadmap.md +35 -0
  403. package/template/pods/hormozi-method/knowledge/swipefiles-curados.md +44 -0
  404. package/template/pods/hormozi-method/knowledge/value-equation-diagnostic.md +77 -0
  405. package/template/pods/hormozi-method/memory/README.md +16 -0
  406. package/template/pods/hormozi-method/memory/learnings.consolidated.md +6 -0
  407. package/template/pods/hormozi-method/memory/learnings.jsonl +0 -0
  408. package/template/pods/hormozi-method/pod-spec.json +50 -0
  409. package/template/pods/hormozi-method/specs/wf-full-launch-sequence.spec.json +149 -0
  410. package/template/pods/hormozi-method/specs/wf-lead-magnet-pipeline.spec.json +125 -0
  411. package/template/pods/hormozi-method/specs/wf-money-model-design.spec.json +117 -0
  412. package/template/pods/hormozi-method/specs/wf-paid-ads-campaign.spec.json +132 -0
  413. package/template/pods/hormozi-method/specs/wf-scaling-diagnostic.spec.json +121 -0
  414. package/template/pods/hormozi-method/squad-io.yaml +43 -0
  415. package/template/pods/hormozi-method/templates/conversion-copywriter-tmpl.md +20 -0
  416. package/template/pods/hormozi-method/templates/launch-execucao-tmpl.md +17 -0
  417. package/template/pods/hormozi-method/templates/launch-fechamento-tmpl.md +17 -0
  418. package/template/pods/hormozi-method/templates/launch-pos-tmpl.md +17 -0
  419. package/template/pods/hormozi-method/templates/launch-preparacao-tmpl.md +17 -0
  420. package/template/pods/hormozi-method/templates/lm-copy-tmpl.md +17 -0
  421. package/template/pods/hormozi-method/templates/lm-distribuicao-tmpl.md +18 -0
  422. package/template/pods/hormozi-method/templates/lm-estrategia-tmpl.md +17 -0
  423. package/template/pods/hormozi-method/templates/mm-arquitetura-tmpl.md +18 -0
  424. package/template/pods/hormozi-method/templates/mm-copy-tmpl.md +17 -0
  425. package/template/pods/hormozi-method/templates/mm-diagnostico-tmpl.md +14 -0
  426. package/template/pods/hormozi-method/templates/monetization-architect-tmpl.md +17 -0
  427. package/template/pods/hormozi-method/templates/offer-engineer-tmpl.md +20 -0
  428. package/template/pods/hormozi-method/templates/paid-criativos-tmpl.md +19 -0
  429. package/template/pods/hormozi-method/templates/paid-fundacao-tmpl.md +17 -0
  430. package/template/pods/hormozi-method/templates/paid-teste-escala-tmpl.md +17 -0
  431. package/template/pods/hormozi-method/templates/scaling-diagnostico-tmpl.md +17 -0
  432. package/template/pods/hormozi-method/templates/scaling-priorizacao-tmpl.md +17 -0
  433. package/template/pods/hormozi-method/templates/scaling-roadmap-tmpl.md +17 -0
  434. package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.smoke.json +12 -0
  435. package/template/pods/hormozi-method/workflows/wf-full-launch-sequence.yaml +56 -0
  436. package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.smoke.json +11 -0
  437. package/template/pods/hormozi-method/workflows/wf-grand-slam-offer.yaml +45 -0
  438. package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.smoke.json +9 -0
  439. package/template/pods/hormozi-method/workflows/wf-lead-magnet-pipeline.yaml +45 -0
  440. package/template/pods/hormozi-method/workflows/wf-money-model-design.smoke.json +11 -0
  441. package/template/pods/hormozi-method/workflows/wf-money-model-design.yaml +45 -0
  442. package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.smoke.json +9 -0
  443. package/template/pods/hormozi-method/workflows/wf-paid-ads-campaign.yaml +46 -0
  444. package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.smoke.json +11 -0
  445. package/template/pods/hormozi-method/workflows/wf-scaling-diagnostic.yaml +44 -0
  446. package/template/pods/squad-forge/README.md +53 -0
  447. package/template/pods/squad-forge/agents/forge-chief.md +31 -0
  448. package/template/pods/squad-forge/agents/mind-extractor.md +29 -0
  449. package/template/pods/squad-forge/agents/pod-critic.md +26 -0
  450. package/template/pods/squad-forge/config/heuristic-watcher-rubric.yaml +74 -0
  451. package/template/pods/squad-forge/knowledge/fidelity-rubric.yaml +176 -0
  452. package/template/pods/squad-forge/knowledge/g6-memory-check.md +17 -0
  453. package/template/pods/squad-forge/knowledge/memory-ingest.md +16 -0
  454. package/template/pods/squad-forge/knowledge/source-audit-rubric.yaml +60 -0
  455. package/template/pods/squad-forge/memory/README.md +16 -0
  456. package/template/pods/squad-forge/memory/learnings.consolidated.md +8 -0
  457. package/template/pods/squad-forge/memory/learnings.jsonl +0 -0
  458. package/template/pods/squad-forge/pod-spec.json +166 -0
  459. package/template/pods/squad-forge/squad-io.yaml +13 -0
  460. package/template/pods/squad-forge/tasks/pipeline.md +158 -0
  461. package/template/pods/squad-forge/templates/discovery-tmpl.md +40 -0
  462. package/template/pods/squad-forge/templates/generation-tmpl.md +18 -0
  463. package/template/pods/squad-forge/templates/red-team-tmpl.md +17 -0
  464. package/template/pods/squad-forge/templates/register-tmpl.md +17 -0
  465. package/template/pods/squad-forge/templates/workflow-tmpl.yaml +101 -0
  466. package/template/pods/squad-forge/workflows/wf-forge.smoke.json +12 -0
  467. 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
+ };