@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,678 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ /**
4
+ * pod-export-executor.cjs — ENTRYPOINT de PRODUÇÃO do épico pod-export (F2, Story SF10.2).
5
+ *
6
+ * Dirige a Messages API da Anthropic com o prompt e o modelo PINADO vindos do BUNDLE compilado
7
+ * por F1 (`pod-export-compile.cjs`), usando SÓ as 4 tools confinadas (`pod-export-tools.cjs`), e
8
+ * REUSA o motor de produção `pc-run-pod.cjs` POR IMPORT (state/vetos/verificação-em-disco/retomada
9
+ * — ZERO reimplementação). Industrializa o PoC `spike/pod-export-c3/` (barra 7/7), consumindo o
10
+ * BUNDLE (não a compilação manual do spike) e corrigindo os 2 bugs medidos no spike (loop
11
+ * descartando tool_use em max_tokens; teto pequeno em fases multi-artefato).
12
+ *
13
+ * CLI (ADR-018 Adendo F2 / Decisão 1):
14
+ * node scripts/pod-export-executor.cjs <bundle-dir> <run|resume|approve|status> [runId] \
15
+ * [--input <payload.json>] [--runs-root <dir>] [--lock <path>] [--kill-during <phase>]
16
+ *
17
+ * Decisões vinculantes (seção "Arquitetura" da story + ADR-018 Adendo F2):
18
+ * DF2-1 `pc-run-pod.cjs` INTOCADO; framework é dependência versionada; AC16 fail-loud:
19
+ * framework_version do motor == framework_version do lock do bundle (senão RECUSA).
20
+ * DF2-2 isolamento de memória por CÓDIGO: memoryPodDir efêmero por run (nunca o memory/ do bundle).
21
+ * DF2-3 whitelist de fetch derivada do payload declarado; isBlockedHost barra incondicionalmente.
22
+ * DF5-1 (SF10.8) MATERIALIZAÇÃO da referência: os inputs pinados do run são copiados POR
23
+ * CÓDIGO para `<runDir>/inputs/` no arranque (`materializeInputs`), porque o motor é
24
+ * cego ao `inputs_dir` e o veto `phash-gate.cjs` precisa alcançar a referência por um
25
+ * path FIXO. Determinística — NÃO depende de o modelo chamar `read_image`. O motor
26
+ * segue INTOCADO (a mudança vive aqui, cujo blast radius não alcança pc-run-pipeline).
27
+ * DF-SF10.11-1/-2 (SF10.11, Adendo F6-a) FIXER determinístico PRÉ-VETO: entre `runPhase` e
28
+ * `motor.advance`, `pod-export-postprocess.cjs` normaliza a classe MECÂNICA (tabela
29
+ * declarada) em TODOS os paths de `write_file` da tentativa — não só o artefato que o
30
+ * veto lê. Módulo in-process do export: NÃO blessed, NÃO command_check, motor INTOCADO.
31
+ * DF-SF10.12-1 (SF10.12, Adendo F6-a) CORREÇÃO GUIADA PÓS-VETO: quando `motor.advance` devolve
32
+ * `blocked/verification_failed`, a tentativa seguinte NÃO reamostra às cegas — ela RETOMA
33
+ * a MESMA conversa (`runPhase` devolve `messages`, `execPhase` repassa, `drive` reinjeta)
34
+ * com as `failures[]` REAIS do motor + o diff do fixer + a ordem de EDITAR, não refazer.
35
+ * Antes desta story cada retry reconstruía `userContent` do zero e `messages` nascia
36
+ * vazio: o artefato reprovado NUNCA entrava no contexto (`DF-SF10.11+12-0(b)`).
37
+ * DF-SF10.12-2 (SF10.12) ZERO LIMITES NOVOS: a correção guiada CONSOME o `MAX_RETRY` que já
38
+ * existe. Nenhuma constante, contador ou laço novo — o número de edições guiadas é
39
+ * `MAX_RETRY - 1`, DERIVADO. `MAX_TOKENS`/`MAX_ITERS` seguem governando `runPhase`.
40
+ * LIMITE DE PROCESSO DECLARADO: a conversa vive em memória; após crash/`resume` a fase
41
+ * recomeça no comportamento atual (`buildUserContent` fresco), sem convergência herdada.
42
+ * DF-SF10.19-2 (SF10.19, Adendo F6-b) A PROVENIÊNCIA BLOQUEIA AQUI, não no veto do wf: o blessed
43
+ * `phash-gate.cjs` virou MEDIDA-ONLY (nunca sai não-zero por insumo) porque o mesmo
44
+ * `wf-*.yaml` é consumido por um 2º driver não-confinado (`pc-run-pod.cjs`), onde a
45
+ * premissa da invariante é INSATISFAZÍVEL (DF-SF10.19-0). O invariante não perdeu força:
46
+ * mudou de HOSPEDEIRO — `tools.assertRunProvenance` roda no fim de `execPhase`, antes de
47
+ * `motor.advance`, e violação é HALT do run (SEM consumir `MAX_RETRY`, DF-SF10.19-2/e3).
48
+ * DF5-6 (SF10.8, fix round) PROVENIÊNCIA: cada referência materializada tem o sha256
49
+ * registrado no ledger `<runDir>.provenance.json` (IRMÃO do runDir ⇒ fora do alcance
50
+ * de escrita das tools), e cada imagem gravada por `openrouter_image` também. É o que
51
+ * o veto passa a exigir — o limiar perceptual (R4) foi FALSIFICADO e revogado.
52
+ *
53
+ * NÃO faz: serviço-irmão/systemd/deploy (SF10.3), login/UI/aprovação por identidade (F3),
54
+ * release/selo/paridade selada (F4). Sem git push/PR (exclusivo pc-devops).
55
+ *
56
+ * Node >= 18. Rede INJETÁVEL (callModel/tool transports) → suíte de CI hermética.
57
+ */
58
+
59
+ const fs = require('node:fs');
60
+ const os = require('node:os');
61
+ const path = require('node:path');
62
+ const https = require('node:https');
63
+
64
+ // MOTOR DE PRODUÇÃO reusado por IMPORT (read-only, INTOCADO — DF2-1 / AC9).
65
+ const motor = require('./pc-run-pod.cjs');
66
+ const tools = require('./pod-export-tools.cjs');
67
+ // FIXER determinístico pré-veto (SF10.11 / DF-SF10.11-2): módulo in-process do EXPORT — NÃO é
68
+ // blessed, NÃO é command_check, NÃO é declarável em wf-*.yaml. Roda entre runPhase e motor.advance.
69
+ const postprocess = require('./pod-export-postprocess.cjs');
70
+
71
+ const REPO_ROOT = path.resolve(__dirname, '..');
72
+ const MAX_TOKENS = 8192; // Achado 3/5 do spike: 4096 truncava assembly (7 HTMLs). FIXO.
73
+ const MAX_ITERS = 30; // teto de turns da API por fase (assembly multi-peça precisa de folga).
74
+ const MAX_RETRY = 3; // tentativas por fase quando o veto de máquina reprova (feedback real).
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // Bundle + coerência de versão (AC16 / DF2-1).
78
+ // ---------------------------------------------------------------------------
79
+
80
+ function loadBundle(bundleDir) {
81
+ const root = path.resolve(bundleDir);
82
+ const bundleJsonPath = path.join(root, 'bundle.json');
83
+ if (!fs.existsSync(bundleJsonPath)) throw new Error(`bundle inválido: bundle.json ausente em ${bundleDir}`);
84
+ const bundle = JSON.parse(fs.readFileSync(bundleJsonPath, 'utf8'));
85
+ const wfPath = path.join(root, 'workflow.yaml');
86
+ if (!fs.existsSync(wfPath)) throw new Error(`bundle inválido: workflow.yaml ausente em ${bundleDir}`);
87
+ if (!bundle.modelo_pinado || !bundle.modelo_pinado.agents) throw new Error('bundle inválido: modelo_pinado.agents ausente em bundle.json');
88
+ return { root, bundle, wfPath };
89
+ }
90
+
91
+ /** framework_version do motor instalado (mesma fonte que o compilador usa: package.json do repo). */
92
+ function engineFrameworkVersion() {
93
+ return JSON.parse(fs.readFileSync(path.join(REPO_ROOT, 'package.json'), 'utf8')).version;
94
+ }
95
+
96
+ /** Localiza o lock do bundle: --lock explícito; senão exports/<pod>/export.lock.json no repo. */
97
+ function resolveLockPath(bundle, lockOverride) {
98
+ if (lockOverride) return path.resolve(lockOverride);
99
+ return path.join(REPO_ROOT, 'exports', bundle.pod, 'export.lock.json');
100
+ }
101
+
102
+ /**
103
+ * AC16 / DF2-1 — invariante fail-loud: o motor NÃO roda blessed de versão diferente da que a
104
+ * paridade selou. Divergência entre framework_version do motor e do lock = run RECUSADO.
105
+ */
106
+ function assertFrameworkCoherence(bundle, lockPath, engineVersion = engineFrameworkVersion()) {
107
+ if (!fs.existsSync(lockPath)) {
108
+ throw new Error(`AC16: export.lock.json não encontrado (${lockPath}) — impossível conferir coerência de framework_version. Run RECUSADO.`);
109
+ }
110
+ let lock;
111
+ try { lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); } catch (e) { throw new Error(`AC16: lock ilegível (${lockPath}): ${e.message}`); }
112
+ const lockVersion = lock.framework_version;
113
+ if (!lockVersion) throw new Error(`AC16: lock sem framework_version (${lockPath}) — run RECUSADO.`);
114
+ if (String(lockVersion) !== String(engineVersion)) {
115
+ throw new Error(
116
+ `AC16: MISMATCH de framework_version — motor instalado=${engineVersion}, lock do bundle=${lockVersion}. ` +
117
+ `O bundle foi selado contra outra versão do framework; blessed/vetos podem divergir da paridade. Run RECUSADO (fail-loud).`,
118
+ );
119
+ }
120
+ return { engineVersion, lockVersion };
121
+ }
122
+
123
+ // ---------------------------------------------------------------------------
124
+ // Loop de tool-use da Messages API (industrialização de executor.cjs do spike).
125
+ // ---------------------------------------------------------------------------
126
+
127
+ const TOOL_DEFS = [
128
+ { name: 'http_fetch', description: 'Busca uma URL via HTTP GET. Só hosts da whitelist do run; sem SSRF. Retorna o corpo (texto).', input_schema: { type: 'object', properties: { url: { type: 'string' } }, required: ['url'] } },
129
+ { name: 'openrouter_image', description: 'Gera uma imagem via OpenRouter (modelo PINADO do bundle) e salva como arquivo no runDir. Confirma por path+tamanho (nunca devolve o base64).', input_schema: { type: 'object', properties: { prompt: { type: 'string' }, out_path: { type: 'string', description: 'ex.: assets/cover-bg.png (relativo ao runDir)' } }, required: ['prompt', 'out_path'] } },
130
+ { name: 'write_file', description: 'Escreve um arquivo de texto confinado ao runDir (sem traversal, sem path absoluto). Em fases multi-artefato, escreva UM arquivo por turn.', input_schema: { type: 'object', properties: { path: { type: 'string' }, content: { type: 'string' } }, required: ['path', 'content'] } },
131
+ { name: 'read_image', description: 'Referência pinada "inputs:<nome>" → devolve a imagem para você VER (multimodal). Imagem já gerada (path no runDir) → confirma por path+tamanho, sem re-enviar o base64.', input_schema: { type: 'object', properties: { ref: { type: 'string' } }, required: ['ref'] } },
132
+ ];
133
+
134
+ /** Chamada real à Messages API. Rede INJETÁVEL via `transport` (CI hermética). */
135
+ function anthropicCall({ apiKey, model, system, messages, toolDefs, maxTokens = MAX_TOKENS, transport = null }) {
136
+ const payload = { model, max_tokens: maxTokens, system, messages, tools: toolDefs };
137
+ if (transport) return Promise.resolve(transport(payload));
138
+ const body = JSON.stringify(payload);
139
+ return new Promise((resolve, reject) => {
140
+ const req = https.request('https://api.anthropic.com/v1/messages', {
141
+ method: 'POST', timeout: 120000,
142
+ headers: { 'x-api-key': apiKey, 'anthropic-version': '2023-06-01', 'content-type': 'application/json', 'content-length': Buffer.byteLength(body) },
143
+ }, (res) => {
144
+ let s = '';
145
+ res.on('data', (d) => { s += d; });
146
+ res.on('end', () => { try { const j = JSON.parse(s); if (j.type === 'error') return reject(new Error(`anthropic ${j.error.type}: ${j.error.message}`)); resolve(j); } catch (e) { reject(new Error(`parse: ${e.message} :: ${s.slice(0, 200)}`)); } });
147
+ });
148
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout anthropic')); });
149
+ req.on('error', reject);
150
+ req.write(body); req.end();
151
+ });
152
+ }
153
+
154
+ async function execTool(name, input, env) {
155
+ if (name === 'http_fetch') {
156
+ const r = await tools.httpFetch(input.url, { whitelistHosts: env.whitelistHosts, transport: env.httpTransport });
157
+ return r.ok ? { text: `status ${r.status} (${r.bytes}B)\n${r.body}` } : { text: `ERRO: ${r.error}`, isError: true };
158
+ }
159
+ if (name === 'write_file') {
160
+ try { const r = tools.writeFile(input.path, input.content, { runDir: env.runDir }); return { text: `escrito: ${r.path} (${r.bytes}B)` }; }
161
+ catch (e) { return { text: `ERRO: ${e.message}`, isError: true }; }
162
+ }
163
+ if (name === 'openrouter_image') {
164
+ const r = await tools.openrouterImage(input.prompt, input.out_path, { runDir: env.runDir, model: env.imageModel, apiKey: env.orKey, imageTransport: env.imageTransport });
165
+ return r.ok ? { text: `imagem salva: ${r.path} (${r.bytes}B, modelo ${r.model}) — confirmada por path+tamanho` } : { text: `ERRO: ${r.error}`, isError: true };
166
+ }
167
+ if (name === 'read_image') {
168
+ const r = tools.readImage(input.ref, { runDir: env.runDir, inputsDir: env.inputsDir });
169
+ if (!r.ok) return { text: `ERRO: ${r.error}`, isError: true };
170
+ if (r.kind === 'reference') return { image: { base64: r.base64, mediaType: r.mediaType } };
171
+ return { text: `imagem confirmada em disco: ${r.path} (${r.bytes}B). NÃO reenviada como base64 (economia de contexto).` };
172
+ }
173
+ return { text: `tool desconhecida: ${name}`, isError: true };
174
+ }
175
+
176
+ function toolResultContent(out) {
177
+ if (out.image) return [{ type: 'image', source: { type: 'base64', media_type: out.image.mediaType, data: out.image.base64 } }, { type: 'text', text: 'referência carregada (veja acima).' }];
178
+ return [{ type: 'text', text: out.text }];
179
+ }
180
+
181
+ /**
182
+ * Acrescenta um turn `user` a uma conversa VIVA sem quebrar a alternância de papéis da Messages API.
183
+ *
184
+ * `runPhase` pode parar com a última mensagem no papel `user` (tool_results do turn que estourou
185
+ * `MAX_ITERS`). Empilhar outra mensagem `user` ali seria REJEITADO pela API ("roles must
186
+ * alternate"), então o texto entra como mais um bloco DENTRO daquele turn. Não-mutante de
187
+ * propósito: a conversa anterior é insumo de auditoria e não pode ser reescrita por efeito colateral.
188
+ */
189
+ function appendUserTurn(messages, text) {
190
+ const last = messages[messages.length - 1];
191
+ if (last && last.role === 'user' && Array.isArray(last.content)) {
192
+ return messages.slice(0, -1).concat([{ role: 'user', content: last.content.concat([{ type: 'text', text }]) }]);
193
+ }
194
+ return messages.concat([{ role: 'user', content: text }]);
195
+ }
196
+
197
+ /**
198
+ * Roda UMA fase até o agente parar (sem tool_use) ou o teto de iterações. AC2 (regressão do bug
199
+ * do spike): em stop_reason=max_tokens COM tool_use, NÃO descarta as tools — executa e CONTINUA;
200
+ * só encerra quando a resposta NÃO contém bloco tool_use. `callModel` injetável (CI).
201
+ *
202
+ * `priorMessages` (SF10.12 / DF-SF10.12-1): conversa VIVA da tentativa anterior desta MESMA fase.
203
+ * Quando presente, `userContent` é a MENSAGEM DE CORREÇÃO (não o contrato da fase) e a conversa
204
+ * CONTINUA — o modelo segue vendo o artefato que ele mesmo escreveu e as tools que já executou.
205
+ * Ausente (o padrão, e todo `resume`), a conversa nasce do zero: comportamento pré-SF10.12.
206
+ * Devolve `messages` para que `drive` possa reinjetá-lo na tentativa seguinte.
207
+ */
208
+ async function runPhase({ system, userContent, priorMessages = null, apiKey, model, env, maxIters = MAX_ITERS, onLog, killAfterTurn = 0, callModel = anthropicCall }) {
209
+ const messages = Array.isArray(priorMessages) && priorMessages.length > 0
210
+ ? appendUserTurn(priorMessages, userContent)
211
+ : [{ role: 'user', content: userContent }];
212
+ let iters = 0; let inTok = 0; let outTok = 0; const toolTrail = [];
213
+ while (iters < maxIters) {
214
+ iters++;
215
+ const resp = await callModel({ apiKey, model, system, messages, toolDefs: TOOL_DEFS, maxTokens: MAX_TOKENS, transport: env.apiTransport });
216
+ if (resp.usage) { inTok += resp.usage.input_tokens || 0; outTok += resp.usage.output_tokens || 0; }
217
+ if (killAfterTurn && iters >= killAfterTurn) {
218
+ if (onLog) onLog(` >>> KILL SIMULADO no MEIO da fase (após turn ${iters}, antes do artefato). PID ${process.pid} saindo hard.`);
219
+ process.exit(137);
220
+ }
221
+ messages.push({ role: 'assistant', content: resp.content });
222
+ const toolUses = (resp.content || []).filter((c) => c.type === 'tool_use');
223
+ if (onLog) onLog(` turn ${iters}: stop=${resp.stop_reason} tools=[${toolUses.map((t) => t.name).join(',') || '—'}]`);
224
+ // AC2: encerra SOMENTE quando não há tool_use (end_turn/texto puro). Em max_tokens COM
225
+ // tool_use, o one-file-per-turn evita truncar o bloco e o loop continua.
226
+ if (toolUses.length === 0) break;
227
+ const results = [];
228
+ for (const tu of toolUses) {
229
+ const out = await execTool(tu.name, tu.input, env);
230
+ toolTrail.push({ name: tu.name, ok: !out.isError, arg: tu.name === 'write_file' ? tu.input.path : (tu.name === 'openrouter_image' ? tu.input.out_path : (tu.input.url || tu.input.ref || '')) });
231
+ results.push({ type: 'tool_result', tool_use_id: tu.id, content: toolResultContent(out), is_error: Boolean(out.isError) });
232
+ }
233
+ messages.push({ role: 'user', content: results });
234
+ }
235
+ return { iters, inTok, outTok, toolTrail, messages };
236
+ }
237
+
238
+ // ---------------------------------------------------------------------------
239
+ // Ponte bundle → user content da fase (o bundle.user.md é só o CONTRATO/template; o
240
+ // executor injeta os INPUTS pinados do run + o contexto das fases anteriores + a diretiva
241
+ // de runtime de escrita-por-peça). Nenhum knowledge/agente é reinjetado (já está no system.md).
242
+ // ---------------------------------------------------------------------------
243
+
244
+ function readIf(p) { return fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : ''; }
245
+
246
+ function pinnedInputsBlock(payload) {
247
+ const meta = new Set(['pod', 'workflow', 'fetch_allow_hosts', 'inputs_dir']);
248
+ const pinned = {};
249
+ for (const [k, v] of Object.entries(payload || {})) if (!meta.has(k)) pinned[k] = v;
250
+ if (Object.keys(pinned).length === 0) return '';
251
+ return ['## Inputs FIXADOS do run (não substitua; use-os como fonte pinada)', '```json', JSON.stringify(pinned, null, 2), '```'].join('\n');
252
+ }
253
+
254
+ function priorArtifactsBlock(bundleRoot, runDir, order, stepId) {
255
+ const idx = order.indexOf(stepId);
256
+ const parts = [];
257
+ for (let i = 0; i < idx; i++) {
258
+ const prev = order[i];
259
+ const content = readIf(path.join(runDir, 'artifacts', `${prev}.md`));
260
+ if (content.trim()) parts.push([`## Artefato da fase anterior — ${prev}`, '```', content.trim(), '```'].join('\n'));
261
+ }
262
+ return parts.join('\n\n');
263
+ }
264
+
265
+ function buildUserContent({ bundleRoot, stepId, payload, runDir, order, whitelist }) {
266
+ const contract = readIf(path.join(bundleRoot, 'phases', stepId, 'user.md'));
267
+ const artRel = path.join('artifacts', `${stepId}.md`);
268
+ const parts = [`# RODADA — fase ${stepId}`];
269
+ const pinned = pinnedInputsBlock(payload);
270
+ if (pinned) parts.push(pinned);
271
+ const prior = priorArtifactsBlock(bundleRoot, runDir, order, stepId);
272
+ if (prior) parts.push(prior);
273
+ parts.push(contract);
274
+ parts.push([
275
+ '## Execução (runtime server-side)',
276
+ `- Escreva o artefato final da fase com write_file EXATAMENTE em: ${artRel} (path relativo ao runDir).`,
277
+ `- Para buscar dados, use http_fetch — SÓ os hosts da whitelist deste run são permitidos: ${whitelist.join(', ') || '(nenhum)'}. Hosts privados/metadata são bloqueados.`,
278
+ '- Se a fase produz MÚLTIPLOS arquivos (ex.: peças HTML), escreva UM arquivo por turn (um único write_file por vez), aguarde a confirmação e escreva o próximo — nunca despeje tudo num turn (trunca).',
279
+ '- Gere imagens só com openrouter_image (modelo pinado). Falha de API = pare, nunca substitua (regra de ouro do pod). Confirme imagens geradas por path+tamanho; não peça o base64 de volta.',
280
+ '- Ao terminar o artefato final da fase, pare (não peça confirmação).',
281
+ ].join('\n'));
282
+ return parts.join('\n\n');
283
+ }
284
+
285
+ /**
286
+ * MENSAGEM DE CORREÇÃO GUIADA (SF10.12 / `DF-SF10.12-1`) — o turn `user` que retoma a conversa
287
+ * depois de `motor.advance` reprovar. Substitui a reamostragem cega de antes.
288
+ *
289
+ * Três insumos, exatamente os da decisão:
290
+ * (i) as `failures[]` REAIS do motor, LITERAIS (AC5) — nunca resumo/paráfrase. Quem julga é
291
+ * `verifyStep`/`evalVeto`; reescrever o veredito da autoridade seria fabricar oráculo.
292
+ * (ii) o diff do FIXER da SF10.11, se houve, via `postprocess.renderFixMessage` — sem ele o
293
+ * modelo reescreve por cima da normalização mecânica que já está em disco.
294
+ * (iii) a ordem de EDITAR o que existe, não refazer a fase. É a diferença inteira entre esta
295
+ * tentativa e as três amostras independentes que o retry produzia (`DF-SF10.11+12-0(b)`).
296
+ *
297
+ * Sem `artRel` nem contrato da fase reinjetados: eles já estão na conversa que está sendo retomada.
298
+ */
299
+ function buildCorrectionContent({ stepId, attempt, failures, fixReport }) {
300
+ const list = (failures || []).map((f) => String(f));
301
+ const parts = [
302
+ `# VERIFICAÇÃO DE MÁQUINA REPROVOU — fase ${stepId} (tentativa ${attempt})`,
303
+ [
304
+ 'O verificador determinístico do motor (não eu, não você) rodou sobre o que está EM DISCO e',
305
+ 'devolveu as falhas abaixo. Elas são o veredito LITERAL da máquina, transcrito sem edição:',
306
+ '',
307
+ ...(list.length > 0 ? list.map((f) => `- ${f}`) : ['- (o motor reprovou sem detalhar falhas)']),
308
+ ].join('\n'),
309
+ ];
310
+ const fixBlock = postprocess.renderFixMessage(fixReport);
311
+ if (fixBlock) parts.push(fixBlock);
312
+ parts.push([
313
+ '## O QUE FAZER AGORA — EDITE, não refaça',
314
+ '- O artefato e os demais arquivos que você escreveu CONTINUAM EM DISCO, do jeito que estão acima.',
315
+ '- Corrija EXATAMENTE as falhas listadas, com a menor alteração possível. Não reescreva o que já passou.',
316
+ '- Regrave com write_file APENAS os arquivos que precisam mudar — reenvie o conteúdo COMPLETO do arquivo corrigido.',
317
+ '- NÃO gere imagem de novo: as imagens desta fase já estão em disco e foram confirmadas nesta conversa. Regerá-las custa dinheiro e não corrige nenhuma falha de texto.',
318
+ '- Não recomece a fase do zero e não repita as buscas que você já fez.',
319
+ '- Terminada a correção, pare (não peça confirmação).',
320
+ ].join('\n'));
321
+ return parts.join('\n\n');
322
+ }
323
+
324
+ // ---------------------------------------------------------------------------
325
+ // Driver: reusa o motor por import (mesma lógica do spike run-c3.cjs), sem reimplementar
326
+ // state/vetos/verificação/retomada. execPhase produz o artefato; motor.advance VERIFICA em disco.
327
+ // ---------------------------------------------------------------------------
328
+
329
+ /**
330
+ * Executa UMA tentativa da fase. `guided` (SF10.12) é `{ messages, correction }` da tentativa
331
+ * anterior REPROVADA: presente ⇒ a conversa CONTINUA com a mensagem de correção; ausente ⇒ a
332
+ * conversa nasce de `buildUserContent` (1ª tentativa da fase, e TODO `resume` — DF-SF10.12-1).
333
+ * Um único ramo, sem caminho morto: a correção nunca existe sem a conversa que ela corrige.
334
+ */
335
+ async function execPhase(ctx, run, stepId, guided, killAfterTurn) {
336
+ const bundle = run.bundle;
337
+ const model = bundle.modelo_pinado.agents[stepId];
338
+ if (!model) throw new Error(`fase "${stepId}" sem modelo pinado em bundle.json (modelo_pinado.agents) — nunca hardcodar (AC3)`);
339
+ const system = readIf(path.join(run.bundleRoot, 'phases', stepId, 'system.md'));
340
+ const priorMessages = guided ? guided.messages : null;
341
+ const userContent = guided
342
+ ? guided.correction
343
+ : buildUserContent({ bundleRoot: run.bundleRoot, stepId, payload: run.payload, runDir: ctx.runDir, order: ctx.order, whitelist: run.whitelist });
344
+ const env = {
345
+ runDir: ctx.runDir,
346
+ inputsDir: run.inputsDir,
347
+ whitelistHosts: run.whitelist,
348
+ imageModel: bundle.modelo_pinado.image, // AC3: modelo de imagem pinado do bundle.
349
+ orKey: run.orKey,
350
+ apiTransport: run.deps.apiTransport,
351
+ httpTransport: run.deps.httpTransport,
352
+ imageTransport: run.deps.imageTransport,
353
+ };
354
+ const r = await runPhase({ system, userContent, priorMessages, apiKey: run.anthropicKey, model, env, onLog: run.log, killAfterTurn: killAfterTurn || 0, callModel: run.deps.callModel || anthropicCall });
355
+ run.log(` [${stepId}] ${r.iters} turns, tools=${r.toolTrail.map((t) => t.name).join(',') || '—'}`);
356
+ // PASSO 2 do laço (SF10.11 / DF-SF10.11+12-1): o FIXER determinístico é o ÚLTIMO ESCRITOR ANTES
357
+ // DE TODA VERIFICAÇÃO. Domínio = os paths de `write_file` DESTA tentativa (DF-SF10.11-1) — cobre
358
+ // as 7 peças HTML, não só o artefato que o veto lê. `motor.advance` roda logo depois, em `drive`,
359
+ // e continua sendo a última linha: o fixer reduz quantas vezes o veto DISPARA, nunca o substitui.
360
+ // Fail-loud de propósito (sem try/catch): erro aqui é bug de domínio e o run deve PARAR.
361
+ const fix = postprocess.postProcessAttempt({ runDir: ctx.runDir, toolTrail: r.toolTrail, log: run.log });
362
+ // PASSO 3 do laço (SF10.19 / DF-SF10.19-2/e2): ASSERÇÃO DE PROVENIÊNCIA — o invariante que a
363
+ // SF10.8 entregou como `command_check` e que NÃO pode viver num veto de wf, porque o mesmo yaml é
364
+ // consumido por um driver não-confinado (`pc-run-pod.cjs`), onde a premissa dele é insatisfazível
365
+ // (DF-SF10.19-0). Aqui a premissa vale: as 4 tools são a única porta de bytes deste run.
366
+ // ONDE: última linha de `execPhase`, DEPOIS do fixer (que é o último escritor) e imediatamente
367
+ // antes de `motor.advance` em `drive` — nenhuma escrita acontece entre uma coisa e outra, então
368
+ // não há janela para gravar depois da asserção e antes da verificação.
369
+ // FORMA: módulo in-process do EXPORT (não blessed, não `command_check`, não declarável por pod),
370
+ // mesmo slot do fixer (precedente `DF-SF10.11-2`), fail-loud SEM try/catch: lançar aqui é o HALT
371
+ // do run (`DF-SF10.19-2/e3`) — a exceção atravessa o laço de tentativas SEM consumir `MAX_RETRY`,
372
+ // porque violação de proveniência não é conteúdo que o modelo possa corrigir. Nenhum contador,
373
+ // constante ou limite novo nasce disto (`MAX_TOKENS`/`MAX_ITERS`/`MAX_RETRY` seguem os únicos 3).
374
+ // HERANÇA (DF-SF10.19-4): todo driver de bundle futuro que rode uma fase passa por `execPhase` —
375
+ // é o ponto que ele teria de reescrever de propósito para não asserir.
376
+ tools.assertRunProvenance({
377
+ runDir: ctx.runDir,
378
+ stepId,
379
+ requireNonVacuous: phasesRequiringRefs(run.bundleRoot).includes(stepId),
380
+ });
381
+ // Usage da fase (DF3-4): tokens acumulados no runPhase + imagens OpenRouter geradas com sucesso
382
+ // (contadas do toolTrail — barato). Agregado por drive ao longo do run e exposto no RESULTADO.
383
+ const images = r.toolTrail.filter((t) => t.name === 'openrouter_image' && t.ok).length;
384
+ // `fix` sobe junto do usage: é evidência de auditoria (AC4) E o insumo ESTRUTURADO que a mensagem
385
+ // de correção da SF10.12 consome (DF-SF10.12-1(ii)) — não só log local.
386
+ // `messages` (SF10.12): a conversa VIVA desta tentativa, para `drive` retomá-la se o veto reprovar.
387
+ // `toolTrail` sobe junto porque é o ORÁCULO da reivindicação de custo (AC3): zero `openrouter_image`
388
+ // na tentativa guiada é verificável nele, não em relato.
389
+ return { input_tokens: r.inTok || 0, output_tokens: r.outTok || 0, images, fix, messages: r.messages, toolTrail: r.toolTrail };
390
+ }
391
+
392
+ function currentState(state, order) {
393
+ const running = order.find((id) => state.steps[id].status === 'running');
394
+ const awaiting = order.find((id) => state.steps[id].status === 'awaiting_approval');
395
+ const allDone = order.every((id) => state.steps[id].status === 'done');
396
+ return { running, awaiting, allDone };
397
+ }
398
+
399
+ async function drive(ctx, run, { killDuring } = {}) {
400
+ const order = ctx.order;
401
+ // Usage AGREGADO do run (DF3-4) — somado a cada fase e exposto no RESULTADO final (o ledger do
402
+ // serviço lê `result.usage`). Não altera fases/tools/vetos/coerência/retomada: só observa.
403
+ const usage = { input_tokens: 0, output_tokens: 0, images: 0 };
404
+ // AC4 (SF10.11) — trilha COMPACTA do fixer determinístico por tentativa que mudou algo. O
405
+ // relatório COMPLETO (com diff por linha) não entra aqui: ele viaja em `lastFix`, que é o insumo
406
+ // da mensagem de correção da SF10.12 (DF-SF10.12-1(ii)). Aqui fica só o que um operador precisa
407
+ // ler no ledger da fila, limitado por construção (fases x MAX_RETRY).
408
+ const fixes = [];
409
+ while (true) {
410
+ const state = motor.readState(ctx.statePath); ctx.state = state;
411
+ const { running, awaiting, allDone } = currentState(state, order);
412
+ if (awaiting) { run.log(`\n>>> CHECKPOINT HUMANO: fase "${awaiting}" em awaiting_approval. Rode: approve ${state.run_id}`); return { awaiting, usage, fixes }; }
413
+ if (allDone) { run.log('\n>>> PIPELINE COMPLETO (todas as fases done).'); return { complete: true, usage, fixes }; }
414
+ if (!running) { run.log('\n>>> parado sem fase running (state inconsistente?)'); return { halted: true, usage, fixes }; }
415
+ const killMid = killDuring && killDuring === running;
416
+ let ok = false;
417
+ // Último relatório do fixer da fase corrente. SF10.11 o PRODUZ e o CARREGA até aqui; a SF10.12
418
+ // o CONSOME (junto das `failures[]` reais) ao retomar a conversa em vez de reamostrar às cegas.
419
+ let lastFix = null;
420
+ // PASSO 4 do laço (SF10.12 / DF-SF10.12-1): a conversa VIVA da fase corrente. `null` na 1ª
421
+ // tentativa e em TODO `resume` (memória de PROCESSO, limite declarado, nunca persistida no
422
+ // runDir). Preenchida só quando o veto reprova ⇒ custo ZERO no caminho limpo.
423
+ // Escopo: declarada DENTRO do `while` ⇒ morre com a fase; nenhuma conversa vaza entre fases.
424
+ let guided = null;
425
+ for (let attempt = 1; attempt <= MAX_RETRY; attempt++) {
426
+ const phaseUsage = await execPhase(ctx, run, running, guided, killMid ? 1 : 0);
427
+ usage.input_tokens += phaseUsage.input_tokens; usage.output_tokens += phaseUsage.output_tokens; usage.images += phaseUsage.images;
428
+ lastFix = phaseUsage.fix || null;
429
+ if (lastFix && lastFix.changed) fixes.push({ step: running, attempt, files: lastFix.files.length, replacements: lastFix.totalReplacements });
430
+ const res = motor.advance(ctx); // VERIFICAÇÃO EM DISCO (verifyStep/evalVeto) — motor de produção, INTOCADO.
431
+ if (res.action === 'blocked' && res.reason === 'verification_failed') {
432
+ const failures = res.failures || [];
433
+ run.log(` [${running}] VETO DISPAROU (tentativa ${attempt}): ${failures.join(' | ')}`);
434
+ // DF-SF10.11+12-2(3): quando o veto reprova, o diff do fixer aparece AO LADO das falhas, na
435
+ // mesma tentativa — se foi o fixer que causou a reprovação, as duas causas ficam visíveis
436
+ // juntas, nunca a duas tentativas de distância.
437
+ if (lastFix && lastFix.changed) run.log(` [${running}] (o fixer havia alterado ${lastFix.files.length} arquivo(s) nesta tentativa: ${lastFix.files.map((f) => f.path).join(', ')})`);
438
+ // AC5 — auditoria do que o MODELO recebe: cada falha REAL do motor, uma por linha, LITERAL.
439
+ // O log do run precisa permitir conferir que nenhuma paráfrase foi entregue no lugar do
440
+ // veredito da máquina; sem isso a promessa "failures reais" não é verificável depois do fato.
441
+ // Sem laço de statement de propósito (AC2/DF-SF10.12-2): esta story não acrescenta NENHUMA
442
+ // estrutura de repetição ao arquivo — o único laço que governa tentativas segue sendo o
443
+ // `for (attempt <= MAX_RETRY)` acima.
444
+ if (failures.length > 0) run.log(failures.map((f) => ` [${running}] → entregue ao modelo (literal): ${f}`).join('\n'));
445
+ if (attempt < MAX_RETRY) {
446
+ // Retoma a MESMA conversa em vez de reamostrar às cegas. Nenhum contador/limite novo:
447
+ // quem governa quantas edições guiadas existem é o `MAX_RETRY` acima (DF-SF10.12-2).
448
+ guided = {
449
+ messages: phaseUsage.messages,
450
+ correction: buildCorrectionContent({ stepId: running, attempt, failures, fixReport: lastFix }),
451
+ };
452
+ run.log(` [${running}] CORREÇÃO GUIADA: retomando a MESMA conversa (${phaseUsage.messages.length} mensagens) com ordem de EDITAR, não refazer (DF-SF10.12-1).`);
453
+ }
454
+ continue;
455
+ }
456
+ run.log(` [${running}] advance → ${res.action}${res.step ? ' (' + res.step + ')' : ''}`);
457
+ ok = true; break;
458
+ }
459
+ if (!ok) { run.log(`\n>>> BLOQUEIO: fase "${running}" não passou o veto em ${MAX_RETRY} tentativas.`); return { blocked: running, usage, fixes }; }
460
+ }
461
+ }
462
+
463
+ // ---------------------------------------------------------------------------
464
+ // Setup de um run (comum a run/resume/approve/status). Reúne bundle + payload + chaves + deps.
465
+ // ---------------------------------------------------------------------------
466
+
467
+ function readEnvVar(file, key) {
468
+ if (!fs.existsSync(file)) return null;
469
+ const line = fs.readFileSync(file, 'utf8').split(/\r?\n/).find((l) => l.startsWith(`${key}=`));
470
+ return line ? (line.slice(key.length + 1).trim().replace(/^["']|["']$/g, '') || null) : null;
471
+ }
472
+
473
+ function loadPayload(inputPath) {
474
+ if (!inputPath) return {};
475
+ const abs = path.resolve(inputPath);
476
+ if (!fs.existsSync(abs)) throw new Error(`--input não encontrado: ${inputPath}`);
477
+ const payload = JSON.parse(fs.readFileSync(abs, 'utf8'));
478
+ payload.__dir = path.dirname(abs);
479
+ return payload;
480
+ }
481
+
482
+ /**
483
+ * Monta o objeto `run` (bundle carregado, coerência AC16 já conferida, whitelist derivada,
484
+ * memoryPodDir efêmero (DF2-2), chaves de runtime, deps injetáveis). NÃO abre o motor ainda.
485
+ */
486
+ function setupRun({ bundleDir, lockOverride, payload = {}, deps = {}, log }) {
487
+ const { root: bundleRoot, bundle } = loadBundle(bundleDir);
488
+ const lockPath = resolveLockPath(bundle, lockOverride);
489
+ const coherence = assertFrameworkCoherence(bundle, lockPath); // AC16 fail-loud ANTES de qualquer run.
490
+ const whitelist = tools.computeWhitelist(payload);
491
+ const inputsDir = payload.inputs_dir
492
+ ? (path.isAbsolute(payload.inputs_dir) ? payload.inputs_dir : path.resolve(payload.__dir || process.cwd(), payload.inputs_dir))
493
+ : null;
494
+ const anthropicKey = process.env.ANTHROPIC_API_KEY
495
+ || readEnvVar(path.join(os.homedir(), 'projetos/dev/second-brain/app/.env.local'), 'ANTHROPIC_API_KEY');
496
+ const orKey = process.env.OPENROUTER_API_KEY
497
+ || readEnvVar(path.join(os.homedir(), 'projetos/bench/.env'), 'OPENROUTER_API_KEY');
498
+ return {
499
+ bundleRoot, bundle, lockPath, coherence, whitelist, inputsDir,
500
+ payload, anthropicKey, orKey, deps,
501
+ pod: bundle.pod,
502
+ workflow: payload.workflow || `wf-${bundle.pod}`,
503
+ log: log || ((m) => console.log(m)),
504
+ };
505
+ }
506
+
507
+ // ---------------------------------------------------------------------------
508
+ // Materialização dos inputs pinados no runDir (DF5-1 / SF10.8) — o par de máquina da não-cópia.
509
+ // ---------------------------------------------------------------------------
510
+
511
+ // Fonte ÚNICA da convenção: a constante vive em `pod-export-tools.cjs`, que é quem PRECISA dela
512
+ // para negar escrita sob `<runDir>/inputs/` (camada 1 de INTEG-1). Aqui só se reexporta — duas
513
+ // cópias literais divergiriam em silêncio e reabririam o vetor.
514
+ const RUN_INPUTS_DIRNAME = tools.RUN_INPUTS_DIRNAME; // convenção FIXA lida pelo veto (`--refs-dir ../inputs`)
515
+ const PHASH_VETO_SCRIPT = 'phash-gate.cjs'; // blessed que EXIGE a referência materializada
516
+
517
+ /**
518
+ * Fases do bundle que declaram o veto de pHash (lidas de `phases/<id>/meta.json`, escrito pelo
519
+ * compilador a partir das assertions `command_check` do wf — não de texto de agente).
520
+ */
521
+ function phasesRequiringRefs(bundleRoot) {
522
+ const phasesDir = path.join(bundleRoot, 'phases');
523
+ if (!fs.existsSync(phasesDir)) return [];
524
+ const out = [];
525
+ for (const id of fs.readdirSync(phasesDir).sort()) {
526
+ const metaPath = path.join(phasesDir, id, 'meta.json');
527
+ if (!fs.existsSync(metaPath)) continue;
528
+ try {
529
+ const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
530
+ if (Array.isArray(meta.veto_scripts) && meta.veto_scripts.includes(PHASH_VETO_SCRIPT)) out.push(id);
531
+ } catch { /* meta ilegível: o compilador já falharia antes; não inventar requisito aqui */ }
532
+ }
533
+ return out;
534
+ }
535
+
536
+ /**
537
+ * COPIA os inputs pinados do run para `<runDir>/inputs/` (DF5-1). Determinística e idempotente
538
+ * (roda igual em run e resume). Só arquivos regulares, um nível — nomes preservados; nada de
539
+ * symlink/traversal (o destino é sempre `<runDir>/inputs/<basename>`).
540
+ *
541
+ * REGISTRA o sha256 de CADA referência materializada no ledger de proveniência do run
542
+ * (`<runDir>.provenance.json`, IRMÃO do runDir — fora da árvore gravável pelo agente). É a
543
+ * camada 2 do fechamento de INTEG-1 (DF5-6/e1): o veto recusa fail-loud se o arquivo em
544
+ * `inputs/` divergir do hash aqui registrado, mesmo que a camada 1 (denylist de escrita nas
545
+ * tools) tenha algum caminho não antecipado.
546
+ *
547
+ * FAIL-LOUD: se alguma fase declara o veto `phash-gate.cjs` e o run NÃO tem `inputs_dir` com
548
+ * imagem, ABORTA ANTES de gastar API — o veto bloquearia adiante de qualquer forma, e falhar
549
+ * cedo com mensagem acionável é melhor que queimar tokens para morrer no gate.
550
+ */
551
+ function materializeInputs({ bundleRoot, inputsDir, runDir, log = () => {} }) {
552
+ const required = bundleRoot ? phasesRequiringRefs(bundleRoot) : [];
553
+ const dest = path.join(runDir, RUN_INPUTS_DIRNAME);
554
+ let copied = [];
555
+ if (inputsDir && fs.existsSync(inputsDir)) {
556
+ fs.mkdirSync(dest, { recursive: true });
557
+ for (const e of fs.readdirSync(inputsDir, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))) {
558
+ if (!e.isFile() || e.name.startsWith('.')) continue;
559
+ const target = path.join(dest, path.basename(e.name));
560
+ fs.copyFileSync(path.join(inputsDir, e.name), target);
561
+ // Proveniência da REFERÊNCIA: o hash é tirado DEPOIS da cópia, do arquivo que o veto vai
562
+ // ler — é exatamente a igualdade bit-a-bit que o invariante promete.
563
+ tools.recordProvenance(runDir, 'inputs', target, { source: 'materializeInputs' });
564
+ copied.push(e.name);
565
+ }
566
+ }
567
+ if (required.length > 0 && copied.length === 0) {
568
+ throw new Error(
569
+ `fase(s) [${required.join(', ')}] declaram o veto de não-cópia "${PHASH_VETO_SCRIPT}", que compara as ` +
570
+ `imagens geradas contra a REFERÊNCIA do run — mas nenhum input foi materializado em ${dest}. ` +
571
+ 'Passe --input com "inputs_dir" apontando o diretório da referência (ADR-018 Adendo F5/DF5-1). ' +
572
+ 'ABORTANDO antes de gastar API (o veto bloquearia a etapa de qualquer forma).',
573
+ );
574
+ }
575
+ if (copied.length > 0) log(`[inputs] materializados em ${RUN_INPUTS_DIRNAME}/: ${copied.join(', ')} (DF5-1 — referência do veto de não-cópia)`);
576
+ return { dest, copied, required };
577
+ }
578
+
579
+ // ---------------------------------------------------------------------------
580
+ // CLI.
581
+ // ---------------------------------------------------------------------------
582
+
583
+ function parseArgs(argv) {
584
+ const positionals = [];
585
+ const flags = {};
586
+ for (let i = 0; i < argv.length; i++) {
587
+ const a = argv[i];
588
+ if (a === '--input') flags.input = argv[++i];
589
+ else if (a === '--runs-root') flags.runsRoot = argv[++i];
590
+ else if (a === '--lock') flags.lock = argv[++i];
591
+ else if (a === '--kill-during') flags.killDuring = argv[++i];
592
+ else positionals.push(a);
593
+ }
594
+ return { positionals, flags };
595
+ }
596
+
597
+ async function main() {
598
+ const { positionals, flags } = parseArgs(process.argv.slice(2));
599
+ const bundleDir = positionals[0];
600
+ const cmd = positionals[1];
601
+ const runIdArg = positionals[2];
602
+ if (!bundleDir || !cmd) {
603
+ console.error('Uso: node scripts/pod-export-executor.cjs <bundle-dir> <run|resume|approve|status> [runId] [--input <payload.json>] [--runs-root <dir>] [--lock <path>] [--kill-during <phase>]');
604
+ process.exit(2);
605
+ }
606
+ const runsRoot = flags.runsRoot ? path.resolve(flags.runsRoot) : path.join(REPO_ROOT, '.power-claude', 'pod-export-runs');
607
+ fs.mkdirSync(runsRoot, { recursive: true });
608
+
609
+ const payload = loadPayload(flags.input);
610
+ const run = setupRun({ bundleDir, lockOverride: flags.lock, payload });
611
+ run.log(`[coerência] framework_version motor=${run.coherence.engineVersion} == lock=${run.coherence.lockVersion} (AC16 OK)`);
612
+
613
+ if (cmd === 'run') {
614
+ if (!run.anthropicKey) { console.error('[FALHA] ANTHROPIC_API_KEY não encontrada (env ou second-brain/app/.env.local).'); process.exit(1); }
615
+ const runId = runIdArg || ('pex-' + new Date().toISOString().replace(/[:.]/g, '-'));
616
+ const memoryPodDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pex-mem-')); // DF2-2: memória efêmera, NUNCA o bundle.
617
+ run.log(`\n=== RUN ${runId} — pod ${run.pod} — modelos ${JSON.stringify(run.bundle.modelo_pinado.agents)} ===`);
618
+ const { ctx } = motor.startRun({ workflowPath: run.bundleRoot + '/workflow.yaml', podRootOverride: run.bundleRoot, pod: run.pod, workflow: run.workflow, runsRoot, runId, memoryPodDir });
619
+ run.log(`runDir=${ctx.runDir}`);
620
+ materializeInputs({ bundleRoot: run.bundleRoot, inputsDir: run.inputsDir, runDir: ctx.runDir, log: run.log }); // DF5-1
621
+ const r = await drive(ctx, run, { killDuring: flags.killDuring });
622
+ console.log('\nRESULTADO:', JSON.stringify(r));
623
+ } else if (cmd === 'resume') {
624
+ const statePath = motor.findStateByRunId(runsRoot, runIdArg);
625
+ if (!statePath) { console.error(`run ${runIdArg} não encontrado em ${runsRoot}`); process.exit(1); }
626
+ const memoryPodDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pex-mem-'));
627
+ const ctx = motor.openRun({ statePath, workflowPath: run.bundleRoot + '/workflow.yaml', podRootOverride: run.bundleRoot, memoryPodDir });
628
+ materializeInputs({ bundleRoot: run.bundleRoot, inputsDir: run.inputsDir, runDir: ctx.runDir, log: run.log }); // DF5-1 (idempotente)
629
+ run.log(`\n=== RESUME ${runIdArg} ===`);
630
+ const r = await drive(ctx, run, {});
631
+ console.log('\nRESULTADO:', JSON.stringify(r));
632
+ } else if (cmd === 'approve') {
633
+ const statePath = motor.findStateByRunId(runsRoot, runIdArg);
634
+ if (!statePath) { console.error(`run ${runIdArg} não encontrado em ${runsRoot}`); process.exit(1); }
635
+ const memoryPodDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pex-mem-'));
636
+ const ctx = motor.openRun({ statePath, workflowPath: run.bundleRoot + '/workflow.yaml', podRootOverride: run.bundleRoot, memoryPodDir });
637
+ const res = motor.approve(ctx);
638
+ run.log(`\n>>> CHECKPOINT APROVADO (operador; sem identidade nesta fase — F3). approve → ${res.action}`);
639
+ console.log('\nRESULTADO:', JSON.stringify({ approved: true, next: res.next && res.next.action }));
640
+ } else if (cmd === 'status') {
641
+ const statePath = motor.findStateByRunId(runsRoot, runIdArg);
642
+ if (!statePath) { console.error(`run ${runIdArg} não encontrado em ${runsRoot}`); process.exit(1); }
643
+ const ctx = motor.openRun({ statePath, workflowPath: run.bundleRoot + '/workflow.yaml', podRootOverride: run.bundleRoot });
644
+ console.log(motor.statusSummary(ctx));
645
+ } else {
646
+ console.error('cmd: run|resume|approve|status');
647
+ process.exit(2);
648
+ }
649
+ }
650
+
651
+ if (require.main === module) {
652
+ main().catch((e) => { console.error('[ERRO]', e.message); process.exit(1); });
653
+ }
654
+
655
+ module.exports = {
656
+ loadBundle,
657
+ engineFrameworkVersion,
658
+ resolveLockPath,
659
+ assertFrameworkCoherence,
660
+ anthropicCall,
661
+ execTool,
662
+ runPhase,
663
+ appendUserTurn,
664
+ buildUserContent,
665
+ buildCorrectionContent,
666
+ pinnedInputsBlock,
667
+ priorArtifactsBlock,
668
+ setupRun,
669
+ materializeInputs,
670
+ phasesRequiringRefs,
671
+ RUN_INPUTS_DIRNAME,
672
+ PHASH_VETO_SCRIPT,
673
+ drive,
674
+ execPhase,
675
+ parseArgs,
676
+ TOOL_DEFS,
677
+ MAX_TOKENS,
678
+ };