@orkastery/cli 0.4.3 → 0.5.0

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 (121) hide show
  1. package/adapters/README.md +11 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +3 -1
  3. package/adapters/claude-code/agents/ork-check.md +1 -1
  4. package/adapters/claude-code/agents/ork-go.md +2 -2
  5. package/adapters/claude-code/agents/ork-goal.md +1 -1
  6. package/adapters/claude-code/agents/ork-master.md +1 -1
  7. package/adapters/claude-code/agents/ork-plan.md +1 -1
  8. package/adapters/claude-code/agents/ork-ship.md +1 -1
  9. package/adapters/claude-code/commands/master.md +11 -8
  10. package/adapters/claude-code/commands/ork.md +8 -0
  11. package/adapters/claude-code/commands/ship.md +2 -2
  12. package/adapters/codex/skills/ork/SKILL.md +12 -1
  13. package/adapters/hermes/README.md +3 -0
  14. package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
  15. package/adapters/hermes/bin/ork-brain.sh +3 -0
  16. package/adapters/hermes/bin/ork-maestro.sh +4 -1
  17. package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
  18. package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
  19. package/adapters/hermes/hermes.plugin.json +2 -0
  20. package/adapters/hermes/hitl-ingress/__init__.py +36 -3
  21. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
  22. package/adapters/openclaw/README.md +34 -2
  23. package/adapters/openclaw/dist/hitl-ingress.js +37 -3
  24. package/adapters/openclaw/dist/index.js +92 -20
  25. package/adapters/openclaw/openclaw.plugin.json +10 -1
  26. package/adapters/openclaw/package.json +2 -2
  27. package/adapters/openclaw/src/hitl-ingress.ts +32 -3
  28. package/adapters/openclaw/src/index.ts +108 -20
  29. package/assets/docs/padroes/documentacao-de-produto.md +2 -2
  30. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  31. package/assets/docs/produto/_modelo-feature.md +2 -0
  32. package/assets/orkmind_bridge.py +214 -1
  33. package/dist/adapters/claude-bg.js +6 -3
  34. package/dist/board.js +74 -0
  35. package/dist/branch-de-estado.js +5 -4
  36. package/dist/busca-semantica.js +161 -0
  37. package/dist/ci.js +141 -10
  38. package/dist/company-brain-cli.js +27 -2
  39. package/dist/company-brain-context.js +132 -0
  40. package/dist/company-brain-dossie.js +376 -0
  41. package/dist/company-brain-mcp.js +4 -1
  42. package/dist/conducao.js +71 -18
  43. package/dist/decisao-autonoma.js +42 -0
  44. package/dist/docs.js +64 -22
  45. package/dist/doctor.js +33 -0
  46. package/dist/entrega-pr.js +109 -5
  47. package/dist/experiencia-instalacao.js +256 -0
  48. package/dist/experiencia.js +72 -0
  49. package/dist/fabrica-estado.js +43 -10
  50. package/dist/fechamento.js +105 -0
  51. package/dist/forja.js +435 -0
  52. package/dist/gates.js +9 -1
  53. package/dist/hitl-classificacao.js +11 -1
  54. package/dist/hitl-contract.js +50 -7
  55. package/dist/hitl-curto.js +158 -0
  56. package/dist/hitl-gates.js +67 -1
  57. package/dist/hitl-lote.js +30 -15
  58. package/dist/hitl-presentation.js +10 -7
  59. package/dist/hitl-resumo.js +33 -12
  60. package/dist/hitl-texto-livre.js +150 -0
  61. package/dist/hosts.js +86 -1
  62. package/dist/index.js +602 -38
  63. package/dist/indice-vetorial.js +317 -0
  64. package/dist/init.js +13 -0
  65. package/dist/integracoes-locais.js +1 -1
  66. package/dist/intelligence-benchmark-contract.js +570 -0
  67. package/dist/intelligence-graph-cli.js +430 -0
  68. package/dist/intelligence-graph-contract.js +577 -0
  69. package/dist/intelligence-graph-extract-md.js +469 -0
  70. package/dist/intelligence-graph-extract-ts.js +810 -0
  71. package/dist/intelligence-graph-extract.js +369 -0
  72. package/dist/intelligence-graph-index.js +512 -0
  73. package/dist/intelligence-graph-parsers.js +327 -0
  74. package/dist/intelligence-graph-query.js +344 -0
  75. package/dist/intelligence-graph-repo.js +187 -0
  76. package/dist/leases.js +84 -0
  77. package/dist/ledger.js +14 -0
  78. package/dist/maestro-cli.js +10 -1
  79. package/dist/maestro-contract.js +5 -1
  80. package/dist/maestro-discovery.js +16 -2
  81. package/dist/maestro-snapshot.js +6 -2
  82. package/dist/manifest.js +142 -5
  83. package/dist/master-batch.js +3 -2
  84. package/dist/master-digest.js +2 -2
  85. package/dist/master-nota.js +203 -0
  86. package/dist/master.js +4 -0
  87. package/dist/mcp-experiencia.js +164 -0
  88. package/dist/mcp-git.js +4 -0
  89. package/dist/mcp-install.js +3 -1
  90. package/dist/mcp-maestro.js +3 -2
  91. package/dist/mcp-server.js +84 -5
  92. package/dist/memoria.js +147 -1
  93. package/dist/network-roadmap.js +907 -0
  94. package/dist/ocupacao.js +38 -2
  95. package/dist/onboarding.js +113 -7
  96. package/dist/orkmind.js +165 -9
  97. package/dist/phase.js +166 -13
  98. package/dist/policies.js +2 -0
  99. package/dist/projeto-alvo.js +551 -0
  100. package/dist/prompts.js +1 -1
  101. package/dist/pulse-consentimento.js +4 -2
  102. package/dist/pulse-delivery.js +5 -0
  103. package/dist/pulse-resposta.js +674 -49
  104. package/dist/pulse.js +21 -0
  105. package/dist/retry.js +51 -8
  106. package/dist/roadmap-reservas.js +262 -20
  107. package/dist/roadmap-status.js +213 -0
  108. package/dist/thread-close.js +3 -0
  109. package/dist/verify.js +4 -3
  110. package/eval/casos/orchestration-experience-pt-br.json +48 -0
  111. package/eval/casos/orchestration-experience.json +48 -0
  112. package/package.json +1 -1
  113. package/schemas/code-artifact-graph.v1.schema.json +581 -0
  114. package/schemas/graph-benchmark.v1.schema.json +2240 -0
  115. package/schemas/maestro-snapshot.schema.json +23 -0
  116. package/skills/README.md +7 -5
  117. package/skills/core/onboarding/SKILL.md +7 -0
  118. package/skills/core/orchestration-experience/SKILL.md +113 -0
  119. package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
  120. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  121. package/skills/phases/go-implementation/SKILL.md +2 -0
package/dist/phase.js CHANGED
@@ -43,11 +43,14 @@ exports.valoresDoPrompt = valoresDoPrompt;
43
43
  exports.montarPrompt = montarPrompt;
44
44
  exports.montarPromptComMemoria = montarPromptComMemoria;
45
45
  exports.hashDoPrompt = hashDoPrompt;
46
+ exports.modoDaSessaoDoBloco = modoDaSessaoDoBloco;
46
47
  exports.slugDaSessao = slugDaSessao;
47
48
  exports.resolverDespacho = resolverDespacho;
48
49
  exports.dadosDoDespacho = dadosDoDespacho;
49
50
  exports.concluirDespacho = concluirDespacho;
50
51
  exports.prazoDaSessao = prazoDaSessao;
52
+ exports.baselineDoDespachoNecessaria = baselineDoDespachoNecessaria;
53
+ exports.garantirBaselineDoDespacho = garantirBaselineDoDespacho;
51
54
  exports.rodarFase = rodarFase;
52
55
  exports.tabelaDoLedger = tabelaDoLedger;
53
56
  exports.descreverSlug = descreverSlug;
@@ -64,6 +67,8 @@ const runtime_context_1 = require("./runtime-context");
64
67
  const node_crypto_1 = require("node:crypto");
65
68
  const fs = __importStar(require("node:fs"));
66
69
  const path = __importStar(require("node:path"));
70
+ const board_1 = require("./board");
71
+ const verify_1 = require("./verify");
67
72
  const session_watcher_1 = require("./session-watcher");
68
73
  const session_watcher_claude_1 = require("./session-watcher-claude");
69
74
  const runtimes_1 = require("./runtimes");
@@ -328,6 +333,20 @@ function schemaDeClaimsDoPacote() {
328
333
  throw new Error('runtime.unavailable: schema de claims nao encontrado no pacote');
329
334
  return JSON.parse(fs.readFileSync(arquivo, 'utf8'));
330
335
  }
336
+ /**
337
+ * RM-037 (rm037defeito, defeito 2): o modo da sessao sai do BLOCO, nao da fase de entrada. O modo plano
338
+ * (codex em `collaborationMode: plan`; claude-bg sem Edit/Write e com MCP so de consulta) e o review
339
+ * nativo do codex (`review/start`) valem para a sessao inteira. Aplicados pela fase de entrada, o PLAN
340
+ * redespachado de um bloco GOAL..MASTER abria a sessao em modo plano e ela nao podia seguir para o GO
341
+ * (rollout 01a0ed23, 29/09/2026), e o CHECK de entrada no codex so revisava, sem SHIP nem MASTER. Os
342
+ * dois modos ficam para o bloco que termina na propria fase de entrada. Domicilio unico: `ork phase run`
343
+ * e o redespacho do `ork retry` leem daqui.
344
+ */
345
+ function modoDaSessaoDoBloco(thread, fase) {
346
+ const bloco = (0, thread_1.blocoDaThread)(thread, fase);
347
+ const terminaNaEntrada = bloco.fases[bloco.fases.length - 1] === fase;
348
+ return { plano: fase === 'PLAN' && terminaNaEntrada, revisaoNativa: fase === 'CHECK' && terminaNaEntrada };
349
+ }
331
350
  /** Slug da sessao que conduz esta fase, rotacionando quando o slug ja foi usado na thread. */
332
351
  function slugDaSessao(thread, fase) {
333
352
  const bloco = (0, thread_1.blocoDaThread)(thread, fase);
@@ -521,22 +540,100 @@ function registrarObservacao(ctx, sessao, dir, controlador, sensores) {
521
540
  origem: 'phase.dispatch', ...(controlador ? { controlador } : {}) });
522
541
  }
523
542
  }
543
+ /**
544
+ * RM-037 (rm037defeito, defeito 1): o despacho precisa gravar a baseline antes de soltar o bloco? O codex
545
+ * roda em sandbox que so grava a worktree; o estado canonico fica fora dela, e `ork verify --baseline`
546
+ * de dentro da sessao morre em EROFS (rollouts 01a0ecff e 01a0ed16, 29/09/2026). A sessao parava antes
547
+ * do GO, porque a skill exige a baseline antes da primeira linha. Vale para o despacho real do codex
548
+ * com sandbox que nao grava o estado, num bloco que tem GO a partir da entrada, sem baseline gravada.
549
+ */
550
+ function baselineDoDespachoNecessaria(carregado, threadId, opcoes) {
551
+ if (opcoes.dryRun)
552
+ return false;
553
+ const { raiz, manifesto } = carregado;
554
+ const thread = (0, thread_1.lerThread)(raiz, threadId);
555
+ if (thread.status === 'fechada')
556
+ return false;
557
+ // Pedido que nem resolve o trio (runtime trocado sem modelo) recebe a recusa do proprio despacho.
558
+ let runtime;
559
+ try {
560
+ runtime = resolverDespacho(manifesto, opcoes, (0, setup_1.configDoBloco)((0, setup_1.lerSetup)(raiz), thread.modo, opcoes.fase)).runtime;
561
+ }
562
+ catch {
563
+ return false;
564
+ }
565
+ if (runtime !== 'codex' || manifesto.runtime.sandbox === 'danger-full-access')
566
+ return false;
567
+ const bloco = (0, thread_1.blocoDaThread)(thread, opcoes.fase);
568
+ if (!bloco.fases.slice(bloco.fases.indexOf(opcoes.fase)).includes('GO'))
569
+ return false;
570
+ return !(0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, thread.id)).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.baselineGravada);
571
+ }
572
+ /**
573
+ * Grava a baseline do despacho quando ela e necessaria, pela mesma `gravarBaseline` do CLI e fora do lock
574
+ * HITL. O despacho (`ork phase run`, e o redespacho do `ork retry` quando o fallback leva ao codex) chega
575
+ * aqui depois de passar por todos os portoes e RETENDO a conducao que tomou (B-1 e A-1r do CHECK 4): a
576
+ * baseline roda como reentrada dessa mesma conducao, sem `conducao_recusada` e sem soltar a reserva do dono
577
+ * ou a sessao bloqueada que a tomada sucedeu. A segunda passada do despacho usa a tomada retida.
578
+ */
579
+ function garantirBaselineDoDespacho(carregado, threadId, opcoes, identidade) {
580
+ if (!baselineDoDespachoNecessaria(carregado, threadId, opcoes))
581
+ return;
582
+ try {
583
+ (0, verify_1.gravarBaseline)(carregado, threadId, undefined, { canal: opcoes.canal ?? (0, conducao_1.canalDoProcesso)(), correlacao: opcoes.correlacao ?? null, ...(identidade ? { identidade } : {}) }, 'phase.run');
584
+ }
585
+ catch (e) {
586
+ if (!(e instanceof conducao_1.ErroDeConducao))
587
+ throw e;
588
+ }
589
+ }
524
590
  /** Despacha a fase pelo runtime adapter e registra tudo no ledger da thread. */
525
591
  function rodarFase(carregado, threadId, opcoes) {
526
- const rodar = () => opcoes.dryRun ? rodarFaseSobLock(carregado, threadId, opcoes) :
527
- (0, hitl_gates_1.comLockHitl)(carregado.raiz, threadId, () => rodarFaseSobLock(carregado, threadId, opcoes));
592
+ const rodar = (retida) => opcoes.dryRun ? rodarFaseSobLock(carregado, threadId, opcoes) :
593
+ (0, hitl_gates_1.comLockHitl)(carregado.raiz, threadId, () => rodarFaseSobLock(carregado, threadId, opcoes, retida));
528
594
  // I-36 (D2): `--esperar` espera a vez FORA do lock HITL (que serializa respostas do dono) e so
529
595
  // depois repete o pedido. Sem ele, a recusa sai na hora.
596
+ // RM-037 (defeito 3): a vaga do projeto espera do mesmo jeito, fora do lock, antes de repetir.
530
597
  const prazo = opcoes.esperarMs && opcoes.esperarMs > 0 && !opcoes.dryRun ? Date.now() + opcoes.esperarMs : null;
531
598
  for (;;) {
532
- if (prazo)
599
+ if (prazo) {
533
600
  (0, conducao_1.esperarConducaoLivre)(carregado.raiz, threadId, Math.max(0, prazo - Date.now()));
534
- const r = rodar();
535
- if (r.motivo !== 'conducao.em-andamento' || !prazo || Date.now() >= prazo)
601
+ (0, board_1.esperarVaga)(carregado, threadId, Math.max(0, prazo - Date.now()));
602
+ }
603
+ let r = rodar();
604
+ // RM-037 (defeito 1; N3 e G2 do CHECK 2, B-1 e A-1r do CHECK 4): o despacho so pede a baseline depois de
605
+ // passar por todos os portoes, retendo a conducao que tomou (orfa liberada, sucessao feita, reserva
606
+ // usada). Ela e gravada aqui, fora do lock HITL (que e nao bloqueante e recusaria respostas do dono por
607
+ // minutos), como reentrada da tomada retida, e o despacho repete uma vez com ela. No MCP, que nao roda a
608
+ // suite, a pendencia volta como esta e a tomada ja foi devolvida.
609
+ const retida = r.retida;
610
+ if (retida) {
611
+ delete r.retida;
612
+ // A segunda passada converte a tomada em sessao ou a devolve; devolver de novo e inocuo, e o `finally`
613
+ // cobre tambem a excecao (lock HITL ocupado, por exemplo: R5-A1 do CHECK 5).
614
+ try {
615
+ garantirBaselineDoDespacho(carregado, threadId, opcoes, retida.identidade);
616
+ r = rodar(retida);
617
+ }
618
+ finally {
619
+ retida.devolver();
620
+ }
621
+ }
622
+ const esperavel = r.motivo === 'conducao.em-andamento' || r.motivo === 'concurrency.limite';
623
+ if (!esperavel || !prazo || Date.now() >= prazo)
536
624
  return r;
625
+ // S-5 do CHECK 3: a vaga pode ter sido tomada entre a espera e a tomada; espera um pouco antes de repetir.
626
+ if (r.motivo === 'concurrency.limite')
627
+ (0, conducao_1.dormir)(Math.min(2000, Math.max(0, prazo - Date.now())));
537
628
  }
538
629
  }
539
- function rodarFaseSobLock(carregado, threadId, opcoes) {
630
+ function rodarFaseSobLock(carregado, threadId, opcoes,
631
+ /**
632
+ * A tomada que a primeira passada reteve para a baseline (CHECK 4). Com ela, esta e a repeticao: nao toma a
633
+ * conducao de novo e nao grava de novo os avisos da primeira passada (S-1 do CHECK 3).
634
+ */
635
+ tomadaPrevia) {
636
+ const segundaPassada = tomadaPrevia !== undefined;
540
637
  const { raiz, manifesto } = carregado;
541
638
  const thread = (0, thread_1.lerThread)(raiz, threadId);
542
639
  const fase = opcoes.fase;
@@ -566,12 +663,15 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
566
663
  gate: 'phase.dispatch', prompt, threadId: thread.id, modo: thread.modo, fase,
567
664
  bloco: thread.blocos.indexOf(blocoDespachado) + 1,
568
665
  blocoComGo: blocoDespachado.fases.includes('GO'),
569
- temBaseline: (0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.baselineGravada),
666
+ // RM-037 (defeito 1): a baseline que o proprio despacho vai gravar conta como existente. O ensaio conta a
667
+ // que o despacho real gravaria (S2 do CHECK final), para nao mandar rodar a baseline que o CLI ja grava.
668
+ temBaseline: (0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.baselineGravada) ||
669
+ (opcoes.baselinePeloDespacho !== false && baselineDoDespachoNecessaria(carregado, thread.id, { ...opcoes, dryRun: false })),
570
670
  fallbackDoBloco: (0, setup_1.fallbackDoBloco)(setup, thread.modo, fase),
571
671
  });
572
672
  const bloqueiam = (0, policies_1.bloqueantes)(violacoes);
573
673
  // Warn registra e segue: o aviso vai ao ledger (fora do ensaio) e o despacho continua.
574
- if (!opcoes.dryRun) {
674
+ if (!opcoes.dryRun && !segundaPassada) {
575
675
  for (const v of (0, policies_1.avisos)(violacoes)) {
576
676
  (0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.politicaAviso, { gate: 'phase.dispatch', fase, slug,
577
677
  policy: v.policy, detalhe: v.detalhe, correcao: v.correcao, modo: thread.modo });
@@ -633,7 +733,9 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
633
733
  }
634
734
  // I-36 (T7, T14): validado o pedido, a conducao da thread, antes de tocar a worktree. A mesma fase com o
635
735
  // mesmo prompt de quem conduz devolve a sessao em andamento sem chamar o adapter; outro pedido recebe a recusa.
636
- const identidade = (0, runtime_context_1.novaIdentidadeDeDespacho)(thread.id, fase);
736
+ // Na repeticao, a identidade e a da tomada retida: a sessao reentra pela identidade gravada no lease (D4).
737
+ const identidade = tomadaPrevia ? { ...(0, runtime_context_1.novaIdentidadeDeDespacho)(thread.id, fase), dispatchId: tomadaPrevia.identidade }
738
+ : (0, runtime_context_1.novaIdentidadeDeDespacho)(thread.id, fase);
637
739
  const canal = opcoes.canal ?? (0, conducao_1.canalDoProcesso)();
638
740
  const pedidoDeConducao = { canal, correlacao: opcoes.correlacao ?? null, operacao: 'phase.run', fase,
639
741
  promptSha256: sha, identidade: identidade.dispatchId, prazoMs: prazoDaSessao(limites) };
@@ -654,12 +756,38 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
654
756
  return { ...base, sessionId: null, bloqueado: true, motivo: 'conducao.em-andamento', erro: recusa.texto, recusa,
655
757
  ...(atual ? { conducao: atual } : {}) };
656
758
  };
759
+ // RM-037 (defeito 3): o limite de sessoes do projeto vale no despacho, nao so no board. A recusa nao abre
760
+ // sessao nem toca a worktree; o `slot_refused` e a prova, fora da conta de atividade da thread.
761
+ const recusaPorVaga = (semVaga) => {
762
+ if (!opcoes.dryRun) {
763
+ (0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.vagaRecusada, { gate: 'phase.dispatch', motivo: 'concurrency.limite', fase, slug,
764
+ limite: semVaga.limite, ocupam: semVaga.ocupam, detalhe: semVaga.detalhe, correcao: semVaga.correcao,
765
+ evidencia: 'conducao exec:<thread> de sessao viva nas outras threads do projeto' });
766
+ }
767
+ return { thread, slug, promptPath, promptSha256: sha, comando: [], sessionId: null,
768
+ verificada: false, pausaAoFim: (0, thread_1.pausaNaThread)(thread, fase), dryRun: opcoes.dryRun === true,
769
+ runtime, model, effort, bloqueado: true, motivo: 'concurrency.limite', violacoes, erro: `${semVaga.detalhe}; ${semVaga.correcao}`,
770
+ vaga: semVaga };
771
+ };
657
772
  let conducao = null;
658
773
  if (opcoes.dryRun) {
659
774
  // O ensaio nao toma nada, mas diz a verdade: com conducao em andamento, o despacho real seria recusado.
660
775
  const atual = (0, conducao_1.conducaoDaThread)(raiz, thread.id);
661
776
  if (atual)
662
777
  return ocupadaPor({ ok: false, idempotente: atual.fase === fase && atual.promptSha256 === sha, atual }, false);
778
+ const semVaga = (0, board_1.vagaDoDespacho)(carregado, thread.id);
779
+ if (semVaga)
780
+ return recusaPorVaga(semVaga);
781
+ }
782
+ else if (tomadaPrevia) {
783
+ // R5-B1 do CHECK 5: entre a sucessao da sessao blocked (1a passada) e aqui, a suite rodou com o lock HITL
784
+ // livre. Sob o lock de novo, o runtime confirma que a sucedida continua parada; se o dono a respondeu,
785
+ // ela recebe o lease de volta e este pedido espera a vez.
786
+ if (!tomadaPrevia.sucessaoAindaVale()) {
787
+ tomadaPrevia.devolver();
788
+ return ocupadaPor({ ok: false, idempotente: false, atual: (0, conducao_1.conducaoDaThread)(raiz, thread.id) }, true);
789
+ }
790
+ conducao = tomadaPrevia;
663
791
  }
664
792
  else {
665
793
  const tomada = (0, conducao_1.tomarConducao)(raiz, thread.id, pedidoDeConducao);
@@ -668,6 +796,29 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
668
796
  conducao = tomada;
669
797
  }
670
798
  try {
799
+ if (conducao) {
800
+ // A vaga e a baseline sao conferidas COM a conducao tomada (N2, N3 do CHECK 2): a tomada consulta o
801
+ // runtime, libera a orfa e faz a sucessao, e nenhum desses caminhos pode furar o limite nem soltar o
802
+ // codex sem baseline. Quem recusa antes da sessao DEVOLVE o que a tomada consumiu (A-1 do CHECK 3),
803
+ // pelo `finally`.
804
+ const semVaga = (0, board_1.vagaDoDespacho)(carregado, thread.id, undefined, (0, conducao_1.conducaoDaThread)(raiz, thread.id)?.desde);
805
+ if (semVaga)
806
+ return recusaPorVaga(semVaga);
807
+ if (baselineDoDespachoNecessaria(carregado, thread.id, opcoes)) {
808
+ const erro = `baseline.pendente: o bloco com GO no ${runtime} precisa da baseline antes do despacho` +
809
+ (opcoes.baselinePeloDespacho === false ? ', e o MCP nao roda a suite' : ', e ela nao foi gravada') +
810
+ `; rode ork verify ${thread.id} --baseline pelo CLI e repita o despacho`;
811
+ const pendente = { thread, slug, promptPath, promptSha256: sha, comando: [], sessionId: null,
812
+ verificada: false, pausaAoFim: (0, thread_1.pausaNaThread)(thread, fase), dryRun: false,
813
+ runtime, model, effort, bloqueado: true, motivo: 'baseline.pendente', violacoes, erro };
814
+ // Na primeira passada do CLI e do retry, a tomada fica retida para a baseline (o `finally` nao a solta).
815
+ if (opcoes.baselinePeloDespacho !== false && !segundaPassada) {
816
+ pendente.retida = conducao;
817
+ conducao = null;
818
+ }
819
+ return pendente;
820
+ }
821
+ }
671
822
  const cwd = thread.worktree ?? raiz;
672
823
  let contextoRuntime;
673
824
  try {
@@ -738,6 +889,7 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
738
889
  });
739
890
  }
740
891
  const pausaAoFim = (0, thread_1.pausaNaThread)(thread, fase);
892
+ const modoDaSessao = modoDaSessaoDoBloco(thread, fase);
741
893
  const claimsSchema = fase === 'GO' && runtime === 'codex'
742
894
  ? schemaDeClaimsDoPacote()
743
895
  : undefined;
@@ -755,12 +907,12 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
755
907
  vinculo: { thread: thread.id, fase, promptSha256: sha },
756
908
  contextoRuntime,
757
909
  ...(perfil ? { perfil } : {}),
758
- ...(fase === 'PLAN' ? { colaboracao: 'plan' } : {}),
910
+ ...(modoDaSessao.plano ? { colaboracao: 'plan' } : {}),
759
911
  ...(claimsSchema ? { outputSchema: claimsSchema } : {}),
760
912
  // `thread.base.branch` vira a branch fonte quando a thread ganha worktree
761
913
  // (`ork/<slug>`). O review nativo precisa comparar essa fonte com a base de
762
914
  // integração do projeto; usar a própria fonte produz um diff vazio.
763
- ...(fase === 'CHECK' && runtime === 'codex' ? { reviewBaseBranch: manifesto.worktree.base_branch } : {}),
915
+ ...(modoDaSessao.revisaoNativa && runtime === 'codex' ? { reviewBaseBranch: manifesto.worktree.base_branch } : {}),
764
916
  ...(limites ? { duracaoMaximaMs: limites.duracaoMs } : {}),
765
917
  // I-36 (D4): a sessao filha herda a identidade do despacho e o canal; e assim que ela reentra.
766
918
  ambienteExtra: (0, conducao_1.ambienteDaConducao)(identidade.dispatchId, thread.id, canal),
@@ -929,8 +1081,9 @@ function rodarFaseSobLock(carregado, threadId, opcoes) {
929
1081
  };
930
1082
  }
931
1083
  finally {
932
- // Despacho que nao virou sessao devolve a conducao; o que virou ja a entregou a sessao.
933
- conducao?.liberar();
1084
+ // Despacho que nao virou sessao devolve a conducao, com o que a tomada consumiu (reserva do canal, sessao
1085
+ // blocked sucedida); o que virou ja a entregou a sessao, e devolver entao nao faz nada.
1086
+ conducao?.devolver();
934
1087
  }
935
1088
  }
936
1089
  /** Tabela de `ork phase list`: o historico do ledger da thread. */
package/dist/policies.js CHANGED
@@ -38,6 +38,8 @@ const ENVS_QUE_REDIRECIONAM = [
38
38
  */
39
39
  const PADROES_DE_SEGREDO = [
40
40
  { nome: 'chave da Anthropic', regex: /sk-ant-[A-Za-z0-9_-]{16,}/ },
41
+ // I-38 (T7): chave do OpenRouter; o hifen depois de `sk-or-v1` escapa do padrao da OpenAI.
42
+ { nome: 'chave do OpenRouter', regex: /sk-or-v1-[A-Za-z0-9]{32,}/ },
41
43
  { nome: 'chave da OpenAI', regex: /\bsk-[A-Za-z0-9]{32,}\b/ },
42
44
  { nome: 'chave de acesso AWS', regex: /\bAKIA[0-9A-Z]{16}\b/ },
43
45
  { nome: 'token do GitHub', regex: /\bgh[pousr]_[A-Za-z0-9]{20,}\b/ },