@orkastery/cli 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/adapters/claude-code/README.md +11 -2
  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/onboarding.md +3 -2
  5. package/adapters/claude-code/commands/ork.md +9 -0
  6. package/adapters/codex/skills/ork/SKILL.md +18 -3
  7. package/adapters/hermes/README.md +1 -0
  8. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  9. package/adapters/hermes/hermes.plugin.json +1 -0
  10. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  11. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
  12. package/adapters/openclaw/README.md +35 -4
  13. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  14. package/adapters/openclaw/dist/index.js +47 -12
  15. package/adapters/openclaw/openclaw.plugin.json +5 -1
  16. package/adapters/openclaw/package.json +2 -2
  17. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  18. package/adapters/openclaw/src/index.ts +50 -12
  19. package/assets/orkmind_bridge.py +117 -9
  20. package/dist/adapters/claude-bg.js +59 -11
  21. package/dist/adapters/codex.js +4 -3
  22. package/dist/agents-md.js +1 -0
  23. package/dist/auditrun.js +6 -2
  24. package/dist/board.js +16 -14
  25. package/dist/branch-de-estado.js +66 -10
  26. package/dist/busca-semantica.js +52 -12
  27. package/dist/canarios-rm057.js +149 -0
  28. package/dist/canarios.js +2 -0
  29. package/dist/ci.js +8 -1
  30. package/dist/claim-lint.js +3 -1
  31. package/dist/claims.js +39 -1
  32. package/dist/company-brain-context.js +158 -22
  33. package/dist/docs.js +110 -3
  34. package/dist/doctor-pulse-cron.js +194 -0
  35. package/dist/doctor-rede.js +149 -0
  36. package/dist/doctor.js +294 -37
  37. package/dist/entrega-pr.js +27 -8
  38. package/dist/esgotamentos.js +181 -0
  39. package/dist/experiencia.js +12 -2
  40. package/dist/fabrica-estado.js +35 -9
  41. package/dist/fabrica-publicar.js +6 -0
  42. package/dist/fechamento.js +20 -66
  43. package/dist/fix.js +3 -3
  44. package/dist/forja.js +31 -7
  45. package/dist/gates.js +5 -1
  46. package/dist/hitl-contract.js +59 -4
  47. package/dist/hitl-curto.js +11 -6
  48. package/dist/hitl-gates.js +5 -0
  49. package/dist/hitl-lote.js +5 -2
  50. package/dist/hitl-resumo.js +33 -1
  51. package/dist/hitl-tempo-parado.js +201 -0
  52. package/dist/hitl-texto-livre.js +5 -5
  53. package/dist/horario.js +27 -0
  54. package/dist/hosts.js +59 -13
  55. package/dist/impedimento.js +205 -0
  56. package/dist/index.js +433 -88
  57. package/dist/indice-vetorial.js +87 -10
  58. package/dist/indice.js +3 -1
  59. package/dist/init.js +28 -5
  60. package/dist/integracoes-locais.js +4 -0
  61. package/dist/intelligence-graph-cli.js +267 -30
  62. package/dist/intelligence-graph-contexto.js +215 -0
  63. package/dist/intelligence-graph-contract.js +71 -12
  64. package/dist/intelligence-graph-extract-md.js +41 -23
  65. package/dist/intelligence-graph-extract-ts.js +181 -11
  66. package/dist/intelligence-graph-extract.js +186 -9
  67. package/dist/intelligence-graph-index.js +205 -24
  68. package/dist/intelligence-graph-parsers.js +6 -4
  69. package/dist/intelligence-graph-repo.js +10 -0
  70. package/dist/leases.js +680 -87
  71. package/dist/ledger-stats.js +15 -1
  72. package/dist/ledger.js +12 -0
  73. package/dist/licoes.js +6 -4
  74. package/dist/liveness.js +2 -1
  75. package/dist/maestro-runtime.js +7 -1
  76. package/dist/manifest.js +44 -1
  77. package/dist/master-nota.js +14 -5
  78. package/dist/master.js +129 -12
  79. package/dist/mcp-artifacts.js +36 -3
  80. package/dist/mcp-git.js +80 -15
  81. package/dist/mcp-grafo-worker.js +93 -0
  82. package/dist/mcp-grafo.js +279 -0
  83. package/dist/mcp-install.js +2 -1
  84. package/dist/mcp-server.js +23 -1
  85. package/dist/mcp-ship.js +2 -0
  86. package/dist/mcp-verify.js +3 -1
  87. package/dist/memoria.js +48 -6
  88. package/dist/network-roadmap.js +195 -20
  89. package/dist/ocupacao.js +17 -5
  90. package/dist/onboarding.js +9 -4
  91. package/dist/orkmind.js +90 -5
  92. package/dist/orquestracao.js +14 -11
  93. package/dist/parado-no-condutor.js +1089 -0
  94. package/dist/phase.js +68 -15
  95. package/dist/policies.js +79 -3
  96. package/dist/portfolio.js +4 -1
  97. package/dist/projeto-alvo.js +5 -1
  98. package/dist/prompts.js +36 -1
  99. package/dist/prova-ativacao.js +414 -0
  100. package/dist/pulse-delivery.js +60 -7
  101. package/dist/pulse.js +99 -3
  102. package/dist/ratelimit.js +20 -4
  103. package/dist/recall.js +3 -1
  104. package/dist/rede-adesao.js +399 -0
  105. package/dist/rede-forja.js +289 -0
  106. package/dist/rede-projetos.js +239 -0
  107. package/dist/rede-status.js +336 -0
  108. package/dist/rede.js +980 -0
  109. package/dist/retry.js +69 -2
  110. package/dist/roadmap-status.js +162 -7
  111. package/dist/runtime-context.js +5 -1
  112. package/dist/runtime-profiles.js +22 -1
  113. package/dist/saida-segura.js +58 -0
  114. package/dist/session-watcher-claude.js +113 -23
  115. package/dist/sessoes-contas.js +187 -0
  116. package/dist/sessoes-inventario.js +6 -12
  117. package/dist/sessoes.js +87 -3
  118. package/dist/ship.js +110 -20
  119. package/dist/thread.js +212 -14
  120. package/dist/util.js +71 -4
  121. package/dist/verify.js +2 -2
  122. package/dist/worktree.js +34 -8
  123. package/eval/casos/onboarding.json +1 -1
  124. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  125. package/package.json +7 -3
  126. package/references/definition-of-done.md +1 -1
  127. package/skills/README.md +1 -1
  128. package/skills/core/onboarding/SKILL.md +3 -2
  129. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  130. package/skills/phases/master-metrics/SKILL.md +8 -3
  131. package/skills/phases/ship-release/SKILL.md +6 -3
package/dist/hosts.js CHANGED
@@ -57,6 +57,7 @@ exports.ORDEM_DOS_HOSTS = exports.HOSTS = exports.MAESTRO_HOST_SURFACES = export
57
57
  exports.parseHost = parseHost;
58
58
  exports.lerRecibo = lerRecibo;
59
59
  exports.classificarDivergencia = classificarDivergencia;
60
+ exports.avisoDoOrkNoPath = avisoDoOrkNoPath;
60
61
  exports.renderizarArquivo = renderizarArquivo;
61
62
  exports.instalarAdaptador = instalarAdaptador;
62
63
  exports.desinstalarExperiencia = desinstalarExperiencia;
@@ -64,6 +65,7 @@ exports.tabelaDeHosts = tabelaDeHosts;
64
65
  exports.textoDosPitfalls = textoDosPitfalls;
65
66
  exports.textoDaInstalacao = textoDaInstalacao;
66
67
  const node_crypto_1 = require("node:crypto");
68
+ const node_child_process_1 = require("node:child_process");
67
69
  const fs = __importStar(require("node:fs"));
68
70
  exports.BRAIN_HOST_SURFACES = {
69
71
  hermes: 'cli', openclaw: 'cli', 'claude-code': 'mcp', codex: 'mcp',
@@ -92,8 +94,8 @@ exports.HOSTS = {
92
94
  pitfalls: [
93
95
  {
94
96
  titulo: 'manifesto sem os caminhos das skills instala limpo e nao expoe nada',
95
- detalhe: 'o plugin auto-descobre skills/<nome>/SKILL.md e para ai: ele nao desce nos buckets (core/, phases/, reviewers/, ...) que este catalogo usa, entao o plugin.json declara os 17 caminhos um a um',
96
- prova: 'claude plugin details orkastery # a contagem precisa bater com os SKILL.md em disco',
97
+ detalhe: 'o plugin auto-descobre skills/<nome>/SKILL.md e para ai: ele nao desce nos buckets (core/, phases/, reviewers/, ...) que este catalogo usa, entao o plugin.json declara cada caminho de skill, um a um',
98
+ prova: 'claude plugin details orkastery # Skills (N) soma as skills do plugin.json e os comandos de commands/',
97
99
  },
98
100
  {
99
101
  titulo: 'duas copias do catalogo divergem',
@@ -246,6 +248,31 @@ function listarArquivos(dir, prefixo = '') {
246
248
  }
247
249
  return achados;
248
250
  }
251
+ function mesmoArquivo(a, b) {
252
+ try {
253
+ return fs.realpathSync(a) === fs.realpathSync(b);
254
+ }
255
+ catch {
256
+ return path.resolve(a) === path.resolve(b);
257
+ }
258
+ }
259
+ /**
260
+ * Ensaio de 03/10: com outro `ork` primeiro no PATH, a extensão segue apontando para o binário que roda o
261
+ * install, e o aviso diz as duas versões para ninguém descobrir a diferença pela extensão chamando o velho.
262
+ */
263
+ function avisoDoOrkNoPath(emExecucao, versao, env = process.env) {
264
+ const doPath = (0, util_1.noPath)('ork', env);
265
+ if (!doPath || mesmoArquivo(doPath, emExecucao))
266
+ return undefined;
267
+ let outra = 'versão desconhecida';
268
+ try {
269
+ const saida = (0, node_child_process_1.execFileSync)(doPath, ['--version'], { encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'], env });
270
+ outra = saida.trim().split('\n')[0]?.trim() || outra;
271
+ }
272
+ catch { /* o aviso sai mesmo sem a versão */ }
273
+ return `o ork do PATH (${doPath}, ${outra}) não é o que roda este install (${emExecucao}, ${versao}). ` +
274
+ `A extensão chama ${emExecucao}; para outro binário, passe --ork <caminho>.`;
275
+ }
249
276
  /** Substitui os tres placeholders. Nao ha template engine aqui de proposito. */
250
277
  function renderizarArquivo(conteudo, valores) {
251
278
  return conteudo
@@ -267,8 +294,10 @@ function instalarAdaptador(host, opcoes = {}) {
267
294
  ? path.resolve(projeto, opcoes.dir)
268
295
  : path.join(projeto, def.destinoPadrao);
269
296
  const destino = def.subdir ? path.join(base, def.subdir) : base;
270
- const orkBin = opcoes.orkBin ?? (0, util_1.noPath)('ork') ?? (0, catalogo_1.cliDoCatalogo)(catalogo);
297
+ const orkBin = opcoes.orkBin ?? opcoes.orkEmExecucao ?? (0, util_1.noPath)('ork') ?? (0, catalogo_1.cliDoCatalogo)(catalogo);
271
298
  const versao = opcoes.versao ?? versao_1.VERSAO_DO_ORK;
299
+ const avisoOrk = opcoes.orkBin === undefined && opcoes.orkEmExecucao
300
+ ? avisoDoOrkNoPath(opcoes.orkEmExecucao, versao) : undefined;
272
301
  const dirDoHost = path.join(catalogo, 'adapters', host);
273
302
  if (!fs.existsSync(dirDoHost)) {
274
303
  throw new Error(`adaptador do host ${host} nao existe em ${dirDoHost}`);
@@ -424,6 +453,7 @@ function instalarAdaptador(host, opcoes = {}) {
424
453
  ...(reciboVizinho ? { reciboVizinho } : {}),
425
454
  ok: !barrado,
426
455
  orkBin,
456
+ ...(avisoOrk ? { avisoOrk } : {}),
427
457
  pitfalls: def.pitfalls,
428
458
  ...(preferencias || avisoExperiencia ? { experiencia: { ativa: host !== 'openclaw' && !!preferencias?.experience && !avisoExperiencia,
429
459
  arquivos: planoExperiencia?.mudancas.map(m => path.relative(planoExperiencia.projeto, m.arquivo)) ?? [], skill: preferencias?.skill ?? '',
@@ -510,8 +540,12 @@ function textoDosPitfalls(host) {
510
540
  /** Texto de `ork adapter install`. */
511
541
  function textoDaInstalacao(r) {
512
542
  const linhas = [];
543
+ // Ensaio da 0.5.0: com o pacote ativo e pulado por aviso (catalogo fora do projeto), a linha dizia
544
+ // "desativada"; o aviso logo abaixo diz o motivo.
513
545
  if (r.experiencia)
514
- linhas.push(`Experiência: ${r.experiencia.ativa ? 'ativação preparada' : 'desativada ou sem integração de skills'}${r.experiencia.skill ? ` (${r.experiencia.skill})` : ''}.`);
546
+ linhas.push(`Experiência: ${r.experiencia.ativa ? 'ativação preparada'
547
+ : r.experiencia.aviso ? 'pacote pulado nesta instalação, veja o aviso abaixo' : 'desativada ou sem integração de skills'}` +
548
+ `${r.experiencia.skill ? ` (${r.experiencia.skill})` : ''}.`);
515
549
  if (r.experiencia?.aviso)
516
550
  linhas.push(`Aviso: ${r.experiencia.aviso}`);
517
551
  linhas.push(r.dryRun
@@ -519,28 +553,35 @@ function textoDaInstalacao(r) {
519
553
  : r.ok
520
554
  ? `Arquivos do adaptador ${r.host} preparados.`
521
555
  : `Instalacao do adaptador ${r.host} BARRADA: ha arquivo diferente no destino.`);
556
+ // Ensaio de 03/10 (R6): a ativacao sai no comeco e de novo no fim, depois da lista de arquivos e dos
557
+ // pitfalls, para que o fim da saida diga o proximo passo.
558
+ const ativacao = [];
522
559
  if (r.ok && !r.dryRun && r.host === 'claude-code') {
523
560
  const destino = "'" + r.destino.replace(/'/g, "'\"'\"'") + "'";
524
561
  linhas.push('Uso no Claude Code ainda nao verificado por esta copia.');
525
562
  linhas.push('No diretorio deste projeto, valide e ative o plugin:');
526
- linhas.push(` claude plugin validate ${destino}`);
527
- linhas.push(` claude plugin marketplace add ${destino} --scope project`);
528
- linhas.push(' claude plugin install orkastery@orkastery --scope project');
529
- linhas.push(' claude plugin list --json');
530
- linhas.push('Depois, na sessao deste projeto: /orkastery:ork');
563
+ ativacao.push(` claude plugin validate ${destino}`);
564
+ ativacao.push(` claude plugin marketplace add ${destino} --scope project`);
565
+ ativacao.push(' claude plugin install orkastery@orkastery --scope project');
566
+ ativacao.push(' claude plugin list --json');
567
+ ativacao.push('Depois, na sessao deste projeto: /orkastery:ork');
531
568
  }
532
569
  else if (r.ok && !r.dryRun && r.host === 'codex') {
533
- linhas.push('Abra o Codex neste projeto e use $ork.');
534
- linhas.push('Descoberta e uso nativo ainda nao verificados por esta copia.');
570
+ ativacao.push('Abra o Codex neste projeto e use $ork.');
571
+ ativacao.push('Descoberta e uso nativo ainda nao verificados por esta copia.');
535
572
  }
536
573
  if (r.ok && !r.dryRun && (r.host === 'codex' || r.host === 'claude-code')) {
537
574
  const projeto = "'" + r.projeto.replace(/'/g, "'\"'\"'") + "'";
538
- linhas.push(`Prepare tambem as ferramentas do projeto: ork mcp install --project ${projeto} --host ${r.host}`);
539
- linhas.push('A configuracao MCP exige descoberta e consentimento no cliente; a copia nao concede aprovacoes.');
575
+ ativacao.push(`Prepare tambem as ferramentas do projeto: ork mcp install --project ${projeto} --host ${r.host}`);
540
576
  }
577
+ linhas.push(...ativacao);
578
+ if (ativacao.length)
579
+ linhas.push('A configuracao MCP exige descoberta e consentimento no cliente; a copia nao concede aprovacoes.');
541
580
  linhas.push(` catalogo: ${r.catalogo}`);
542
581
  linhas.push(` destino: ${r.destino}`);
543
582
  linhas.push(` ork: ${r.orkBin}`);
583
+ if (r.avisoOrk)
584
+ linhas.push(` Aviso: ${r.avisoOrk}`);
544
585
  linhas.push('');
545
586
  const novos = r.arquivos.filter((a) => a.estado === 'novo').length;
546
587
  const iguais = r.arquivos.filter((a) => a.estado === 'igual').length;
@@ -588,5 +629,10 @@ function textoDaInstalacao(r) {
588
629
  }
589
630
  linhas.push('');
590
631
  linhas.push(textoDosPitfalls(r.host));
632
+ if (ativacao.length) {
633
+ linhas.push('');
634
+ linhas.push(r.host === 'claude-code' ? 'Proximo passo, no diretorio deste projeto (o mesmo do comeco):' : 'Proximo passo (o mesmo do comeco):');
635
+ linhas.push(...ativacao);
636
+ }
591
637
  return linhas.join('\n');
592
638
  }
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MOTIVOS_DE_IMPEDIMENTO_DO_DONO = void 0;
37
+ exports.ehImpedimentoDoDono = ehImpedimentoDoDono;
38
+ exports.ehEsperaDoDono = ehEsperaDoDono;
39
+ exports.classificarImpedimento = classificarImpedimento;
40
+ exports.impedimentoResolvido = impedimentoResolvido;
41
+ exports.correcaoDoImpedimento = correcaoDoImpedimento;
42
+ exports.registrarImpedimentoDoDono = registrarImpedimentoDoDono;
43
+ exports.impedimentoDoEvento = impedimentoDoEvento;
44
+ exports.pedidoCurtoDoImpedimento = pedidoCurtoDoImpedimento;
45
+ /**
46
+ * RM-055: impedimento que so o dono resolve vira HITL.
47
+ *
48
+ * Em 29/09/2026 tres despachos `claude --bg` morreram com "Workspace not trusted. Run `claude` in
49
+ * <worktree> once and accept the trust prompt". O ledger guardou so `phase_dispatch_failed`, as threads
50
+ * ficaram `aberta` e o board, a fabrica e o pulse disseram "espera voce: -". O dono descobriu horas
51
+ * depois, perguntando.
52
+ *
53
+ * Aqui a saida do runtime vira motivo tipado. O motivo que so o dono resolve (aceitar a confianca do
54
+ * diretorio, aceitar termos novos do CLI) abre a pausa do dono com o que trava, o comando exato que ele
55
+ * roda e o que o `ork` faz depois: `ork retry run <thread>` re-despacha a MESMA fase com o MESMO prompt
56
+ * gravado, sem o dono reescrever o pedido. Login ausente e cota esgotada continuam na rotacao de conta
57
+ * (I-33): la quem resolve primeiro e o orquestrador, trocando de perfil. Motivo desconhecido continua
58
+ * generico (`runtime.unavailable`).
59
+ */
60
+ const fs = __importStar(require("node:fs"));
61
+ const os = __importStar(require("node:os"));
62
+ const path = __importStar(require("node:path"));
63
+ const gates_1 = require("./gates");
64
+ const hitl_curto_1 = require("./hitl-curto");
65
+ exports.MOTIVOS_DE_IMPEDIMENTO_DO_DONO = Object.freeze([
66
+ 'runtime.workspace-untrusted', 'runtime.consent-pending',
67
+ ]);
68
+ function ehImpedimentoDoDono(motivo) {
69
+ return typeof motivo === 'string' && exports.MOTIVOS_DE_IMPEDIMENTO_DO_DONO.includes(motivo);
70
+ }
71
+ /**
72
+ * Um evento do ledger que espera o dono: a escalada `human.pending` ou o impedimento tipado do despacho.
73
+ * E a mesma regra para o monitor, a ocupacao de vaga, a fabrica e o pulse.
74
+ */
75
+ function ehEsperaDoDono(e, tipoGateBloqueado = 'gate_blocked') {
76
+ return e.tipo === tipoGateBloqueado && (e.motivo === 'human.pending' || ehImpedimentoDoDono(e.motivo));
77
+ }
78
+ /** Aspas de shell so quando o caminho precisa. */
79
+ function citar(caminho) {
80
+ return /^[A-Za-z0-9_./:@+-]+$/.test(caminho) ? caminho : `'${caminho.replace(/'/g, `'\\''`)}'`;
81
+ }
82
+ const FRASES_DE_CONFIANCA = [
83
+ /workspace not trusted/i,
84
+ /accept the trust (?:prompt|dialog)/i,
85
+ /not inside a trusted directory/i,
86
+ /(?:folder|directory|workspace) (?:is )?not trusted/i,
87
+ ];
88
+ const FRASES_DE_CONSENTIMENTO = [
89
+ /accept (?:the )?(?:updated |new )?(?:terms|consumer terms|privacy policy|usage policy)/i,
90
+ /(?:terms|policy) (?:have|has) (?:been )?updated[^\n]*accept/i,
91
+ /consent (?:is )?required/i,
92
+ ];
93
+ function trechoDa(texto, regra) {
94
+ const linha = texto.split(/\r?\n/).find(l => regra.test(l)) ?? texto;
95
+ return linha.replace(/\s+/g, ' ').trim().slice(0, 240);
96
+ }
97
+ function binarioDo(runtime) {
98
+ return runtime === 'codex' ? 'codex' : 'claude';
99
+ }
100
+ /**
101
+ * Le a saida do runtime (stderr e o erro do adapter) e devolve o impedimento do dono, ou null.
102
+ * Null quer dizer "nao e do dono": o despacho segue no caminho de antes.
103
+ */
104
+ function classificarImpedimento(saida, ctx) {
105
+ const texto = saida ?? '';
106
+ const bin = binarioDo(ctx.runtime);
107
+ const depois = `depois, \`ork retry run ${ctx.thread}\` re-despacha ${ctx.fase} com o mesmo prompt gravado`;
108
+ const confianca = FRASES_DE_CONFIANCA.find(r => r.test(texto));
109
+ if (confianca) {
110
+ return {
111
+ motivo: 'runtime.workspace-untrusted',
112
+ trava: `o ${bin} não confia no diretório da worktree e recusou o despacho de ${ctx.fase}`,
113
+ comando: `cd ${citar(ctx.cwd)} && ${bin}`,
114
+ depois: `aceite a confiança no diretório e saia; ${depois}`,
115
+ trecho: trechoDa(texto, confianca),
116
+ };
117
+ }
118
+ const consentimento = FRASES_DE_CONSENTIMENTO.find(r => r.test(texto));
119
+ if (consentimento) {
120
+ return {
121
+ motivo: 'runtime.consent-pending',
122
+ trava: `o ${bin} espera você aceitar termos novos e recusou o despacho de ${ctx.fase}`,
123
+ comando: bin,
124
+ depois: `aceite os termos e saia; ${depois}`,
125
+ trecho: trechoDa(texto, consentimento),
126
+ };
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * O impedimento ja foi resolvido? So o de confianca do diretorio tem prova local: o `claude` grava
132
+ * `hasTrustDialogAccepted` por projeto no `.claude.json` da conta (o do perfil, com `CLAUDE_CONFIG_DIR`),
133
+ * e a confianca de um diretorio vale para os de baixo. `null` e "nao sei": o retry despacha e o runtime
134
+ * decide; se recusar de novo, a mesma pausa volta.
135
+ */
136
+ function impedimentoResolvido(motivo, ctx) {
137
+ if (motivo !== 'runtime.workspace-untrusted' || ctx.runtime !== 'claude-bg')
138
+ return null;
139
+ // A conta do processo segue o `CLAUDE_CONFIG_DIR` do ambiente, como o proprio `claude`.
140
+ const configDir = ctx.configDir ?? (ctx.home ? null : process.env.CLAUDE_CONFIG_DIR) ?? null;
141
+ const arquivo = configDir ? path.join(configDir, '.claude.json') : path.join(ctx.home ?? os.homedir(), '.claude.json');
142
+ let projetos;
143
+ try {
144
+ const dados = JSON.parse(fs.readFileSync(arquivo, 'utf8'));
145
+ if (!dados || typeof dados.projects !== 'object' || dados.projects === null)
146
+ return null;
147
+ projetos = dados.projects;
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ for (let dir = path.resolve(ctx.cwd);; dir = path.dirname(dir)) {
153
+ if (projetos[dir]?.hasTrustDialogAccepted === true)
154
+ return true;
155
+ if (path.dirname(dir) === dir)
156
+ return false;
157
+ }
158
+ }
159
+ /** A frase de correcao que vai ao gate e ao monitor: o comando e o que vem depois. */
160
+ function correcaoDoImpedimento(i) {
161
+ return `rode \`${i.comando}\`; ${i.depois}`;
162
+ }
163
+ /**
164
+ * RM-055: classifica a saida de um despacho recusado e, quando so o dono resolve, grava o `gate_blocked`
165
+ * tipado que o monitor, a fabrica, o board e o pulse leem como espera do dono. Devolve null quando o
166
+ * motivo nao e do dono (o chamador segue no caminho de antes). Tambem usado pelo redespacho do retry.
167
+ */
168
+ function registrarImpedimentoDoDono(dir, thread, d) {
169
+ const impedimento = classificarImpedimento(d.saida, { thread: thread.id, fase: d.fase, runtime: d.runtime, cwd: d.cwd });
170
+ if (!impedimento)
171
+ return null;
172
+ (0, gates_1.registrarGateBloqueado)(dir, thread.id, { gate: 'phase.dispatch', motivo: impedimento.motivo, modo: thread.modo,
173
+ detalhe: impedimento.trava, correcao: correcaoDoImpedimento(impedimento), fase: d.fase, slug: d.slug,
174
+ runtime: d.runtime, cwd: d.cwd, origem: d.origem, promptPath: d.promptPath, promptSha256: d.promptSha256,
175
+ impedimento: { motivo: impedimento.motivo, comando: impedimento.comando, depois: impedimento.depois, trecho: impedimento.trecho },
176
+ ...(d.perfil ? { perfil: d.perfil } : {}), pausaQualquerModo: true,
177
+ evidencia: 'stderr real do runtime adapter no despacho, nao relato do agente' });
178
+ return impedimento;
179
+ }
180
+ /** O impedimento gravado no `gate_blocked`, lido de volta com tipos; null quando o evento nao o traz. */
181
+ function impedimentoDoEvento(e) {
182
+ const i = e.impedimento;
183
+ if (!i || typeof i.comando !== 'string' || typeof i.depois !== 'string')
184
+ return null;
185
+ return { comando: i.comando, depois: i.depois, trecho: typeof i.trecho === 'string' ? i.trecho : '' };
186
+ }
187
+ /**
188
+ * RM-055 (b): o pedido do impedimento no contrato curto da RM-048 (`ork.hitl-curto/v1`): o que trava,
189
+ * desde quando, o comando exato que o dono roda e o que o ork faz depois. A recomendada e o re-despacho
190
+ * do mesmo prompt; as outras dizem o custo de nao fazer nada e de trocar o runtime do bloco.
191
+ */
192
+ function pedidoCurtoDoImpedimento(d, quando) {
193
+ const retry = `ork retry run ${d.thread}`;
194
+ return (0, hitl_curto_1.montarPedidoCurto)({
195
+ thread: d.thread, fase: d.fase, desde: d.desdeEm,
196
+ pergunta: `Você roda \`${d.impedimento.comando}\` no terminal para destravar o despacho?`,
197
+ corpo: [`${d.motivo}: ${d.detalhe}`, `Depois: ${d.impedimento.depois}.`],
198
+ alternativas: [
199
+ { chave: 'a', texto: 'Rodei o comando', consequencia: `\`${retry}\` re-despacha ${d.fase ?? 'a fase'} com o mesmo prompt gravado`,
200
+ recomendada: { porque: 'nada rodou ainda; o pedido volta igual, sem você reescrever nada' } },
201
+ { chave: 'b', texto: 'Trocar o runtime do bloco', consequencia: 'ork setup <modo> --bloco N --runtime <outro>, e depois o mesmo retry' },
202
+ { chave: 'c', texto: 'Deixar parada', consequencia: 'nada é despachado; a thread segue esperando você' },
203
+ ],
204
+ }, { quando, responder: { tipo: 'terminal', comando: retry } });
205
+ }