@orkastery/cli 0.4.3 → 0.5.1

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 (146) 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/README.md +11 -2
  4. package/adapters/claude-code/agents/ork-check.md +1 -1
  5. package/adapters/claude-code/agents/ork-go.md +2 -2
  6. package/adapters/claude-code/agents/ork-goal.md +1 -1
  7. package/adapters/claude-code/agents/ork-master.md +1 -1
  8. package/adapters/claude-code/agents/ork-plan.md +1 -1
  9. package/adapters/claude-code/agents/ork-ship.md +1 -1
  10. package/adapters/claude-code/commands/master.md +11 -8
  11. package/adapters/claude-code/commands/onboarding.md +3 -2
  12. package/adapters/claude-code/commands/ork.md +8 -0
  13. package/adapters/claude-code/commands/ship.md +2 -2
  14. package/adapters/codex/skills/ork/SKILL.md +12 -1
  15. package/adapters/hermes/README.md +3 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
  17. package/adapters/hermes/bin/ork-brain.sh +3 -0
  18. package/adapters/hermes/bin/ork-maestro.sh +4 -1
  19. package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
  20. package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
  21. package/adapters/hermes/hermes.plugin.json +2 -0
  22. package/adapters/hermes/hitl-ingress/__init__.py +36 -3
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
  24. package/adapters/openclaw/README.md +45 -2
  25. package/adapters/openclaw/dist/hitl-ingress.js +37 -3
  26. package/adapters/openclaw/dist/index.js +93 -21
  27. package/adapters/openclaw/openclaw.plugin.json +10 -1
  28. package/adapters/openclaw/package.json +2 -2
  29. package/adapters/openclaw/src/hitl-ingress.ts +32 -3
  30. package/adapters/openclaw/src/index.ts +109 -21
  31. package/assets/docs/padroes/documentacao-de-produto.md +2 -2
  32. package/assets/docs/padroes/roadmap-de-produto.md +1 -1
  33. package/assets/docs/produto/_modelo-feature.md +2 -0
  34. package/assets/orkmind_bridge.py +214 -1
  35. package/dist/adapters/claude-bg.js +24 -7
  36. package/dist/auditrun.js +1 -1
  37. package/dist/board.js +74 -0
  38. package/dist/branch-de-estado.js +5 -4
  39. package/dist/busca-semantica.js +161 -0
  40. package/dist/ci.js +141 -10
  41. package/dist/claim-lint.js +3 -1
  42. package/dist/company-brain-cli.js +27 -2
  43. package/dist/company-brain-context.js +132 -0
  44. package/dist/company-brain-dossie.js +376 -0
  45. package/dist/company-brain-mcp.js +4 -1
  46. package/dist/conducao.js +71 -18
  47. package/dist/decisao-autonoma.js +42 -0
  48. package/dist/docs.js +135 -25
  49. package/dist/doctor.js +242 -32
  50. package/dist/entrega-pr.js +116 -5
  51. package/dist/experiencia-instalacao.js +256 -0
  52. package/dist/experiencia.js +72 -0
  53. package/dist/fabrica-estado.js +63 -12
  54. package/dist/fechamento.js +105 -0
  55. package/dist/fix.js +3 -3
  56. package/dist/forja.js +435 -0
  57. package/dist/gates.js +9 -1
  58. package/dist/hitl-classificacao.js +11 -1
  59. package/dist/hitl-contract.js +50 -7
  60. package/dist/hitl-curto.js +158 -0
  61. package/dist/hitl-gates.js +67 -1
  62. package/dist/hitl-lote.js +30 -15
  63. package/dist/hitl-presentation.js +10 -7
  64. package/dist/hitl-resumo.js +57 -13
  65. package/dist/hitl-texto-livre.js +150 -0
  66. package/dist/hosts.js +92 -3
  67. package/dist/index.js +637 -45
  68. package/dist/indice-vetorial.js +317 -0
  69. package/dist/init.js +24 -5
  70. package/dist/integracoes-locais.js +3 -1
  71. package/dist/intelligence-benchmark-contract.js +570 -0
  72. package/dist/intelligence-graph-cli.js +584 -0
  73. package/dist/intelligence-graph-contract.js +636 -0
  74. package/dist/intelligence-graph-extract-md.js +487 -0
  75. package/dist/intelligence-graph-extract-ts.js +980 -0
  76. package/dist/intelligence-graph-extract.js +546 -0
  77. package/dist/intelligence-graph-index.js +693 -0
  78. package/dist/intelligence-graph-parsers.js +327 -0
  79. package/dist/intelligence-graph-query.js +344 -0
  80. package/dist/intelligence-graph-repo.js +197 -0
  81. package/dist/leases.js +100 -0
  82. package/dist/ledger.js +23 -0
  83. package/dist/licoes.js +5 -4
  84. package/dist/liveness.js +2 -1
  85. package/dist/maestro-cli.js +10 -1
  86. package/dist/maestro-contract.js +5 -1
  87. package/dist/maestro-discovery.js +16 -2
  88. package/dist/maestro-runtime.js +3 -0
  89. package/dist/maestro-snapshot.js +6 -2
  90. package/dist/manifest.js +166 -5
  91. package/dist/master-batch.js +3 -2
  92. package/dist/master-digest.js +2 -2
  93. package/dist/master-nota.js +203 -0
  94. package/dist/master.js +4 -0
  95. package/dist/mcp-artifacts.js +2 -0
  96. package/dist/mcp-experiencia.js +164 -0
  97. package/dist/mcp-git.js +64 -12
  98. package/dist/mcp-grafo-worker.js +91 -0
  99. package/dist/mcp-grafo.js +233 -0
  100. package/dist/mcp-install.js +5 -2
  101. package/dist/mcp-maestro.js +3 -2
  102. package/dist/mcp-server.js +93 -5
  103. package/dist/mcp-ship.js +2 -0
  104. package/dist/mcp-verify.js +3 -1
  105. package/dist/memoria.js +147 -1
  106. package/dist/network-roadmap.js +907 -0
  107. package/dist/ocupacao.js +43 -3
  108. package/dist/onboarding.js +122 -11
  109. package/dist/orkmind.js +165 -9
  110. package/dist/orquestracao.js +2 -1
  111. package/dist/parado-no-condutor.js +933 -0
  112. package/dist/phase.js +166 -13
  113. package/dist/policies.js +29 -2
  114. package/dist/projeto-alvo.js +551 -0
  115. package/dist/prompts.js +1 -1
  116. package/dist/prova-ativacao.js +345 -0
  117. package/dist/pulse-consentimento.js +4 -2
  118. package/dist/pulse-delivery.js +32 -6
  119. package/dist/pulse-resposta.js +674 -49
  120. package/dist/pulse.js +74 -3
  121. package/dist/retry.js +51 -8
  122. package/dist/roadmap-reservas.js +262 -20
  123. package/dist/roadmap-status.js +348 -0
  124. package/dist/runtime-context.js +5 -1
  125. package/dist/sessoes-inventario.js +7 -1
  126. package/dist/sessoes.js +4 -1
  127. package/dist/ship.js +25 -1
  128. package/dist/thread-close.js +3 -0
  129. package/dist/thread.js +21 -2
  130. package/dist/util.js +71 -4
  131. package/dist/verify.js +6 -5
  132. package/dist/worktree.js +29 -6
  133. package/eval/casos/onboarding.json +1 -1
  134. package/eval/casos/orchestration-experience-pt-br.json +48 -0
  135. package/eval/casos/orchestration-experience.json +48 -0
  136. package/package.json +1 -1
  137. package/schemas/code-artifact-graph.v1.schema.json +581 -0
  138. package/schemas/graph-benchmark.v1.schema.json +2240 -0
  139. package/schemas/maestro-snapshot.schema.json +23 -0
  140. package/skills/README.md +7 -5
  141. package/skills/core/onboarding/SKILL.md +10 -2
  142. package/skills/core/orchestration-experience/SKILL.md +113 -0
  143. package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
  144. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  145. package/skills/phases/go-implementation/SKILL.md +2 -0
  146. package/skills/phases/ship-release/SKILL.md +6 -3
@@ -9,7 +9,7 @@ const maestro_cli_1 = require("./maestro-cli");
9
9
  exports.maestroInputSchema = zod_1.z.object({ threadId: zod_1.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/).optional(),
10
10
  section: zod_1.z.enum(maestro_contract_1.SECTION_NAMES).optional(), offset: zod_1.z.number().int().min(0).max(100000).optional() }).strict();
11
11
  function registerMaestro(register, options) {
12
- register('ork_maestro', { description: 'Panorama Maestro somente leitura, fixado ao projeto e ao escopo da sessão; cobertura, lacunas e próximas ações pelos endpoints existentes.',
12
+ register('ork_maestro', { description: 'Panorama Maestro somente leitura, fixado ao projeto e ao escopo da sessão; cobertura, lacunas e próximas ações pelos endpoints existentes. Não lê o roadmap, as reservas nem as outras máquinas (veja notConsulted): zero threads nunca é roadmap vazio; para o roadmap, com as threads de todas as máquinas, use ork_network_roadmap.',
13
13
  inputSchema: exports.maestroInputSchema, annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false } }, async (args) => {
14
14
  options.load();
15
15
  if ((args.section === undefined) !== (args.offset === undefined))
@@ -17,7 +17,8 @@ function registerMaestro(register, options) {
17
17
  const threadId = args.threadId ?? options.threadId;
18
18
  if (threadId)
19
19
  options.checkThread(threadId);
20
- const context = (0, maestro_discovery_1.discoverMaestro)({ cwd: options.root, pinned: options.root });
20
+ // RM-052 (D5): fixado no projeto servido; os outros projetos da maquina nao entram na conta.
21
+ const context = (0, maestro_discovery_1.discoverMaestro)({ cwd: options.root, pinned: options.root, countOtherProjects: false });
21
22
  const result = (0, maestro_cli_1.readMaestro)(context, { threadId, native: true, offsets: args.section ? { [args.section]: args.offset } : undefined,
22
23
  host: { tools: options.tools(), child: !!options.threadId } });
23
24
  return { content: [{ type: 'text', text: JSON.stringify(result) }] };
@@ -56,6 +56,8 @@ const leases_1 = require("./leases");
56
56
  const hitl_gates_1 = require("./hitl-gates");
57
57
  const hitl_contract_1 = require("./hitl-contract");
58
58
  const hitl_presentation_1 = require("./hitl-presentation");
59
+ const roadmap_status_1 = require("./roadmap-status");
60
+ const network_roadmap_1 = require("./network-roadmap");
59
61
  const hitl_sessions_1 = require("./hitl-sessions");
60
62
  const hitl_local_1 = require("./hitl-local");
61
63
  const mcp_artifacts_1 = require("./mcp-artifacts");
@@ -65,6 +67,7 @@ const modos_1 = require("./modos");
65
67
  const versao_1 = require("./versao");
66
68
  const mcp_verify_1 = require("./mcp-verify");
67
69
  const conducao_1 = require("./conducao");
70
+ const decisao_autonoma_1 = require("./decisao-autonoma");
68
71
  const conducao_texto_1 = require("./conducao-texto");
69
72
  const mcp_ship_1 = require("./mcp-ship");
70
73
  const company_brain_mcp_1 = require("./company-brain-mcp");
@@ -72,6 +75,9 @@ const claude_bg_1 = require("./adapters/claude-bg");
72
75
  const session_watcher_claude_1 = require("./session-watcher-claude");
73
76
  const runtime_profiles_1 = require("./runtime-profiles");
74
77
  const mcp_maestro_1 = require("./mcp-maestro");
78
+ const projeto_alvo_1 = require("./projeto-alvo");
79
+ const mcp_experiencia_1 = require("./mcp-experiencia");
80
+ const mcp_grafo_1 = require("./mcp-grafo");
75
81
  const identidade = zod_1.z.string().min(1).max(80).regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/);
76
82
  const daThread = zod_1.z.object({ threadId: identidade }).strict();
77
83
  const daDecisao = daThread.extend({ pedidoId: identidade }).strict();
@@ -291,21 +297,43 @@ function criarServidorMcp(opcoes) {
291
297
  };
292
298
  const livre = (id) => {
293
299
  const nomes = ['main-tree', ...(id ? ['worktree-write:' + id] : [])];
300
+ // RM-037 (fatia 3, GO-FIX 2, achado 1 do CHECK): esta e a primeira conferencia de toda tool de escrita.
301
+ // Lease e fila de thread fechada sao orfaos e saem aqui, com registro no ledger dela; sem isso o
302
+ // main-tree de um SHIP que caiu antes do fechamento travava verify, commit, ship e artefato pelo MCP.
303
+ (0, leases_1.podarRegioesDeThreadsFechadas)(raiz, nomes, id ?? '');
294
304
  for (const nome of nomes) {
295
305
  const conflitos = (0, leases_1.leasesColidentes)(raiz, nome, id);
296
306
  if (conflitos.length)
297
307
  throw Error('lease.busy: ' + conflitos.map(l => l.nome + ' (' + l.thread + ')').join(', '));
298
308
  }
299
309
  };
300
- const server = new index_js_1.Server({ name: 'orkastery', version: versao_1.VERSAO_DO_ORK }, { capabilities: { tools: {} }, instructions: 'Opere somente este projeto pelas ferramentas do nucleo. Decisoes humanas usam ork_request_decision e o dialogo do host; argumentos de ferramenta nunca sao respostas.' });
310
+ const server = new index_js_1.Server({ name: 'orkastery', version: versao_1.VERSAO_DO_ORK }, { capabilities: { tools: {} }, instructions: 'Opere somente este projeto pelas ferramentas do nucleo. O parametro opcional projeto so confere o projeto servido; nunca troca a raiz. O status do roadmap vem de ork_network_roadmap, transportado como vem. Decisoes humanas usam ork_request_decision e o dialogo do host; argumentos de ferramenta nunca sao respostas.' });
311
+ /**
312
+ * RM-052 (D5): toda tool aceita `projeto`, e ele so CONFERE o projeto fixado no startup. Pedido de
313
+ * outro projeto recusa tipado, com o projeto servido como unico candidato; a raiz nunca muda aqui.
314
+ */
315
+ const conferirProjeto = (pedido) => {
316
+ const c = carregar(), nome = c.manifesto.project.name, abbrev = c.manifesto.project.abbrev, v = pedido.toLowerCase();
317
+ if (nome.toLowerCase() === v || (!!abbrev && abbrev.toLowerCase() === v))
318
+ return;
319
+ throw new projeto_alvo_1.ErroDeProjeto('projeto.fora-do-servidor', `este servidor MCP atende somente o projeto ${nome}; "${pedido}" nao e ele`, [{ nome, abbrev, raiz: (0, projeto_alvo_1.raizParaExibir)(raiz), remoto: (0, projeto_alvo_1.remotoDoProjeto)(raiz, c.manifesto.fabrica?.remoto ?? 'origin'), presente: true }], 'Use o servidor MCP instalado no outro projeto (ork mcp install --project <raiz>), ou o CLI com --projeto <nome>.');
320
+ };
321
+ const campoProjeto = zod_1.z.string().regex(projeto_alvo_1.PADRAO_DO_NOME_DE_PROJETO)
322
+ .describe('Nome ou abbrev do projeto pedido; este servidor atende somente o projeto fixado na instalacao');
301
323
  const ferramentas = new Map();
302
324
  function registrarTool(nome, config, executar) {
303
325
  if (opcoes.threadId && ['ork_thread_new', 'ork_phase_run', 'ork_request_decision', 'ork_preflight'].includes(nome))
304
326
  return;
305
- const schema = converterSchema(config.inputSchema, { $refStrategy: 'none' });
327
+ const entrada = config.inputSchema.extend({ projeto: campoProjeto.optional() });
328
+ const schema = converterSchema(entrada, { $refStrategy: 'none' });
306
329
  ferramentas.set(nome, { tool: { name: nome, description: config.description, annotations: config.annotations,
307
330
  inputSchema: schema },
308
- executar: async (raw, extra) => executar(config.inputSchema.parse(raw), extra) });
331
+ executar: async (raw, extra) => {
332
+ const { projeto, ...args } = entrada.parse(raw);
333
+ if (projeto !== undefined)
334
+ conferirProjeto(projeto);
335
+ return executar(args, extra);
336
+ } });
309
337
  }
310
338
  server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: [...ferramentas.values()].map(f => f.tool) }));
311
339
  server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request, extra) => {
@@ -316,6 +344,8 @@ function criarServidorMcp(opcoes) {
316
344
  return await f.executar(request.params.arguments ?? {}, extra);
317
345
  }
318
346
  catch (e) {
347
+ if (e instanceof projeto_alvo_1.ErroDeProjeto)
348
+ return { ...resposta(e.recusa), isError: true };
319
349
  return { ...resposta({ erro: e.message }), isError: true };
320
350
  }
321
351
  });
@@ -344,6 +374,7 @@ function criarServidorMcp(opcoes) {
344
374
  });
345
375
  server.onclose = () => ingresso.fechar();
346
376
  (0, company_brain_mcp_1.registerBrainTools)(registrarTool, carregar, thread, opcoes.brainWrites ?? []);
377
+ (0, mcp_experiencia_1.registrarConsultasExperiencia)(registrarTool, { raiz, carregar, transporte: opcoes.transporteShip ?? 'github-ssh' });
347
378
  (0, mcp_maestro_1.registerMaestro)(registrarTool, { root: raiz, threadId: opcoes.threadId, load: carregar, checkThread: thread, tools: () => [...ferramentas.keys()] });
348
379
  registrarTool('ork_preflight', { description: 'Preflight contextual por modo e bloco, sem inventário global/modelos. Não autoriza despacho nem comprova entrega.',
349
380
  inputSchema: zod_1.z.object({ modo: modoDeConducao }).strict(), annotations: { readOnlyHint: true } }, async ({ modo }) => {
@@ -402,6 +433,35 @@ function criarServidorMcp(opcoes) {
402
433
  livre(threadId);
403
434
  return resposta((0, mcp_artifacts_1.escreverArtefatoMcp)(raiz, threadId, tipo, conteudo, expectedSha256));
404
435
  });
436
+ // RM-037 (rm037defeito, defeito 1): a decisao que a sessao toma sem perguntar ao dono. O sandbox do
437
+ // codex nao grava o ledger e o `ork decisao registrar` morria em EROFS. Mesma `registrarDecisao` do CLI:
438
+ // contrato v2, criterio que resolve e rastro no mesmo evento. Nao pergunta ao dono e nao toca gate.
439
+ const campoDaDecisao = zod_1.z.string().min(1).max(4096);
440
+ registrarTool('ork_decision_record', { description: 'Registra decisao ja tomada pela sessao sem perguntar ao dono (classe decidido), com criterio que resolve e rastro. Nao pergunta, nao responde nem aprova gate.',
441
+ inputSchema: daThread.extend({ decidido: campoDaDecisao, porque: campoDaDecisao, comoMudar: campoDaDecisao,
442
+ custoAgora: campoDaDecisao, custoDepois: campoDaDecisao,
443
+ criterio: zod_1.z.object({ tipo: zod_1.z.enum(['manifesto', 'ledger', 'medicao']), referencia: campoDaDecisao }).strict(),
444
+ quemDecidiu: zod_1.z.string().min(1).max(200), evidencia: campoDaDecisao, razao: campoDaDecisao.optional(),
445
+ reverte: zod_1.z.string().min(1).max(80).optional() }).strict(),
446
+ annotations: { readOnlyHint: false, destructiveHint: false } }, async ({ threadId, ...e }) => {
447
+ thread(threadId);
448
+ livre(threadId);
449
+ // A sessao decide por ela: o rastro nao pode nascer assinado em nome do dono.
450
+ if (/^\s*(?:o\s+|a\s+)?(?:dono|owner|builder|maestro)\b/i.test(e.quemDecidiu))
451
+ throw Error('mcp.decision.author: quemDecidiu e a sessao que decidiu, nunca o dono');
452
+ let registro;
453
+ try {
454
+ registro = (0, decisao_autonoma_1.registrarDecisao)(raiz, threadId, { decidido: e.decidido, porque: e.porque, comoMudar: e.comoMudar,
455
+ custoDeReverter: { agora: e.custoAgora, depois: e.custoDepois }, criterio: e.criterio, quemDecidiu: e.quemDecidiu,
456
+ evidencia: e.evidencia, ...(e.razao ? { razao: e.razao } : {}), ...(e.reverte ? { reverte: e.reverte } : {}), origem: 'mcp', host: opcoes.host,
457
+ despacho: opcoes.dispatchId ?? null });
458
+ }
459
+ catch (erro) {
460
+ throw Error((0, hitl_contract_1.recusaNaSuperficie)(erro.message, hitl_contract_1.CAMPOS_DA_DECISAO_NO_MCP));
461
+ }
462
+ const { pedido, evento } = registro;
463
+ return resposta({ ok: true, pedidoId: pedido.id, eventId: evento.eventId, fase: pedido.fase, reciboOficial: false });
464
+ });
405
465
  registrarTool('ork_claims_list', { description: 'Lista alegacoes e seu estado de verificacao registrado pelo nucleo.',
406
466
  inputSchema: daThread, annotations: { readOnlyHint: true } }, async ({ threadId }) => {
407
467
  thread(threadId);
@@ -423,6 +483,25 @@ function criarServidorMcp(opcoes) {
423
483
  });
424
484
  registrarTool('ork_hitl_pending', { description: 'Pedidos HITL atuais da thread, incluindo prazo; nao aprova nem abre pedido.',
425
485
  inputSchema: daThread, annotations: { readOnlyHint: true } }, async ({ threadId }) => resposta({ threadId, pendencias: pendencias(threadId) }));
486
+ registrarTool('ork_roadmap_status', { description: 'Status report do roadmap SO desta maquina (o checkout local), no formato aprovado pelo dono: grupos com icones, #HITL no que espera o dono e o fecho. Somente leitura; transporte o texto como vem. O cabecalho diz o projeto consultado e o que nao foi lido (reservas, outras maquinas). Para o status do roadmap com as threads de todas as maquinas, as reservas, as fontes e as lacunas, use ork_network_roadmap; nunca conclua sobre ele a partir de ork_maestro ou de threads.',
487
+ inputSchema: zod_1.z.object({}).strict(), annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false } }, async () => {
488
+ const c = carregar();
489
+ // RM-052: origem `instalacao`; o servidor fixado nao revela os outros projetos da maquina.
490
+ const consulta = (0, projeto_alvo_1.consultaDoProjeto)(c, { origem: 'instalacao', outrosProjetos: false,
491
+ lido: ['roadmap (docs/roadmap)', projeto_alvo_1.FORA_DA_CONSULTA.threadsDaMaquina], naoLido: [projeto_alvo_1.FORA_DA_CONSULTA.reservas, 'threads de outras máquinas (ork network roadmap)'] });
492
+ const status = (0, roadmap_status_1.montarStatusDoRoadmap)(raiz, { projeto: c.manifesto.project.name, consulta });
493
+ return resposta({ texto: (0, roadmap_status_1.textoDoStatusDoRoadmap)(status), status });
494
+ });
495
+ /**
496
+ * RM-054 (fatia 2, D-G5): o roadmap da rede do projeto servido, em todas as maquinas dele. O servidor
497
+ * fixado nao le o registro nem revela os outros projetos (D5 da RM-052); o texto e o do CLI.
498
+ */
499
+ registrarTool('ork_network_roadmap', { description: 'Roadmap da rede do projeto servido, somente leitura: o status report do roadmap (RM-048) com as threads de TODAS as maquinas, as reservas, as threads por maquina com a idade da batida, a fonte e a hora de cada parte e as lacunas tipadas. E a fonte do status do roadmap: transporte o texto como vem, sem reescrever nem resumir. Lacuna e "Nao consultado" sao o que nao foi lido: nunca conclua "roadmap vazio" nem "nenhuma maquina publicou" a partir deles. Este servidor le so o projeto fixado; os outros projetos vem do CLI ork network roadmap.',
500
+ inputSchema: zod_1.z.object({}).strict(), annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true } }, async () => {
501
+ carregar();
502
+ const panorama = (0, network_roadmap_1.montarPanoramaDaRede)({ fixado: raiz });
503
+ return resposta({ texto: (0, network_roadmap_1.textoDoPanoramaDaRede)(panorama), panorama });
504
+ });
426
505
  registrarTool('ork_observe', { description: 'Observa uma vez o progresso canonico e pedidos da thread. Nao cria monitor ou despacho.',
427
506
  inputSchema: daThread, annotations: { readOnlyHint: true } }, async ({ threadId }) => {
428
507
  return resposta(observar(threadId));
@@ -439,14 +518,19 @@ function criarServidorMcp(opcoes) {
439
518
  while (!fs.existsSync(existente))
440
519
  existente = path.dirname(existente);
441
520
  confinado(existente);
442
- return resposta((0, thread_1.novaThread)(c, { nome, modo: modo ?? c.manifesto.conduction.default_mode, criarWorktree: true }));
521
+ const criada = (0, thread_1.novaThread)(c, { nome, modo: modo ?? c.manifesto.conduction.default_mode, criarWorktree: true });
522
+ // RM-052 (D7): thread nova, projeto conhecido pelo nome nesta maquina; o registro nunca derruba a criacao.
523
+ if (criada.gravada)
524
+ (0, projeto_alvo_1.registrarProjetoEmSilencio)(raiz, 'mcp thread new');
525
+ return resposta(criada);
443
526
  });
444
527
  registrarTool('ork_phase_run', { description: 'Despacha fase autorizada pelo nucleo, preservando policies, estado e runtime/modelo. dryRun nao inicia modelo, mas pode registrar prompt/eventos.',
445
528
  inputSchema: fase, annotations: { readOnlyHint: false, destructiveHint: false } }, async (args) => {
446
529
  const t = thread(args.threadId);
447
530
  livre(t.id);
448
531
  const { threadId, fase: f, ...op } = args;
449
- return resposta((0, phase_1.rodarFase)(carregar(), threadId, { ...op, fase: (0, thread_1.exigirFase)(t, f), canal: conducao.canal }));
532
+ // RM-037 (A3): o MCP nao roda a suite para a baseline do despacho; a falta dela volta como pendencia.
533
+ return resposta((0, phase_1.rodarFase)(carregar(), threadId, { ...op, fase: (0, thread_1.exigirFase)(t, f), canal: conducao.canal, baselinePeloDespacho: false }));
450
534
  });
451
535
  registrarTool('ork_gate_request', { description: 'Abre pedido de gate somente quando pausa ou escalacao tipada esta comprovada no nucleo; nao aprova.',
452
536
  inputSchema: daThread.extend({ motivo: zod_1.z.enum(['human.pending', 'policy.violation', 'cost.violation',
@@ -461,6 +545,10 @@ function criarServidorMcp(opcoes) {
461
545
  thread(threadId);
462
546
  return resposta(await ingresso.solicitar(threadId, pedidoId, extra.signal));
463
547
  });
548
+ // RM-031 KG5 (D2): as tools do grafo so existem com a flag do manifesto da raiz no startup; sem ela, nada muda.
549
+ // CHECK rodada 1 (S8): o startup le so o manifesto, como antes; as conferencias de estado ficam na chamada.
550
+ if ((0, mcp_grafo_1.grafoLigado)((0, manifest_1.exigirManifesto)(raiz).manifesto))
551
+ (0, mcp_grafo_1.registrarConsultasDoGrafo)(registrarTool, { raiz, carregar, thread });
464
552
  return server;
465
553
  }
466
554
  async function servirMcp(opcoes) {
package/dist/mcp-ship.js CHANGED
@@ -324,6 +324,8 @@ function executar(f, p) {
324
324
  if (comandos.length > 512 || comandos.reduce((n, s) => n + Buffer.byteLength(s), 0) > LIMITE)
325
325
  erro('verify.limit');
326
326
  const nome = `worktree-write:${t.id}`, nomes = [nome, `path:.orkastery/threads/${t.id}`];
327
+ // RM-037 (fatia 3, defeito 4): lease e fila de thread fechada sao orfaos e saem antes da conferencia.
328
+ (0, leases_1.podarRegioesDeThreadsFechadas)(raiz, [...nomes, 'main-tree'], t.id);
327
329
  for (const n of [...nomes, 'main-tree'])
328
330
  if (fs.lstatSync((0, leases_1.caminhoLease)(raiz, n), { throwIfNoEntry: false }) || (0, leases_1.leasesColidentes)(raiz, n).length)
329
331
  erro('lease.busy');
@@ -97,7 +97,9 @@ function verificarMcp(raizEntrada, threadId, conducao = {}) {
97
97
  const stFila = fs.lstatSync((0, leases_1.caminhoFila)(raiz), { throwIfNoEntry: false });
98
98
  if (stFila && (!stFila.isFile() || stFila.nlink !== 1))
99
99
  throw Error('mcp.verify.queue.unsafe');
100
- // Não herda nem remove lease existente, inclusive própria, expirada ou corrompida.
100
+ // RM-037 (fatia 3, defeito 4): lease e fila de thread fechada são órfãos e saem antes da conferência.
101
+ (0, leases_1.podarRegioesDeThreadsFechadas)(raiz, [...nomes, 'main-tree'], threadId);
102
+ // Não herda nem remove lease existente de thread aberta, inclusive própria, expirada ou corrompida.
101
103
  if (nomes.some(nome => fs.lstatSync((0, leases_1.caminhoLease)(raiz, nome), { throwIfNoEntry: false }) ||
102
104
  (0, leases_1.leasesColidentes)(raiz, nome).length) || (0, leases_1.leasesColidentes)(raiz, 'main-tree').length) {
103
105
  throw Error('lease.busy: verificação exige leases próprias livres');
package/dist/memoria.js CHANGED
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.sincronizarOnboarding = sincronizarOnboarding;
37
37
  exports.abrirMemoria = abrirMemoria;
38
+ exports.estadoDeEmbeddings = estadoDeEmbeddings;
39
+ exports.sondarEmbeddings = sondarEmbeddings;
38
40
  exports.tagsDoProjeto = tagsDoProjeto;
39
41
  exports.situacaoDaThread = situacaoDaThread;
40
42
  exports.situacaoDaFase = situacaoDaFase;
@@ -64,6 +66,7 @@ exports.sincronizarMemoria = sincronizarMemoria;
64
66
  exports.publicar = publicar;
65
67
  exports.publicarPropostas = publicarPropostas;
66
68
  exports.textoDoEstado = textoDoEstado;
69
+ exports.textoDosEmbeddings = textoDosEmbeddings;
67
70
  exports.textoDoSync = textoDoSync;
68
71
  exports.parsePrioridade = parsePrioridade;
69
72
  const write_activation_1 = require("./write-activation");
@@ -97,6 +100,7 @@ const memoria_humana_1 = require("./memoria-humana");
97
100
  const master_1 = require("./master");
98
101
  const modos_1 = require("./modos");
99
102
  const orkmind_1 = require("./orkmind");
103
+ const indice_vetorial_1 = require("./indice-vetorial");
100
104
  const ledger_1 = require("./ledger");
101
105
  const thread_1 = require("./thread");
102
106
  const util_1 = require("./util");
@@ -167,6 +171,10 @@ function abrirMemoria(carregado, opcoes = {}) {
167
171
  const leituraRestrita = resolverLeituraRestrita(carregado.manifesto, opcoes.leituraRestrita);
168
172
  const { estado, driver } = (0, orkmind_1.resolverRegime)(carregado.manifesto, opcoes.driver ?? null);
169
173
  const ativo = estado.efetivo === 'orkmind' && driver !== null;
174
+ const config = (0, orkmind_1.configDoManifesto)(carregado.manifesto);
175
+ const embeddings = (universo) => estadoDeEmbeddings(carregado.manifesto, ativo ? driver?.disponivel().saude ?? null : null, carregado.raiz, estado.tenant, config.dsn, { universo });
176
+ if (estado.pedido === 'orkmind')
177
+ estado.embeddings = embeddings();
170
178
  const consultarRestrito = (collection, tags) => {
171
179
  if (!leituraRestrita)
172
180
  throw Error('memory.query.invalid');
@@ -178,7 +186,7 @@ function abrirMemoria(carregado, opcoes = {}) {
178
186
  throw Error('memory.query.unsupported');
179
187
  return (0, orkmind_1.concluirConsultaDelimitada)(driver.consultar(q), q);
180
188
  };
181
- return {
189
+ const memoria = {
182
190
  configSource: context.source,
183
191
  configDivergent: context.divergent,
184
192
  get leituraRestrita() { return leituraRestrita; },
@@ -243,6 +251,114 @@ function abrirMemoria(carregado, opcoes = {}) {
243
251
  return driver.exportar(colecao).find((e) => e.id === id) ?? null;
244
252
  },
245
253
  };
254
+ // A cobertura precisa do universo do tenant (um export por colecao): so quando pedida.
255
+ if (opcoes.embeddings === 'detalhado' && ativo && !leituraRestrita) {
256
+ estado.embeddings = embeddings((0, indice_vetorial_1.universoDoTenant)(memoria, estado.tenant));
257
+ }
258
+ return memoria;
259
+ }
260
+ // ---------------------------------------------------------------------------
261
+ // I-38 (T4, D6): estado sondado dos embeddings. Nunca derruba o regime.
262
+ // ---------------------------------------------------------------------------
263
+ /** Os indices locais do tenant nesta base, por modelo e dimensao. */
264
+ function indicesDoTenant(raiz, tenant, base, universo) {
265
+ const dir = (0, indice_vetorial_1.dirDosIndices)(raiz, tenant);
266
+ if (!fs.existsSync(dir))
267
+ return [];
268
+ const indices = [];
269
+ for (const nome of fs.readdirSync(dir).filter(n => n.endsWith('.json')).sort()) {
270
+ try {
271
+ const bruto = JSON.parse(fs.readFileSync(path.join(dir, nome), 'utf8'));
272
+ if (bruto.contrato !== indice_vetorial_1.CONTRATO_INDICE || bruto.tenant !== tenant || bruto.base !== base)
273
+ continue;
274
+ const { indice } = (0, indice_vetorial_1.lerIndice)(path.join(dir, nome), { tenant, base, modelo: bruto.modelo, dim: bruto.dim });
275
+ const vetores = Object.keys(indice.entradas).length;
276
+ const coerentes = (0, indice_vetorial_1.vetoresCoerentes)(indice, universo).size;
277
+ indices.push({ modelo: indice.modelo, dim: indice.dim, vetores, coerentes, desatualizados: vetores - coerentes });
278
+ }
279
+ catch { /* arquivo ilegivel nao e indice: `ork memory index` o reconstroi */ }
280
+ }
281
+ return indices;
282
+ }
283
+ /**
284
+ * Estado de embeddings: configuracao, presenca da chave (nome, nunca valor), a sonda `health`
285
+ * da ponte e os arquivos de indice. `saude` null quer dizer que a ponte nao foi sondada.
286
+ */
287
+ function estadoDeEmbeddings(manifesto, saude, raiz, tenant, dsn, opcoes = {}) {
288
+ const config = (0, manifest_1.configDeEmbedding)(manifesto);
289
+ const env = opcoes.env ?? process.env;
290
+ const configurado = config.provider !== 'none';
291
+ const variavel = config.api_key_env;
292
+ const bruto = variavel ? (env[variavel] ?? '').trim() : '';
293
+ const chavePresente = !!variavel && (0, orkmind_1.chaveDeEmbeddingAceita)(bruto, dsn);
294
+ const recusada = bruto !== '' && !chavePresente;
295
+ const dimLocal = configurado && config.fallback_model ? (0, indice_vetorial_1.dimDoModeloLocal)(config.fallback_model, env) : null;
296
+ const dependencias = saude?.fallback.dependencias ?? false;
297
+ const fallback = { modelo: config.fallback_model || null, presente: dimLocal !== null, dependencias, dim: dimLocal };
298
+ const base = (0, indice_vetorial_1.impressaoDaBase)(dsn);
299
+ const existe = (modelo, dim) => dim !== null && fs.existsSync((0, indice_vetorial_1.arquivoDoIndice)(raiz, tenant, modelo, dim));
300
+ const estado = {
301
+ configurado, provider: config.provider, modelo: configurado ? config.model : null, dim: configurado ? config.dim : null,
302
+ variavelDaChave: variavel, chavePresente, fallback, indices: [], entradas: null, cobertura: null,
303
+ ativo: 'nenhum', sondado: saude !== null, motivo: null, detalhe: '', correcao: '',
304
+ };
305
+ if (!configurado) {
306
+ return { ...estado, motivo: 'embeddings.nao-configurado',
307
+ detalhe: 'memory.embedding ausente ou provider none: busca por significado desligada; o recall por tag segue identico',
308
+ correcao: 'declare memory.embedding no manifesto (provider openrouter e api_key_env com o NOME da variavel da chave)' };
309
+ }
310
+ const fallbackUsavel = saude !== null && fallback.presente && dependencias;
311
+ if (chavePresente) {
312
+ estado.ativo = 'primario';
313
+ if (!existe(config.model, config.dim)) {
314
+ estado.motivo = 'embeddings.indice-ausente';
315
+ estado.detalhe = `chave presente em ${variavel}; o indice local de ${config.model} ainda nao existe`;
316
+ estado.correcao = 'rode ork memory index (use --dry-run antes para ver tokens e custo)';
317
+ }
318
+ else
319
+ estado.detalhe = `primario ${config.model} (${config.dim} dim) pela chave em ${variavel}`;
320
+ }
321
+ else {
322
+ estado.ativo = fallbackUsavel ? 'fallback' : 'nenhum';
323
+ estado.motivo = 'embeddings.chave-ausente';
324
+ const local = !fallback.modelo ? 'sem fallback local declarado: a busca por significado cai para FTS'
325
+ : !fallback.presente ? `fallback ${fallback.modelo} ausente do cache local: a busca cai para FTS`
326
+ : !saude ? 'ponte nao sondada: fallback local nao conferido'
327
+ : !dependencias ? `fallback ${fallback.modelo} sem torch/transformers no interpretador da ponte: a busca cai para FTS`
328
+ : `busca usa o fallback local ${fallback.modelo} (${fallback.dim} dim)` +
329
+ (existe(fallback.modelo, fallback.dim) ? '' : '; indice local ausente: rode ork memory index --modelo fallback');
330
+ estado.detalhe = `${variavel} ${recusada ? 'tem valor recusado (parece URL, DSN ou texto com espaco; nunca impresso)' : 'nao esta no ambiente (valor nunca impresso)'}; ${local}`;
331
+ estado.correcao = `exporte ${variavel} com a chave dedicada ao Orkastery; o valor nunca vai ao manifesto`;
332
+ }
333
+ if (opcoes.universo) {
334
+ const universo = opcoes.universo.filter(e => (e.tags.project ?? []).includes(tenant));
335
+ estado.indices = indicesDoTenant(raiz, tenant, base, universo);
336
+ estado.entradas = universo.length;
337
+ const referencia = estado.ativo === 'fallback' ? { modelo: fallback.modelo, dim: fallback.dim } : { modelo: config.model, dim: config.dim };
338
+ const indice = estado.indices.find(i => i.modelo === referencia.modelo && i.dim === referencia.dim);
339
+ estado.cobertura = universo.length === 0 ? 0 : Math.round(((indice?.coerentes ?? 0) / universo.length) * 10_000) / 10_000;
340
+ }
341
+ return estado;
342
+ }
343
+ /**
344
+ * `ork memory status --sondar`: UMA chamada real com texto fixo curto pelo caminho ativo, com
345
+ * a latencia medida (primario custa cerca de US$ 0,00000005; fallback local, so CPU).
346
+ */
347
+ function sondarEmbeddings(manifesto, estado, embeddar, timeoutMs) {
348
+ if (estado.ativo === 'nenhum')
349
+ return { ok: false, alvo: null, latenciaMs: null, motivo: estado.motivo };
350
+ const config = (0, manifest_1.configDeEmbedding)(manifesto);
351
+ const primario = estado.ativo === 'primario';
352
+ const modelo = primario ? config.model : estado.fallback.modelo;
353
+ const dim = primario ? config.dim : estado.fallback.dim;
354
+ const inicio = Date.now();
355
+ try {
356
+ embeddar({ papel: 'consulta', alvo: estado.ativo, modelo, dim, textos: ['sonda de saude do ork'] }, { timeoutMs });
357
+ return { ok: true, alvo: estado.ativo, latenciaMs: Date.now() - inicio, motivo: null };
358
+ }
359
+ catch (erro) {
360
+ return { ok: false, alvo: estado.ativo, latenciaMs: Date.now() - inicio, motivo: (0, indice_vetorial_1.codigoDeEmbedding)(erro) };
361
+ }
246
362
  }
247
363
  // ---------------------------------------------------------------------------
248
364
  // Tags: as 5 dimensoes, montadas em um lugar so.
@@ -968,8 +1084,38 @@ function textoDoEstado(estado) {
968
1084
  linhas.push(` colecoes gravadas: ${orkmind_1.COLECOES_DO_ORK.join(', ')}`);
969
1085
  linhas.push(' governanca: source=agent; decision/human exige human_gate comprovado; mandatory=false e regra nunca critical.');
970
1086
  }
1087
+ if (estado.embeddings)
1088
+ linhas.push('', ...textoDosEmbeddings(estado.embeddings));
971
1089
  return linhas.join('\n');
972
1090
  }
1091
+ /** Secao de embeddings do `ork memory status` (I-38 D6): nome da variavel, nunca o valor. */
1092
+ function textoDosEmbeddings(e) {
1093
+ const linhas = ['Busca por significado (embeddings, nao deterministica; o recall por tag nao muda)', ''];
1094
+ linhas.push(` provider ${e.configurado ? `${e.provider} ${e.modelo} (${e.dim} dim)` : 'none (desligada)'}`);
1095
+ if (e.configurado) {
1096
+ linhas.push(` chave ${e.variavelDaChave} ${e.chavePresente ? 'presente' : 'ausente'} no ambiente (valor nunca impresso)`);
1097
+ linhas.push(` fallback local ${e.fallback.modelo ? `${e.fallback.modelo}: ${e.fallback.presente ? `no cache (${e.fallback.dim} dim)` : 'ausente do cache'}, ` +
1098
+ `dependencias ${e.fallback.dependencias ? 'ok' : e.sondado ? 'ausentes' : 'nao sondadas'}` : '(nao declarado)'}`);
1099
+ linhas.push(` caminho ativo ${e.ativo}${e.sondado ? '' : ' (ponte nao sondada)'}`);
1100
+ }
1101
+ for (const i of e.indices) {
1102
+ linhas.push(` indice ${i.modelo} / ${i.dim} dim: ${i.vetores} vetor(es), ${i.coerentes ?? '?'} coerente(s), ${i.desatualizados ?? '?'} desatualizado(s)`);
1103
+ }
1104
+ if (e.entradas !== null) {
1105
+ linhas.push(` cobertura ${e.cobertura === null ? '-' : `${Math.round(e.cobertura * 1000) / 10}%`} de ${e.entradas} entrada(s) do tenant`);
1106
+ }
1107
+ if (e.sonda) {
1108
+ linhas.push(` sonda ${e.sonda.ok ? `${e.sonda.alvo} respondeu em ${e.sonda.latenciaMs} ms` : `sem resposta (${e.sonda.motivo ?? 'sem caminho ativo'})`}`);
1109
+ }
1110
+ if (e.motivo) {
1111
+ linhas.push(` motivo ${e.motivo}`);
1112
+ linhas.push(` ${e.detalhe}`);
1113
+ linhas.push(` correcao: ${e.correcao}`);
1114
+ }
1115
+ else
1116
+ linhas.push(` ${e.detalhe}`);
1117
+ return linhas;
1118
+ }
973
1119
  /** Texto de `ork memory sync`. */
974
1120
  function textoDoSync(r) {
975
1121
  const linhas = [];