@orkastery/cli 0.5.1 → 0.5.6

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 (260) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/agents/ork-master.md +2 -0
  3. package/adapters/claude-code/commands/master.md +8 -0
  4. package/adapters/claude-code/commands/ork.md +9 -0
  5. package/adapters/claude-code/mods/autoridade.json +56 -0
  6. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  8. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  9. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  10. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  11. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  12. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  13. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  16. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  17. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  18. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  19. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  20. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  21. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  25. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  27. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  28. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  29. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  30. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  33. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  34. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  35. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  36. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  37. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  38. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  44. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  45. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  46. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  47. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  48. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  49. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  52. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  53. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  54. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  55. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  56. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  57. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  59. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  60. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  61. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  62. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  63. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  64. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  67. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  68. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  69. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  70. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  71. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  72. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  77. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  78. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  79. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  80. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  81. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  82. package/adapters/codex/skills/ork/SKILL.md +18 -3
  83. package/adapters/hermes/README.md +1 -0
  84. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  85. package/adapters/hermes/hermes.plugin.json +1 -0
  86. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  87. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +7 -6
  88. package/adapters/openclaw/README.md +26 -5
  89. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  90. package/adapters/openclaw/dist/index.js +46 -11
  91. package/adapters/openclaw/openclaw.plugin.json +5 -1
  92. package/adapters/openclaw/package.json +2 -2
  93. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  94. package/adapters/openclaw/src/index.ts +49 -11
  95. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  96. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  97. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  98. package/assets/docs-en/produto/README.md +14 -0
  99. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  100. package/assets/docs-en/roadmap/README.md +14 -0
  101. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  102. package/assets/orkmind_bridge.py +117 -9
  103. package/dist/adapters/claude-bg.js +116 -18
  104. package/dist/adapters/codex.js +14 -4
  105. package/dist/agents-md.js +24 -14
  106. package/dist/auditrun.js +22 -3
  107. package/dist/board.js +20 -17
  108. package/dist/branch-de-estado.js +88 -10
  109. package/dist/busca-semantica.js +52 -12
  110. package/dist/canarios-rm057.js +149 -0
  111. package/dist/canarios.js +2 -0
  112. package/dist/catalogo.js +33 -0
  113. package/dist/ci.js +21 -8
  114. package/dist/claims-conferir.js +342 -0
  115. package/dist/claims.js +41 -1
  116. package/dist/company-brain-client.js +36 -1
  117. package/dist/company-brain-context.js +158 -22
  118. package/dist/company-brain-journal.js +2 -1
  119. package/dist/company-brain-migration.js +36 -1
  120. package/dist/conducao-sentinela.js +388 -0
  121. package/dist/conducao-texto.js +12 -18
  122. package/dist/conducao.js +122 -30
  123. package/dist/conhecimento.js +490 -0
  124. package/dist/docs.js +70 -17
  125. package/dist/doctor-pulse-cron.js +349 -0
  126. package/dist/doctor-rede.js +150 -0
  127. package/dist/doctor.js +195 -111
  128. package/dist/entrega-pr.js +42 -29
  129. package/dist/escopo-escrita.js +10 -1
  130. package/dist/esgotamentos.js +181 -0
  131. package/dist/estado-thread.js +23 -1
  132. package/dist/experiencia-instalacao.js +45 -25
  133. package/dist/experiencia.js +12 -2
  134. package/dist/fabrica-batida.js +310 -0
  135. package/dist/fabrica-estado.js +52 -14
  136. package/dist/fabrica-publicar.js +9 -1
  137. package/dist/fechamento.js +20 -66
  138. package/dist/fila-pesada.js +444 -0
  139. package/dist/fix.js +3 -2
  140. package/dist/forja.js +31 -7
  141. package/dist/gates.js +3 -24
  142. package/dist/handoff.js +10 -6
  143. package/dist/hitl-contract.js +59 -4
  144. package/dist/hitl-curto.js +11 -6
  145. package/dist/hitl-gates.js +5 -0
  146. package/dist/hitl-local-receipt.js +2 -0
  147. package/dist/hitl-lote.js +5 -2
  148. package/dist/hitl-resumo.js +38 -3
  149. package/dist/hitl-tempo-parado.js +201 -0
  150. package/dist/hitl-texto-livre.js +5 -5
  151. package/dist/hitl.js +29 -33
  152. package/dist/horario.js +41 -7
  153. package/dist/hosts.js +104 -11
  154. package/dist/impedimento.js +299 -0
  155. package/dist/index.js +961 -542
  156. package/dist/indice-vetorial.js +87 -10
  157. package/dist/indice.js +9 -1
  158. package/dist/init.js +56 -43
  159. package/dist/instabilidade.js +144 -0
  160. package/dist/integracoes-locais.js +4 -0
  161. package/dist/intelligence-graph-cli.js +170 -16
  162. package/dist/intelligence-graph-contexto.js +254 -0
  163. package/dist/intelligence-graph-contract.js +2 -1
  164. package/dist/intelligence-graph-extract-md.js +56 -4
  165. package/dist/intelligence-graph-extract-ts.js +71 -3
  166. package/dist/intelligence-graph-parsers.js +6 -4
  167. package/dist/intelligence-graph-query.js +66 -19
  168. package/dist/leases.js +664 -87
  169. package/dist/ledger-stats.js +15 -1
  170. package/dist/ledger.js +18 -1
  171. package/dist/licoes.js +1 -0
  172. package/dist/liveness.js +6 -3
  173. package/dist/locale-ajuda.js +761 -0
  174. package/dist/locale-gerados.js +160 -0
  175. package/dist/locale-master.js +99 -0
  176. package/dist/locale-onboarding.js +92 -0
  177. package/dist/locale-phase.js +151 -0
  178. package/dist/locale-pulse.js +211 -0
  179. package/dist/locale-retry.js +385 -0
  180. package/dist/locale-roadmap.js +102 -0
  181. package/dist/locale-ship.js +494 -0
  182. package/dist/locale-thread.js +277 -0
  183. package/dist/locale-verify.js +125 -0
  184. package/dist/locale.js +714 -0
  185. package/dist/maestro-runtime.js +4 -1
  186. package/dist/manifest.js +149 -4
  187. package/dist/maquina.js +23 -4
  188. package/dist/master-digest.js +6 -1
  189. package/dist/master-nota.js +18 -11
  190. package/dist/master.js +145 -31
  191. package/dist/mcp-artifacts.js +43 -3
  192. package/dist/mcp-git.js +42 -8
  193. package/dist/mcp-grafo-worker.js +5 -3
  194. package/dist/mcp-grafo.js +55 -6
  195. package/dist/mcp-server.js +22 -3
  196. package/dist/mcp-ship.js +3 -1
  197. package/dist/mcp-verify.js +6 -1
  198. package/dist/memoria.js +48 -6
  199. package/dist/modos.js +3 -6
  200. package/dist/network-roadmap.js +196 -18
  201. package/dist/noctum-arco.js +911 -0
  202. package/dist/noctum-capacidade.js +141 -0
  203. package/dist/noctum-envelope.js +810 -0
  204. package/dist/noctum-execucao.js +304 -0
  205. package/dist/noctum-fila.js +280 -0
  206. package/dist/ocupacao.js +40 -5
  207. package/dist/onboarding.js +40 -21
  208. package/dist/orkmind.js +99 -7
  209. package/dist/orquestracao.js +24 -21
  210. package/dist/parado-no-condutor.js +219 -38
  211. package/dist/phase.js +160 -52
  212. package/dist/policies.js +56 -5
  213. package/dist/portfolio.js +8 -3
  214. package/dist/postura-local.js +234 -0
  215. package/dist/preflight.js +11 -10
  216. package/dist/procedencia.js +225 -0
  217. package/dist/projeto-alvo.js +132 -5
  218. package/dist/prompts.js +40 -1
  219. package/dist/prova-ativacao.js +75 -6
  220. package/dist/pulse-delivery.js +47 -4
  221. package/dist/pulse.js +98 -19
  222. package/dist/ratelimit.js +24 -6
  223. package/dist/recall.js +3 -1
  224. package/dist/redacao-saida.js +63 -0
  225. package/dist/rede-adesao.js +399 -0
  226. package/dist/rede-forja.js +289 -0
  227. package/dist/rede-projetos.js +239 -0
  228. package/dist/rede-status.js +337 -0
  229. package/dist/rede.js +980 -0
  230. package/dist/retry.js +291 -140
  231. package/dist/roadmap-reservas.js +20 -3
  232. package/dist/roadmap-status.js +150 -34
  233. package/dist/runtime-context.js +181 -3
  234. package/dist/runtime-profiles.js +22 -1
  235. package/dist/runtimes.js +2 -1
  236. package/dist/saida-segura.js +58 -0
  237. package/dist/session-events.js +7 -3
  238. package/dist/session-watcher-claude.js +120 -24
  239. package/dist/session-watcher.js +185 -33
  240. package/dist/sessoes-contas.js +187 -0
  241. package/dist/sessoes-inventario.js +6 -18
  242. package/dist/sessoes.js +83 -2
  243. package/dist/ship-publicar.js +800 -0
  244. package/dist/ship.js +157 -88
  245. package/dist/steal.js +77 -0
  246. package/dist/thread-close.js +3 -2
  247. package/dist/thread.js +299 -49
  248. package/dist/util.js +8 -1
  249. package/dist/verify.js +141 -52
  250. package/dist/vida-da-thread.js +254 -0
  251. package/dist/worktree-local.js +165 -0
  252. package/dist/worktree.js +25 -2
  253. package/dist/yaml.js +27 -8
  254. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  255. package/package.json +7 -3
  256. package/references/definition-of-done.md +1 -1
  257. package/schemas/code-artifact-graph.v1.schema.json +2 -1
  258. package/skills/README.md +1 -1
  259. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  260. package/skills/phases/master-metrics/SKILL.md +8 -3
package/dist/master.js CHANGED
@@ -49,7 +49,9 @@ var __importStar = (this && this.__importStar) || (function () {
49
49
  };
50
50
  })();
51
51
  Object.defineProperty(exports, "__esModule", { value: true });
52
- exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.ORDEM_DAS_CLASSES = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
52
+ exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.FASE_DO_TIPO = exports.ORDEM_DAS_CLASSES = exports.CLASSE_DO_MOTIVO = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
53
+ exports.classesPelosGates = classesPelosGates;
54
+ exports.sincronizacoesComABase = sincronizacoesComABase;
53
55
  exports.parseClasse = parseClasse;
54
56
  exports.caminhoPostmortem = caminhoPostmortem;
55
57
  exports.caminhoMasterLog = caminhoMasterLog;
@@ -72,6 +74,8 @@ exports.aceitosPorOmissao = aceitosPorOmissao;
72
74
  exports.pendentesDeScore = pendentesDeScore;
73
75
  exports.tabelaDeEntregas = tabelaDeEntregas;
74
76
  exports.aceitarPendentesPorOmissao = aceitarPendentesPorOmissao;
77
+ exports.entregasParaOmissao = entregasParaOmissao;
78
+ exports.motivoForaDaOmissao = motivoForaDaOmissao;
75
79
  exports.textoDoMaster = textoDoMaster;
76
80
  exports.tabelaDeClasses = tabelaDeClasses;
77
81
  const path = __importStar(require("node:path"));
@@ -83,6 +87,7 @@ const modos_1 = require("./modos");
83
87
  const thread_1 = require("./thread");
84
88
  const types_1 = require("./types");
85
89
  const util_1 = require("./util");
90
+ const locale_1 = require("./locale");
86
91
  const fs = __importStar(require("node:fs"));
87
92
  const horario_1 = require("./horario");
88
93
  const indice_1 = require("./indice");
@@ -105,6 +110,65 @@ exports.CLASSES_DE_FALHA = {
105
110
  'scope-creep': 'a entrega cresceu alem do que o GOAL prometia',
106
111
  outra: 'nao cabe em nenhuma classe acima (descreva na justificativa)',
107
112
  };
113
+ /**
114
+ * RM-008 (classe pelo gate): a classe que cada motivo tipado do gate sustenta quando ninguem informa
115
+ * `--classe`. Antes, todo gate virava "outra", a classe que o `ork licoes` ignora: 8 POSTMORTEMs de
116
+ * 03/10 fecharam assim por aceite por omissao. Motivo fora da tabela (prazo, falta de veredito,
117
+ * runtime, conta, custo, espera humana) nao cabe numa classe fixa e segue "outra".
118
+ */
119
+ exports.CLASSE_DO_MOTIVO = {
120
+ 'artifact.missing': 'processo',
121
+ 'claims.failed': 'processo',
122
+ 'claims.unverifiable': 'processo',
123
+ 'policy.violation': 'processo',
124
+ 'runtime.autoconferencia': 'processo',
125
+ 'verify.regression': 'processo',
126
+ 'verify.failed': 'processo',
127
+ 'ci.failed': 'processo',
128
+ 'hitl.formato': 'processo',
129
+ 'runtime.rate-limited': 'rate-limit',
130
+ 'runtime.quota-exhausted': 'rate-limit',
131
+ 'lease.busy': 'conflito',
132
+ 'conducao.em-andamento': 'conflito',
133
+ 'tree.blocked': 'conflito',
134
+ };
135
+ /** As classes que os motivos dos gates sustentam, na ordem canonica e sem repetir. */
136
+ function classesPelosGates(motivos) {
137
+ const achadas = new Set();
138
+ for (const m of motivos)
139
+ achadas.add(exports.CLASSE_DO_MOTIVO[m] ?? 'outra');
140
+ if (achadas.size === 0)
141
+ achadas.add('sem-falha');
142
+ return exports.ORDEM_DAS_CLASSES.filter((c) => achadas.has(c));
143
+ }
144
+ /** Teto de merges conferidos por entrega: a branch de 03/10 com mais sincronizacoes trouxe 16. */
145
+ const TETO_DE_MERGES_POR_ENTREGA = 200;
146
+ /**
147
+ * RM-008 (base-avancou): quantas vezes a thread precisou trazer a base para dentro da branch. Conta os
148
+ * `worktree_synced` do ledger e, em cada entrega com merge, os merges da branch (entre o primeiro e o
149
+ * segundo pai do merge) cujo pai trazido ja estava na base. Em 03/10/2026, 29 de 35 entregas trouxeram
150
+ * a `origin/main` antes do merge, e nenhuma fechou com `base-avancou`. Git sem resposta conta 0 e nunca
151
+ * derruba o MASTER.
152
+ */
153
+ function sincronizacoesComABase(raiz, eventos, mergeShas) {
154
+ let total = eventos.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.worktreeSincronizada).length;
155
+ for (const sha of new Set(mergeShas)) {
156
+ if (!/^[0-9a-f]{40}$/.test(sha))
157
+ continue;
158
+ const r = (0, util_1.exec)('git', ['rev-list', '--merges', '--parents', `--max-count=${TETO_DE_MERGES_POR_ENTREGA}`,
159
+ `${sha}^1..${sha}^2`], raiz, 30000);
160
+ if (!r.ok)
161
+ continue;
162
+ for (const linha of r.stdout.split('\n')) {
163
+ const pais = linha.trim().split(/\s+/).slice(1);
164
+ // O pai trazido (o segundo em diante) ja estava na base: e a base entrando na branch.
165
+ if (pais.slice(1).some((p) => /^[0-9a-f]{40}$/.test(p) &&
166
+ (0, util_1.exec)('git', ['merge-base', '--is-ancestor', p, `${sha}^1`], raiz, 30000).ok))
167
+ total += 1;
168
+ }
169
+ }
170
+ return total;
171
+ }
108
172
  /** Ordem canonica das classes na saida do CLI. */
109
173
  exports.ORDEM_DAS_CLASSES = [
110
174
  'sem-falha',
@@ -138,6 +202,19 @@ function caminhoPostmortem(raiz, id) {
138
202
  function caminhoMasterLog(raiz, id) {
139
203
  return path.join((0, thread_1.dirThread)(raiz, id), 'master-log.json');
140
204
  }
205
+ /**
206
+ * RM-008 (fases pelo tipo): a fase dos eventos que o nucleo grava sem o campo `fase`. O `verify_run`
207
+ * e o `ship_done` nunca trouxeram fase, e 34 dos 35 POSTMORTEM de 03/10 sairam sem o CHECK, e 33 sem o
208
+ * SHIP, embora o ledger os tivesse (`ork-rm037testesi`: 6 `verify_run`, 1 `ship_done`, "GOAL GO MASTER").
209
+ * So vale quando o evento nao traz `fase`: o campo explicito continua vencendo.
210
+ */
211
+ exports.FASE_DO_TIPO = {
212
+ [ledger_1.TIPOS_DE_EVENTO.verificacao]: 'CHECK',
213
+ [ledger_1.TIPOS_DE_EVENTO.reverifyConcluido]: 'CHECK',
214
+ [ledger_1.TIPOS_DE_EVENTO.shipIniciado]: 'SHIP',
215
+ [ledger_1.TIPOS_DE_EVENTO.shipConcluido]: 'SHIP',
216
+ [ledger_1.TIPOS_DE_EVENTO.shipBloqueado]: 'SHIP',
217
+ };
141
218
  /**
142
219
  * As fases que a thread realmente percorreu, reconstruidas do LEDGER.
143
220
  *
@@ -148,7 +225,7 @@ function fasesPercorridas(raiz, id) {
148
225
  const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
149
226
  const porFase = new Map();
150
227
  for (const e of eventos) {
151
- const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : null;
228
+ const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : (exports.FASE_DO_TIPO[e.tipo] ?? null);
152
229
  if (!bruta || !types_1.FASES.includes(bruta))
153
230
  continue;
154
231
  const atual = porFase.get(bruta) ?? {
@@ -244,7 +321,8 @@ function prepararDocumentos(raiz, id, opcoes) {
244
321
  sincronizarReversao(raiz, id);
245
322
  const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
246
323
  const gatesBloqueados = eventos
247
- .filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.gateBloqueado)
324
+ // Ensaio de 03/10/2026 (RM-049): o gate barrado por um `ork ship --dry-run` e ensaio, nao reprovacao.
325
+ .filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.gateBloqueado && e.dryRun !== true)
248
326
  .map((e) => ({
249
327
  ts: e.ts,
250
328
  motivo: String(e.motivo ?? '(sem motivo)'),
@@ -264,11 +342,20 @@ function prepararDocumentos(raiz, id, opcoes) {
264
342
  let classes = opcoes.classes ?? [];
265
343
  if (classes.length === 0) {
266
344
  classesInferidas = true;
267
- classes = gatesBloqueados.length > 0 ? ['outra'] : ['sem-falha'];
268
- avisos.push(gatesBloqueados.length > 0
269
- ? `a thread levou ${gatesBloqueados.length} reprovacao(oes) tipada(s) e nenhuma --classe foi ` +
270
- 'informada: o `ork` gravou "outra". Corrija com --classe <classe> --refazer.'
271
- : 'nenhuma --classe informada e nenhum gate reprovou: o `ork` gravou "sem-falha".');
345
+ classes = classesPelosGates(gatesBloqueados.map((g) => g.motivo));
346
+ const motivos = [...new Set(gatesBloqueados.map((g) => g.motivo))];
347
+ const sincronizacoes = sincronizacoesComABase(raiz, eventos, entregas.map((e) => e.mergeSha));
348
+ if (sincronizacoes > 0) {
349
+ classes = exports.ORDEM_DAS_CLASSES.filter((c) => c === 'base-avancou' || (c !== 'sem-falha' && classes.includes(c)));
350
+ }
351
+ const pelaBase = sincronizacoes > 0
352
+ ? ` A branch trouxe a base ${sincronizacoes} vez(es) antes da entrega: o \`ork\` juntou "base-avancou".` : '';
353
+ avisos.push((gatesBloqueados.length > 0
354
+ ? `a thread levou ${gatesBloqueados.length} reprovacao(oes) tipada(s) (${motivos.join(', ')}) e nenhuma --classe foi ` +
355
+ `informada: o \`ork\` inferiu "${classes.join('", "')}" pelo motivo do gate.${pelaBase} Corrija com --classe <classe> --refazer.`
356
+ : sincronizacoes > 0
357
+ ? `nenhuma --classe informada e nenhum gate reprovou.${pelaBase} Corrija com --classe <classe> --refazer.`
358
+ : 'nenhuma --classe informada e nenhum gate reprovou: o `ork` gravou "sem-falha".'));
272
359
  }
273
360
  // I-43 (D3): o indice e DERIVADO do ledger no momento do registro, e acompanha o
274
361
  // score como o que a maquina achava antes de o dono falar. Quando as duas existem,
@@ -351,7 +438,7 @@ function autoriaHumana(por) {
351
438
  }
352
439
  function exigirAutoriaHumana(por) {
353
440
  if (!autoriaHumana(por))
354
- throw new Error('ratificação exige --por humano explícito; agente ou autoria pendente não pode pontuar');
441
+ throw new Error('ratificação exige --por humano explícito (ex.: --por "seu-nome"); agente ou autoria pendente não pode pontuar');
355
442
  }
356
443
  function masterRatificado(raiz, id) {
357
444
  const t = (0, thread_1.lerThread)(raiz, id);
@@ -646,6 +733,7 @@ function pendentesDeScore(raiz, todas = false) {
646
733
  * inteiro, e a nota humana continua sobrescrevendo o indice quando o dono reclama.
647
734
  */
648
735
  function tabelaDeEntregas(raiz, todas = false) {
736
+ const m = (0, locale_1.msg)().master;
649
737
  const pendentes = pendentesDeScore(raiz, todas);
650
738
  const omissoes = aceitosPorOmissao(raiz);
651
739
  // A1: o indice da coluna e o de AGORA; `SCORE GRAVADO` e o que o MASTER log congelou.
@@ -653,23 +741,18 @@ function tabelaDeEntregas(raiz, todas = false) {
653
741
  const caiuDepoisDeAceita = omissoes.filter((o) => typeof o.scoreGravado === 'number' && o.indice.valor < o.scoreGravado);
654
742
  const secaoOmissao = omissoes.length === 0
655
743
  ? []
656
- : ['', `Aceitas por omissao (${omissoes.length}): o que passou sem voce olhar.`, '',
657
- (0, util_1.tabela)(['ID', 'INDICE', 'SCORE GRAVADO', 'ACEITA EM'], omissoes.map((o) => [o.thread, `${o.indice.valor}/${o.indice.base}`,
744
+ : ['', m.aceitasTitulo(omissoes.length), '',
745
+ (0, util_1.tabela)([...m.colunasAceitas], omissoes.map((o) => [o.thread, `${o.indice.valor}/${o.indice.base}`,
658
746
  typeof o.scoreGravado === 'number' ? `${o.scoreGravado}/5` : '-',
659
747
  (0, horario_1.formatarDataHora)(o.aceitoEm)])),
660
748
  (0, horario_1.legendaDoFuso)(),
661
749
  ...(caiuDepoisDeAceita.length === 0 ? [] : ['',
662
- `ATENCAO: ${caiuDepoisDeAceita.length} entrega(s) cairam DEPOIS de aceitas: ` +
663
- caiuDepoisDeAceita.map((o) => o.thread).join(', ') + '.',
664
- ' O MASTER log e contrato congelado e nao se reescreve sozinho. Pontue para o',
665
- ' registro humano alcancar o fato; o registro da omissao permanece no ledger.']),
666
- '', 'Discordou de alguma? A nota humana sobrescreve, e o registro da omissao permanece:',
667
- ' ork master <thread-id> --score <0-5> --justificativa "<por que>" --por <humano>'];
750
+ m.caiuDepois(caiuDepoisDeAceita.length, caiuDepoisDeAceita.map((o) => o.thread).join(', ')),
751
+ m.caiuDepoisLinha1, m.caiuDepoisLinha2]),
752
+ '', m.discordouDeAlguma, m.pontuar];
668
753
  if (pendentes.length === 0) {
669
754
  return [
670
- todas
671
- ? 'Nenhuma thread aberta sem score.'
672
- : 'Nenhuma entrega esperando decisao. Para ver tambem as que ainda nao entregaram: ork master --todas',
755
+ todas ? m.semEntregaTodas : m.semEntrega,
673
756
  ...secaoOmissao,
674
757
  ].join('\n');
675
758
  }
@@ -680,22 +763,23 @@ function tabelaDeEntregas(raiz, todas = false) {
680
763
  p.thread.slug,
681
764
  (0, modos_1.tagDoModo)(p.thread.modo),
682
765
  p.thread.faseAtual,
683
- p.thread.status,
684
- p.entregou ? 'sim' : 'nao',
766
+ (0, locale_1.msg)().thread.status(p.thread.status),
767
+ m.simNao(p.entregou),
685
768
  `${indice.valor}/${indice.base}`,
686
- indice.parcelas.length === 0 ? 'sem tropeco' : indice.parcelas.map((x) => `${x.evento} x${x.ocorrencias}`).join(', '),
769
+ indice.parcelas.length === 0 ? m.semTropeco : indice.parcelas.map((x) => `${x.evento} x${x.ocorrencias}`).join(', '),
687
770
  ];
688
771
  });
689
772
  return [
690
- `Entregas (${pendentes.length}) com o indice ja derivado do ledger. O numero nao foi digitado por ninguem.`,
773
+ m.entregas(pendentes.length),
691
774
  '',
692
- (0, util_1.tabela)(['ID', 'SLUG', 'MODO', 'FASE', 'STATUS', 'ENTREGOU', 'INDICE', 'DE ONDE VEIO'], linhas),
775
+ (0, util_1.tabela)([...m.colunas], linhas),
693
776
  '',
694
- 'ENTREGUE E ACEITO, a menos que voce diga o contrario.',
695
- ' ork master --aceitar-omissao aceita as entregues, com o indice e os insumos no ledger',
696
- ' ork master <id> --score <0-5> --justificativa "<por que>" --por <humano> se quiser reclamar',
777
+ m.entregueEAceito,
778
+ m.aceitarEsta,
779
+ m.aceitarTodas,
780
+ m.reclamar,
697
781
  '',
698
- `Classes fixas: ${exports.ORDEM_DAS_CLASSES.join(', ')}`,
782
+ m.classesFixas(exports.ORDEM_DAS_CLASSES.join(', ')),
699
783
  ...secaoOmissao,
700
784
  ].join('\n');
701
785
  }
@@ -706,10 +790,40 @@ function tabelaDeEntregas(raiz, todas = false) {
706
790
  * ENTREGOU: uma thread que nunca chegou ao ship nao tem entrega para aceitar, e
707
791
  * aceita-la seria inventar um fato.
708
792
  */
709
- function aceitarPendentesPorOmissao(raiz) {
793
+ function aceitarPendentesPorOmissao(raiz, opcoes = {}) {
794
+ return entregasParaOmissao(raiz, opcoes.thread).map((p) => aceitarPorOmissao(raiz, p.thread.id));
795
+ }
796
+ /**
797
+ * RM-008 (03/10/2026): o que `ork master --aceitar-omissao` fecharia, sem gravar nada.
798
+ *
799
+ * Na madrugada de 03/10, tres vezes, um condutor rodou `ork master --aceitar-omissao` para fechar
800
+ * a PROPRIA thread, e o comando fechou tambem as entregues de outras frentes paralelas. A CLI nao
801
+ * deixava indicar a thread. Com `thread`, o alvo e so ela; sem, continua sendo toda entrega que
802
+ * espera decisao (o padrao nao mudou). Thread inexistente recusa pelo `lerThread`.
803
+ */
804
+ function entregasParaOmissao(raiz, thread) {
805
+ if (thread !== undefined)
806
+ (0, thread_1.lerThread)(raiz, thread);
710
807
  return pendentesDeScore(raiz)
711
808
  .filter((p) => p.entregou)
712
- .map((p) => aceitarPorOmissao(raiz, p.thread.id));
809
+ .filter((p) => thread === undefined || p.thread.id === thread);
810
+ }
811
+ /**
812
+ * Por que a thread indicada nao entra no aceite por omissao, ou `null` quando entra.
813
+ * `ja-fechada` e idempotencia (nada a fazer); `fechamento-admin` e `sem-entrega` sao recusa.
814
+ */
815
+ function motivoForaDaOmissao(raiz, id) {
816
+ const thread = (0, thread_1.lerThread)(raiz, id);
817
+ if (thread.fechamentoAdmin) {
818
+ return { motivo: 'fechamento-admin', texto: (0, locale_1.msg)().master.foraAdmin(id, thread.fechamentoAdmin.motivo) };
819
+ }
820
+ if (masterRatificado(raiz, id)) {
821
+ return { motivo: 'ja-fechada', texto: (0, locale_1.msg)().master.foraJaFechada(id) };
822
+ }
823
+ if (!entregou(raiz, id)) {
824
+ return { motivo: 'sem-entrega', texto: (0, locale_1.msg)().master.foraSemEntrega(id) };
825
+ }
826
+ return null;
713
827
  }
714
828
  /** Texto de `ork master <thread-id> --score`. */
715
829
  function textoDoMaster(r) {
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.diagnosticoNomeForaDeUtf8 = diagnosticoNomeForaDeUtf8;
36
37
  exports.validarArquivosEstadoMcp = validarArquivosEstadoMcp;
37
38
  exports.lerArtefatoMcp = lerArtefatoMcp;
38
39
  exports.escreverArtefatoMcp = escreverArtefatoMcp;
@@ -49,6 +50,14 @@ const claims_1 = require("./claims");
49
50
  const fases = { goal: 'GOAL', plan: 'PLAN', check: 'CHECK' };
50
51
  const limite = 128 * 1024;
51
52
  const hash = (bytes) => (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
53
+ /** Diagnostico relativo, sem perda de bytes nem controles de terminal; nao e um comando shell. */
54
+ function diagnosticoNomeForaDeUtf8(raiz, pasta, nome) {
55
+ const pai = path.relative(raiz, pasta);
56
+ const entrada = Buffer.concat([Buffer.from(pai ? pai + path.sep : ''), nome]);
57
+ const rotulo = Array.from(entrada, byte => byte >= 0x20 && byte <= 0x7e && byte !== 0x5c
58
+ ? String.fromCharCode(byte) : '\\x' + byte.toString(16).padStart(2, '0')).join('');
59
+ return `nome fora de UTF-8 em ${rotulo}\nRenomeie a entrada pelo shell para um nome UTF-8 valido e repita a operacao.`;
60
+ }
52
61
  /** Core legado usa nomes de arquivos: este preflight recusa links existentes, nao promete CAS contra writers hostis. */
53
62
  function validarArquivosEstadoMcp(raiz, id) {
54
63
  validarId(id);
@@ -150,8 +159,39 @@ function comEscrita(raiz, id, executar) {
150
159
  if (st) {
151
160
  if (!st.isDirectory() || st.isSymbolicLink() || fs.realpathSync(pastaLeases) !== pastaLeases)
152
161
  throw Error('mcp.state.unsafe: leases');
153
- for (const nome of fs.readdirSync(pastaLeases)) {
154
- const s = fs.lstatSync(path.join(pastaLeases, nome));
162
+ for (const nomeBytes of fs.readdirSync(pastaLeases, { encoding: 'buffer' })) {
163
+ const nome = nomeBytes.toString('utf8');
164
+ // Antes do lstat: uma decodificacao com perda nao prova que a entrada desapareceu.
165
+ if (!Buffer.from(nome, 'utf8').equals(nomeBytes))
166
+ throw Error('mcp.state.unsafe: ' + diagnosticoNomeForaDeUtf8(raiz, pastaLeases, nomeBytes));
167
+ const entrada = path.join(pastaLeases, nome), s = fs.lstatSync(entrada, { throwIfNoEntry: false });
168
+ if (!s)
169
+ continue; // Uma retomada pode ter acabado durante o preflight.
170
+ if (s.isDirectory() && nome.endsWith('.json.retomadas')) {
171
+ const base = nome.slice(0, -'.json.retomadas'.length);
172
+ if (!base || encodeURIComponent(decodeURIComponent(base)) !== base)
173
+ throw Error('mcp.state.unsafe: fila de retomada');
174
+ let candidatos;
175
+ try {
176
+ candidatos = fs.readdirSync(entrada, { encoding: 'buffer' });
177
+ }
178
+ catch (e) {
179
+ if (e.code === 'ENOENT')
180
+ continue;
181
+ throw e;
182
+ }
183
+ for (const candidatoBytes of candidatos) {
184
+ const candidato = candidatoBytes.toString('utf8');
185
+ if (!Buffer.from(candidato, 'utf8').equals(candidatoBytes))
186
+ throw Error('mcp.state.unsafe: ' + diagnosticoNomeForaDeUtf8(raiz, entrada, candidatoBytes));
187
+ const c = fs.lstatSync(path.join(entrada, candidato), { throwIfNoEntry: false });
188
+ if (!c)
189
+ continue;
190
+ if (!/^\d+-[a-f0-9-]+\.json(?:\.tmp)?$/.test(candidato) || !c.isFile() || c.nlink !== 1)
191
+ throw Error('mcp.state.unsafe: candidato de retomada');
192
+ }
193
+ continue;
194
+ }
155
195
  if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1)
156
196
  throw Error('mcp.state.unsafe: lease ou fila');
157
197
  }
@@ -231,6 +271,6 @@ function adicionarClaimMcp(raiz, id, entrada) {
231
271
  if ((0, thread_1.lerThread)(raiz, id).status === 'fechada')
232
272
  throw Error('mcp.claim.closed');
233
273
  // Strings sao dados da claim; a reexecucao MCP deve usar o executor confinado.
234
- return (0, claims_1.adicionarClaim)(raiz, id, entrada);
274
+ return (0, claims_1.adicionarClaim)(raiz, id, { ...entrada, semProvaLocal: true });
235
275
  }));
236
276
  }
package/dist/mcp-git.js CHANGED
@@ -195,7 +195,9 @@ function arvoreMetadados(root, alvo, opcoes = {}) {
195
195
  ? '; empacote os objetos soltos sem perda com git repack -d (git count-objects -v mostra quantos)' : ''));
196
196
  if (profundidade > 32)
197
197
  falha(`metadata.unsupported: mais de 32 niveis em ${rotulo(alvo)}`);
198
- const st = fs.lstatSync(f);
198
+ const st = fs.lstatSync(f, { throwIfNoEntry: false });
199
+ if (!st)
200
+ return; // Uma retomada pode remover a fila ou o candidato depois da enumeracao.
199
201
  if (st.isSymbolicLink())
200
202
  falha(`metadata.unsafe: link simbolico em ${rotulo(f)}`);
201
203
  if (!st.isDirectory() && !st.isFile())
@@ -205,9 +207,24 @@ function arvoreMetadados(root, alvo, opcoes = {}) {
205
207
  `tire o vinculo sem perder conteudo: cp -p ${rotulo(f)} ${rotulo(f + '.tmp')} && mv ${rotulo(f + '.tmp')} ${rotulo(f)}`);
206
208
  if (f !== root && !dentro(root, f))
207
209
  falha(`metadata.unsafe: ${rotulo(f)} fora de ${path.basename(root)}`);
208
- if (st.isDirectory())
209
- for (const n of fs.readdirSync(f))
210
+ if (st.isDirectory()) {
211
+ let entradas;
212
+ try {
213
+ entradas = fs.readdirSync(f, { encoding: 'buffer' });
214
+ }
215
+ catch (e) {
216
+ if (e.code === 'ENOENT')
217
+ return;
218
+ throw e;
219
+ }
220
+ for (const bytes of entradas) {
221
+ const n = bytes.toString('utf8');
222
+ // Perda de bytes nao e ENOENT transitorio: o nome decodificado pode nem apontar para esta entrada.
223
+ if (!Buffer.from(n, 'utf8').equals(bytes))
224
+ falha('metadata.unsafe: ' + (0, mcp_artifacts_1.diagnosticoNomeForaDeUtf8)(opcoes.relativoA ?? path.dirname(root), f, bytes));
210
225
  visitar(path.join(f, n), profundidade + 1);
226
+ }
227
+ }
211
228
  };
212
229
  if (fs.realpathSync(alvo) !== alvo)
213
230
  falha(`metadata.unsafe: ${rotulo(alvo)} passa por link simbolico`);
@@ -337,7 +354,7 @@ function estadoGitMcp(raiz, threadId) {
337
354
  scope: 'local-only', observedAt: new Date().toISOString() };
338
355
  }
339
356
  /** Somente o worker dedicado chama este corpo; não altera env do servidor. */
340
- function executar(raiz, p) {
357
+ function executar(raiz, p, dispatchId) {
341
358
  const proprias = [];
342
359
  let commit = null, estadoAuditado = false;
343
360
  try {
@@ -347,6 +364,23 @@ function executar(raiz, p) {
347
364
  fisico(raiz, (0, thread_1.dirThread)(raiz, p.threadId));
348
365
  (0, mcp_artifacts_1.validarArquivosEstadoMcp)(raiz, p.threadId);
349
366
  const t = (0, thread_1.lerThread)(raiz, p.threadId), wt = t.worktree;
367
+ // Identidade vem do startup do servidor, nunca dos argumentos públicos da tool.
368
+ // Sem vínculo conhecido, o recibo continua sem atribuição de sessão.
369
+ let vinculo;
370
+ if (dispatchId !== undefined) {
371
+ if (!/^[a-f0-9-]{36}$/.test(dispatchId))
372
+ falha('session.invalid');
373
+ const despachos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)).filter(e => e.tipo === 'phase_dispatch');
374
+ const despacho = despachos.filter(e => e.identidade?.dispatchId === dispatchId).at(-1);
375
+ const proximo = despacho ? despachos[despachos.indexOf(despacho) + 1] : undefined;
376
+ const sessoes = despacho ? t.sessoes.filter(s => s.sessionId === despacho.sessionId && s.origem !== 'adocao' &&
377
+ s.fase === despacho.fase && s.promptSha256 === despacho.promptSha256 && typeof s.despachadaEm === 'string' &&
378
+ Date.parse(s.despachadaEm) >= Date.parse(despacho.ts) &&
379
+ (!proximo || Date.parse(s.despachadaEm) < Date.parse(proximo.ts))) : [];
380
+ if (sessoes.length !== 1)
381
+ falha('session.invalid');
382
+ vinculo = { sessionId: sessoes[0].sessionId, despachoEm: sessoes[0].despachadaEm };
383
+ }
350
384
  if (!wt || t.status === 'fechada' || !(0, thread_1.blocoDaThread)(t, t.faseAtual).fases.includes('GO') || wt === raiz)
351
385
  falha('thread.invalid');
352
386
  // I-42 (D7): ciclo sem PLAN nem CHECK nao commita contrato publico; a mudanca vira iniciativa.
@@ -428,7 +462,7 @@ function executar(raiz, p) {
428
462
  const alterados = git(wt, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', commit]).split('\0').filter(Boolean);
429
463
  if (!alterados.length || alterados.some(f => !p.paths.includes(f)))
430
464
  falha('commit.paths-invalid');
431
- (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, t.id), t.id, 'mcp_git_committed', { commit, paths: alterados, origem: 'mcp.git', estadoAuditado });
465
+ (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, t.id), t.id, 'mcp_git_committed', { commit, paths: alterados, origem: 'mcp.git', estadoAuditado, ...vinculo });
432
466
  return { ok: true, commit, erro: null, estadoAuditado };
433
467
  }
434
468
  catch (e) {
@@ -442,7 +476,7 @@ function executar(raiz, p) {
442
476
  }
443
477
  }
444
478
  /** Entrada do servidor: argumentos nunca escolhem executável/env/cwd/opções Git. */
445
- async function commitMcp(raiz, pedido, signal) {
479
+ async function commitMcp(raiz, pedido, signal, dispatchId) {
446
480
  validar(pedido);
447
481
  if (signal?.aborted)
448
482
  return { ok: false, commit: null, erro: 'mcp.git.cancelled', estadoAuditado: false };
@@ -466,7 +500,7 @@ async function commitMcp(raiz, pedido, signal) {
466
500
  erro = true;
467
501
  child.stdin.end();
468
502
  return;
469
- } child.stdin.end(JSON.stringify({ raiz, pedido })); });
503
+ } child.stdin.end(JSON.stringify({ raiz, pedido, dispatchId })); });
470
504
  child.stdin.on('error', () => { erro = true; });
471
505
  child.on('error', () => { erro = true; });
472
506
  child.stdout.on('data', (b) => { if (Buffer.byteLength(stdout) + b.length > LIMITE)
@@ -499,7 +533,7 @@ if (require.main === module && process.argv[2] === '--worker') {
499
533
  if (Buffer.byteLength(raw) > LIMITE)
500
534
  falha('request.invalid');
501
535
  const p = JSON.parse(raw);
502
- process.stdout.write(JSON.stringify(executar(p.raiz, p.pedido)));
536
+ process.stdout.write(JSON.stringify(executar(p.raiz, p.pedido, p.dispatchId)));
503
537
  }
504
538
  catch {
505
539
  process.stdout.write(JSON.stringify({ ok: false, commit: null, erro: 'mcp.git.worker.invalid', estadoAuditado: false }));
@@ -38,7 +38,7 @@ exports.rodarConsulta = rodarConsulta;
38
38
  * RM-031 KG5 (D3, D8): o worker da consulta do grafo pelo MCP.
39
39
  *
40
40
  * Roda num processo filho, aberto pelo `mcp-grafo.ts` com o ambiente minimo do MCP. Le `{raiz, argv}`
41
- * do stdin, confere que o cwd e a raiz, aceita so as quatro consultas no argv que as tools montam (com
41
+ * do stdin, confere que o cwd e a raiz, aceita so as cinco consultas no argv que as tools montam (com
42
42
  * `--json` e `--teto-bytes`), carrega o manifesto da raiz (a worktree da thread) e chama o
43
43
  * `executarGrafo` com o argv que a CLI receberia: a resposta e a do `ork grafo`, byte a byte. O `main` do
44
44
  * `ork` nao roda aqui, entao nada do argv vira `--projeto`, `--version` ou `--help`.
@@ -52,7 +52,8 @@ const zod_1 = require("zod");
52
52
  const intelligence_graph_cli_1 = require("./intelligence-graph-cli");
53
53
  const manifest_1 = require("./manifest");
54
54
  const estado_thread_1 = require("./estado-thread");
55
- const CONSULTAS = Object.freeze({ vizinhos: 1, chamadores: 1, importadores: 1, caminho: 2 });
55
+ const mcp_grafo_1 = require("./mcp-grafo");
56
+ const CONSULTAS = Object.freeze({ vizinhos: 1, chamadores: 1, importadores: 1, caminho: 2, contexto: 1 });
56
57
  const OPCAO = /^--(profundidade|sentido|tipo|limite|teto-bytes)=[a-z0-9_,]{1,120}$/;
57
58
  const PEDIDO = zod_1.z.object({
58
59
  raiz: zod_1.z.string().min(1).max(4096).refine((p) => path.isAbsolute(p), 'raiz absoluta'),
@@ -78,7 +79,8 @@ function rodarConsulta(entrada, cwd, escrever) {
78
79
  const carregado = (0, manifest_1.exigirManifesto)(raiz);
79
80
  if (fs.realpathSync(carregado.raiz) !== fs.realpathSync(raiz))
80
81
  throw Error('grafo.mcp.worker: o manifesto nao e o da raiz pedida');
81
- return (0, intelligence_graph_cli_1.executarGrafo)(argv, { raiz: carregado.raiz, estado: (0, estado_thread_1.raizDoEstado)(carregado.raiz), repositorio: carregado.manifesto.project.name, escrever });
82
+ return (0, intelligence_graph_cli_1.executarGrafo)(argv, { raiz: carregado.raiz, estado: (0, estado_thread_1.raizDoEstado)(carregado.raiz), repositorio: carregado.manifesto.project.name,
83
+ contextoDaThread: (id) => (0, mcp_grafo_1.lerEntradaDaThread)(carregado.raiz, id), escrever });
82
84
  }
83
85
  if (require.main === module) {
84
86
  try {
package/dist/mcp-grafo.js CHANGED
@@ -35,16 +35,18 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.LIMITE_MAXIMO_DO_MCP = exports.PROFUNDIDADE_MAXIMA_DO_MCP = exports.TIPOS_DE_ARESTA_DO_MCP = exports.PRAZO_DA_CONSULTA_MS = exports.TETO_MAXIMO = exports.TETO_MINIMO = exports.TETO_PADRAO = exports.TOOLS_DO_GRAFO = void 0;
37
37
  exports.grafoLigado = grafoLigado;
38
+ exports.lerEntradaDaThread = lerEntradaDaThread;
38
39
  exports.argvDaTool = argvDaTool;
39
40
  exports.consultarPeloWorker = consultarPeloWorker;
40
41
  exports.registrarConsultasDoGrafo = registrarConsultasDoGrafo;
41
42
  /**
42
43
  * RM-031 KG5: a consulta do grafo de codigo pelas fases, pelo MCP do projeto.
43
44
  *
44
- * Quatro tools de leitura com o contrato do `ork grafo` (D6): cada uma roda, na worktree da thread, o
45
+ * Cinco tools de leitura com o contrato do `ork grafo` (D6): cada uma roda, na worktree da thread, o
45
46
  * argv que a CLI receberia (`<consulta> ... --json --teto-bytes N`) e devolve o que ela escreve, sem
46
47
  * transformar: a resposta e JSON `ork.code-graph-query/v0` com a evidencia de cada aresta e no maximo
47
- * `tetoBytes` bytes (D4); a recusa da consulta sai compacta e nao passa pelo teto.
48
+ * `tetoBytes` bytes (D4); contexto usa ork.thread-graph-context/v2. A recusa nao passa pelo teto. Desde a
49
+ * fatia 5, a resposta traz as fontes (sha256 e blob) e diz por aresta se elas conferem com a arvore.
48
50
  *
49
51
  * Desligadas por padrao (D2): so existem com `grafo.mcp: true` no manifesto da raiz, lido no startup, e
50
52
  * cada chamada confere a flag de novo. A consulta roda num worker (D3), um processo filho por chamada,
@@ -58,7 +60,10 @@ const path = __importStar(require("node:path"));
58
60
  const node_child_process_1 = require("node:child_process");
59
61
  const zod_1 = require("zod");
60
62
  const mcp_git_1 = require("./mcp-git");
61
- exports.TOOLS_DO_GRAFO = ['ork_grafo_vizinhos', 'ork_grafo_chamadores', 'ork_grafo_importadores', 'ork_grafo_caminho'];
63
+ const mcp_artifacts_1 = require("./mcp-artifacts");
64
+ const thread_1 = require("./thread");
65
+ const estado_thread_1 = require("./estado-thread");
66
+ exports.TOOLS_DO_GRAFO = ['ork_grafo_vizinhos', 'ork_grafo_chamadores', 'ork_grafo_importadores', 'ork_grafo_caminho', 'ork_grafo_contexto'];
62
67
  /** D4: o teto das respostas, em bytes do JSON. */
63
68
  exports.TETO_PADRAO = 32768;
64
69
  exports.TETO_MINIMO = 4096;
@@ -71,7 +76,7 @@ const TETO_DO_STDOUT = 1024 * 1024;
71
76
  * O vocabulario e os limites da consulta do KG3, repetidos aqui porque este modulo nao importa a
72
77
  * familia do grafo (D8); o teste confere que sao os mesmos do contrato v1 e da consulta.
73
78
  */
74
- exports.TIPOS_DE_ARESTA_DO_MCP = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from'];
79
+ exports.TIPOS_DE_ARESTA_DO_MCP = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from', 'cites'];
75
80
  exports.PROFUNDIDADE_MAXIMA_DO_MCP = 5;
76
81
  exports.LIMITE_MAXIMO_DO_MCP = 10_000;
77
82
  /** D2: so o booleano `true` do manifesto da raiz liga as tools. */
@@ -94,7 +99,8 @@ const tipos = zod_1.z.array(zod_1.z.enum(exports.TIPOS_DE_ARESTA_DO_MCP)).min(1)
94
99
  const tetoBytes = zod_1.z.number().int().min(exports.TETO_MINIMO).max(exports.TETO_MAXIMO).optional()
95
100
  .describe(`teto da resposta em bytes (padrao ${exports.TETO_PADRAO}); acima, saem as arestas mais longe`);
96
101
  const COMUM = 'Leitura do grafo do HEAD da worktree da thread (o do ork grafo): so o que o extrator prova. '
97
- + 'Resposta JSON ork.code-graph-query/v0 de ate tetoBytes; sem indice do HEAD, recusa com a correcao ork grafo indexar.';
102
+ + 'Resposta JSON ork.code-graph-query/v0 de ate tetoBytes; sem indice do HEAD, recusa com a correcao ork grafo indexar. '
103
+ + 'Cada aresta traz arvore (modificada quando uma fonte dela mudou depois do HEAD) e a resposta traz fontes, com o sha256 e o blob de cada arquivo citado.';
98
104
  /** As opcoes da CLI, na ordem dela, com `=`: o valor nunca vira outro argumento. */
99
105
  function opcoes(a) {
100
106
  const r = [];
@@ -134,7 +140,50 @@ const DEFINICOES = [
134
140
  schema: zod_1.z.object({ threadId, de: no(`origem: ${DESCRICAO_DO_NO}`), para: no('destino, na mesma forma'), sentido, tipos, tetoBytes }).strict(),
135
141
  argv: (a) => ['caminho', a.de, a.para, ...opcoes(a)],
136
142
  },
143
+ {
144
+ nome: 'ork_grafo_contexto',
145
+ descricao: 'Pacote deterministico da thread: diff da worktree contra base (ignorado sem worktree), GOAL, PLAN e claims; fan-in agregado e evidencias compactas. '
146
+ + 'JSON ork.thread-graph-context/v2 limitado em bytes, refs locais, prioridade entre arquivos e por proximidade ao diff. Citacoes literais cites; segundo salto marcado usa a sobra apos ligacoes diretas. '
147
+ + 'Grupo com fonte que mudou depois do HEAD traz arvore: modificada. Sem indice do HEAD, recusa com ork grafo indexar.',
148
+ schema: zod_1.z.object({ threadId, tetoBytes }).strict(),
149
+ argv: (a) => ['contexto', a.threadId, ...opcoes(a)],
150
+ },
137
151
  ];
152
+ /** Leitura compartilhada por CLI e worker, fora da familia do grafo. Nunca escreve estado. */
153
+ function lerEntradaDaThread(raiz, id) {
154
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(id))
155
+ throw Error('grafo.contexto.thread-invalida: id invalido');
156
+ const projeto = fs.realpathSync((0, estado_thread_1.raizDoEstado)(raiz));
157
+ (0, mcp_artifacts_1.validarArquivosEstadoMcp)(projeto, id);
158
+ const t = (0, thread_1.lerThread)(projeto, id);
159
+ const cwd = fs.realpathSync(t.worktree ?? projeto);
160
+ if (cwd !== projeto && !cwd.startsWith(projeto + path.sep))
161
+ throw Error('grafo.contexto.escopo: worktree fora do projeto');
162
+ if (fs.realpathSync((0, estado_thread_1.raizDoEstado)(cwd)) !== projeto)
163
+ throw Error('grafo.contexto.escopo: worktree de outro repositorio');
164
+ // Em uma WT, consultar outra thread daria um pacote de outra arvore silenciosamente.
165
+ const origem = fs.realpathSync(raiz);
166
+ if (origem !== projeto && origem !== cwd)
167
+ throw Error('grafo.contexto.escopo: thread de outra worktree');
168
+ if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(t.base.commit))
169
+ throw Error('grafo.contexto.base-invalida: thread sem commit base');
170
+ const git = (args) => {
171
+ const r = (0, node_child_process_1.spawnSync)('git', ['-c', 'core.fsmonitor=false', ...args], {
172
+ cwd, env: { ...(0, mcp_git_1.ambienteGitMcp)(), GIT_OPTIONAL_LOCKS: '0' }, encoding: 'utf8', timeout: 10000, maxBuffer: 8 * 1024 * 1024,
173
+ });
174
+ if (r.error || r.status !== 0)
175
+ throw Error('grafo.contexto.git-falhou: nao foi possivel ler HEAD/base/diff da thread');
176
+ return r.stdout;
177
+ };
178
+ const head = git(['rev-parse', '--verify', 'HEAD']).trim();
179
+ const diff = !t.worktree || cwd === projeto ? [] : git(['diff', '--no-ext-diff', '--no-textconv', '--no-renames', '--name-only', '-z', t.base.commit, '--']).split('\0').filter(Boolean);
180
+ const goal = (0, mcp_artifacts_1.lerArtefatoMcp)(projeto, id, 'goal').conteudo;
181
+ const plan = (0, mcp_artifacts_1.lerArtefatoMcp)(projeto, id, 'plan').conteudo;
182
+ const claims = (0, mcp_artifacts_1.listarClaimsMcp)(projeto, id).filter((c) => c.estado !== 'retirada').map(({ id, arquivo }) => ({ id, arquivo }));
183
+ if (head !== git(['rev-parse', '--verify', 'HEAD']).trim())
184
+ throw Error('grafo.contexto.revisao-mudou: HEAD mudou durante a leitura; repita');
185
+ return { raiz: cwd, head, entrada: { thread: id, base: t.base.commit, diff, diffEstado: !t.worktree || cwd === projeto ? 'ignorado-sem-worktree' : 'coletado-na-worktree', goal, plan, claims } };
186
+ }
138
187
  /** D9: o argv que a tool monta para os argumentos dados; a medida offline usa o mesmo. */
139
188
  function argvDaTool(nome, args) {
140
189
  const d = DEFINICOES.find((x) => x.nome === nome);
@@ -204,7 +253,7 @@ function consultarPeloWorker(raiz, argv, opcoesDoWorker = {}) {
204
253
  }
205
254
  const texto = (t, isError = false) => ({ content: [{ type: 'text', text: t }], ...(isError ? { isError: true } : {}) });
206
255
  /**
207
- * As quatro tools, chamadas pelo servidor so com a flag ligada no startup. `carregar` e `thread` sao os
256
+ * As cinco tools, chamadas pelo servidor so com a flag ligada no startup. `carregar` e `thread` sao os
208
257
  * do servidor: o projeto fixado e a thread conferida (escopo da sessao filha e worktree confinada).
209
258
  */
210
259
  function registrarConsultasDoGrafo(registrar, contexto) {