@orkastery/cli 0.5.6 → 0.6.1

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.
Files changed (396) hide show
  1. package/adapters/README.md +18 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
  3. package/adapters/claude-code/README.md +37 -5
  4. package/adapters/claude-code/agents/ork-check.md +1 -0
  5. package/adapters/claude-code/agents/ork-go.md +1 -0
  6. package/adapters/claude-code/agents/ork-goal.md +1 -0
  7. package/adapters/claude-code/agents/ork-master.md +1 -0
  8. package/adapters/claude-code/agents/ork-plan.md +1 -0
  9. package/adapters/claude-code/agents/ork-ship.md +1 -0
  10. package/adapters/claude-code/hooks/hooks.json +2 -1
  11. package/adapters/claude-code/hooks/ork-guard.js +15 -1
  12. package/adapters/claude-code/hooks/ork-resposta.js +91 -0
  13. package/adapters/claude-code/hooks/ork-sensor.js +18 -2
  14. package/adapters/claude-code/hooks/quota-signal.js +14 -0
  15. package/adapters/claude-code/mods/ork-mensageiro/.claude-plugin/plugin.json +14 -0
  16. package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
  17. package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
  18. package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
  19. package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
  20. package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
  21. package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
  22. package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -0
  23. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +9 -5
  24. package/adapters/claude-code/mods/ork-ritual/.claude-plugin/plugin.json +14 -0
  25. package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
  27. package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
  28. package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
  29. package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
  30. package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
  31. package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -0
  32. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +1 -1
  33. package/adapters/codex/skills/ork/SKILL.md +2 -0
  34. package/adapters/hermes/README.md +64 -1
  35. package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
  36. package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
  37. package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
  38. package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
  39. package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
  40. package/adapters/hermes/hermes.plugin.json +4 -0
  41. package/adapters/hermes/hitl-ingress/__init__.py +101 -8
  42. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +2 -2
  43. package/adapters/openclaw/README.md +81 -9
  44. package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
  45. package/adapters/openclaw/dist/hitl-ingress.js +106 -9
  46. package/adapters/openclaw/dist/index.js +86 -0
  47. package/adapters/openclaw/openclaw.plugin.json +34 -4
  48. package/adapters/openclaw/package.json +2 -2
  49. package/adapters/openclaw/src/hitl-ingress.ts +103 -9
  50. package/adapters/openclaw/src/index.ts +94 -0
  51. package/assets/adapters-en/claude-code/README.md +403 -0
  52. package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
  53. package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
  54. package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
  55. package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
  56. package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
  57. package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
  58. package/assets/adapters-en/claude-code/commands/check.md +46 -0
  59. package/assets/adapters-en/claude-code/commands/go.md +46 -0
  60. package/assets/adapters-en/claude-code/commands/goal.md +55 -0
  61. package/assets/adapters-en/claude-code/commands/master.md +54 -0
  62. package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
  63. package/assets/adapters-en/claude-code/commands/ork.md +126 -0
  64. package/assets/adapters-en/claude-code/commands/plan.md +47 -0
  65. package/assets/adapters-en/claude-code/commands/ship.md +45 -0
  66. package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
  67. package/assets/adapters-en/hermes/README.md +273 -0
  68. package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
  69. package/assets/references-en/README.md +25 -0
  70. package/assets/references-en/code-review-axes.md +82 -0
  71. package/assets/references-en/definition-of-done.md +74 -0
  72. package/assets/references-en/performance-checklist.md +53 -0
  73. package/assets/references-en/security-checklist.md +101 -0
  74. package/assets/references-en/testing-patterns.md +51 -0
  75. package/assets/security-scan/defaults/.golangci.yml +2 -0
  76. package/assets/security-scan/defaults/eslint.config.mjs +11 -0
  77. package/assets/security-scan/defaults/gitleaks.toml +3 -0
  78. package/assets/security-scan/defaults/ruff.toml +1 -0
  79. package/assets/security-scan/tools-agil.json +87 -0
  80. package/assets/security-scan/tools.json +625 -0
  81. package/assets/skills-en/core/onboarding/SKILL.md +58 -0
  82. package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
  83. package/assets/skills-en/core/thread-state/SKILL.md +88 -0
  84. package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
  85. package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
  86. package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
  87. package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
  88. package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
  89. package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
  90. package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
  91. package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
  92. package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
  93. package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
  94. package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
  95. package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
  96. package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
  97. package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
  98. package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
  99. package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
  100. package/dist/adapters/claude-bg.js +123 -9
  101. package/dist/adapters/codex-controller-worker.js +12 -5
  102. package/dist/adapters/codex-events.js +16 -4
  103. package/dist/adapters/codex.js +3 -1
  104. package/dist/adapters/grok-events.js +227 -0
  105. package/dist/adapters/grok-mcp-servidor.js +612 -0
  106. package/dist/adapters/grok-mcp.js +178 -0
  107. package/dist/adapters/grok.js +686 -0
  108. package/dist/agendador-cpu.js +92 -0
  109. package/dist/atualizar-branch.js +245 -0
  110. package/dist/auditoria.js +13 -11
  111. package/dist/auditrun.js +51 -46
  112. package/dist/autorizacao-duravel.js +327 -0
  113. package/dist/board.js +94 -40
  114. package/dist/branch-de-estado.js +23 -10
  115. package/dist/busca-semantica.js +7 -5
  116. package/dist/catalogo.js +2 -1
  117. package/dist/changelog-reconciliacao.js +290 -0
  118. package/dist/check-agil.js +528 -0
  119. package/dist/check-modo.js +41 -0
  120. package/dist/check-paralelo.js +238 -0
  121. package/dist/ci.js +248 -45
  122. package/dist/ciclos.js +8 -6
  123. package/dist/claim-lint.js +12 -8
  124. package/dist/claims-conferir.js +47 -39
  125. package/dist/claims.js +10 -9
  126. package/dist/company-brain-client.js +10 -3
  127. package/dist/company-brain-migration.js +11 -5
  128. package/dist/conducao-batida.js +759 -0
  129. package/dist/conducao-sentinela.js +25 -8
  130. package/dist/conducao.js +89 -29
  131. package/dist/conhecimento-consulta.js +270 -0
  132. package/dist/conhecimento.js +111 -87
  133. package/dist/conta-esgotada.js +127 -0
  134. package/dist/dado-privado.js +816 -0
  135. package/dist/decisao-autonoma.js +5 -4
  136. package/dist/demo.js +14 -12
  137. package/dist/dependencias-da-worktree.js +25 -0
  138. package/dist/divida.js +38 -36
  139. package/dist/docs.js +89 -89
  140. package/dist/doctor-forja.js +343 -0
  141. package/dist/doctor-pulse-cron.js +113 -1
  142. package/dist/doctor.js +164 -6
  143. package/dist/dsn-da-memoria.js +417 -0
  144. package/dist/entrega-por-mod.js +503 -0
  145. package/dist/entrega-pr.js +154 -54
  146. package/dist/esgotamentos.js +13 -11
  147. package/dist/estado-thread.js +21 -18
  148. package/dist/evalrunner.js +35 -32
  149. package/dist/fabrica-batida.js +34 -21
  150. package/dist/fabrica-estado.js +33 -21
  151. package/dist/fix.js +21 -19
  152. package/dist/forja/adaptador.js +6 -0
  153. package/dist/forja/ambiente-de-ci.js +27 -0
  154. package/dist/forja/api.js +256 -0
  155. package/dist/forja/cache.js +89 -0
  156. package/dist/forja/cli.js +60 -0
  157. package/dist/forja/contrato.js +9 -0
  158. package/dist/forja/endereco.js +43 -0
  159. package/dist/forja/estado.js +22 -0
  160. package/dist/forja/executor.js +73 -0
  161. package/dist/forja/github/ci.js +95 -0
  162. package/dist/forja/github/dono-da-rede.js +18 -0
  163. package/dist/forja/github/metadados.js +15 -0
  164. package/dist/forja/github/pedidos.js +200 -0
  165. package/dist/forja/gitlab/ci.js +141 -0
  166. package/dist/forja/gitlab/consultas.js +59 -0
  167. package/dist/forja/gitlab/dono-da-rede.js +43 -0
  168. package/dist/forja/gitlab/metadados.js +15 -0
  169. package/dist/forja/gitlab/pedidos-abertos.js +158 -0
  170. package/dist/forja/gitlab/pedidos.js +141 -0
  171. package/dist/forja/produtor.js +32 -0
  172. package/dist/forja/registro.js +31 -0
  173. package/dist/forja/resolver.js +121 -0
  174. package/dist/forja/texto.js +13 -0
  175. package/dist/forja/versao.js +71 -0
  176. package/dist/forja.js +123 -80
  177. package/dist/handoff.js +23 -13
  178. package/dist/hitl-contract.js +46 -43
  179. package/dist/hitl-curto.js +37 -25
  180. package/dist/hitl-gates.js +13 -11
  181. package/dist/hitl-local-receipt.js +51 -0
  182. package/dist/hitl-local.js +11 -2
  183. package/dist/hitl-lock.js +5 -11
  184. package/dist/hitl-public-receipt.js +11 -0
  185. package/dist/hitl-resumo.js +44 -1
  186. package/dist/hitl-sessions.js +62 -9
  187. package/dist/hitl-texto-livre.js +7 -4
  188. package/dist/hitl.js +34 -31
  189. package/dist/horario.js +20 -1
  190. package/dist/hosts.js +104 -134
  191. package/dist/index.js +864 -554
  192. package/dist/indice-vetorial.js +14 -12
  193. package/dist/init.js +11 -2
  194. package/dist/integracoes-locais.js +4 -0
  195. package/dist/intelligence-graph-cli.js +123 -69
  196. package/dist/intelligence-graph-query.js +37 -22
  197. package/dist/leases.js +19 -18
  198. package/dist/ledger-stats.js +17 -16
  199. package/dist/ledger.js +31 -1
  200. package/dist/licoes.js +12 -11
  201. package/dist/locale-accounts.js +228 -0
  202. package/dist/locale-adapter.js +291 -0
  203. package/dist/locale-ajuda.js +86 -10
  204. package/dist/locale-audit.js +199 -0
  205. package/dist/locale-claims.js +213 -0
  206. package/dist/locale-conducao.js +138 -0
  207. package/dist/locale-conhecimento.js +181 -0
  208. package/dist/locale-decisao.js +205 -0
  209. package/dist/locale-docs.js +230 -0
  210. package/dist/locale-estado.js +101 -0
  211. package/dist/locale-forja.js +288 -0
  212. package/dist/locale-gerados.js +5 -0
  213. package/dist/locale-grafo.js +129 -0
  214. package/dist/locale-master.js +83 -0
  215. package/dist/locale-network.js +524 -0
  216. package/dist/locale-operacao-restante.js +931 -0
  217. package/dist/locale-projetos.js +100 -0
  218. package/dist/locale-prompts.js +194 -0
  219. package/dist/locale-pulse.js +140 -2
  220. package/dist/locale-reservas.js +87 -0
  221. package/dist/locale-retry.js +183 -6
  222. package/dist/locale-security-scan.js +69 -0
  223. package/dist/locale-setup.js +192 -0
  224. package/dist/locale-ship.js +177 -66
  225. package/dist/locale-thread.js +149 -5
  226. package/dist/locale-verify.js +80 -4
  227. package/dist/locale-worktree.js +246 -0
  228. package/dist/locale.js +553 -9
  229. package/dist/maestro-runtime.js +22 -3
  230. package/dist/manifest.js +293 -12
  231. package/dist/maquina-ociosa.js +211 -0
  232. package/dist/maquina.js +10 -5
  233. package/dist/master-nota-local.js +200 -0
  234. package/dist/master-nota.js +10 -2
  235. package/dist/master.js +118 -41
  236. package/dist/mcp-conhecimento.js +52 -0
  237. package/dist/mcp-experiencia.js +26 -5
  238. package/dist/mcp-install.js +90 -15
  239. package/dist/mcp-noctum.js +101 -0
  240. package/dist/mcp-server.js +116 -22
  241. package/dist/mcp-ship-transporte.js +977 -0
  242. package/dist/mcp-ship.js +68 -24
  243. package/dist/mcp-transportes.js +17 -0
  244. package/dist/memoria.js +63 -58
  245. package/dist/merge-da-entrega.js +85 -0
  246. package/dist/modos-migracao.js +8 -6
  247. package/dist/modos.js +17 -18
  248. package/dist/network-roadmap.js +94 -54
  249. package/dist/noctum-aceite.js +929 -0
  250. package/dist/noctum-arco.js +540 -33
  251. package/dist/noctum-capacidade.js +3 -3
  252. package/dist/noctum-changelog.js +399 -0
  253. package/dist/noctum-cli.js +539 -0
  254. package/dist/noctum-coordenacao.js +1225 -0
  255. package/dist/noctum-entrega.js +1217 -0
  256. package/dist/noctum-envelope.js +253 -17
  257. package/dist/noctum-execucao.js +100 -24
  258. package/dist/noctum-fechamento.js +416 -0
  259. package/dist/noctum-fila.js +49 -10
  260. package/dist/noctum-guarda.js +333 -0
  261. package/dist/noctum-integracao.js +507 -0
  262. package/dist/noctum-maquinas.js +387 -0
  263. package/dist/noctum-medicao.js +450 -0
  264. package/dist/noctum-modo.js +390 -0
  265. package/dist/noctum-pergunta-canal.js +96 -0
  266. package/dist/noctum-pergunta.js +115 -0
  267. package/dist/noctum-provas.js +838 -0
  268. package/dist/noctum-reconciliacao.js +594 -0
  269. package/dist/noctum-rede.js +102 -0
  270. package/dist/noctum-registro.js +215 -0
  271. package/dist/noctum-relatorio.js +861 -0
  272. package/dist/noctum-resposta.js +207 -0
  273. package/dist/noctum-retomada-rede.js +71 -0
  274. package/dist/noctum-sessoes-em-voo.js +93 -0
  275. package/dist/noctum-supervisao.js +649 -0
  276. package/dist/noctum-terminal.js +459 -0
  277. package/dist/noctum-transporte.js +655 -0
  278. package/dist/noctum-vigia.js +679 -0
  279. package/dist/ocupacao.js +3 -1
  280. package/dist/onboarding.js +16 -5
  281. package/dist/orkmind.js +39 -23
  282. package/dist/orquestracao.js +31 -35
  283. package/dist/parado-no-condutor.js +160 -139
  284. package/dist/phase.js +96 -42
  285. package/dist/policies.js +33 -0
  286. package/dist/postura-local.js +11 -6
  287. package/dist/preflight.js +2 -1
  288. package/dist/procedencia.js +9 -14
  289. package/dist/projeto-alvo.js +59 -20
  290. package/dist/prompts.js +136 -42
  291. package/dist/prova-minima.js +5 -6
  292. package/dist/pulse-cadencia.js +5 -4
  293. package/dist/pulse-consentimento.js +53 -1
  294. package/dist/pulse-delivery.js +143 -27
  295. package/dist/pulse-resposta.js +368 -4
  296. package/dist/pulse.js +136 -3
  297. package/dist/ratelimit.js +13 -4
  298. package/dist/recall.js +14 -13
  299. package/dist/rede-adesao.js +13 -8
  300. package/dist/rede-forja.js +108 -24
  301. package/dist/rede-status.js +63 -45
  302. package/dist/rede.js +86 -46
  303. package/dist/retomada-checkpoint.js +101 -0
  304. package/dist/retry.js +326 -78
  305. package/dist/roadmap-reservas.js +32 -32
  306. package/dist/runtime-ambiente.js +5 -0
  307. package/dist/runtime-context.js +279 -85
  308. package/dist/runtime-escada.js +429 -0
  309. package/dist/runtime-profiles.js +130 -63
  310. package/dist/runtimes.js +42 -5
  311. package/dist/saida-segura.js +3 -2
  312. package/dist/security-scan/agil.js +366 -0
  313. package/dist/security-scan/cli.js +76 -0
  314. package/dist/security-scan/compare.js +149 -0
  315. package/dist/security-scan/config.js +93 -0
  316. package/dist/security-scan/detect.js +97 -0
  317. package/dist/security-scan/executor.js +196 -0
  318. package/dist/security-scan/guard.js +180 -0
  319. package/dist/security-scan/imagem-de-lint.js +96 -0
  320. package/dist/security-scan/normalize/actionlint.js +12 -0
  321. package/dist/security-scan/normalize/eslint.js +12 -0
  322. package/dist/security-scan/normalize/gitleaks.js +13 -0
  323. package/dist/security-scan/normalize/golangci-lint.js +13 -0
  324. package/dist/security-scan/normalize/govulncheck.js +36 -0
  325. package/dist/security-scan/normalize/index.js +25 -0
  326. package/dist/security-scan/normalize/npm-audit.js +30 -0
  327. package/dist/security-scan/normalize/osv-scanner.js +32 -0
  328. package/dist/security-scan/normalize/oxlint.js +51 -0
  329. package/dist/security-scan/normalize/pip-audit.js +16 -0
  330. package/dist/security-scan/normalize/ruff.js +12 -0
  331. package/dist/security-scan/normalize/semgrep.js +20 -0
  332. package/dist/security-scan/normalize/trivy.js +33 -0
  333. package/dist/security-scan/normalize/util.js +204 -0
  334. package/dist/security-scan/normalize/zizmor.js +19 -0
  335. package/dist/security-scan/report.js +156 -0
  336. package/dist/security-scan/run.js +448 -0
  337. package/dist/security-scan/tools.js +62 -0
  338. package/dist/security-scan/trabalhador.js +74 -0
  339. package/dist/security-scan/types.js +15 -0
  340. package/dist/session-events.js +19 -2
  341. package/dist/session-watcher-claude.js +74 -19
  342. package/dist/session-watcher-grok.js +425 -0
  343. package/dist/session-watcher.js +174 -13
  344. package/dist/sessoes-contas.js +42 -5
  345. package/dist/sessoes-inventario.js +1 -1
  346. package/dist/sessoes.js +25 -23
  347. package/dist/setup.js +67 -66
  348. package/dist/ship-publicar.js +263 -92
  349. package/dist/ship.js +160 -17
  350. package/dist/superficie.js +14 -11
  351. package/dist/thread-close.js +9 -9
  352. package/dist/thread.js +121 -18
  353. package/dist/tokens.js +15 -11
  354. package/dist/trabalho-thread.js +297 -0
  355. package/dist/transporte-do-canal.js +189 -0
  356. package/dist/types.js +12 -1
  357. package/dist/util.js +5 -2
  358. package/dist/varredura-acoes.js +500 -0
  359. package/dist/verify.js +491 -32
  360. package/dist/worktree-local.js +12 -10
  361. package/dist/worktree.js +81 -85
  362. package/eval/casos/check-quality.json +77 -0
  363. package/eval/casos/security-auditor.json +148 -0
  364. package/eval/casos/security-remediation.json +161 -0
  365. package/eval/fixtures/security-scan/README.md +8 -0
  366. package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
  367. package/eval/fixtures/security-scan/go/Dockerfile +4 -0
  368. package/eval/fixtures/security-scan/go/README.md +4 -0
  369. package/eval/fixtures/security-scan/go/config.go +4 -0
  370. package/eval/fixtures/security-scan/go/go.mod +5 -0
  371. package/eval/fixtures/security-scan/go/go.sum +2 -0
  372. package/eval/fixtures/security-scan/go/main.go +31 -0
  373. package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
  374. package/eval/fixtures/security-scan/js/Dockerfile +3 -0
  375. package/eval/fixtures/security-scan/js/README.md +4 -0
  376. package/eval/fixtures/security-scan/js/package-lock.json +844 -0
  377. package/eval/fixtures/security-scan/js/package.json +10 -0
  378. package/eval/fixtures/security-scan/js/src/config.js +4 -0
  379. package/eval/fixtures/security-scan/js/src/server.js +17 -0
  380. package/eval/fixtures/security-scan/js/src/util.ts +4 -0
  381. package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
  382. package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
  383. package/eval/fixtures/security-scan/python/Dockerfile +3 -0
  384. package/eval/fixtures/security-scan/python/README.md +4 -0
  385. package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
  386. package/eval/fixtures/security-scan/python/app/config.py +2 -0
  387. package/eval/fixtures/security-scan/python/app/main.py +19 -0
  388. package/eval/fixtures/security-scan/python/requirements.txt +1 -0
  389. package/package.json +10 -5
  390. package/references/security-checklist.md +3 -3
  391. package/skills/README.md +1 -0
  392. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  393. package/skills/phases/check-quality/SKILL.md +16 -0
  394. package/skills/phases/go-implementation/SKILL.md +6 -0
  395. package/skills/phases/security-remediation/SKILL.md +70 -0
  396. package/skills/reviewers/security-auditor/SKILL.md +25 -0
package/dist/docs.js CHANGED
@@ -81,6 +81,7 @@ const thread_1 = require("./thread");
81
81
  const ledger_1 = require("./ledger");
82
82
  const branch_de_estado_1 = require("./branch-de-estado");
83
83
  const locale_1 = require("./locale");
84
+ const merge_da_entrega_1 = require("./merge-da-entrega");
84
85
  exports.DIR_PRODUTO = 'docs/produto';
85
86
  exports.DIR_ROADMAP = 'docs/roadmap';
86
87
  exports.DIR_PADROES = 'docs/padroes';
@@ -163,17 +164,18 @@ function paginas(raiz, dir) {
163
164
  function documentoDeTexto(arquivo, texto) {
164
165
  const { bruto, corpo } = separarFrontmatter(texto);
165
166
  if (bruto === null) {
166
- return { achado: erro(arquivo, undefined, 'docs.frontmatter.ausente', 'página sem frontmatter YAML', 'comece o arquivo com as chaves do modelo entre duas linhas ---') };
167
+ return { achado: erro(arquivo, undefined, 'docs.frontmatter.ausente', (m) => m.semFrontmatter, (m) => m.semFrontmatterCorrecao) };
167
168
  }
168
169
  let dados;
169
170
  try {
170
171
  dados = (0, yaml_1.lerYaml)(bruto);
171
172
  }
172
173
  catch (e) {
173
- return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', `frontmatter inválido: ${e.message}`) };
174
+ const detalhe = e.message;
175
+ return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', (m) => m.frontmatterInvalido(detalhe)) };
174
176
  }
175
177
  if (!ehMapa(dados)) {
176
- return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', 'o frontmatter precisa ser um mapa de chaves') };
178
+ return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', (m) => m.frontmatterNaoMapa) };
177
179
  }
178
180
  return { doc: { arquivo, tipo: dados.tipo, id: String(dados.id ?? ''), dados, corpo } };
179
181
  }
@@ -189,11 +191,15 @@ function carregarDocs(raiz) {
189
191
  }
190
192
  return { docs, achados };
191
193
  }
194
+ function achado(gravidade, arquivo, id, regra, mensagem, correcao) {
195
+ const texto = (montar) => (0, locale_1.textoDoCatalogo)((m) => montar(m.docs));
196
+ return { arquivo, ...(id ? { id } : {}), regra, gravidade, mensagem: texto(mensagem), ...(correcao ? { correcao: texto(correcao) } : {}) };
197
+ }
192
198
  function erro(arquivo, id, regra, mensagem, correcao) {
193
- return { arquivo, ...(id ? { id } : {}), regra, gravidade: 'erro', mensagem, ...(correcao ? { correcao } : {}) };
199
+ return achado('erro', arquivo, id, regra, mensagem, correcao);
194
200
  }
195
201
  function aviso(arquivo, id, regra, mensagem, correcao) {
196
- return { arquivo, ...(id ? { id } : {}), regra, gravidade: 'aviso', mensagem, ...(correcao ? { correcao } : {}) };
202
+ return achado('aviso', arquivo, id, regra, mensagem, correcao);
197
203
  }
198
204
  function git(raiz, args) {
199
205
  const r = (0, node_child_process_1.spawnSync)('git', args, { cwd: raiz, encoding: 'utf8' });
@@ -233,23 +239,23 @@ function verificarDocs(raiz, opcoes = {}) {
233
239
  const porId = new Map();
234
240
  for (const d of docs) {
235
241
  if (!TIPOS.includes(d.tipo)) {
236
- achados.push(erro(d.arquivo, d.id || undefined, 'docs.tipo', `tipo "${String(d.dados.tipo)}" desconhecido`, `use um de: ${TIPOS.join(', ')}`));
242
+ achados.push(erro(d.arquivo, d.id || undefined, 'docs.tipo', (m) => m.tipoDesconhecido(String(d.dados.tipo)), (m) => m.useUmDe(TIPOS.join(', '))));
237
243
  continue;
238
244
  }
239
245
  if (!PADRAO_ID[d.tipo].test(d.id)) {
240
- achados.push(erro(d.arquivo, d.id || undefined, 'docs.id.formato', `ID "${d.id}" fora do padrão de ${d.tipo}`, `formato esperado: ${PADRAO_ID[d.tipo].source.replace(/[\^$\\]/g, '')}`));
246
+ achados.push(erro(d.arquivo, d.id || undefined, 'docs.id.formato', (m) => m.idForaDoPadrao(d.id, d.tipo), (m) => m.formatoEsperado(PADRAO_ID[d.tipo].source.replace(/[\^$\\]/g, ''))));
241
247
  }
242
248
  const nome = path.posix.basename(d.arquivo);
243
249
  if (!(nome === `${d.id}.md` || nome.startsWith(`${d.id}-`))) {
244
- achados.push(erro(d.arquivo, d.id, 'docs.id.arquivo', 'o nome do arquivo não começa pelo ID', `renomeie para ${d.id}-<assunto>.md`));
250
+ achados.push(erro(d.arquivo, d.id, 'docs.id.arquivo', (m) => m.arquivoSemId, (m) => m.renomeie(d.id)));
245
251
  }
246
252
  const pastaCerta = d.tipo === 'roadmap' ? exports.DIR_ROADMAP : exports.DIR_PRODUTO;
247
253
  if (path.posix.dirname(d.arquivo) !== pastaCerta) {
248
- achados.push(erro(d.arquivo, d.id, 'docs.pasta', `${d.tipo} mora em ${pastaCerta}`));
254
+ achados.push(erro(d.arquivo, d.id, 'docs.pasta', (m) => m.pastaErrada(d.tipo, pastaCerta)));
249
255
  }
250
256
  const anterior = porId.get(d.id);
251
257
  if (anterior) {
252
- achados.push(erro(d.arquivo, d.id, 'docs.id.duplicado', `ID repetido: também em ${anterior.arquivo}`, 'IDs são estáveis e únicos; renumere o novo, nunca o antigo'));
258
+ achados.push(erro(d.arquivo, d.id, 'docs.id.duplicado', (m) => m.idRepetido(anterior.arquivo), (m) => m.idRepetidoCorrecao));
253
259
  }
254
260
  else {
255
261
  porId.set(d.id, d);
@@ -257,7 +263,7 @@ function verificarDocs(raiz, opcoes = {}) {
257
263
  }
258
264
  const base = opcoes.semGit ? null : resolverBase(raiz, opcoes.baseBranch);
259
265
  if (!opcoes.semGit && !base) {
260
- achados.push(aviso('.', undefined, 'docs.git.base', `branch base "${opcoes.baseBranch ?? 'main'}" não encontrada: a paridade com o git ficou de fora`, 'rode com o histórico do git disponível (fetch-depth: 0 no CI)'));
266
+ achados.push(aviso('.', undefined, 'docs.git.base', (m) => m.baseAusente(opcoes.baseBranch ?? 'main'), (m) => m.baseAusenteCorrecao));
261
267
  }
262
268
  const comandos = opcoes.ajudaDoCli ? comandosDaAjuda(opcoes.ajudaDoCli) : null;
263
269
  for (const d of docs) {
@@ -274,56 +280,59 @@ function verificarDocs(raiz, opcoes = {}) {
274
280
  verificarTabelasDeEstado(d, achados);
275
281
  }
276
282
  }
277
- verificarIndices(raiz, docs, achados, opcoes.pr === true);
283
+ verificarIndices(raiz, docs, achados);
278
284
  return { docs, achados };
279
285
  }
280
286
  function verificarChaves(d, achados) {
281
287
  for (const k of CHAVES[d.tipo]) {
282
288
  if (!(k in d.dados)) {
283
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', `falta a chave "${k}"`, 'copie a chave do modelo; lacuna é "A definir — responsável, prazo"'));
289
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', (m) => m.faltaChave(k), (m) => m.faltaChaveCorrecao));
284
290
  }
285
291
  }
286
292
  if (d.tipo !== 'roadmap' && 'estado' in d.dados) {
287
293
  const e = String(d.dados.estado);
288
294
  if (!exports.ESTADOS_DA_ESPECIFICACAO.includes(e)) {
289
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', `estado "${e}" fora do padrão`, `use um de: ${exports.ESTADOS_DA_ESPECIFICACAO.join(', ')}`));
295
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', (m) => m.estadoForaDoPadrao(e), (m) => m.useUmDe(exports.ESTADOS_DA_ESPECIFICACAO.join(', '))));
290
296
  }
291
297
  }
292
298
  if (d.tipo === 'roadmap') {
293
299
  const cat = String(d.dados.categoria ?? '');
294
300
  if ('categoria' in d.dados && !exports.CATEGORIAS.includes(cat)) {
295
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', `categoria "${cat}" fora do padrão`, `use uma de: ${exports.CATEGORIAS.join(', ')}`));
301
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', (m) => m.categoriaForaDoPadrao(cat), (m) => m.useUmaDe(exports.CATEGORIAS.join(', '))));
296
302
  }
297
303
  const estado = d.dados.estado;
298
304
  if ('estado' in d.dados && !ehMapa(estado)) {
299
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', 'estado do roadmap é um mapa de dimensões', `dimensões: ${Object.keys(exports.DIMENSOES).join(', ')}`));
305
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', (m) => m.estadoNaoMapa, (m) => m.dimensoes(Object.keys(exports.DIMENSOES).join(', '))));
300
306
  }
301
307
  else if (ehMapa(estado)) {
302
308
  for (const [dim, valores] of Object.entries(exports.DIMENSOES)) {
303
309
  if (!(dim in estado)) {
304
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', `falta a dimensão estado.${dim}`, 'o padrão atualiza cada dimensão separadamente'));
310
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', (m) => m.faltaDimensao(dim), (m) => m.faltaDimensaoCorrecao));
305
311
  }
306
312
  else if (!valores.includes(String(estado[dim]))) {
307
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', `estado.${dim} "${String(estado[dim])}" fora do padrão`, `use um de: ${valores.join(', ')}`));
313
+ const valor = String(estado[dim]);
314
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', (m) => m.dimensaoForaDoPadrao(dim, valor), (m) => m.useUmDe(valores.join(', '))));
308
315
  }
309
316
  }
310
317
  for (const dim of Object.keys(estado)) {
311
318
  if (!(dim in exports.DIMENSOES)) {
312
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', `dimensão desconhecida estado.${dim}`));
319
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.chave', (m) => m.dimensaoDesconhecida(dim)));
313
320
  }
314
321
  }
315
322
  }
316
323
  }
317
324
  for (const k of ['verificado_em', 'atualizado_em']) {
318
325
  if (k in d.dados && !ISO_COM_FUSO.test(String(d.dados[k]))) {
319
- achados.push(erro(d.arquivo, d.id, 'docs.data', `${k} "${String(d.dados[k])}" não é ISO 8601 com fuso`, 'exemplo: 2026-09-24T20:00:00-03:00'));
326
+ const valor = String(d.dados[k]);
327
+ achados.push(erro(d.arquivo, d.id, 'docs.data', (m) => m.dataSemFuso(k, valor), (m) => m.dataExemplo));
320
328
  }
321
329
  }
322
330
  // Valor de modelo esquecido no frontmatter: `<...>` ou ID zerado (FEAT-000, MOD-00, RM-000).
323
331
  const visitar = (v, onde) => {
324
332
  if (typeof v === 'string') {
325
333
  if (/^<[^>]*>$/.test(v.trim()) || /^(PLAT|SYS|MOD|FEAT|RM)-0+$/.test(v.trim()) || /@0{7}$/.test(v.trim())) {
326
- achados.push(erro(d.arquivo, d.id, 'docs.modelo', `valor do modelo não preenchido em ${onde}: ${v}`));
334
+ const valor = v;
335
+ achados.push(erro(d.arquivo, d.id, 'docs.modelo', (m) => m.valorDoModelo(onde, valor)));
327
336
  }
328
337
  }
329
338
  else if (Array.isArray(v))
@@ -397,15 +406,15 @@ function substituirBloco(corpo, ini, fim, conteudo) {
397
406
  }
398
407
  function verificarTabelasDeEstado(d, achados) {
399
408
  for (const [ini, fim, render, nome] of [
400
- [RELANCE_INI, RELANCE_FIM, renderizarRelance, 'a linha de relance'],
401
- [ESTADO_INI, ESTADO_FIM, renderizarEstado, 'a tabela "Estado com evidências"'],
409
+ [RELANCE_INI, RELANCE_FIM, renderizarRelance, (m) => m.nomeDaRelance],
410
+ [ESTADO_INI, ESTADO_FIM, renderizarEstado, (m) => m.nomeDoEstado],
402
411
  ]) {
403
412
  const atual = blocoEntre(d.corpo, ini, fim);
404
413
  if (atual === null) {
405
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.estado', `falta ${nome} gerada do frontmatter`, 'copie os marcadores do modelo e rode ork docs sincronizar --escrever'));
414
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.estado', (m) => m.faltaTabela(nome(m)), (m) => m.faltaTabelaCorrecao));
406
415
  }
407
416
  else if (atual !== render(d)) {
408
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.estado', `${nome} diverge do frontmatter`, 'o estado se edita no frontmatter; rode ork docs sincronizar --escrever para regerar a tabela'));
417
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.estado', (m) => m.tabelaDiverge(nome(m)), (m) => m.tabelaDivergeCorrecao));
409
418
  }
410
419
  }
411
420
  }
@@ -415,14 +424,14 @@ function verificarReferencias(raiz, d, porId, achados) {
415
424
  if (esperadoDoPai && pai !== undefined && pai !== null) {
416
425
  const idPai = String(pai);
417
426
  if (!esperadoDoPai.test(idPai)) {
418
- achados.push(erro(d.arquivo, d.id, 'docs.referencia', `pai "${idPai}" não é do nível acima de ${d.tipo}`));
427
+ achados.push(erro(d.arquivo, d.id, 'docs.referencia', (m) => m.paiDeOutroNivel(idPai, d.tipo)));
419
428
  }
420
429
  else if (!porId.has(idPai)) {
421
- achados.push(erro(d.arquivo, d.id, 'docs.referencia', `pai ${idPai} não existe`, 'crie a página do pai ou corrija o ID'));
430
+ achados.push(erro(d.arquivo, d.id, 'docs.referencia', (m) => m.paiNaoExiste(idPai), (m) => m.paiNaoExisteCorrecao));
422
431
  }
423
432
  }
424
433
  else if (esperadoDoPai && d.tipo !== 'roadmap' && (pai === undefined || pai === null)) {
425
- achados.push(erro(d.arquivo, d.id, 'docs.referencia', `${d.tipo} precisa de pai`));
434
+ achados.push(erro(d.arquivo, d.id, 'docs.referencia', (m) => m.precisaDePai(d.tipo)));
426
435
  }
427
436
  const cruzadas = d.tipo === 'feature' ? [['roadmap', 'roadmap', 'features']]
428
437
  : d.tipo === 'roadmap' ? [['features', 'feature', 'roadmap']] : [];
@@ -430,10 +439,10 @@ function verificarReferencias(raiz, d, porId, achados) {
430
439
  for (const alvo of lista(d.dados[chave])) {
431
440
  const outro = porId.get(alvo);
432
441
  if (!outro || outro.tipo !== tipoAlvo) {
433
- achados.push(erro(d.arquivo, d.id, 'docs.referencia', `${chave} cita ${alvo}, que não existe como ${tipoAlvo}`));
442
+ achados.push(erro(d.arquivo, d.id, 'docs.referencia', (m) => m.citaInexistente(chave, alvo, tipoAlvo)));
434
443
  }
435
444
  else if (!lista(outro.dados[chaveDeVolta]).includes(d.id)) {
436
- achados.push(aviso(d.arquivo, d.id, 'docs.referencia.reciproca', `${alvo} não cita ${d.id} de volta`, `acrescente ${d.id} em ${chaveDeVolta} de ${alvo}`));
445
+ achados.push(aviso(d.arquivo, d.id, 'docs.referencia.reciproca', (m) => m.naoCitaDeVolta(alvo, d.id), (m) => m.naoCitaDeVoltaCorrecao(d.id, chaveDeVolta, alvo)));
437
446
  }
438
447
  }
439
448
  }
@@ -444,7 +453,7 @@ function verificarReferencias(raiz, d, porId, achados) {
444
453
  continue;
445
454
  const abs = path.resolve(path.dirname(path.join(raiz, d.arquivo)), decodeURIComponent(alvo));
446
455
  if (!fs.existsSync(abs)) {
447
- achados.push(erro(d.arquivo, d.id, 'docs.link', `link quebrado: ${alvo}`));
456
+ achados.push(erro(d.arquivo, d.id, 'docs.link', (m) => m.linkQuebrado(alvo)));
448
457
  }
449
458
  }
450
459
  }
@@ -456,36 +465,36 @@ function verificarLeitura(d, achados) {
456
465
  const linhas = d.corpo.split('\n');
457
466
  const h1 = linhas.find((l) => l.startsWith('# '));
458
467
  if (!h1 || !h1.includes(d.id)) {
459
- achados.push(erro(d.arquivo, d.id, 'docs.leitura.titulo', 'o título (#) não começa pelo ID', `# ${d.id} — <nome>: humano e agente acham a página pelo mesmo nome`));
468
+ achados.push(erro(d.arquivo, d.id, 'docs.leitura.titulo', (m) => m.tituloSemId, (m) => m.tituloSemIdCorrecao(d.id)));
460
469
  }
461
470
  const frase = linhas.find((l) => /^>\s*\*\*Em uma frase:\*\*/.test(l));
462
471
  if (!frase) {
463
- achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', 'falta a linha "> **Em uma frase:**" logo abaixo do título', 'escreva o que a página responde, antes de qualquer detalhe'));
472
+ achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', (m) => m.faltaFrase, (m) => m.faltaFraseCorrecao));
464
473
  }
465
474
  else {
466
475
  const n = frase.replace(/^>\s*\*\*Em uma frase:\*\*\s*/, '').trim().length;
467
476
  if (n === 0)
468
- achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', 'a frase de abertura está vazia'));
477
+ achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', (m) => m.fraseVazia));
469
478
  else if (n > exports.LIMITE_DA_FRASE) {
470
- achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', `a frase de abertura tem ${n} caracteres (limite ${exports.LIMITE_DA_FRASE})`, 'corte para uma ideia só; o resto vai em tópicos'));
479
+ achados.push(erro(d.arquivo, d.id, 'docs.leitura.resumo', (m) => m.fraseLonga(n, exports.LIMITE_DA_FRASE), (m) => m.fraseLongaCorrecao));
471
480
  }
472
481
  }
473
482
  const h2 = new Set(linhas.filter((l) => l.startsWith('## ')).map((l) => l.slice(3).trim()));
474
483
  for (const s of SECOES[d.tipo]) {
475
484
  if (!h2.has(s)) {
476
- achados.push(erro(d.arquivo, d.id, 'docs.secao', `falta a seção "## ${s}"`, 'se não se aplica, escreva dentro dela: Não aplicável — motivo'));
485
+ achados.push(erro(d.arquivo, d.id, 'docs.secao', (m) => m.faltaSecao(s), (m) => m.faltaSecaoCorrecao));
477
486
  }
478
487
  }
479
488
  const texto = semCodigo(d.corpo);
480
- for (const m of texto.matchAll(/\[(\.\.\.|[^\]\n]{1,60})\](?!\()/g)) {
481
- achados.push(erro(d.arquivo, d.id, 'docs.modelo', `campo do modelo não preenchido: [${m[1]}]`, 'preencha, ou escreva "A definir — responsável, prazo" / "Não aplicável — motivo"'));
489
+ for (const [, campo] of texto.matchAll(/\[(\.\.\.|[^\]\n]{1,60})\](?!\()/g)) {
490
+ achados.push(erro(d.arquivo, d.id, 'docs.modelo', (m) => m.campoDoModelo(campo), (m) => m.campoDoModeloCorrecao));
482
491
  }
483
492
  for (const p of texto.split(/\n\s*\n/)) {
484
493
  const bloco = p.trim();
485
494
  if (!bloco || /^(#|>|\||[-*+] |\d+\. |<!--)/.test(bloco))
486
495
  continue;
487
496
  if (bloco.length > exports.LIMITE_DO_PARAGRAFO) {
488
- achados.push(aviso(d.arquivo, d.id, 'docs.leitura.paragrafo', `parágrafo com ${bloco.length} caracteres`, 'quebre em tópicos: uma ideia por linha'));
497
+ achados.push(aviso(d.arquivo, d.id, 'docs.leitura.paragrafo', (m) => m.paragrafoLongo(bloco.length), (m) => m.paragrafoLongoCorrecao));
489
498
  }
490
499
  }
491
500
  }
@@ -494,36 +503,36 @@ function verificarFontes(raiz, d, comandos, achados) {
494
503
  if (f === undefined || f === null)
495
504
  return;
496
505
  if (!ehMapa(f)) {
497
- achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', 'fontes é um mapa (codigo, testes, simbolos, contratos, comandos)'));
506
+ achados.push(erro(d.arquivo, d.id, 'docs.frontmatter.valor', (m) => m.fontesNaoMapa));
498
507
  return;
499
508
  }
500
509
  const existe = (p) => fs.existsSync(path.join(raiz, p));
501
510
  for (const chave of ['codigo', 'testes', 'docs']) {
502
511
  for (const p of lista(f[chave])) {
503
512
  if (path.isAbsolute(p) || p.split('/').includes('..')) {
504
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.fonte', `${p}: caminho fora do repositório`, 'use caminho relativo à raiz'));
513
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.fonte', (m) => m.caminhoFora(p), (m) => m.caminhoForaCorrecao));
505
514
  }
506
515
  else if (!existe(p)) {
507
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.fonte', `${p} não existe no repositório`, 'a doc descreve o código que existe: corrija o caminho ou a página'));
516
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.fonte', (m) => m.caminhoNaoExiste(p), (m) => m.caminhoNaoExisteCorrecao));
508
517
  }
509
518
  }
510
519
  }
511
520
  for (const s of lista(f.simbolos)) {
512
521
  const [arq, simbolo] = s.split('#');
513
522
  if (!arq || !simbolo) {
514
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', `símbolo "${s}" fora do formato arquivo#nome`));
523
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', (m) => m.simboloForaDoFormato(s)));
515
524
  }
516
525
  else if (!existe(arq)) {
517
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', `${arq} não existe (símbolo ${simbolo})`));
526
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', (m) => m.arquivoDoSimbolo(arq, simbolo)));
518
527
  }
519
528
  else if (!new RegExp(`\\b${escapar(simbolo)}\\b`).test(fs.readFileSync(path.join(raiz, arq), 'utf8'))) {
520
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', `${simbolo} não aparece em ${arq}`, 'o código mudou de nome ou a página ficou para trás'));
529
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.simbolo', (m) => m.simboloAusente(simbolo, arq), (m) => m.simboloAusenteCorrecao));
521
530
  }
522
531
  }
523
532
  const codigo = lista(f.codigo).filter(existe).map((p) => fs.readFileSync(path.join(raiz, p), 'utf8'));
524
533
  for (const c of lista(f.contratos)) {
525
534
  if (!codigo.some((t) => t.includes(c))) {
526
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.contrato', `o contrato ${c} não aparece nos arquivos de fontes.codigo`));
535
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.contrato', (m) => m.contratoAusente(c)));
527
536
  }
528
537
  }
529
538
  if (comandos) {
@@ -535,7 +544,8 @@ function verificarFontes(raiz, d, comandos, achados) {
535
544
  const temSubcomandos = [...comandos].some((c) => c.startsWith(`${topo} `));
536
545
  const exigePar = temSubcomandos && /^[a-z][a-z-]*$/.test(sub);
537
546
  if (!comandos.has(topo) || (exigePar && !comandos.has(`${topo} ${sub}`))) {
538
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.comando', `o CLI não declara "${[programa, topo, sub].join(' ').trim()}"`, 'confira `ork --help`: a doc descreve o CLI que existe'));
547
+ const comando = [programa, topo, sub].join(' ').trim();
548
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.comando', (m) => m.comandoAusente(comando), (m) => m.comandoAusenteCorrecao));
539
549
  }
540
550
  }
541
551
  }
@@ -551,27 +561,28 @@ function verificarEstadoDoRoadmap(raiz, d, base, achados) {
551
561
  const [ciclo, codigo, testes, deploy] = [e.ciclo, e.codigo, e.testes, e.deploy].map((v) => String(v ?? ''));
552
562
  // Coerencia entre dimensoes (padrao 3.6): o status nao pode esconder o que falta.
553
563
  if (ciclo === 'Concluído' && codigo !== 'Mesclado') {
554
- achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', 'ciclo Concluído com código que não está Mesclado'));
564
+ achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', (m) => m.concluidoSemMerge));
555
565
  }
556
566
  if (ciclo === 'Concluído' && testes !== 'Aprovados') {
557
- achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', 'ciclo Concluído com testes que não estão Aprovados'));
567
+ achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', (m) => m.concluidoSemTestes));
558
568
  }
559
569
  if (deploy === 'Produção' && codigo !== 'Mesclado') {
560
- achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', 'deploy em Produção com código que não está Mesclado'));
570
+ achados.push(erro(d.arquivo, d.id, 'docs.estado.coerencia', (m) => m.producaoSemMerge));
561
571
  }
562
572
  if (ciclo === 'Bloqueado' && !ehMapa(d.dados.bloqueio)) {
563
- achados.push(erro(d.arquivo, d.id, 'docs.estado.bloqueio', 'Bloqueado exige o mapa "bloqueio"', 'bloqueio: motivo, dependencia, responsavel, proxima_revisao'));
573
+ achados.push(erro(d.arquivo, d.id, 'docs.estado.bloqueio', (m) => m.bloqueadoSemMapa, (m) => m.bloqueadoSemMapaCorrecao));
564
574
  }
565
575
  if (codigo === 'Mesclado' && !commit) {
566
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', 'código Mesclado sem o commit do merge', 'preencha evidencias.codigo.commit (ork docs sincronizar faz isso a partir do ledger e do git)'));
576
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', (m) => m.mescladoSemCommit, (m) => m.mescladoSemCommitCorrecao));
567
577
  }
568
578
  if (commit && base) {
569
579
  // RM-047: o commit vem do frontmatter do clone; só sha hexadecimal vai ao git.
570
580
  if (!(0, branch_de_estado_1.shaValido)(commit) || !git(raiz, ['cat-file', '-e', `${commit}^{commit}`]).ok) {
571
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', `o commit ${commit} não existe neste repositório`));
581
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', (m) => m.commitInexistente(commit)));
572
582
  }
573
583
  else if (codigo === 'Mesclado' && !git(raiz, ['merge-base', '--is-ancestor', commit, base]).ok) {
574
- achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', `o commit ${commit} não está na ${base}: o merge não aconteceu`, 'volte o estado.codigo para "PR aberto" ou "Branch criada" até o merge'));
584
+ const naBase = base;
585
+ achados.push(erro(d.arquivo, d.id, 'docs.paridade.git', (m) => m.commitForaDaBase(commit, naBase), (m) => m.commitForaDaBaseCorrecao));
575
586
  }
576
587
  }
577
588
  }
@@ -587,9 +598,7 @@ function verificarMergeDaThread(raiz, d, base, achados, pr = false) {
587
598
  if (!pendente)
588
599
  return;
589
600
  const { thread, merges, codigo } = pendente;
590
- achados.push((pr ? aviso : erro)(d.arquivo, d.id, 'docs.paridade.merge', `a thread ${thread} entrou na ${base} pelo merge ${merges[0].slice(0, 7)} (ship(${thread})), e o estado.codigo diz "${codigo || 'vazio'}"` +
591
- (pr ? ' (no PR, aviso: o push da main reprova)' : ''), `abra um PR de docs sobre a ${base} atualizada com ork docs sincronizar --escrever --so ${d.id} (o item e os índices); ` +
592
- `se o item tem outra fatia em curso, aponte sdlc.thread para a thread dela`));
601
+ achados.push((pr ? aviso : erro)(d.arquivo, d.id, 'docs.paridade.merge', (m) => m.mergeDaThread(thread, base, merges[0].slice(0, 7), codigo, pr), (m) => m.mergeDaThreadCorrecao(base, d.id)));
593
602
  }
594
603
  /**
595
604
  * A regra do `docs.paridade.merge`, isolada para o `ork ship registrar-pr` (RM-044, A3): a pagina cujo
@@ -645,7 +654,7 @@ const INDICES_GERADOS = [
645
654
  * do mesmo jeito: sem a RM-051 e com a RM-031 de antes. Divergente reprova; vazio (o modelo recem-copiado
646
655
  * pelo `ork docs init`) so avisa; sem os marcadores, nao ha indice gerado para conferir.
647
656
  */
648
- function verificarIndices(raiz, docs, achados, pr = false) {
657
+ function verificarIndices(raiz, docs, achados) {
649
658
  for (const [arquivo, gerar] of INDICES_GERADOS) {
650
659
  const abs = path.join(raiz, arquivo);
651
660
  if (!fs.existsSync(abs))
@@ -656,34 +665,33 @@ function verificarIndices(raiz, docs, achados, pr = false) {
656
665
  continue;
657
666
  if (atual === '') {
658
667
  if (docs.length > 0) {
659
- achados.push(aviso(arquivo, undefined, 'docs.paridade.indice', 'o índice ainda não foi gerado', 'rode ork docs sincronizar --escrever'));
668
+ achados.push(aviso(arquivo, undefined, 'docs.paridade.indice', (m) => m.indiceNaoGerado, (m) => m.indiceNaoGeradoCorrecao));
660
669
  }
661
670
  }
662
671
  else if (atual !== gerar(docs)) {
663
- achados.push((pr ? aviso : erro)(arquivo, undefined, 'docs.paridade.indice', `o índice diverge do frontmatter das páginas${pr ? ' (no PR, aviso: o push da main reprova)' : ''}`, 'o índice é gerado do frontmatter: rode ork docs sincronizar --escrever e commite o índice'));
672
+ achados.push(erro(arquivo, undefined, 'docs.paridade.indice', (m) => m.indiceDiverge(false), (m) => m.indiceDivergeCorrecao));
664
673
  }
665
674
  }
666
675
  }
667
676
  // --------------------------------------------------------------------------------------------
668
677
  // Saida para humano (TDAH) e para agente
678
+ /** O texto da verificacao, no locale ativo; a mensagem e a correcao de cada achado sao remontadas (G4 da F3b). */
669
679
  function textoDaVerificacao(docs, achados) {
680
+ const m = (0, locale_1.msg)().docs;
670
681
  const conta = (t) => docs.filter((d) => d.tipo === t).length;
671
682
  const erros = achados.filter((a) => a.gravidade === 'erro');
672
683
  const avisos = achados.filter((a) => a.gravidade === 'aviso');
673
684
  const L = [];
674
- L.push(`Documentação: ${docs.length} páginas — ${conta('feature')} features, ${conta('roadmap')} itens de roadmap, `
675
- + `${conta('plataforma') + conta('sistema') + conta('modulo')} de contexto`);
676
- L.push(erros.length === 0
677
- ? `OK: nenhum erro de paridade${avisos.length ? ` · ${avisos.length} aviso(s) de leitura` : ''}`
678
- : `REPROVADO: ${erros.length} erro(s)${avisos.length ? ` · ${avisos.length} aviso(s)` : ''}`);
679
- for (const [titulo, grupo] of [['Erros', erros], ['Avisos', avisos]]) {
685
+ L.push(m.resumo(docs.length, conta('feature'), conta('roadmap'), conta('plataforma') + conta('sistema') + conta('modulo')));
686
+ L.push(erros.length === 0 ? m.semErro(avisos.length) : m.reprovado(erros.length, avisos.length));
687
+ for (const [titulo, grupo] of [[m.tituloErros, erros], [m.tituloAvisos, avisos]]) {
680
688
  if (grupo.length === 0)
681
689
  continue;
682
690
  L.push('', titulo);
683
691
  for (const a of grupo) {
684
- L.push(` ${(a.id ?? a.arquivo).padEnd(9)} ${a.mensagem}`);
692
+ L.push(` ${(a.id ?? a.arquivo).padEnd(9)} ${(0, locale_1.remontar)(a.mensagem)}`);
685
693
  if (a.correcao)
686
- L.push(` ${''.padEnd(9)} → ${a.correcao}`);
694
+ L.push(` ${''.padEnd(9)} → ${(0, locale_1.remontar)(a.correcao)}`);
687
695
  }
688
696
  }
689
697
  return L.join('\n');
@@ -772,22 +780,14 @@ function mergeDaThread(raiz, thread, base) {
772
780
  return null;
773
781
  }
774
782
  /**
775
- * Os commits `ship(<thread>)` da base, do mais velho ao mais novo, so pelo git (o CI nao tem ledger).
783
+ * Os merges da entrega na base, do mais velho ao mais novo, so pelo git (o CI pode nao ter ledger).
776
784
  * RM-037 (fatia 3): um lugar so para o `sincronizarDocs` e o `verificarDocs` acharem o mesmo merge.
777
785
  */
778
786
  function mergesDaThreadNoGit(raiz, thread, base) {
779
- // Sem `-n 1`: o git corta antes de inverter, e `--reverse -n 1` devolveria o mais recente.
780
- // GO-FIX 2 (achado 4 do CHECK): so a linha de primeiro pai da base e o assunto que COMECA com
781
- // `ship(<thread>)`, como no `mergeDaEntrega`. Commit que cita o merge no corpo, ou o Revert dele, nao e merge.
782
- // RM-047 (fronteira de confiança): a base pode ser o `worktree.base_branch` cru do clone.
783
- if (!(0, branch_de_estado_1.branchValida)(base))
784
- return [];
785
- const log = git(raiz, ['log', base, '--first-parent', '--reverse', '--format=%H%x09%s', '--fixed-strings', `--grep=ship(${thread})`]);
786
- if (!log.ok)
787
- return [];
788
- return log.saida.split('\n').map((l) => l.split('\t'))
789
- .filter(([sha, assunto]) => !!sha && typeof assunto === 'string' && assunto.startsWith(`ship(${thread})`))
790
- .map(([sha]) => sha);
787
+ // O ref resolvido pode ser local, remoto abreviado ou remoto completo; a mensagem padrao do GitLab leva so a base.
788
+ const destino = base.replace(/^refs\/heads\//, '').replace(/^refs\/remotes\/[^/]+\//, '').replace(/^origin\//, '');
789
+ const branch = (0, merge_da_entrega_1.branchRegistradaDaEntrega)(raiz, thread);
790
+ return ((0, merge_da_entrega_1.mergesDasEntregasNaBase)(raiz, base, destino, [{ thread, branch }], true).get(thread) ?? []).map((m) => m.mergeSha);
791
791
  }
792
792
  function temBranch(raiz, thread) {
793
793
  const r = git(raiz, ['for-each-ref', '--format=%(refname:short)', `refs/heads/ork/${thread}-*`, `refs/remotes/origin/ork/${thread}-*`]);
@@ -938,18 +938,18 @@ function tabelaDoProduto(docs) {
938
938
  }
939
939
  return L.join('\n');
940
940
  }
941
+ /** O texto da sincronizacao, no locale ativo; o campo e os valores de cada mudanca sao dado e so a impressao os traduz. */
941
942
  function textoDaSincronizacao(r, escreveu) {
943
+ const m = (0, locale_1.msg)().docs;
942
944
  const L = [];
943
- const ids = new Set(r.mudancas.map((m) => m.id));
944
- L.push(r.mudancas.length === 0 && r.indices.length === 0
945
- ? 'Sincronizado: a documentação já bate com o ledger e o git.'
946
- : `${escreveu ? 'Atualizado' : 'A atualizar'}: ${ids.size} item(ns) de roadmap, ${r.indices.length} índice(s).`);
947
- for (const m of r.mudancas)
948
- L.push(` ${m.id.padEnd(7)} ${m.campo}: ${m.de || '—'} → ${m.para} (${m.fonte})`);
945
+ const ids = new Set(r.mudancas.map((x) => x.id));
946
+ L.push(r.mudancas.length === 0 && r.indices.length === 0 ? m.sincronizado : m.aAtualizar(escreveu, ids.size, r.indices.length));
947
+ for (const x of r.mudancas)
948
+ L.push(m.linhaDaMudanca(x.id, x.campo, x.de, x.para, x.fonte));
949
949
  for (const i of r.indices)
950
- L.push(` índice ${i}`);
950
+ L.push(m.indice(i));
951
951
  if (!escreveu && (r.mudancas.length || r.indices.length))
952
- L.push('', 'Nada foi gravado. Para gravar: ork docs sincronizar --escrever');
952
+ L.push('', m.nadaGravado);
953
953
  return L.join('\n');
954
954
  }
955
955
  // --------------------------------------------------------------------------------------------