@orkastery/cli 0.6.1 → 0.6.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 (102) hide show
  1. package/adapters/claude-code/README.md +1 -1
  2. package/adapters/claude-code/agents/ork-check.md +1 -1
  3. package/adapters/claude-code/agents/ork-go.md +1 -1
  4. package/adapters/claude-code/agents/ork-goal.md +1 -1
  5. package/adapters/claude-code/agents/ork-master.md +1 -1
  6. package/adapters/claude-code/agents/ork-plan.md +1 -1
  7. package/adapters/claude-code/agents/ork-ship.md +1 -1
  8. package/adapters/claude-code/commands/ork.md +1 -1
  9. package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +2 -0
  10. package/adapters/codex/skills/ork/SKILL.md +1 -1
  11. package/adapters/hermes/README.md +1 -1
  12. package/adapters/openclaw/openclaw.plugin.json +1 -1
  13. package/adapters/openclaw/package.json +1 -1
  14. package/assets/adapters-en/claude-code/README.md +1 -1
  15. package/assets/adapters-en/claude-code/agents/ork-check.md +1 -1
  16. package/assets/adapters-en/claude-code/agents/ork-go.md +1 -1
  17. package/assets/adapters-en/claude-code/agents/ork-goal.md +1 -1
  18. package/assets/adapters-en/claude-code/agents/ork-master.md +1 -1
  19. package/assets/adapters-en/claude-code/agents/ork-plan.md +1 -1
  20. package/assets/adapters-en/claude-code/agents/ork-ship.md +1 -1
  21. package/assets/adapters-en/claude-code/commands/ork.md +1 -1
  22. package/assets/adapters-en/codex/skills/ork/SKILL.md +1 -1
  23. package/assets/adapters-en/hermes/README.md +1 -1
  24. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  25. package/assets/docs-en/padroes/roadmap-de-produto.md +1 -1
  26. package/assets/orkmind_fixture.py +4 -1
  27. package/assets/references-en/testing-patterns.md +1 -1
  28. package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +1 -1
  29. package/assets/skills-en/phases/check-quality/SKILL.md +1 -1
  30. package/assets/skills-en/phases/go-implementation/SKILL.md +1 -1
  31. package/dist/adapters/claude-bg.js +3 -1
  32. package/dist/adapters/grok-mcp-servidor.js +22 -12
  33. package/dist/adapters/grok.js +1 -1
  34. package/dist/agendador-cpu.js +10 -2
  35. package/dist/catalogo.js +3 -3
  36. package/dist/{canarios-hitl.js → cenarios-hitl.js} +7 -7
  37. package/dist/{canarios-i43.js → cenarios-i43.js} +16 -16
  38. package/dist/{canarios-pulse.js → cenarios-pulse.js} +3 -3
  39. package/dist/{canarios-rm057.js → cenarios-rm057.js} +3 -3
  40. package/dist/{canarios-sensores.js → cenarios-sensores.js} +5 -5
  41. package/dist/{canarios.js → cenarios.js} +22 -22
  42. package/dist/changelog-check.js +217 -0
  43. package/dist/check-agil.js +242 -5
  44. package/dist/check-paralelo.js +17 -4
  45. package/dist/ci.js +3 -2
  46. package/dist/claim-lint.js +29 -0
  47. package/dist/claims.js +5 -1
  48. package/dist/docs.js +8 -1
  49. package/dist/evalrunner.js +37 -37
  50. package/dist/fila-pesada.js +121 -11
  51. package/dist/hitl-canais.js +1 -1
  52. package/dist/hitl-classificacao.js +1 -0
  53. package/dist/hitl-presentation.js +1 -1
  54. package/dist/hitl-tempo-parado.js +1 -1
  55. package/dist/index.js +47 -29
  56. package/dist/init.js +1 -1
  57. package/dist/intelligence-graph-cli.js +27 -9
  58. package/dist/locale-ajuda.js +6 -6
  59. package/dist/locale-claims.js +16 -2
  60. package/dist/locale-grafo.js +56 -1
  61. package/dist/locale-maestro.js +38 -0
  62. package/dist/locale-network.js +8 -6
  63. package/dist/locale-onboarding.js +14 -0
  64. package/dist/locale-operacao-restante.js +18 -18
  65. package/dist/locale-preflight.js +80 -0
  66. package/dist/locale-projetos.js +6 -0
  67. package/dist/locale-prompts.js +8 -8
  68. package/dist/locale-pulse.js +4 -0
  69. package/dist/locale-retry.js +16 -0
  70. package/dist/locale-security-scan.js +35 -1
  71. package/dist/locale-verify.js +15 -0
  72. package/dist/locale.js +24 -7
  73. package/dist/maestro-cli.js +12 -17
  74. package/dist/mcp-install.js +2 -1
  75. package/dist/mcp-server.js +20 -17
  76. package/dist/mcp-verify-async.js +353 -0
  77. package/dist/mcp-verify-worker.js +17 -0
  78. package/dist/mcp-verify.js +10 -1
  79. package/dist/pedido-conducao.js +51 -0
  80. package/dist/preflight.js +25 -26
  81. package/dist/prompts.js +4 -2
  82. package/dist/pulse.js +4 -2
  83. package/dist/rede.js +24 -12
  84. package/dist/retry.js +12 -0
  85. package/dist/sandbox.js +11 -11
  86. package/dist/security-scan/cli.js +2 -2
  87. package/dist/security-scan/report.js +1 -1
  88. package/dist/session-watcher.js +33 -7
  89. package/dist/verify.js +166 -34
  90. package/eval/README.md +8 -8
  91. package/eval/fixtures/fx-codex-dry/caso.json +1 -1
  92. package/eval/fixtures/fx-happy/caso.json +1 -1
  93. package/eval/fixtures/fx-indice-reversao/caso.json +1 -1
  94. package/eval/fixtures/fx-listagem-abertas/caso.json +1 -1
  95. package/eval/fixtures/fx-omnicanal/caso.json +1 -1
  96. package/eval/fixtures/fx-pedido-colado/caso.json +1 -1
  97. package/eval/fixtures/fx-schema-drift/caso.json +1 -1
  98. package/package.json +1 -1
  99. package/references/testing-patterns.md +1 -1
  100. package/skills/core/orkastery-bootstrap/SKILL.md +1 -1
  101. package/skills/phases/check-quality/SKILL.md +1 -1
  102. package/skills/phases/go-implementation/SKILL.md +1 -1
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.ErroDaFilaPesada = exports.ENV_DONO_DA_FILA = exports.CONTRATO_FILA_PESADA = void 0;
37
+ exports.avaliarVidaDoOcupante = avaliarVidaDoOcupante;
37
38
  exports.kernelDisponivel = kernelDisponivel;
38
39
  exports.tentarTravaExclusiva = tentarTravaExclusiva;
39
40
  exports.dirDaFilaPesada = dirDaFilaPesada;
@@ -66,6 +67,7 @@ const fs = __importStar(require("node:fs"));
66
67
  const path = __importStar(require("node:path"));
67
68
  const node_crypto_1 = require("node:crypto");
68
69
  const node_child_process_1 = require("node:child_process");
70
+ const node_worker_threads_1 = require("node:worker_threads");
69
71
  const estado_thread_1 = require("./estado-thread");
70
72
  const horario_1 = require("./horario");
71
73
  exports.CONTRATO_FILA_PESADA = 'ork.fila-pesada/v1';
@@ -75,11 +77,27 @@ const FLOCK = '/usr/bin/flock';
75
77
  const DIR = 'fila-pesada';
76
78
  /** Entre uma tentativa e outra. A vez costuma durar minutos; meio segundo não pesa em ninguém. */
77
79
  const PAUSA_MS = 500;
80
+ /** A batida e complementar ao flock: atravessa a observacao de um sandbox com outro namespace de PID. */
81
+ const BATIDA_CADA_MS = 1_000;
82
+ const BATIDA_VALE_MS = 5_000;
83
+ function avaliarVidaDoOcupante(e) {
84
+ if (e.trava === 'ocupada')
85
+ return { vida: 'vivo', prova: 'trava-kernel' };
86
+ if (e.trava === 'livre')
87
+ return { vida: 'morto', prova: 'trava-livre' };
88
+ if (e.batidaValida)
89
+ return { vida: 'vivo', prova: 'batida' };
90
+ if (e.mesmoHost && e.mesmoEspacoPids && e.processo === 'vivo')
91
+ return { vida: 'vivo', prova: 'processo' };
92
+ if (e.mesmoHost && e.mesmoEspacoPids && e.processo === 'ausente')
93
+ return { vida: 'morto', prova: 'processo-ausente' };
94
+ return { vida: 'desconhecido', prova: 'indeterminada' };
95
+ }
78
96
  /** A recusa é resposta, não falha: o CLI a imprime como a da condução, e sai com 3. */
79
97
  class ErroDaFilaPesada extends Error {
80
98
  recusa;
81
99
  constructor(recusa) {
82
- super(`fila-pesada.ocupada: ${recusa.texto}`);
100
+ super(`${recusa.motivo}: ${recusa.texto}`);
83
101
  this.name = 'ErroDaFilaPesada';
84
102
  this.recusa = recusa;
85
103
  }
@@ -88,11 +106,17 @@ exports.ErroDaFilaPesada = ErroDaFilaPesada;
88
106
  function kernelDisponivel() {
89
107
  return process.platform === 'linux' && fs.existsSync(FLOCK);
90
108
  }
91
- /** O `flock` exclusivo sem espera sobre um descritor já aberto. O helper tranca a descrição de arquivo, que fica do processo. */
92
- function trancar(fd) {
109
+ /** Diferencia a contencao provada do erro de observacao; erro nunca vira trava livre. */
110
+ function observarTrava(fd) {
93
111
  const r = (0, node_child_process_1.spawnSync)(FLOCK, ['--exclusive', '--nonblock', '3'], { stdio: ['ignore', 'ignore', 'ignore', fd], timeout: 5000 });
94
- return r.status === 0 && !r.error;
112
+ if (!r.error && r.status === 0)
113
+ return 'adquirida';
114
+ if (!r.error && r.status === 1)
115
+ return 'ocupada';
116
+ return 'desconhecida';
95
117
  }
118
+ /** Tomar a trava exige prova positiva. Contencao e observacao inconclusiva falham fechadas. */
119
+ function trancar(fd) { return observarTrava(fd) === 'adquirida'; }
96
120
  function abrirTrava(arquivo, criar) {
97
121
  const fd = fs.openSync(arquivo, fs.constants.O_RDWR | fs.constants.O_NOFOLLOW | (criar ? fs.constants.O_CREAT : 0), 0o600);
98
122
  const st = fs.fstatSync(fd);
@@ -210,11 +234,57 @@ function minhaVez(dir, senha) {
210
234
  }
211
235
  return true;
212
236
  }
237
+ function hashLocal(valor) { return (0, node_crypto_1.createHash)('sha256').update(valor).digest('hex').slice(0, 24); }
238
+ /** Identidades opacas: provam igualdade sem publicar hostname, boot id ou inode do namespace. */
239
+ function identidadeDaMaquina() {
240
+ let host = null, espacoPids = null;
241
+ try {
242
+ host = hashLocal(fs.readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim());
243
+ }
244
+ catch { /* nao observavel */ }
245
+ try {
246
+ espacoPids = hashLocal(fs.readlinkSync('/proc/self/ns/pid'));
247
+ }
248
+ catch { /* nao observavel */ }
249
+ return { host, espacoPids };
250
+ }
213
251
  function gravarDono(fd, dono, posse) {
214
252
  const bytes = Buffer.from(JSON.stringify({ contrato: exports.CONTRATO_FILA_PESADA, ...dono, posse }) + '\n', 'utf8');
215
253
  fs.ftruncateSync(fd, 0);
216
254
  fs.writeSync(fd, bytes, 0, bytes.length, 0);
217
255
  }
256
+ function arquivoDaBatida(dir, slot, posse) {
257
+ return path.join(dir, `vaga-${slot}.${posse}.heartbeat.json`);
258
+ }
259
+ /** Worker nativo: a batida continua enquanto o verify sincrono bloqueia a thread JS, sem processo shell perdido. */
260
+ function iniciarBatida(dir, slot, posse) {
261
+ const arquivo = arquivoDaBatida(dir, slot, posse);
262
+ try {
263
+ const worker = new node_worker_threads_1.Worker(`
264
+ const fs = require('node:fs');
265
+ const { parentPort, workerData } = require('node:worker_threads');
266
+ const { randomUUID } = require('node:crypto');
267
+ let ativo = true;
268
+ parentPort.on('message', () => { ativo = false; });
269
+ function bater() {
270
+ if (!ativo) return;
271
+ const tmp = workerData.arquivo + '.' + randomUUID() + '.tmp';
272
+ try {
273
+ fs.writeFileSync(tmp, JSON.stringify({ contrato: 'ork.fila-pesada-heartbeat/v1', posse: workerData.posse,
274
+ expiraEm: new Date(Date.now() + workerData.validadeMs).toISOString() }) + '\\n', { flag: 'wx', mode: 0o600 });
275
+ fs.renameSync(tmp, workerData.arquivo);
276
+ } catch (_) { try { fs.unlinkSync(tmp); } catch (_) {} }
277
+ if (ativo) setTimeout(bater, workerData.intervaloMs);
278
+ }
279
+ bater();
280
+ `, { eval: true, workerData: { arquivo, posse, intervaloMs: BATIDA_CADA_MS, validadeMs: BATIDA_VALE_MS } });
281
+ worker.unref();
282
+ return { worker, arquivo };
283
+ }
284
+ catch {
285
+ return null;
286
+ }
287
+ }
218
288
  /** O artefato primeiro, depois a primeira vaga livre; sem vaga, solta o artefato. Nunca espera segurando nada. */
219
289
  function tentarVaga(dir, pedido) {
220
290
  const fdArtefato = tentarTravaExclusiva(path.join(dir, `artefato-${chaveDoArtefato(pedido.artefato)}.lock`));
@@ -224,17 +294,29 @@ function tentarVaga(dir, pedido) {
224
294
  const fdVaga = tentarTravaExclusiva(path.join(dir, `vaga-${slot}.lock`));
225
295
  if (fdVaga === null)
226
296
  continue;
227
- const dono = { slot, operacao: pedido.operacao, thread: pedido.thread, artefato: path.resolve(pedido.artefato),
228
- pid: process.pid, desde: new Date().toISOString() };
229
297
  const id = (0, node_crypto_1.randomUUID)();
298
+ const identidade = identidadeDaMaquina();
299
+ const dono = { slot, operacao: pedido.operacao, thread: pedido.thread, artefato: path.resolve(pedido.artefato),
300
+ pid: process.pid, desde: new Date().toISOString(), inicio: inicioDoProcesso(process.pid), ...identidade };
230
301
  gravarDono(fdVaga, dono, id);
231
302
  gravarDono(fdArtefato, dono, id);
232
- return { fdArtefato, fdVaga, slot, id };
303
+ const batida = iniciarBatida(dir, slot, id);
304
+ return { fdArtefato, fdVaga, slot, id, batida: batida?.worker ?? null, arquivoDaBatida: batida?.arquivo ?? null };
233
305
  }
234
306
  fs.closeSync(fdArtefato);
235
307
  return null;
236
308
  }
237
309
  function soltar(posse) {
310
+ try {
311
+ posse.batida?.postMessage('parar');
312
+ void posse.batida?.terminate();
313
+ }
314
+ catch { /* o processo tambem encerra o worker */ }
315
+ if (posse.arquivoDaBatida)
316
+ try {
317
+ fs.unlinkSync(posse.arquivoDaBatida);
318
+ }
319
+ catch { /* batida expira sozinha */ }
238
320
  for (const fd of [posse.fdVaga, posse.fdArtefato]) {
239
321
  try {
240
322
  fs.ftruncateSync(fd, 0);
@@ -264,7 +346,8 @@ function ocupantesDaFilaPesada(raiz) {
264
346
  continue;
265
347
  }
266
348
  try {
267
- if (trancar(fd))
349
+ const trava = observarTrava(fd);
350
+ if (trava === 'adquirida')
268
351
  continue;
269
352
  const slot = Number(/^vaga-(\d+)\.lock$/.exec(nome)[1]);
270
353
  let dono = {};
@@ -272,9 +355,31 @@ function ocupantesDaFilaPesada(raiz) {
272
355
  dono = JSON.parse(fs.readFileSync(path.join(dir, nome), 'utf8'));
273
356
  }
274
357
  catch { /* dono ainda gravando */ }
358
+ let batidaExpiraEm = null;
359
+ if (typeof dono.posse === 'string') {
360
+ try {
361
+ const batida = JSON.parse(fs.readFileSync(arquivoDaBatida(dir, slot, dono.posse), 'utf8'));
362
+ if (batida.posse === dono.posse && typeof batida.expiraEm === 'string')
363
+ batidaExpiraEm = batida.expiraEm;
364
+ }
365
+ catch { /* batida ausente, vencida ou ainda sendo publicada */ }
366
+ }
367
+ const local = identidadeDaMaquina();
368
+ const mesmoHost = typeof dono.host === 'string' && local.host === dono.host;
369
+ const mesmoEspacoPids = typeof dono.espacoPids === 'string' && local.espacoPids === dono.espacoPids;
370
+ let processo = 'desconhecido';
371
+ if (mesmoHost && mesmoEspacoPids && typeof dono.pid === 'number' && typeof dono.inicio === 'string') {
372
+ const atual = inicioDoProcesso(dono.pid);
373
+ processo = atual === dono.inicio ? 'vivo' : atual === null ? 'ausente' : 'ausente';
374
+ }
375
+ const estado = avaliarVidaDoOcupante({ trava: trava === 'ocupada' ? 'ocupada' : 'desconhecida',
376
+ batidaValida: batidaExpiraEm !== null && Date.parse(batidaExpiraEm) > Date.now(), mesmoHost, mesmoEspacoPids, processo });
275
377
  ocupantes.push({ slot, operacao: typeof dono.operacao === 'string' ? dono.operacao : 'desconhecida',
276
378
  thread: typeof dono.thread === 'string' ? dono.thread : null, artefato: typeof dono.artefato === 'string' ? dono.artefato : '',
277
- pid: typeof dono.pid === 'number' ? dono.pid : 0, desde: typeof dono.desde === 'string' ? dono.desde : '' });
379
+ pid: typeof dono.pid === 'number' ? dono.pid : 0, desde: typeof dono.desde === 'string' ? dono.desde : '',
380
+ inicio: typeof dono.inicio === 'string' ? dono.inicio : null, host: typeof dono.host === 'string' ? dono.host : null,
381
+ espacoPids: typeof dono.espacoPids === 'string' ? dono.espacoPids : null,
382
+ posse: typeof dono.posse === 'string' ? dono.posse : undefined, batidaExpiraEm, ...estado });
278
383
  }
279
384
  finally {
280
385
  fs.closeSync(fd);
@@ -283,19 +388,24 @@ function ocupantesDaFilaPesada(raiz) {
283
388
  return ocupantes;
284
389
  }
285
390
  function recusaDaFila(pedido, esperouMs, ocupantes) {
391
+ const indeterminado = ocupantes.some(o => o.vida === 'desconhecido');
392
+ const motivo = indeterminado ? 'concurrency.lease-indeterminado' : 'fila-pesada.ocupada';
286
393
  const espera = esperouMs < 60000 ? `${Math.round(esperouMs / 1000)} s` : `${Math.round(esperouMs / 60000)} min`;
287
394
  const linhas = [
288
395
  `Operação pesada não executada: ${pedido.operacao}${pedido.thread ? ` da thread ${pedido.thread}` : ''} esperou ${espera} ` +
289
396
  `e a fila de recursos pesados não liberou a vez (até ${pedido.slots} ao mesmo tempo, concurrency.max_parallel_heavy). ` +
290
397
  'Verify e build juntos nesta máquina dão regressão falsa.',
291
398
  ...(ocupantes.length ? ocupantes.map(o => ` Quem ocupa: ${o.operacao}${o.thread ? ` da thread ${o.thread}` : ''}, ` +
292
- `desde ${(0, horario_1.formatarDesde)(o.desde)}, processo ${o.pid}.`) : [' Quem ocupa: a vez é de outro pedido que chegou antes e ainda espera.']),
399
+ `desde ${(0, horario_1.formatarDesde)(o.desde)}, processo ${o.pid}${o.vida === 'desconhecido' ? '; vida indeterminada' : ''}.`) :
400
+ [' Quem ocupa: a vez é de outro pedido que chegou antes e ainda espera.']),
401
+ ...(indeterminado ? ['A vida do lease não pôde ser comprovada deste ambiente; “não sei” nunca é órfão. ' +
402
+ 'Espere com --esperar ou devolva à condução com concurrency.lease-indeterminado.'] : []),
293
403
  'O que você pode fazer:',
294
404
  ' 1. Esperar a vez: o dono da vaga segue rodando e, quando ele termina ou morre, a vaga volta sozinha.',
295
405
  ...(pedido.comandoDeEsperar ? [` ${pedido.comandoDeEsperar}`] : []),
296
406
  ' 2. Desligar a fila só nesta máquina, se ela aguenta: concurrency.max_parallel_heavy no orkastery.yaml (0 desliga).',
297
407
  ];
298
- return { contrato: 'ork.fila-pesada-recusa/v1', motivo: 'fila-pesada.ocupada', operacao: pedido.operacao, thread: pedido.thread,
408
+ return { contrato: 'ork.fila-pesada-recusa/v1', motivo, operacao: pedido.operacao, thread: pedido.thread,
299
409
  slots: pedido.slots, esperouMs, ocupantes, texto: linhas.join('\n') };
300
410
  }
301
411
  const pausa = new Int32Array(new SharedArrayBuffer(4));
@@ -204,7 +204,7 @@ function recusarIngressoNaoHomologado(ingresso) {
204
204
  }
205
205
  return ingresso;
206
206
  }
207
- /** Invariantes do registro. O teste chama isto; o produto tambem, no canario. */
207
+ /** Invariantes do registro. O teste chama isto; o produto tambem, no cenario. */
208
208
  function conferirRegistro() {
209
209
  const canais = canaisHomologados();
210
210
  if (canais.length !== hosts_1.ORDEM_DOS_HOSTS.length || canais.length !== 4) {
@@ -71,6 +71,7 @@ exports.MOTIVOS_DO_ORQUESTRADOR = Object.freeze([
71
71
  'verify.failed', 'verify.regression', 'verify.timeout', 'verify.sem-veredito',
72
72
  'claims.failed', 'claims.unverifiable', 'ci.failed', 'hitl.formato',
73
73
  'lease.busy', 'vaga.stale', 'conducao.em-andamento', 'concurrency.limite',
74
+ 'concurrency.lease-indeterminado', 'conducao.acao-necessaria',
74
75
  ]);
75
76
  function quemDecide(motivo) {
76
77
  return exports.MOTIVOS_DO_ORQUESTRADOR.includes(String(motivo ?? '')) ? 'orquestrador' : 'dono';
@@ -178,7 +178,7 @@ function pedidoHitlAberto(raiz, id, fase, sessionId) {
178
178
  /**
179
179
  * FX6: a oferta de canais que acompanha um pedido HITL REAL.
180
180
  *
181
- * `ofertaDeCanais` existia desde D12 e era chamada de um lugar so: o canario. No caminho de
181
+ * `ofertaDeCanais` existia desde D12 e era chamada de um lugar so: o cenario. No caminho de
182
182
  * producao o humano via a pergunta e um `comandoResposta`, e nada dizia por quais canais dava
183
183
  * para responder AGORA nem por que os outros nao serviam. Uma oferta que so aparece em
184
184
  * simulacao nao e oferta; e uma tabela bonita, como a propria narrativa de D12 admitia.
@@ -29,7 +29,7 @@ exports.linhaDoHitlAcimaDaMeta = linhaDoHitlAcimaDaMeta;
29
29
  * aberto nada disso ainda: a espera corre ate o fim do periodo.
30
30
  *
31
31
  * Limite dito: o "confirmo" que um condutor pede na conversa, fora do ork, nao chega ao ledger e
32
- * nao entra aqui. Por isso o canario `fx-pedido-colado` e a regra nos adaptadores existem.
32
+ * nao entra aqui. Por isso o cenario `fx-pedido-colado` e a regra nos adaptadores existem.
33
33
  *
34
34
  * Funcoes puras sobre eventos: nao leem disco nem relogio. Ausencia de pedido e zero pedidos, e a
35
35
  * mediana sem resposta e `null`, nunca zero inventado. A unica leitura de disco e
package/dist/index.js CHANGED
@@ -633,11 +633,12 @@ function comandoOnboarding(args) {
633
633
  if (sub === 'reset' && (args.posicionais.length > 3 || 'conteudo' in args.opcoes))
634
634
  invalido();
635
635
  if (sub === 'sync' && 'por' in args.opcoes)
636
- throw new Error('onboarding.input.invalid: sync não aceita --por; informe autoria em set ou reset.');
636
+ throw new Error((0, locale_1.msg)().onboarding.syncPor);
637
637
  const carregado = (0, manifest_1.exigirManifesto)(), raiz = carregado.raiz, por = texto(args.opcoes.por) ?? 'owner';
638
638
  if (sub === 'sync') {
639
- const r = (0, memoria_1.sincronizarOnboarding)(carregado);
640
- console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2) : `${r.regime}${r.motivo ? ` (${r.motivo})` : ''}: ${r.detalhe}`);
639
+ const r = (0, locale_1.comLocale)('pt-BR', () => (0, memoria_1.sincronizarOnboarding)(carregado));
640
+ console.log(args.opcoes.json === true ? JSON.stringify(r, null, 2)
641
+ : (0, locale_1.msg)().onboarding.syncResultado(r.regime, r.motivo, r.respondidas, r.gravadas, r.duplicadas, r.falhas));
641
642
  return 0;
642
643
  }
643
644
  let estado;
@@ -3042,7 +3043,7 @@ function comandoMaster(args) {
3042
3043
  return 0;
3043
3044
  }
3044
3045
  if (sub !== 'enviar')
3045
- throw new Error('uso: ork master digest <enviar|preview|responder>');
3046
+ throw new Error((0, locale_1.msg)().cli.masterDigestUso);
3046
3047
  const r = (0, master_digest_1.enviarDigest)({ raiz: carregado.raiz });
3047
3048
  console.log(JSON.stringify(r, null, 2));
3048
3049
  return r.code;
@@ -3062,14 +3063,14 @@ function comandoMaster(args) {
3062
3063
  const partes = (texto(args.opcoes.resposta) ?? '').trim().split(/\s+/);
3063
3064
  const classe = (0, master_2.parseClasse)(partes[3]);
3064
3065
  if (partes.length !== 4 || partes[0] !== 'ratificar' || !classe)
3065
- throw new Error('resposta deve ser ratificar <thread> <assinatura> <classe>');
3066
+ throw new Error((0, locale_1.msg)().cli.masterRatificarUso);
3066
3067
  selecao = [{ thread: partes[1], assinatura: partes[2], classe }];
3067
3068
  }
3068
3069
  else {
3069
3070
  selecao = (texto(args.opcoes.aceitar) ?? '').split(',').map(v => {
3070
3071
  const partes = v.trim().split(':');
3071
3072
  if (partes.length !== 2 || !/^[a-f0-9]{64}$/.test(partes[1]))
3072
- throw new Error('seleção deve ser thread:assinatura');
3073
+ throw new Error((0, locale_1.msg)().cli.masterSelecaoUso);
3073
3074
  return { thread: partes[0], assinatura: partes[1] };
3074
3075
  });
3075
3076
  }
@@ -3411,7 +3412,9 @@ function comandoDocs(args) {
3411
3412
  if (sub === 'verificar') {
3412
3413
  // RM-037 (fatia 3, GO-FIX 2): o CI passa --pr no pull_request; no push da main as duas regras novas reprovam.
3413
3414
  // RM-061 (F3b, G4): verifica no escopo pt-BR, como o `--json` leva os achados; o texto os remonta no locale do comando.
3414
- const { docs, achados } = (0, locale_1.comLocale)('pt-BR', () => (0, docs_1.verificarDocs)(raiz, { baseBranch, ajudaDoCli: AJUDA, pr: args.opcoes.pr === true }));
3415
+ const threadDaWorktree = (0, docs_1.escopoPadraoDoSync)(raiz).thread;
3416
+ const baseCarimbada = threadDaWorktree ? (0, thread_1.lerThread)(raiz, threadDaWorktree).base?.commit : undefined;
3417
+ const { docs, achados } = (0, locale_1.comLocale)('pt-BR', () => (0, docs_1.verificarDocs)(raiz, { baseBranch, baseCarimbada, ajudaDoCli: AJUDA, pr: args.opcoes.pr === true }));
3415
3418
  if (args.opcoes.json === true) {
3416
3419
  console.log(JSON.stringify({ paginas: docs.length, erros: achados.filter((a) => a.gravidade === 'erro').length,
3417
3420
  achados }, null, 2));
@@ -3619,9 +3622,9 @@ function comandoAdapter(args) {
3619
3622
  return 2;
3620
3623
  }
3621
3624
  /**
3622
- * `ork eval`: canarios de comportamento e o corpus das skills finas (bloco B4).
3625
+ * `ork eval`: cenarios de comportamento e o corpus das skills finas (bloco B4).
3623
3626
  *
3624
- * Skill sem eval nao entra, e comportamento sem canario tambem nao. O comando sai diferente
3627
+ * Skill sem eval nao entra, e comportamento sem cenario tambem nao. O comando sai diferente
3625
3628
  * de zero em qualquer falha, para o CI do kit poder barrar merge sem eval.
3626
3629
  */
3627
3630
  function comandoEval(args) {
@@ -3634,8 +3637,8 @@ function comandoEval(args) {
3634
3637
  const r = (0, evalrunner_1.rodarEval)({
3635
3638
  catalogo,
3636
3639
  skills: lista(args.opcoes.skill),
3637
- canarios: lista(args.opcoes.canario) ?? lista(args.opcoes.fixture),
3638
- soCanarios: args.opcoes['so-canarios'] === true,
3640
+ cenarios: lista(args.opcoes.cenario) ?? lista(args.opcoes.fixture),
3641
+ soCenarios: args.opcoes['so-cenarios'] === true,
3639
3642
  soSkills: args.opcoes['so-skills'] === true,
3640
3643
  });
3641
3644
  if (args.opcoes.json === true) {
@@ -4435,8 +4438,10 @@ function executarComando(argvBruto) {
4435
4438
  const projeto = proprio ? undefined : extraida.projeto;
4436
4439
  // Helper fixo do host confiável: o projeto vem da instalação, nunca de toolargs.
4437
4440
  if (argv[0] === 'receipt-verifiers') {
4438
- if (argv.length !== 2 || argv[1] !== '--json' || projeto !== undefined)
4439
- throw Error('uso: ork receipt-verifiers --json');
4441
+ if (argv.length !== 2 || argv[1] !== '--json' || projeto !== undefined) {
4442
+ (0, locale_1.ativarLocale)(localeDaAjuda());
4443
+ throw new locale_1.ErroDoCatalogo((m) => m.cli.receiptVerifiersUso);
4444
+ }
4440
4445
  const root = process.env.ORK_HITL_ROOT;
4441
4446
  const privateKey = Object.keys(process.env).some(name => /^ORK_HITL_(?:INGRESS_KEY|NATIVE_KEY)/.test(name));
4442
4447
  if (root !== undefined || privateKey) {
@@ -4452,13 +4457,14 @@ function executarComando(argvBruto) {
4452
4457
  return 0;
4453
4458
  }
4454
4459
  if (argv[0] === 'maestro') {
4460
+ const textos = (0, locale_1.msg)(localeDaAjuda(projeto)).maestro;
4455
4461
  if (argv.length === 2 && argv[1] === '--help')
4456
- return (0, maestro_cli_1.runMaestroCli)(argv.slice(1));
4462
+ return (0, maestro_cli_1.runMaestroCli)(argv.slice(1), process.cwd(), {}, undefined, textos);
4457
4463
  // RM-052: o alvo explicito vira SELECAO entre as raizes permitidas; sem ele, o cwd de sempre. O
4458
4464
  // snapshot ja declara o projeto consultado (project.root, notConsulted): sem a linha da fatia 2.
4459
4465
  const alvo = fixarAlvoDoProcesso(projeto, false);
4460
- return alvo ? (0, maestro_cli_1.runMaestroCli)(argv.slice(1), alvo.raiz, { allowedRoots: [alvo.raiz], selected: alvo.raiz })
4461
- : (0, maestro_cli_1.runMaestroCli)(argv.slice(1));
4466
+ return alvo ? (0, maestro_cli_1.runMaestroCli)(argv.slice(1), alvo.raiz, { allowedRoots: [alvo.raiz], selected: alvo.raiz }, undefined, textos)
4467
+ : (0, maestro_cli_1.runMaestroCli)(argv.slice(1), process.cwd(), {}, undefined, textos);
4462
4468
  }
4463
4469
  const args = parseArgs(argv);
4464
4470
  const comando = args.posicionais[0];
@@ -4472,14 +4478,21 @@ function executarComando(argvBruto) {
4472
4478
  console.log((0, locale_1.msg)().ajuda.texto(dadosDaAjuda()));
4473
4479
  return 0;
4474
4480
  }
4481
+ // F3e (D2): a recusa do projeto-alvo e os usos das rotas cobertas acontecem antes do manifesto efetivo.
4482
+ // Resolva a lingua aqui; `--json` continua fora e um `mcp serve` valido desliga o locale antes de servir.
4483
+ if ((0, locale_1.cobreLocale)(args.posicionais, args.opcoes)) {
4484
+ (0, locale_1.ativarLocale)(localeDaAjuda(projeto));
4485
+ (0, locale_1.ligarRemontagem)(true);
4486
+ }
4475
4487
  if (!COMANDOS_SEM_PROJETO.has(comando) && !proprio) {
4476
4488
  fixarAlvoDoProcesso(projeto, !SEM_DECLARACAO_DO_PROJETO.has(`${comando} ${args.posicionais[1] ?? ''}`.trim()));
4477
4489
  }
4478
4490
  else if (projeto !== undefined && comando !== 'projetos') {
4491
+ const mp = (0, locale_1.msg)().projetos;
4479
4492
  throw new Error(comando === 'init'
4480
- ? 'uso: ork init cria o projeto no diretório atual; entre nele e rode ork init, sem --projeto'
4481
- : comando === 'mcp' ? 'uso: o servidor MCP recebe a raiz por --project <raiz absoluta>, não por --projeto'
4482
- : `uso: ork ${comando} não lê projeto; tire --projeto`);
4493
+ ? mp.initNaoLeProjeto
4494
+ : comando === 'mcp' ? mp.mcpNaoLeProjeto
4495
+ : mp.comandoNaoLeProjeto(comando));
4483
4496
  }
4484
4497
  const nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)();
4485
4498
  const ambienteManifesto = (0, manifest_1.carregarManifesto)();
@@ -4495,10 +4508,6 @@ function executarComando(argvBruto) {
4495
4508
  // CLI por locale (RM-061, EN1 e EN7): a escolha do onboarding (owner.language) ou o LC_ALL/LC_MESSAGES/LANG
4496
4509
  // decidem a lingua do TEXTO dos comandos cobertos (`cobreLocale`); `--json` e contrato, e os recortes ainda
4497
4510
  // fora do catalogo (`doctor --modo` e os subcomandos fora da lista) ficam em pt-BR.
4498
- if ((0, locale_1.cobreLocale)(args.posicionais, args.opcoes)) {
4499
- (0, locale_1.ativarLocale)((0, locale_1.resolverLocale)(ambienteManifesto?.manifesto.owner?.language).locale);
4500
- (0, locale_1.ligarRemontagem)(true);
4501
- }
4502
4511
  switch (comando) {
4503
4512
  case 'mcp': {
4504
4513
  const projeto = texto(args.opcoes.project), host = texto(args.opcoes.host), threadId = texto(args.opcoes.thread);
@@ -4535,6 +4544,9 @@ function executarComando(argvBruto) {
4535
4544
  .catch(e => { console.error((0, locale_1.msg)().operacao.restante.mcp.erro(e.message)); process.exitCode = 1; });
4536
4545
  return 0;
4537
4546
  }
4547
+ // O servidor e contrato com hosts e nao ganha uma moldura inglesa por herdar o locale do erro de uso.
4548
+ (0, locale_1.ativarLocale)(undefined);
4549
+ (0, locale_1.ligarRemontagem)(false);
4538
4550
  void Promise.resolve().then(() => __importStar(require('./mcp-server'))).then(({ servirMcp }) => servirMcp({ projeto, host, threadId, dispatchId, nomesProviderHerdados: nomesHerdados, transporteShip: transporteShip, permissoesFilho: permissoesFilho })).catch(e => { console.error(`mcp: ${e.message}`); process.exitCode = 1; });
4539
4551
  return 0;
4540
4552
  }
@@ -4543,7 +4555,7 @@ function executarComando(argvBruto) {
4543
4555
  const bruto = texto(args.opcoes.modo);
4544
4556
  if (args.posicionais.length !== 1 || !bruto ||
4545
4557
  Object.keys(args.opcoes).some(k => k !== 'modo') || argv.filter(a => a === '--modo' || a.startsWith('--modo=')).length !== 1)
4546
- throw Error(`uso: ork doctor --modo ${modos_1.ORDEM_DOS_MODOS.join('|')}`);
4558
+ throw Error((0, locale_1.msg)().doctor.modoUso(modos_1.ORDEM_DOS_MODOS.join('|')));
4547
4559
  const r = (0, preflight_1.preflight)((0, manifest_1.diretorioDoProjeto)(), (0, modos_1.exigirModoVivo)(bruto), nomesHerdados);
4548
4560
  console.log((0, preflight_1.textoPreflight)(r));
4549
4561
  return r.prontoPrimeiroBloco ? 0 : 1;
@@ -4679,10 +4691,9 @@ function executarComando(argvBruto) {
4679
4691
  if (!host || !['claude-code', 'codex'].includes(host) || args.posicionais.length !== 3 ||
4680
4692
  Object.keys(args.opcoes).some(k => !['dry-run', 'json'].includes(k)) ||
4681
4693
  Object.values(args.opcoes).some(v => v !== true))
4682
- throw Error('uso: ork experiencia uninstall claude-code|codex [--dry-run] [--json]');
4694
+ throw Error((0, locale_1.msg)().onboarding.experienciaUninstallUso);
4683
4695
  const r = (0, hosts_2.desinstalarExperiencia)((0, manifest_1.exigirManifesto)().raiz, host, args.opcoes['dry-run'] === true);
4684
- console.log(args.opcoes.json ? JSON.stringify(r, null, 2) :
4685
- `${r.dryRun ? 'Simulação de remoção' : 'Remoção concluída'}: ${r.arquivos.length} arquivo(s). O adaptador permanece instalado. Para manter o pacote desativado, configure owner.experience:false no onboarding.`);
4696
+ console.log(args.opcoes.json ? JSON.stringify(r, null, 2) : (0, locale_1.msg)().onboarding.experienciaUninstall(r.dryRun, r.arquivos.length));
4686
4697
  return 0;
4687
4698
  }
4688
4699
  if ((args.posicionais[1] ?? 'show') !== 'show' || args.posicionais.length > 2 ||
@@ -4773,7 +4784,7 @@ function executarComando(argvBruto) {
4773
4784
  case 'recall':
4774
4785
  return comandoRecall(args);
4775
4786
  case 'brain': {
4776
- const result = (0, company_brain_cli_1.runBrain)((0, manifest_1.exigirManifesto)(), args.posicionais[1] ?? 'status', args.opcoes, args.posicionais.slice(2));
4787
+ const result = (0, locale_1.comLocale)('pt-BR', () => (0, company_brain_cli_1.runBrain)((0, manifest_1.exigirManifesto)(), args.posicionais[1] ?? 'status', args.opcoes, args.posicionais.slice(2)));
4777
4788
  console.log(JSON.stringify(result, null, 2));
4778
4789
  return ['ok', 'empty', 'unknown', 'withheld', 'applied', 'rolled-back'].includes(result.state) ? 0 : 1;
4779
4790
  }
@@ -4801,7 +4812,14 @@ function executarComando(argvBruto) {
4801
4812
  case 'ship':
4802
4813
  return comandoShip(args);
4803
4814
  case 'activation':
4804
- return (0, write_activation_1.comandoAtivacao)((0, manifest_1.exigirManifesto)(), args);
4815
+ try {
4816
+ return (0, locale_1.comLocale)('pt-BR', () => (0, write_activation_1.comandoAtivacao)((0, manifest_1.exigirManifesto)(), args));
4817
+ }
4818
+ catch (e) {
4819
+ if (e.message === 'uso: ork activation plan|status|enable|disable')
4820
+ throw new locale_1.ErroDoCatalogo((m) => m.cli.activationUso);
4821
+ throw e;
4822
+ }
4805
4823
  case 'lease':
4806
4824
  return comandoLease(args);
4807
4825
  case 'conducao':
package/dist/init.js CHANGED
@@ -267,7 +267,7 @@ policies:
267
267
  * exemplo) gravava manifesto, `AGENTS.md` e `.orkastery/` ali e saia 0; um repositorio criado depois
268
268
  * dentro dessa pasta herdava o manifesto de fora, com outro nome e outra abbrev, e o doctor dizia PRONTO.
269
269
  * A CLI recusa antes de gravar qualquer coisa. A funcao `init` segue aceitando qualquer pasta (demo e
270
- * canarios montam o projeto por ela).
270
+ * cenarios montam o projeto por ela).
271
271
  */
272
272
  function exigirRepositorioParaInit(dir) {
273
273
  const r = (0, util_1.exec)('git', ['rev-parse', '--is-inside-work-tree'], dir);
@@ -38,6 +38,7 @@ exports.descreverVersoes = descreverVersoes;
38
38
  exports.correcaoDosAnalisadores = correcaoDosAnalisadores;
39
39
  exports.checarAnalisadoresDoGrafo = checarAnalisadoresDoGrafo;
40
40
  exports.lerPedido = lerPedido;
41
+ exports.linhasDaExtracao = linhasDaExtracao;
41
42
  exports.situacaoNaArvore = situacaoNaArvore;
42
43
  exports.executarGrafo = executarGrafo;
43
44
  /**
@@ -128,6 +129,7 @@ exports.USO_DO_GRAFO = [
128
129
  exports.TEXTOS_DO_GRAFO = {
129
130
  uso: exports.USO_DO_GRAFO.split('\n'),
130
131
  erroUso: (motivo) => `grafo.uso: ${motivo}`,
132
+ erroTipado: (mensagem) => mensagem,
131
133
  motivos: {
132
134
  semSub: 'falta o subcomando', desconhecido: (sub) => `subcomando desconhecido: ${sub}`,
133
135
  repetida: (nome) => `--${nome} repetida`, semValor: (nome) => `--${nome} nao leva valor`,
@@ -149,6 +151,15 @@ exports.TEXTOS_DO_GRAFO = {
149
151
  naoConferido: (motivo) => ` incremental nao conferido: ${motivo}`,
150
152
  aprovado: 'aprovado',
151
153
  semBase: 'sem base',
154
+ extracao: {
155
+ lista: (itens) => itens.length ? ` (${itens.slice(0, 5).join(', ')}${itens.length > 5 ? ` e mais ${itens.length - 5}` : ''})` : '',
156
+ incremental: (base, alterados, novos, removidos) => ` extracao incremental a partir do indice de ${base}: ${alterados} alterado(s), ${novos} novo(s), ${removidos} removido(s)`,
157
+ tsInteiro: (motivo) => `TypeScript inteiro (${motivo ?? ''})`,
158
+ tsParcial: (reextraidos, lista, programa, reaproveitados) => `TypeScript parcial, ${reextraidos} reextraido(s)${lista} num programa de ${programa}, ${reaproveitados} da base`,
159
+ tsBase: (reaproveitados) => `TypeScript todo da base (${reaproveitados})`,
160
+ markdown: (reextraidos, lista, reaproveitados) => ` Markdown: ${reextraidos} reextraido(s)${lista}, ${reaproveitados} da base`,
161
+ completa: (motivo) => ` extracao completa${motivo ? `: ${motivo}` : ''}`,
162
+ },
152
163
  },
153
164
  status: {
154
165
  titulo: (head, arvore) => `grafo: HEAD ${head}, arvore ${arvore}`,
@@ -282,23 +293,24 @@ const contagem = (o) => Object.entries(o).map(([k, v]) => `${k}=${v}`).join(' ')
282
293
  /** Ate cinco caminhos e quantos ficaram de fora. */
283
294
  const alguns = (lista) => (lista.length ? ` (${lista.slice(0, 5).join(', ')}${lista.length > 5 ? ` e mais ${lista.length - 5}` : ''})` : '');
284
295
  /** KG4: como a extracao rodou, a base e o que veio dela, ou por que foi completa. */
285
- function linhasDaExtracao(r) {
296
+ function linhasDaExtracao(r, mi) {
286
297
  if (r.modo === null)
287
298
  return [];
288
299
  const a = r.reaproveitamento;
300
+ const me = mi.extracao;
289
301
  if (r.modo === 'incremental' && r.base && a) {
290
302
  // Desestruturado: o lint de horario le o campo de nome curto do TypeScript como instante.
291
303
  const { ts: doTs, md: doMd, mudanca } = a;
292
- const ts = doTs.modo === 'inteiro' ? `TypeScript inteiro (${doTs.motivo})`
293
- : doTs.modo === 'parcial' ? `TypeScript parcial, ${doTs.reextraidos.length} reextraido(s)${alguns(doTs.reextraidos)} num programa de ${doTs.programa}, ${doTs.reaproveitados} da base`
294
- : `TypeScript todo da base (${doTs.reaproveitados})`;
304
+ const ts = doTs.modo === 'inteiro' ? me.tsInteiro(doTs.motivo)
305
+ : doTs.modo === 'parcial' ? me.tsParcial(doTs.reextraidos.length, me.lista(doTs.reextraidos), doTs.programa, doTs.reaproveitados)
306
+ : me.tsBase(doTs.reaproveitados);
295
307
  return [
296
- ` extracao incremental a partir do indice de ${r.base.revision.slice(0, 12)}: ${mudanca.alterados} alterado(s), ${mudanca.novos} novo(s), ${mudanca.removidos} removido(s)`,
308
+ me.incremental(r.base.revision.slice(0, 12), mudanca.alterados, mudanca.novos, mudanca.removidos),
297
309
  ` ${ts}`,
298
- ` Markdown: ${doMd.reextraidos.length} reextraido(s)${alguns(doMd.reextraidos)}, ${doMd.reaproveitados} da base`,
310
+ me.markdown(doMd.reextraidos.length, me.lista(doMd.reextraidos), doMd.reaproveitados),
299
311
  ];
300
312
  }
301
- return [` extracao completa${r.motivo_completo ? `: ${r.motivo_completo}` : ''}`];
313
+ return [me.completa(r.motivo_completo)];
302
314
  }
303
315
  function indexar(ctx, p) {
304
316
  const r = (0, intelligence_graph_index_1.construirIndice)(ctx, { verificar: p.bandeiras.has('verificar'), forcar: p.bandeiras.has('forcar') });
@@ -314,7 +326,7 @@ function indexar(ctx, p) {
314
326
  mi.campo(mi.campos.conferencia, mi.conferencia(m.conferencia.fontes, m.conferencia.evidencias)),
315
327
  mi.campo(mi.campos.nos, contagem(m.contagens.nos)), mi.campo(mi.campos.arestas, contagem(m.contagens.arestas)),
316
328
  mi.campo(mi.campos.lugar, `${r.dir} (${mb(m.graph_bytes + m.report_bytes + m.units_bytes)})`),
317
- ...linhasDaExtracao(r),
329
+ ...linhasDaExtracao(r, mi),
318
330
  ];
319
331
  if (r.motivo)
320
332
  linhas.push(mi.campo(mi.campos.motivo, r.motivo));
@@ -757,6 +769,12 @@ const erroEmJson = (ctx, e, compacto, schema = intelligence_graph_query_1.CONSUL
757
769
  ctx.escrever(compacto ? JSON.stringify(r) : JSON.stringify(r, null, 2));
758
770
  return 1;
759
771
  };
772
+ /** Traduz a mensagem sem apagar a classe, os candidatos ou o stack do erro tipado. */
773
+ const erroHumano = (ctx, e) => {
774
+ const erro = e instanceof Error ? e : new Error(String(e));
775
+ erro.message = textosDe(ctx).erroTipado(erro.message);
776
+ return erro;
777
+ };
760
778
  /** `ork grafo <subcomando> ...`: devolve o codigo de saida; sem `--json`, o erro de uso ou tipado e lancado. */
761
779
  function executarGrafo(argv, ctx) {
762
780
  const schema = argv[0] === 'contexto' ? intelligence_graph_contexto_1.CONTEXTO_SCHEMA : intelligence_graph_query_1.CONSULTA_SCHEMA;
@@ -786,7 +804,7 @@ function executarGrafo(argv, ctx) {
786
804
  }
787
805
  catch (e) {
788
806
  if (!p.bandeiras.has('json'))
789
- throw e;
807
+ throw erroHumano(ctx, e);
790
808
  return erroEmJson(ctx, e, compacto, schema);
791
809
  }
792
810
  }
@@ -364,8 +364,8 @@ Uso: ork [--projeto <nome|caminho>] <comando> [argumentos]
364
364
  [--aceitar-catalogo <arquivo>] sobrescreve a copia com o catalogo, arquivo a arquivo
365
365
  [--manter-copia <arquivo>] deixa a copia como esta, arquivo a arquivo
366
366
 
367
- eval [--skill S] [--canario C] Canarios de comportamento + corpus das skills finas
368
- [--so-canarios] [--so-skills] [--json] (sai != 0 em qualquer falha)
367
+ eval [--skill S] [--cenario C] Cenarios de comportamento + corpus das skills finas
368
+ [--so-cenarios] [--so-skills] [--json] (sai != 0 em qualquer falha)
369
369
 
370
370
  audit packs [--estagio E] [--pack P] Os 7 packs, o estagio que os ativa e a postura
371
371
  audit run <pack> [--profile P] Monta o prompt do pack e despacha pelo runtime adapter
@@ -413,7 +413,7 @@ Fases: GOAL PLAN GO CHECK SHIP MASTER. Modos: ${v.tags}.
413
413
  Familias de lease: main-tree, worktree-write:<thread>, path:<glob>, board:<card>, service:<porta>.
414
414
  Ciclos: greenfield, merge-branch, goal-plan, gap, feature-xl-faseada.
415
415
  Fontes de medida do gate de tokens: runtime_reported, estimated, informada, unavailable.
416
- Hosts de Camada 1: claude-code, codex, hermes, openclaw. Canarios: fx-happy, fx-hallucination,
416
+ Hosts de Camada 1: claude-code, codex, hermes, openclaw. Cenarios: fx-happy, fx-hallucination,
417
417
  fx-stale-base, fx-wiki-destroy, fx-schema-drift, fx-concurrency.
418
418
  Packs de auditoria: clean-code, reuse, architecture, data-model, ux, security-privacy, process.
419
419
  Superficie de ataque de rede (SP8..SP12, varredura deterministica): rota sem auth, endpoint de
@@ -778,8 +778,8 @@ Usage: ork [--projeto <name|path>] <command> [arguments]
778
778
  [--aceitar-catalogo <file>] overwrites the copy with the catalog, file by file
779
779
  [--manter-copia <file>] keeps the copy as it is, file by file
780
780
 
781
- eval [--skill S] [--canario C] Behavior canaries + corpus of the thin skills
782
- [--so-canarios] [--so-skills] [--json] (exits != 0 on any failure)
781
+ eval [--skill S] [--cenario C] Behavior scenarios + corpus of the thin skills
782
+ [--so-cenarios] [--so-skills] [--json] (exits != 0 on any failure)
783
783
 
784
784
  audit packs [--estagio E] [--pack P] The 7 packs, the stage that activates them and the posture
785
785
  audit run <pack> [--profile P] Builds the pack prompt and dispatches through the runtime adapter
@@ -827,7 +827,7 @@ Phases: GOAL PLAN GO CHECK SHIP MASTER. Modes: ${v.tags}.
827
827
  Lease families: main-tree, worktree-write:<thread>, path:<glob>, board:<card>, service:<port>.
828
828
  Cycles: greenfield, merge-branch, goal-plan, gap, feature-xl-faseada.
829
829
  Token gate measurement sources: runtime_reported, estimated, informada, unavailable.
830
- Layer 1 hosts: claude-code, codex, hermes, openclaw. Canaries: fx-happy, fx-hallucination,
830
+ Layer 1 hosts: claude-code, codex, hermes, openclaw. Scenarios: fx-happy, fx-hallucination,
831
831
  fx-stale-base, fx-wiki-destroy, fx-schema-drift, fx-concurrency.
832
832
  Audit packs: clean-code, reuse, architecture, data-model, ux, security-privacy, process.
833
833
  Network attack surface (SP8..SP12, deterministic scan): route without auth, exposed admin