@orkastery/cli 0.5.3 → 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 (212) hide show
  1. package/adapters/claude-code/README.md +158 -0
  2. package/adapters/claude-code/mods/autoridade.json +56 -0
  3. package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
  4. package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
  5. package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
  6. package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
  7. package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
  8. package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
  9. package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
  10. package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
  11. package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
  12. package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
  13. package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
  14. package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
  15. package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
  16. package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
  17. package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
  18. package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
  19. package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
  20. package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
  21. package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
  22. package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
  23. package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
  24. package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
  25. package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
  26. package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
  27. package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
  28. package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
  29. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
  30. package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
  31. package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
  32. package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
  33. package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
  34. package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
  35. package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
  36. package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
  37. package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
  38. package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
  39. package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
  40. package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
  41. package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
  42. package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
  43. package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
  44. package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
  45. package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
  46. package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
  47. package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
  48. package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
  49. package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
  50. package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
  51. package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
  52. package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
  53. package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
  54. package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
  55. package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
  56. package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
  57. package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
  58. package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
  59. package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
  60. package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
  61. package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
  62. package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
  63. package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
  64. package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
  65. package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
  66. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
  67. package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
  68. package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
  69. package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
  70. package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
  71. package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
  72. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
  73. package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
  74. package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
  75. package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
  76. package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
  77. package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
  78. package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
  79. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +1 -1
  80. package/adapters/openclaw/README.md +2 -1
  81. package/adapters/openclaw/openclaw.plugin.json +1 -1
  82. package/adapters/openclaw/package.json +1 -1
  83. package/assets/docs-en/markdownlint-cli2.jsonc +22 -0
  84. package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
  85. package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
  86. package/assets/docs-en/produto/README.md +14 -0
  87. package/assets/docs-en/produto/_modelo-feature.md +62 -0
  88. package/assets/docs-en/roadmap/README.md +14 -0
  89. package/assets/docs-en/roadmap/_modelo-item.md +75 -0
  90. package/dist/adapters/claude-bg.js +77 -13
  91. package/dist/adapters/codex.js +10 -1
  92. package/dist/agents-md.js +24 -15
  93. package/dist/auditrun.js +17 -2
  94. package/dist/board.js +4 -3
  95. package/dist/branch-de-estado.js +23 -1
  96. package/dist/catalogo.js +33 -0
  97. package/dist/ci.js +13 -7
  98. package/dist/claims-conferir.js +342 -0
  99. package/dist/claims.js +3 -1
  100. package/dist/company-brain-client.js +36 -1
  101. package/dist/company-brain-journal.js +2 -1
  102. package/dist/company-brain-migration.js +36 -1
  103. package/dist/conducao-sentinela.js +388 -0
  104. package/dist/conducao-texto.js +12 -18
  105. package/dist/conducao.js +122 -30
  106. package/dist/conhecimento.js +490 -0
  107. package/dist/docs.js +22 -8
  108. package/dist/doctor-pulse-cron.js +182 -27
  109. package/dist/doctor-rede.js +18 -17
  110. package/dist/doctor.js +115 -111
  111. package/dist/entrega-pr.js +22 -21
  112. package/dist/escopo-escrita.js +10 -1
  113. package/dist/estado-thread.js +23 -1
  114. package/dist/experiencia-instalacao.js +45 -25
  115. package/dist/fabrica-batida.js +310 -0
  116. package/dist/fabrica-estado.js +38 -8
  117. package/dist/fabrica-publicar.js +3 -1
  118. package/dist/fila-pesada.js +444 -0
  119. package/dist/fix.js +3 -2
  120. package/dist/forja.js +1 -1
  121. package/dist/gates.js +3 -28
  122. package/dist/handoff.js +10 -6
  123. package/dist/hitl-local-receipt.js +2 -0
  124. package/dist/hitl-resumo.js +29 -3
  125. package/dist/hitl-tempo-parado.js +4 -4
  126. package/dist/hitl.js +29 -33
  127. package/dist/horario.js +14 -7
  128. package/dist/hosts.js +52 -1
  129. package/dist/impedimento.js +108 -14
  130. package/dist/index.js +623 -521
  131. package/dist/indice.js +7 -1
  132. package/dist/init.js +43 -47
  133. package/dist/instabilidade.js +144 -0
  134. package/dist/integracoes-locais.js +2 -0
  135. package/dist/intelligence-graph-cli.js +92 -21
  136. package/dist/intelligence-graph-contexto.js +56 -17
  137. package/dist/intelligence-graph-contract.js +2 -1
  138. package/dist/intelligence-graph-extract-md.js +56 -4
  139. package/dist/intelligence-graph-extract-ts.js +71 -3
  140. package/dist/intelligence-graph-query.js +66 -19
  141. package/dist/ledger.js +15 -1
  142. package/dist/liveness.js +6 -3
  143. package/dist/locale-ajuda.js +761 -0
  144. package/dist/locale-gerados.js +160 -0
  145. package/dist/locale-master.js +99 -0
  146. package/dist/locale-onboarding.js +92 -0
  147. package/dist/locale-phase.js +151 -0
  148. package/dist/locale-pulse.js +211 -0
  149. package/dist/locale-retry.js +385 -0
  150. package/dist/locale-roadmap.js +102 -0
  151. package/dist/locale-ship.js +494 -0
  152. package/dist/locale-thread.js +277 -0
  153. package/dist/locale-verify.js +125 -0
  154. package/dist/locale.js +714 -0
  155. package/dist/manifest.js +129 -3
  156. package/dist/maquina.js +23 -4
  157. package/dist/master-digest.js +6 -1
  158. package/dist/master-nota.js +4 -6
  159. package/dist/master.js +21 -24
  160. package/dist/mcp-artifacts.js +11 -2
  161. package/dist/mcp-git.js +23 -6
  162. package/dist/mcp-grafo.js +7 -4
  163. package/dist/mcp-server.js +8 -2
  164. package/dist/mcp-ship.js +3 -1
  165. package/dist/mcp-verify.js +6 -1
  166. package/dist/modos.js +3 -6
  167. package/dist/network-roadmap.js +5 -2
  168. package/dist/noctum-arco.js +911 -0
  169. package/dist/noctum-capacidade.js +141 -0
  170. package/dist/noctum-envelope.js +810 -0
  171. package/dist/noctum-execucao.js +304 -0
  172. package/dist/noctum-fila.js +280 -0
  173. package/dist/ocupacao.js +29 -2
  174. package/dist/onboarding.js +40 -21
  175. package/dist/orkmind.js +9 -2
  176. package/dist/orquestracao.js +13 -12
  177. package/dist/parado-no-condutor.js +34 -9
  178. package/dist/phase.js +94 -39
  179. package/dist/policies.js +4 -4
  180. package/dist/portfolio.js +4 -2
  181. package/dist/postura-local.js +234 -0
  182. package/dist/preflight.js +11 -10
  183. package/dist/procedencia.js +225 -0
  184. package/dist/projeto-alvo.js +127 -4
  185. package/dist/prompts.js +6 -2
  186. package/dist/pulse-delivery.js +13 -2
  187. package/dist/pulse.js +52 -19
  188. package/dist/ratelimit.js +4 -2
  189. package/dist/redacao-saida.js +63 -0
  190. package/dist/rede-status.js +3 -2
  191. package/dist/retry.js +232 -148
  192. package/dist/roadmap-reservas.js +20 -3
  193. package/dist/roadmap-status.js +129 -33
  194. package/dist/runtime-context.js +181 -3
  195. package/dist/runtimes.js +2 -1
  196. package/dist/session-events.js +7 -3
  197. package/dist/session-watcher-claude.js +7 -1
  198. package/dist/session-watcher.js +185 -33
  199. package/dist/sessoes-contas.js +1 -1
  200. package/dist/ship-publicar.js +800 -0
  201. package/dist/ship.js +84 -81
  202. package/dist/steal.js +77 -0
  203. package/dist/thread-close.js +3 -2
  204. package/dist/thread.js +153 -82
  205. package/dist/util.js +8 -1
  206. package/dist/verify.js +141 -52
  207. package/dist/vida-da-thread.js +254 -0
  208. package/dist/worktree-local.js +165 -0
  209. package/dist/worktree.js +20 -0
  210. package/dist/yaml.js +27 -8
  211. package/package.json +1 -1
  212. package/schemas/code-artifact-graph.v1.schema.json +2 -1
@@ -75,6 +75,7 @@ const session_events_1 = require("./session-events");
75
75
  const ledger_1 = require("./ledger");
76
76
  const thread_1 = require("./thread");
77
77
  const util_1 = require("./util");
78
+ const procedencia_1 = require("./procedencia");
78
79
  const hitl_1 = require("./hitl");
79
80
  /** Uma consulta nativa custa cerca de 0,3 s; cinco segundos mantém o custo abaixo de 10%. */
80
81
  exports.INTERVALO_WATCH_CLAUDE_MS = 5000;
@@ -546,6 +547,9 @@ function provaDoOrk(raiz, threadId, sessao, eventos, fonte) {
546
547
  const cwd = fonte?.cwd, headNoDespacho = fonte?.head;
547
548
  if (!cwd || typeof headNoDespacho !== 'string')
548
549
  return falta('HEAD da worktree no despacho não registrado; commit não conferível', { commits: [], recusados: registrados });
550
+ // RM-047 (P2): o git da prova só roda na worktree registrada; o cwd vem do ledger.
551
+ if ((0, procedencia_1.cwdLocalOuNulo)(raiz, threadId, cwd, 'ledger') === null)
552
+ return falta('cwd do despacho fora das worktrees registradas no git; commit não conferível', { commits: [], recusados: registrados });
549
553
  const commits = registrados.filter(sha => commitConferido(cwd, sha, headNoDespacho));
550
554
  const recusados = registrados.filter(sha => !commits.includes(sha));
551
555
  if (!commits.length)
@@ -622,7 +626,9 @@ function garantirFonteClaude(raiz, thread, sessao) {
622
626
  if (atual)
623
627
  return atual;
624
628
  const despacho = eventos.filter(e => e.tipo === 'phase_dispatch' && e.sessionId === sessao.sessionId).at(-1);
625
- const cwd = typeof despacho?.cwd === 'string' ? despacho.cwd : thread.worktree ?? raiz;
629
+ // RM-047 (P2): o cwd do ledger ou do thread.json so vale como worktree registrada no git.
630
+ const cwd = typeof despacho?.cwd === 'string' ? (0, procedencia_1.exigirCwdLocal)(raiz, thread.id, despacho.cwd, 'ledger')
631
+ : (0, procedencia_1.diretorioDaThread)(raiz, thread);
626
632
  const fonte = { nativo: 'claude-agents', cwd, origem: 'sessions.watch' };
627
633
  validarFonteClaude(eventos, sessao.sessionId, fonte);
628
634
  if (!(0, ledger_1.registrarSeExiste)(dir, thread.id, 'session_sensor_registered', { fase: sessao.fase, sessionId: sessao.sessionId,
@@ -33,10 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.BLOCO_WATCH_BYTES = exports.INTERVALO_WATCH_MS = exports.LIMITE_MORTE_MS = void 0;
36
+ exports.BLOCO_WATCH_BYTES = exports.MAX_FALHAS_WATCH = exports.MAX_ESPERA_ERRO_WATCH_MS = exports.INTERVALO_WATCH_MS = exports.LIMITE_MORTE_MS = void 0;
37
37
  exports.observarSessao = observarSessao;
38
38
  exports.validarFonteWatcher = validarFonteWatcher;
39
39
  exports.iniciarWatcher = iniciarWatcher;
40
+ exports.acompanharSessao = acompanharSessao;
40
41
  /** D6: observador restrito a uma sessão, cursor canônico e resultados idempotentes. */
41
42
  const fs = __importStar(require("node:fs"));
42
43
  const path = __importStar(require("node:path"));
@@ -110,6 +111,8 @@ function semProvaNativa(snapshot, terminal, fonteVencedora, fechamento, sessionI
110
111
  }
111
112
  exports.LIMITE_MORTE_MS = 600000;
112
113
  exports.INTERVALO_WATCH_MS = 1000;
114
+ exports.MAX_ESPERA_ERRO_WATCH_MS = 30000;
115
+ exports.MAX_FALHAS_WATCH = 12;
113
116
  exports.BLOCO_WATCH_BYTES = codex_events_1.LIMITE_LINHA_CODEX + 65536;
114
117
  function lerJson(file) {
115
118
  if (!fs.existsSync(file))
@@ -291,8 +294,87 @@ function desfazerNaThreadRemovida(pasta, criadas) {
291
294
  catch { /* já removida ou não vazia */ }
292
295
  }
293
296
  }
297
+ /** Diagnóstico fechado: mensagens de E/S e JSON podem conter caminhos e segredos. */
298
+ function diagnosticoWatcher(e) {
299
+ const erro = e;
300
+ const code = ['ENOENT', 'EAGAIN', 'EBUSY', 'EINTR', 'EACCES', 'EPERM', 'EIO', 'ENOSPC', 'SESSION_STATE_SPLIT']
301
+ .includes(erro?.code ?? '') ? erro.code : null;
302
+ const nome = e instanceof Error ? e.constructor.name : '';
303
+ const construtor = ['Error', 'SyntaxError', 'TypeError', 'RangeError', 'ReferenceError', 'URIError', 'EvalError', 'AggregateError']
304
+ .includes(nome) ? nome : 'desconhecido';
305
+ const base = { code, construtor };
306
+ const mensagem = erro?.message ?? '';
307
+ if (mensagem === 'prazo de observação esgotado')
308
+ return { ...base, categoria: 'observacao.prazo',
309
+ erro: 'nenhuma observação bem-sucedida dentro do orçamento de espera', transitorio: false };
310
+ // Só motivos literais do núcleo saem no diagnóstico: nenhum conteúdo de metadado.
311
+ const motivos = ['sessão do controller divergente', 'instância do controller divergente',
312
+ 'vínculo thread/fase/prompt do controller divergente', 'cwd do controller divergente',
313
+ 'identidade do controller divergente da registrada', 'identidade do runtime divergente da registrada',
314
+ 'rollout do controller ausente', 'rollout do controller divergente do registrado',
315
+ 'rollout do controller rotacionado sem vínculo provado com a fonte fixada',
316
+ 'descritor consumidor de rollout divergente da fonte fixada'];
317
+ const metadado = /^runtime\.unavailable: metadado (state\.json|launch\.json|process-launch\.json) de controller (inválido|ausente)$/.test(mensagem);
318
+ const categoria = metadado || motivos.some(m => mensagem === `runtime.unavailable: ${m}`) ? mensagem
319
+ : mensagem === 'controlador registrado divergente do despacho' ? 'controller.registro-divergente'
320
+ : mensagem === 'despacho do controller sem cwd registrado' ? 'controller.cwd-ausente'
321
+ : mensagem.startsWith('runtime.unavailable:') ? 'runtime.unavailable: motivo não categorizado'
322
+ : code ? `io.${code}` : construtor;
323
+ if (code === 'SESSION_STATE_SPLIT')
324
+ return { ...base, categoria: 'estado.dividido',
325
+ erro: 'estado canônico temporariamente sem vínculo; auditoria será repetida', transitorio: true };
326
+ if (['ENOENT', 'EAGAIN', 'EBUSY', 'EINTR'].includes(erro?.code ?? ''))
327
+ return { ...base, categoria, erro: `leitura temporariamente indisponível (${erro.code})`, transitorio: true };
328
+ if (e instanceof SyntaxError || /^JSON invalido em /.test(erro?.message ?? '') ||
329
+ metadado)
330
+ return { ...base, categoria: metadado ? categoria : 'json.invalido', erro: 'metadado JSON indisponível ou incompleto', transitorio: true };
331
+ if (/^(ingestão ocupada|creation\.busy:)/.test(erro?.message ?? ''))
332
+ return { ...base, categoria: 'observacao.ocupada', erro: 'observação ocupada; nova tentativa agendada', transitorio: true };
333
+ return { ...base, categoria, erro: 'falha permanente na observação; confira vínculo e fonte do sensor', transitorio: false };
334
+ }
335
+ const errosRegistrados = new WeakSet();
336
+ function registrarErroWatcher(raiz, threadId, sessionId, e, serie) {
337
+ if (!serie && e && typeof e === 'object' && errosRegistrados.has(e))
338
+ return true;
339
+ const dados = diagnosticoWatcher(e);
340
+ if (dados.categoria === 'observacao.ocupada')
341
+ return true;
342
+ const registrado = (0, ledger_1.registrarSeExiste)((0, thread_1.dirThread)(raiz, threadId), threadId, 'session_watcher_error', {
343
+ sessionId, motivo: 'runtime.unavailable', ...dados, ...serie,
344
+ transitorio: dados.transitorio && (!serie?.encerramento || serie.encerramento === 'recuperado'), origem: 'sessions.watch',
345
+ });
346
+ if (registrado && e && typeof e === 'object')
347
+ errosRegistrados.add(e);
348
+ return registrado !== null;
349
+ }
350
+ /** Falhar ao diagnosticar não troca o erro observado nem interrompe o retry transitório. */
351
+ function tentarRegistrarErroWatcher(...args) {
352
+ try {
353
+ return registrarErroWatcher(...args);
354
+ }
355
+ catch {
356
+ return false;
357
+ }
358
+ }
359
+ function observarSemDiagnostico(carregado, sessionId, opcoes) {
360
+ return observarSessaoResolvida(carregado, sessionId, (0, session_events_1.resolverSessao)(carregado.raiz, sessionId, opcoes.threadId), opcoes);
361
+ }
294
362
  function observarSessao(carregado, sessionId, opcoes = {}) {
295
- const { thread, sessao: registrada } = (0, session_events_1.resolverSessao)(carregado.raiz, sessionId);
363
+ let threadId = opcoes.threadId;
364
+ try {
365
+ const resolvida = (0, session_events_1.resolverSessao)(carregado.raiz, sessionId, threadId);
366
+ // Recusa de entrada sem despacho não é falha de um watcher ancorado.
367
+ threadId = resolvida.sessao.origem !== 'adocao' && resolvida.sessao.despachadaEm
368
+ ? resolvida.thread.id : undefined;
369
+ return observarSessaoResolvida(carregado, sessionId, resolvida, opcoes);
370
+ }
371
+ catch (e) {
372
+ if (threadId)
373
+ tentarRegistrarErroWatcher(carregado.raiz, threadId, sessionId, e);
374
+ throw e;
375
+ }
376
+ }
377
+ function observarSessaoResolvida(carregado, sessionId, { thread, sessao: registrada }, opcoes) {
296
378
  const sessao = (0, session_events_1.exigirSessaoDespachada)(registrada, sessionId);
297
379
  if (sessao.runtime !== 'codex' && sessao.runtime !== 'claude-bg')
298
380
  throw new Error('watch requer sessão Codex ou claude-bg registrada');
@@ -398,6 +480,27 @@ function observarSessao(carregado, sessionId, opcoes = {}) {
398
480
  cursor.progressoEm = Math.max(cursor.progressoEm, leitura.quando);
399
481
  }
400
482
  }
483
+ // Commit MCP é produção do núcleo, mesmo quando app-server não avança o rollout.
484
+ // Só renova inatividade com ambos os processos vivos, dentro deste despacho e
485
+ // sem terminal/erro nativo. Não substitui terminal, close ou prova de conclusão.
486
+ let progressoMcpEventId;
487
+ if (snapshot?.estadoController === 'vivo' && snapshot.estadoRuntime === 'vivo' &&
488
+ ['working', 'running'].includes(snapshot.estado) && !snapshot.fechamento &&
489
+ !snapshot.terminalNativo && !snapshot.erro && !snapshot.limitacao) {
490
+ for (const e of (0, session_watcher_claude_1.eventosDoIntervalo)(eventos, sessao)) {
491
+ const quando = Date.parse(e.ts);
492
+ if (e.tipo !== 'mcp_git_committed' || e.thread !== thread.id || e.origem !== 'mcp.git' ||
493
+ e.estadoAuditado !== true || typeof e.commit !== 'string' || !/^[a-f0-9]{40}$/.test(e.commit) ||
494
+ (e.sessionId !== undefined && e.sessionId !== sessionId) ||
495
+ (e.despachoEm !== undefined && e.despachoEm !== sessao.despachadaEm) ||
496
+ quando > now || quando <= cursor.progressoEm)
497
+ continue;
498
+ cresceu = true;
499
+ cursor.crescimentoEm = Math.max(cursor.crescimentoEm, quando);
500
+ cursor.progressoEm = quando;
501
+ progressoMcpEventId = e.eventId;
502
+ }
503
+ }
401
504
  // Erro de metadados posterior não obriga a reler o mesmo backlog no restart.
402
505
  (0, codex_runner_1.gravarAtomico)(file, cursor);
403
506
  const processo = registro?.processoPath ? lerJson(registro.processoPath) : null;
@@ -482,7 +585,8 @@ function observarSessao(carregado, sessionId, opcoes = {}) {
482
585
  if (!atuais.some(e => e.sensorEventId === heartbeatId))
483
586
  (0, ledger_1.registrar)(dir, thread.id, 'runtime_heartbeat', {
484
587
  ts: new Date(cursor.crescimentoEm).toISOString(), fase: sessao.fase, sessionId, despachoEm: sessao.despachadaEm,
485
- sensorEventId: heartbeatId, fonte: 'progresso reconhecido do stream/rollout', bytesLidos,
588
+ sensorEventId: heartbeatId, fonte: progressoMcpEventId ? 'mcp_git_committed do despacho' : 'progresso reconhecido do stream/rollout',
589
+ ...(progressoMcpEventId ? { mcpEventId: progressoMcpEventId } : {}), bytesLidos,
486
590
  });
487
591
  cursor.heartbeatEm = cursor.crescimentoEm;
488
592
  (0, codex_runner_1.gravarAtomico)(file, cursor);
@@ -548,13 +652,6 @@ function observarSessao(carregado, sessionId, opcoes = {}) {
548
652
  // Thread apagada no meio da observação: encerra sem erro, sem recriar a pasta e sem resíduo.
549
653
  if (!(0, ledger_1.threadPresente)(dir))
550
654
  return desfazer();
551
- if (!/ocupad/.test(e.message) && !(0, ledger_1.registrarSeExiste)(dir, thread.id, 'session_watcher_error', {
552
- fase: sessao.fase, sessionId, despachoEm: sessao.despachadaEm, motivo: 'runtime.unavailable',
553
- // Não copiar conteúdo de metadados/logs em mensagens de JSON.parse.
554
- erro: e instanceof SyntaxError ? 'metadado JSON inválido' : e.message,
555
- origem: 'sessions.watch',
556
- }))
557
- return removida;
558
655
  throw e;
559
656
  }
560
657
  }
@@ -612,7 +709,7 @@ function iniciarWatcher(raiz, sessionId) {
612
709
  const err = fs.openSync(path.join(dir, `watcher-${sessionId}.stderr`), 'a', 0o600);
613
710
  let child;
614
711
  try {
615
- child = (0, node_child_process_1.spawn)(process.execPath, [__filename, '--run', raiz, sessionId, readyPath, token], {
712
+ child = (0, node_child_process_1.spawn)(process.execPath, [__filename, '--run', raiz, sessionId, readyPath, token, thread.id], {
616
713
  cwd: raiz, detached: true, stdio: ['ignore', 'ignore', err],
617
714
  });
618
715
  }
@@ -661,47 +758,102 @@ function iniciarWatcher(raiz, sessionId) {
661
758
  }
662
759
  async function acompanhar() {
663
760
  const carregado = (0, manifest_1.exigirManifesto)(process.argv[3]), sessionId = process.argv[4];
664
- const { thread } = (0, session_events_1.resolverSessao)(carregado.raiz, sessionId);
665
- const readyPath = process.argv[5], token = process.argv[6];
666
- if (readyPath && token) {
667
- validarFonteWatcher(carregado.raiz, sessionId);
668
- const sessao = (0, session_events_1.exigirSessaoDespachada)((0, session_events_1.resolverSessao)(carregado.raiz, sessionId).sessao, sessionId);
669
- const identidade = (0, codex_runner_1.identidadeProcesso)(process.pid);
670
- if (!identidade)
671
- throw new Error('watcher sem identidade propria');
672
- (0, codex_runner_1.gravarAtomico)(readyPath, { token, sessionId, despachoEm: sessao.despachadaEm, identidade });
673
- const deadline = Date.now() + 5000;
674
- while (lerJson(readyPath + '.ack')?.token !== token) {
675
- if (Date.now() >= deadline)
676
- throw new Error('watcher sem confirmacao do pai');
677
- await new Promise(r => setTimeout(r, 10));
761
+ const threadId = process.argv[7] ?? (0, session_events_1.resolverSessao)(carregado.raiz, sessionId).thread.id;
762
+ try {
763
+ const readyPath = process.argv[5], token = process.argv[6];
764
+ if (readyPath && token) {
765
+ validarFonteWatcher(carregado.raiz, sessionId);
766
+ const sessao = (0, session_events_1.exigirSessaoDespachada)((0, session_events_1.resolverSessao)(carregado.raiz, sessionId, threadId).sessao, sessionId);
767
+ const identidade = (0, codex_runner_1.identidadeProcesso)(process.pid);
768
+ if (!identidade)
769
+ throw new Error('watcher sem identidade propria');
770
+ (0, codex_runner_1.gravarAtomico)(readyPath, { token, sessionId, despachoEm: sessao.despachadaEm, identidade });
771
+ const deadline = Date.now() + 5000;
772
+ while (lerJson(readyPath + '.ack')?.token !== token) {
773
+ if (Date.now() >= deadline)
774
+ throw new Error('watcher sem confirmacao do pai');
775
+ await new Promise(r => setTimeout(r, 10));
776
+ }
678
777
  }
778
+ await acompanharSessao(carregado, sessionId, { threadId });
679
779
  }
680
- const dir = (0, thread_1.dirThread)(carregado.raiz, thread.id);
780
+ catch (e) {
781
+ tentarRegistrarErroWatcher(carregado.raiz, threadId, sessionId, e);
782
+ throw e;
783
+ }
784
+ }
785
+ /** Mesmo laço do processo destacado, com relógio e espera injetáveis para regressões. */
786
+ async function acompanharSessao(carregado, sessionId, opcoes) {
787
+ const dir = (0, thread_1.dirThread)(carregado.raiz, opcoes.threadId);
788
+ const esperar = opcoes.esperar ?? ((ms) => new Promise(r => setTimeout(r, ms)));
789
+ const agora = opcoes.agora ?? Date.now;
790
+ let falhas = 0, tentativas = 0, esperas = 0, ultimaObservacao = agora(), ultimoErro;
681
791
  for (;;) {
682
792
  // Projeto ou thread apagados encerram o laço em silêncio: nada a observar nem a recriar.
683
793
  if (!(0, ledger_1.threadPresente)(dir))
684
794
  return;
685
795
  let atual;
686
796
  try {
687
- atual = (0, thread_1.lerThread)(carregado.raiz, thread.id);
797
+ atual = (0, thread_1.lerThread)(carregado.raiz, opcoes.threadId);
688
798
  if (atual.status !== 'aberta' || atual.sessoes.at(-1)?.sessionId !== sessionId)
689
799
  return;
690
- const r = observarSessao(carregado, sessionId);
800
+ // O laço agrega sua série de erros; a API de observação avulsa diagnostica separadamente.
801
+ const r = observarSemDiagnostico(carregado, sessionId, { threadId: opcoes.threadId, agoraMs: opcoes.agora?.() });
802
+ if (r.ocupado)
803
+ throw new Error('ingestão ocupada; tente novamente');
804
+ if (!r.ocupado) {
805
+ if (falhas)
806
+ tentarRegistrarErroWatcher(carregado.raiz, opcoes.threadId, sessionId, ultimoErro, { falhasConsecutivas: falhas, etapa: 'final', encerramento: 'recuperado' });
807
+ falhas = 0;
808
+ tentativas = 0;
809
+ esperas = 0;
810
+ ultimaObservacao = agora();
811
+ }
691
812
  if (r.concluido || r.encerrado)
692
813
  return;
693
814
  }
694
815
  catch (e) {
695
816
  if (!(0, ledger_1.threadPresente)(dir))
696
817
  return;
697
- if (!/ocupad/.test(e.message))
698
- throw e;
818
+ esperas++;
819
+ const dados = diagnosticoWatcher(e), ocupado = dados.categoria === 'observacao.ocupada';
820
+ const expirou = agora() - ultimaObservacao >= exports.LIMITE_MORTE_MS;
821
+ // Contenção não é erro. Estado dividido exige nova auditoria; ambos consomem
822
+ // só tempo, sem antecipar os 600 s pelo teto das outras falhas.
823
+ if (!ocupado || expirou) {
824
+ if (ocupado)
825
+ e = new Error('prazo de observação esgotado');
826
+ falhas++;
827
+ if (!ocupado && dados.categoria !== 'estado.dividido')
828
+ tentativas++;
829
+ ultimoErro = e;
830
+ const encerramento = ocupado ? 'prazo' : !dados.transitorio ? 'permanente'
831
+ : expirou ? 'prazo' : tentativas >= exports.MAX_FALHAS_WATCH ? 'tentativas' : undefined;
832
+ if (falhas === 1 || encerramento)
833
+ tentarRegistrarErroWatcher(carregado.raiz, opcoes.threadId, sessionId, e, { falhasConsecutivas: falhas, etapa: encerramento ? 'final' : 'inicial', ...(encerramento ? { encerramento } : {}) });
834
+ if (encerramento)
835
+ throw e;
836
+ }
699
837
  }
700
- await new Promise(r => setTimeout(r, atual?.sessoes.at(-1)?.runtime === 'claude-bg' ? session_watcher_claude_1.INTERVALO_WATCH_CLAUDE_MS : exports.INTERVALO_WATCH_MS));
838
+ await esperar(esperas ? Math.min(exports.MAX_ESPERA_ERRO_WATCH_MS, exports.INTERVALO_WATCH_MS * 2 ** Math.min(esperas - 1, 5), Math.max(1, exports.LIMITE_MORTE_MS - (agora() - ultimaObservacao)))
839
+ : atual?.sessoes.at(-1)?.runtime === 'claude-bg' ? session_watcher_claude_1.INTERVALO_WATCH_CLAUDE_MS : exports.INTERVALO_WATCH_MS);
701
840
  }
702
841
  }
703
842
  if (require.main === module && process.argv[2] === '--run')
704
- acompanhar().catch(() => {
705
- process.stderr.write('ork watcher: observação interrompida; confira session_watcher_error e estado canônico.\n');
843
+ acompanhar().catch(e => {
844
+ // O dispatcher fornece o vínculo antes do spawn: até falha ao carregar o manifesto
845
+ // precisa de diagnóstico. Sem ledger acessível, o stderr não promete um recibo inexistente.
846
+ let registroIndisponivel = !process.argv[7];
847
+ if (process.argv[7]) {
848
+ try {
849
+ registroIndisponivel = !registrarErroWatcher(process.argv[3], process.argv[7], process.argv[4], e);
850
+ }
851
+ catch {
852
+ registroIndisponivel = true;
853
+ }
854
+ }
855
+ process.stderr.write(registroIndisponivel
856
+ ? 'ork watcher: observação interrompida; não foi possível registrar session_watcher_error.\n'
857
+ : 'ork watcher: observação interrompida; confira session_watcher_error e estado canônico.\n');
706
858
  process.exitCode = 1;
707
859
  });
@@ -132,7 +132,7 @@ function consultarContas(raiz, opcoes = {}) {
132
132
  fontes.push({ origem: `claude agents (${rotulo(conta)})`, ok: false, detalhe: e.message });
133
133
  continue;
134
134
  }
135
- const r = (0, claude_bg_1.consultarSessoes)(undefined, opcoes.todas, ambiente);
135
+ const r = (0, claude_bg_1.consultarSessoes)(undefined, opcoes.todas, ambiente, opcoes.prazoMs);
136
136
  const origem = `claude agents --json${opcoes.todas ? ' --all' : ''} (${rotulo(conta)})`;
137
137
  // Fatia 2 do ensaio da 0.5.0 (P1): só o ENOENT antes da consulta prova a fonte ausente; qualquer
138
138
  // outra falha do `claude` continua deixando o inventário incompleto.