@orkastery/cli 0.5.0 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/adapters/claude-code/README.md +11 -2
  2. package/adapters/claude-code/agents/ork-master.md +2 -0
  3. package/adapters/claude-code/commands/master.md +8 -0
  4. package/adapters/claude-code/commands/onboarding.md +3 -2
  5. package/adapters/claude-code/commands/ork.md +9 -0
  6. package/adapters/codex/skills/ork/SKILL.md +18 -3
  7. package/adapters/hermes/README.md +1 -0
  8. package/adapters/hermes/bin/ork-network-status.sh +10 -0
  9. package/adapters/hermes/hermes.plugin.json +1 -0
  10. package/adapters/hermes/hitl-ingress/__init__.py +2 -2
  11. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
  12. package/adapters/openclaw/README.md +35 -4
  13. package/adapters/openclaw/dist/hitl-ingress.js +2 -2
  14. package/adapters/openclaw/dist/index.js +47 -12
  15. package/adapters/openclaw/openclaw.plugin.json +5 -1
  16. package/adapters/openclaw/package.json +2 -2
  17. package/adapters/openclaw/src/hitl-ingress.ts +2 -2
  18. package/adapters/openclaw/src/index.ts +50 -12
  19. package/assets/orkmind_bridge.py +117 -9
  20. package/dist/adapters/claude-bg.js +59 -11
  21. package/dist/adapters/codex.js +4 -3
  22. package/dist/agents-md.js +1 -0
  23. package/dist/auditrun.js +6 -2
  24. package/dist/board.js +16 -14
  25. package/dist/branch-de-estado.js +66 -10
  26. package/dist/busca-semantica.js +52 -12
  27. package/dist/canarios-rm057.js +149 -0
  28. package/dist/canarios.js +2 -0
  29. package/dist/ci.js +8 -1
  30. package/dist/claim-lint.js +3 -1
  31. package/dist/claims.js +39 -1
  32. package/dist/company-brain-context.js +158 -22
  33. package/dist/docs.js +110 -3
  34. package/dist/doctor-pulse-cron.js +194 -0
  35. package/dist/doctor-rede.js +149 -0
  36. package/dist/doctor.js +294 -37
  37. package/dist/entrega-pr.js +27 -8
  38. package/dist/esgotamentos.js +181 -0
  39. package/dist/experiencia.js +12 -2
  40. package/dist/fabrica-estado.js +35 -9
  41. package/dist/fabrica-publicar.js +6 -0
  42. package/dist/fechamento.js +20 -66
  43. package/dist/fix.js +3 -3
  44. package/dist/forja.js +31 -7
  45. package/dist/gates.js +5 -1
  46. package/dist/hitl-contract.js +59 -4
  47. package/dist/hitl-curto.js +11 -6
  48. package/dist/hitl-gates.js +5 -0
  49. package/dist/hitl-lote.js +5 -2
  50. package/dist/hitl-resumo.js +33 -1
  51. package/dist/hitl-tempo-parado.js +201 -0
  52. package/dist/hitl-texto-livre.js +5 -5
  53. package/dist/horario.js +27 -0
  54. package/dist/hosts.js +59 -13
  55. package/dist/impedimento.js +205 -0
  56. package/dist/index.js +433 -88
  57. package/dist/indice-vetorial.js +87 -10
  58. package/dist/indice.js +3 -1
  59. package/dist/init.js +28 -5
  60. package/dist/integracoes-locais.js +4 -0
  61. package/dist/intelligence-graph-cli.js +267 -30
  62. package/dist/intelligence-graph-contexto.js +215 -0
  63. package/dist/intelligence-graph-contract.js +71 -12
  64. package/dist/intelligence-graph-extract-md.js +41 -23
  65. package/dist/intelligence-graph-extract-ts.js +181 -11
  66. package/dist/intelligence-graph-extract.js +186 -9
  67. package/dist/intelligence-graph-index.js +205 -24
  68. package/dist/intelligence-graph-parsers.js +6 -4
  69. package/dist/intelligence-graph-repo.js +10 -0
  70. package/dist/leases.js +680 -87
  71. package/dist/ledger-stats.js +15 -1
  72. package/dist/ledger.js +12 -0
  73. package/dist/licoes.js +6 -4
  74. package/dist/liveness.js +2 -1
  75. package/dist/maestro-runtime.js +7 -1
  76. package/dist/manifest.js +44 -1
  77. package/dist/master-nota.js +14 -5
  78. package/dist/master.js +129 -12
  79. package/dist/mcp-artifacts.js +36 -3
  80. package/dist/mcp-git.js +80 -15
  81. package/dist/mcp-grafo-worker.js +93 -0
  82. package/dist/mcp-grafo.js +279 -0
  83. package/dist/mcp-install.js +2 -1
  84. package/dist/mcp-server.js +23 -1
  85. package/dist/mcp-ship.js +2 -0
  86. package/dist/mcp-verify.js +3 -1
  87. package/dist/memoria.js +48 -6
  88. package/dist/network-roadmap.js +195 -20
  89. package/dist/ocupacao.js +17 -5
  90. package/dist/onboarding.js +9 -4
  91. package/dist/orkmind.js +90 -5
  92. package/dist/orquestracao.js +14 -11
  93. package/dist/parado-no-condutor.js +1089 -0
  94. package/dist/phase.js +68 -15
  95. package/dist/policies.js +79 -3
  96. package/dist/portfolio.js +4 -1
  97. package/dist/projeto-alvo.js +5 -1
  98. package/dist/prompts.js +36 -1
  99. package/dist/prova-ativacao.js +414 -0
  100. package/dist/pulse-delivery.js +60 -7
  101. package/dist/pulse.js +99 -3
  102. package/dist/ratelimit.js +20 -4
  103. package/dist/recall.js +3 -1
  104. package/dist/rede-adesao.js +399 -0
  105. package/dist/rede-forja.js +289 -0
  106. package/dist/rede-projetos.js +239 -0
  107. package/dist/rede-status.js +336 -0
  108. package/dist/rede.js +980 -0
  109. package/dist/retry.js +69 -2
  110. package/dist/roadmap-status.js +162 -7
  111. package/dist/runtime-context.js +5 -1
  112. package/dist/runtime-profiles.js +22 -1
  113. package/dist/saida-segura.js +58 -0
  114. package/dist/session-watcher-claude.js +113 -23
  115. package/dist/sessoes-contas.js +187 -0
  116. package/dist/sessoes-inventario.js +6 -12
  117. package/dist/sessoes.js +87 -3
  118. package/dist/ship.js +110 -20
  119. package/dist/thread.js +212 -14
  120. package/dist/util.js +71 -4
  121. package/dist/verify.js +2 -2
  122. package/dist/worktree.js +34 -8
  123. package/eval/casos/onboarding.json +1 -1
  124. package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
  125. package/package.json +7 -3
  126. package/references/definition-of-done.md +1 -1
  127. package/skills/README.md +1 -1
  128. package/skills/core/onboarding/SKILL.md +3 -2
  129. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  130. package/skills/phases/master-metrics/SKILL.md +8 -3
  131. package/skills/phases/ship-release/SKILL.md +6 -3
@@ -33,9 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.refRemota = void 0;
36
+ exports.refRemota = exports.remotoValido = exports.REMOTO_DO_GIT = void 0;
37
37
  exports.git = git;
38
38
  exports.exigirGit = exigirGit;
39
+ exports.remotoRedigido = remotoRedigido;
40
+ exports.exigirRemoto = exigirRemoto;
39
41
  exports.pontaLocal = pontaLocal;
40
42
  exports.buscarBranch = buscarBranch;
41
43
  exports.jsonsDaPonta = jsonsDaPonta;
@@ -57,6 +59,7 @@ const node_child_process_1 = require("node:child_process");
57
59
  const fs = __importStar(require("node:fs"));
58
60
  const os = __importStar(require("node:os"));
59
61
  const path = __importStar(require("node:path"));
62
+ const redacao_url_1 = require("./redacao-url");
60
63
  function git(raiz, args, extra = {}) {
61
64
  const r = (0, node_child_process_1.spawnSync)('git', args, { cwd: raiz, encoding: 'utf8', input: extra.input, timeout: extra.timeoutMs ?? 60000,
62
65
  env: { ...process.env, ...extra.env } });
@@ -68,6 +71,42 @@ function exigirGit(raiz, args, prefixo, extra = {}) {
68
71
  throw new Error(`${prefixo}.git: git ${args[0]} falhou: ${r.stderr.trim().split('\n').pop() ?? ''}`);
69
72
  return r.stdout;
70
73
  }
74
+ /**
75
+ * Nome de remoto do git, como `origin`, `upstream` ou `meu-remoto.2`. O valor vem do manifesto
76
+ * versionado (`fabrica.remoto`) ou da linha de comando (`--remoto`): quem clona um repositorio roda
77
+ * o `orkastery.yaml` de outra pessoa. Um valor que comece com `-` viraria opcao do git, e uma URL
78
+ * escolheria o transporte (`ext::` roda comando): so este formato chega ao git (RM-047).
79
+ */
80
+ exports.REMOTO_DO_GIT = /^[A-Za-z0-9][A-Za-z0-9._-]*(?:\/[A-Za-z0-9][A-Za-z0-9._-]*)*$/;
81
+ /**
82
+ * `true` quando o valor e nome de remoto que pode ir ao git como argumento. Suspeitas da revisao de
83
+ * 03/10: o git aceita `/` no nome (`time/origem`), e a 0.5.2 tambem; cada parte comeca por letra ou
84
+ * digito, entao a barra nao abre caminho absoluto, `.`/`..`, opcao nem transporte.
85
+ */
86
+ const remotoValido = (remoto) => typeof remoto === 'string' && remoto.length <= 64 && exports.REMOTO_DO_GIT.test(remoto) && !remoto.includes('..') && !remoto.endsWith('.');
87
+ exports.remotoValido = remotoValido;
88
+ /**
89
+ * O valor recusado, para a mensagem: sem credencial de URL, sem caractere de controle e curto.
90
+ * A mensagem vai ao terminal, ao log da publicacao em segundo plano e ao ledger.
91
+ */
92
+ function remotoRedigido(remoto) {
93
+ if (typeof remoto !== 'string')
94
+ return `(${remoto === null ? 'null' : typeof remoto})`;
95
+ const semCredencial = (0, redacao_url_1.redigirCredenciaisUrl)(remoto);
96
+ const curto = semCredencial.length > 40 ? `${semCredencial.slice(0, 40)}...` : semCredencial;
97
+ return JSON.stringify(curto);
98
+ }
99
+ /**
100
+ * Recusa tipada (`<prefixo>.remoto-invalido`) antes de qualquer chamada ao git com o remoto.
101
+ * `prefixo` e o de quem usa: `fabrica` na fabrica, `roadmap` nas reservas.
102
+ */
103
+ function exigirRemoto(remoto, prefixo) {
104
+ if ((0, exports.remotoValido)(remoto))
105
+ return remoto;
106
+ throw new Error(`${prefixo}.remoto-invalido: o remoto ${remotoRedigido(remoto)} não é nome de remoto do git ` +
107
+ '(letras, dígitos, ".", "_", "-" e "/" entre partes, cada parte começando por letra ou dígito, sem URL); nada foi passado ao git. ' +
108
+ 'Corrija fabrica.remoto no orkastery.yaml ou --remoto (padrão: origin).');
109
+ }
71
110
  const refRemota = (remoto, branch) => `refs/remotes/${remoto}/${branch}`;
72
111
  exports.refRemota = refRemota;
73
112
  /** A ultima copia lida da branch nesta maquina, sem rede. `null` quando nunca foi lida. */
@@ -80,16 +119,32 @@ function pontaLocal(raiz, remoto, branch) {
80
119
  * copia local com `atualizado: false`.
81
120
  */
82
121
  function buscarBranch(raiz, remoto, branch, prefixo, timeoutMs, env) {
83
- const r = git(raiz, ['fetch', '--quiet', '--no-tags', remoto, `+refs/heads/${branch}:${(0, exports.refRemota)(remoto, branch)}`], { timeoutMs, env });
84
- if (r.ok)
85
- return { ponta: exigirGit(raiz, ['rev-parse', '--verify', (0, exports.refRemota)(remoto, branch)], prefixo).trim(), atualizado: true };
86
- if (/couldn't find remote ref|could not find remote ref/i.test(r.stderr)) {
87
- // A branch ainda nao nasceu: a primeira gravacao a cria. Copia local antiga nao vale mais.
88
- git(raiz, ['update-ref', '-d', (0, exports.refRemota)(remoto, branch)]);
89
- return { ponta: null, atualizado: true };
122
+ exigirRemoto(remoto, prefixo);
123
+ for (let tentativa = 1;; tentativa++) {
124
+ // `--`: daqui para a frente, so repositorio e refspec, nunca opcao (RM-047).
125
+ const r = git(raiz, ['fetch', '--quiet', '--no-tags', '--', remoto, `+refs/heads/${branch}:${(0, exports.refRemota)(remoto, branch)}`], { timeoutMs, env });
126
+ if (r.ok)
127
+ return { ponta: exigirGit(raiz, ['rev-parse', '--verify', (0, exports.refRemota)(remoto, branch)], prefixo).trim(), atualizado: true };
128
+ if (/couldn't find remote ref|could not find remote ref/i.test(r.stderr)) {
129
+ // A branch ainda nao nasceu: a primeira gravacao a cria. Copia local antiga nao vale mais.
130
+ git(raiz, ['update-ref', '-d', (0, exports.refRemota)(remoto, branch)]);
131
+ return { ponta: null, atualizado: true };
132
+ }
133
+ if (tentativa < TENTATIVAS_NA_DISPUTA_DE_REF && DISPUTA_DE_REF.test(r.stderr)) {
134
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50 * tentativa);
135
+ continue;
136
+ }
137
+ return { ponta: pontaLocal(raiz, remoto, branch), atualizado: false };
90
138
  }
91
- return { ponta: pontaLocal(raiz, remoto, branch), atualizado: false };
92
139
  }
140
+ /**
141
+ * Suspeitas da revisao de 03/10: dois `fetch` simultaneos na mesma copia (o `ork network status` e a
142
+ * publicacao no cache da casa, a leitura e a gravacao da fabrica no clone) disputam o lock da ref
143
+ * remota, e o perdedor sai com "incorrect old value provided" (ou "cannot lock ref") sem que a rede
144
+ * tenha falhado. A ref ja foi atualizada pelo vencedor: buscar de novo da certo.
145
+ */
146
+ const DISPUTA_DE_REF = /incorrect old value provided|cannot lock ref|unable to create '[^']*\.lock'|is at [0-9a-f]+ but expected/i;
147
+ const TENTATIVAS_NA_DISPUTA_DE_REF = 5;
93
148
  /** Os `.json` de um diretorio da ponta, ja lidos. Filtro por caminho: diretorio vazio some da arvore. */
94
149
  function jsonsDaPonta(raiz, ponta, dir, prefixo) {
95
150
  if (!ponta)
@@ -103,6 +158,7 @@ function jsonsDaPonta(raiz, ponta, dir, prefixo) {
103
158
  * indice temporario, blobs, `write-tree` e `commit-tree`. Push sem forca; recusa volta `false`.
104
159
  */
105
160
  function gravarNaBranch(raiz, remoto, branch, ponta, mudancas, mensagem, prefixo, rede = {}) {
161
+ exigirRemoto(remoto, prefixo);
106
162
  const indice = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ork-branch-estado-')), 'index');
107
163
  const env = { GIT_INDEX_FILE: indice };
108
164
  try {
@@ -122,7 +178,7 @@ function gravarNaBranch(raiz, remoto, branch, ponta, mudancas, mensagem, prefixo
122
178
  const arvore = exigirGit(raiz, ['write-tree'], prefixo, { env }).trim();
123
179
  const commit = exigirGit(raiz, ['commit-tree', arvore, ...(ponta ? ['-p', ponta] : []), '-m', mensagem], prefixo).trim();
124
180
  // `rede`: prazo e ambiente so do que vai a rede (RM-037, achado A3: o fechamento nao espera 60 s).
125
- const push = git(raiz, ['push', '--quiet', remoto, `${commit}:refs/heads/${branch}`], rede);
181
+ const push = git(raiz, ['push', '--quiet', '--', remoto, `${commit}:refs/heads/${branch}`], rede);
126
182
  if (push.ok) {
127
183
  git(raiz, ['update-ref', (0, exports.refRemota)(remoto, branch), commit]);
128
184
  return commit;
@@ -6,10 +6,12 @@
6
6
  * deterministicos. Esta busca e superficie separada e todo resultado sai com
7
7
  * `deterministico: false`.
8
8
  *
9
- * O universo e o export governado do tenant (filtro de injecao e visibilidade da biblioteca):
9
+ * O universo e o universo da busca do tenant (RM-038: `universoDaBusca`, o mesmo do indice e do
10
+ * status, com a governanca da biblioteca aplicada na ponte):
10
11
  * - vetor: cosseno da consulta contra o indice local do MESMO modelo e dimensao, so para
11
12
  * entradas com sha256 coerente; nunca compara vetores de espacos diferentes;
12
- * - FTS: `search_by_text` da biblioteca, filtrado por tenant na ponte e intersectado aqui;
13
+ * - FTS: `search_by_text` da biblioteca, restrito ao universo na ponte e intersectado aqui (id
14
+ * fora do universo e descartado e declarado, nunca em silencio);
13
15
  * - fusao: RRF com k = 60.
14
16
  * A cadeia do vetor e primario, fallback local, nenhum; sem vetor, cai para FTS com motivo tipado.
15
17
  */
@@ -18,6 +20,7 @@ exports.CANDIDATOS_DO_VETOR = exports.LIMITE_MAXIMO_DA_BUSCA = exports.LIMITE_PA
18
20
  exports.cosseno = cosseno;
19
21
  exports.fundirRrf = fundirRrf;
20
22
  exports.buscarPorSignificado = buscarPorSignificado;
23
+ exports.textoDaBuscaPorSignificado = textoDaBuscaPorSignificado;
21
24
  const indice_vetorial_1 = require("./indice-vetorial");
22
25
  exports.MODOS_DE_BUSCA = ['hibrido', 'vetor', 'fts'];
23
26
  /** D9: constante da fusao RRF. */
@@ -44,7 +47,7 @@ function fundirRrf(listas, k = exports.RRF_K) {
44
47
  }
45
48
  const resumo = (conteudo) => conteudo.split('\n')[0].slice(0, 100);
46
49
  /** Lado vetorial: o primeiro caminho da cadeia que tem indice, responde e fala o mesmo espaco. */
47
- function ladoVetorial(o) {
50
+ function ladoVetorial(o, entradas) {
48
51
  const detalhes = [];
49
52
  let motivo = null;
50
53
  const falhar = (alvo, m, d) => {
@@ -103,7 +106,7 @@ function ladoVetorial(o) {
103
106
  }
104
107
  if (resposta.truncados?.length)
105
108
  detalhes.push(`${alvo}: consulta acima do contexto do modelo, embedada pelo comeco`);
106
- const ranking = [...(0, indice_vetorial_1.vetoresCoerentes)(lido.indice, o.universo)]
109
+ const ranking = [...(0, indice_vetorial_1.vetoresCoerentes)(lido.indice, entradas)]
107
110
  .map(([id, v]) => ({ id, sim: cosseno(vetor, v) }))
108
111
  .sort((a, b) => b.sim - a.sim || a.id.localeCompare(b.id));
109
112
  return { alvo, modelo: espaco.modelo, ranking, motivo, detalhes };
@@ -112,14 +115,21 @@ function ladoVetorial(o) {
112
115
  }
113
116
  /** `ork memory search --texto`: ranking hibrido, nunca deterministico, sempre dentro do tenant. */
114
117
  function buscarPorSignificado(o) {
115
- const universo = o.universo.filter(e => (e.tags.project ?? []).includes(o.tenant));
116
- const porId = new Map(universo.map(e => [e.id, e]));
118
+ // RM-038 (D6): entrada alheia no universo e violacao antes de embedar a consulta, nunca descarte.
119
+ if (o.universo.tenant !== o.tenant)
120
+ throw new Error('memory.query.scope-violation');
121
+ (0, indice_vetorial_1.conferirUniverso)(o.universo.entradas, o.tenant, o.universo.lidoEm);
122
+ const doUniverso = new Set(o.universo.entradas.map(e => e.id));
123
+ // As entradas buscadas: o universo inteiro, ou so a colecao pedida.
124
+ const buscadas = o.colecao ? o.universo.entradas.filter(e => e.collection === o.colecao) : o.universo.entradas;
125
+ const porId = new Map(buscadas.map(e => [e.id, e]));
117
126
  const saida = { texto: o.texto, modo: o.modo, origem: 'nenhum', modeloUsado: null,
118
- deterministico: false, motivo: null, detalhe: '', resultados: [], listas: { vetor: [], fts: [] } };
127
+ deterministico: false, motivo: null, detalhe: '', resultados: [], listas: { vetor: [], fts: [] },
128
+ ftsForaDoUniverso: 0, coberturaDoIndice: null };
119
129
  const detalhes = [];
120
130
  let similaridade = new Map();
121
131
  if (o.modo !== 'fts') {
122
- const v = ladoVetorial({ ...o, universo });
132
+ const v = ladoVetorial(o, buscadas);
123
133
  detalhes.push(...v.detalhes);
124
134
  saida.motivo = v.motivo;
125
135
  if (v.alvo) {
@@ -128,22 +138,33 @@ function buscarPorSignificado(o) {
128
138
  const candidatos = v.ranking.slice(0, exports.CANDIDATOS_DO_VETOR);
129
139
  saida.listas.vetor = candidatos.map(c => c.id);
130
140
  similaridade = new Map(candidatos.map(c => [c.id, c.sim]));
141
+ // RM-038 (D7): o vetor so ranqueia o que o indice cobre; menos que o universo e dito aqui.
142
+ saida.coberturaDoIndice = { coerentes: v.ranking.length, universo: buscadas.length };
143
+ const aviso = (0, indice_vetorial_1.avisoDeCobertura)(v.ranking.length, buscadas, v.alvo, o.colecao ? ` na colecao ${o.colecao}` : '');
144
+ if (aviso)
145
+ detalhes.push(`vetor: ${aviso}`);
131
146
  }
132
147
  }
133
148
  if (o.modo !== 'vetor') {
149
+ let ftsFalhou = false;
134
150
  try {
135
151
  if (!o.buscarTexto)
136
152
  throw new Error('memory.transport.fts');
137
- // A ponte ja filtra o tenant; a intersecao com o universo governado vale de novo aqui.
138
- saida.listas.fts = [...new Set(o.buscarTexto(o.tenant, o.texto))].filter(id => porId.has(id));
153
+ // A ponte ja restringe ao universo; a intersecao vale de novo aqui e a quantidade que sobra e declarada (D5).
154
+ const ids = [...new Set(o.buscarTexto(o.tenant, o.texto))];
155
+ saida.ftsForaDoUniverso = ids.filter(id => !doUniverso.has(id)).length;
156
+ if (saida.ftsForaDoUniverso)
157
+ detalhes.push(`fts: ${saida.ftsForaDoUniverso} id(s) fora do universo da busca descartado(s)`);
158
+ saida.listas.fts = ids.filter(id => porId.has(id));
139
159
  }
140
160
  catch (erro) {
141
- const codigo = /^[a-z]+(?:\.[a-z-]+)+/.exec(erro instanceof Error ? erro.message : '')?.[0] ?? 'memory.transport.fts';
161
+ ftsFalhou = true;
162
+ const codigo = (0, indice_vetorial_1.codigoDaFalha)(erro, 'memory.transport.fts');
142
163
  detalhes.push(`fts: ${codigo}`);
143
164
  if (o.modo === 'fts' || saida.origem === 'nenhum')
144
165
  saida.motivo = saida.motivo ?? codigo;
145
166
  }
146
- if (saida.origem === 'nenhum' && !detalhes.some(d => d.startsWith('fts:')))
167
+ if (saida.origem === 'nenhum' && !ftsFalhou)
147
168
  saida.origem = 'fts';
148
169
  }
149
170
  const scores = fundirRrf([saida.listas.vetor, saida.listas.fts]);
@@ -159,3 +180,22 @@ function buscarPorSignificado(o) {
159
180
  saida.detalhe = detalhes.join('; ');
160
181
  return saida;
161
182
  }
183
+ /**
184
+ * Texto de `ork memory search --texto`. Revisao de 03/10 (RM-038): o detalhe sai tambem sem motivo; o
185
+ * id do FTS fora do universo e o aviso de cobertura vivem nele, e o texto os perdia na busca que deu certo.
186
+ */
187
+ function textoDaBuscaPorSignificado(r) {
188
+ const linhas = [`Busca por significado (NAO deterministica; modo ${r.modo}, origem ${r.origem}${r.modeloUsado ? ` ${r.modeloUsado}` : ''})`];
189
+ if (r.motivo)
190
+ linhas.push(` motivo: ${r.motivo}${r.detalhe ? `; ${r.detalhe}` : ''}`);
191
+ else if (r.detalhe)
192
+ linhas.push(` detalhe: ${r.detalhe}`);
193
+ linhas.push('');
194
+ r.resultados.forEach((e, i) => {
195
+ const sim = e.similaridade === null ? '' : ` similaridade ${e.similaridade}`;
196
+ linhas.push(` ${i + 1}. [${e.collection}] ${e.id} score ${e.score} ${e.fontes.join('+')}${sim}`);
197
+ linhas.push(` ${e.resumo}`);
198
+ });
199
+ linhas.push('', ` ${r.resultados.length} resultado(s); busca por tag continua em ork memory search --tags`);
200
+ return linhas.join('\n');
201
+ }
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.fxPedidoColado = exports.PROMPTS_DE_CONDUCAO = exports.FRASE_DO_PEDIDO_COLADO = exports.PEDIDO_COLADO_DO_INCIDENTE = void 0;
37
+ /**
38
+ * RM-057 (fatia 2): o canario do incidente de 01/10/2026.
39
+ *
40
+ * Na noite de 01 para 02/10 o condutor recebeu, colado, o pedido do dono com push e merge
41
+ * autorizados ate um horario, parou para pedir um "confirmo" em texto livre e a fabrica ficou mais
42
+ * de 10 h sem produzir. O canario refaz a conducao inteira em sandbox SIMULADO e exige que o mesmo
43
+ * pedido colado siga sem parar:
44
+ *
45
+ * 1. o modo sai da #TAG do texto colado (`#Auto`), pelo nucleo;
46
+ * 2. o `#Auto` nao abre pausa humana na fase;
47
+ * 3. a duvida dentro da autorizacao vira decisao informada (`ork decisao registrar`), sem pergunta;
48
+ * 4. o "confirmo" em texto livre que o condutor tentaria abrir e recusado com
49
+ * `hitl.selecao.texto-livre`, sem gravar nada no ledger;
50
+ * 5. o pulse nao mostra ninguem esperando o dono, e o tempo parado por HITL de conducao e zero;
51
+ * 6. os quatro adaptadores de conducao (Claude Code, Codex, Hermes e OpenClaw) dizem que o pedido
52
+ * colado com autorizacao explicita vale como instrucao do dono.
53
+ *
54
+ * Nada aqui e resposta humana nem rede: e a forma da conducao, provada contra o codigo real.
55
+ */
56
+ const fs = __importStar(require("node:fs"));
57
+ const path = __importStar(require("node:path"));
58
+ const decisao_autonoma_1 = require("./decisao-autonoma");
59
+ const hitl_contract_1 = require("./hitl-contract");
60
+ const hitl_gates_1 = require("./hitl-gates");
61
+ const ledger_1 = require("./ledger");
62
+ const ledger_stats_1 = require("./ledger-stats");
63
+ const modos_1 = require("./modos");
64
+ const pulse_1 = require("./pulse");
65
+ const sandbox_1 = require("./sandbox");
66
+ const thread_1 = require("./thread");
67
+ /** O pedido do dono como chegou colado no incidente, com a autorizacao explicita e o prazo. */
68
+ exports.PEDIDO_COLADO_DO_INCIDENTE = '#Auto Conduza as threads RM-032, RM-056, RM-053, RM-040 e RM-055 no orkastery. ' +
69
+ 'Push e merge autorizados até 02/10 às 12h. Não me pergunte nada: dúvida menor vira decisão registrada e segue.';
70
+ /** A frase que os quatro adaptadores de conducao carregam desde a RM-057. */
71
+ exports.FRASE_DO_PEDIDO_COLADO = 'o pedido que ele colou com autorização explícita vale como instrução dele';
72
+ /** Onde cada host le a regra: o comando, as skills e as descricoes das tools do OpenClaw. */
73
+ exports.PROMPTS_DE_CONDUCAO = [
74
+ 'adapters/claude-code/commands/ork.md',
75
+ 'adapters/codex/skills/ork/SKILL.md',
76
+ 'adapters/hermes/skills/orkastery-devmaster/SKILL.md',
77
+ 'adapters/openclaw/dist/index.js',
78
+ ];
79
+ exports.fxPedidoColado = {
80
+ id: 'fx-pedido-colado',
81
+ sobre: 'SIMULADO: o pedido colado com autorização explícita segue sem parar (incidente de 01/10, RM-057)',
82
+ precisaDeGit: true,
83
+ rodar: (ctx) => {
84
+ const s = (0, sandbox_1.sandboxGit)('pedido-colado');
85
+ try {
86
+ const modo = (0, modos_1.extrairTagDoPedido)(exports.PEDIDO_COLADO_DO_INCIDENTE);
87
+ const t = (0, thread_1.novaThread)(s.carregado, { nome: 'pedido-colado', modo: modo ?? 'classic' }).thread;
88
+ const dir = (0, thread_1.dirThread)(s.dir, t.id);
89
+ (0, ledger_1.registrar)(dir, t.id, 'phase_result', { fase: t.faseAtual });
90
+ let semPausaDoModo = false;
91
+ try {
92
+ (0, hitl_gates_1.abrirPedidoGate)(s.dir, t.id);
93
+ }
94
+ catch (e) {
95
+ semPausaDoModo = /não prevê pausa/.test(e.message);
96
+ }
97
+ const decisao = (0, decisao_autonoma_1.registrarDecisao)(s.dir, t.id, {
98
+ decidido: 'Seguir com push e merge dentro da autorização colada', porque: 'o dono autorizou até 02/10 às 12h',
99
+ comoMudar: 'reverter o merge', custoDeReverter: { agora: 'um revert', depois: 'um revert' },
100
+ criterio: { tipo: 'ledger', referencia: `${t.id}#evento:1` }, quemDecidiu: 'canario-SIMULADO', evidencia: 'pedido colado',
101
+ });
102
+ const confirmo = {
103
+ contrato: hitl_contract_1.CONTRATO_HITL_V2, id: 'confirmo-SIMULADO', thread: t.id, fase: t.faseAtual, modo: t.modo,
104
+ criadoEm: new Date().toISOString(), profundidade: 'resumo', classe: 'pergunta',
105
+ alvo: { tipo: 'gate', sobre: 'premissas' }, motivo: 'human.pending', pergunta: 'Posso seguir com o push e o merge?',
106
+ alternativas: [
107
+ { letra: 'a', texto: 'Seguir', acao: 'aprovar', consequencia: 'segue', recomendada: true, porque: 'autorizado no pedido' },
108
+ { letra: 'b', texto: 'Parar', acao: 'recusar', consequencia: 'para' },
109
+ { letra: 'c', texto: 'Esperar', acao: 'esperar', consequencia: 'fica' },
110
+ ],
111
+ corpo: ['Responda confirmo para eu continuar'], tipoDeResposta: 'aberta', irreversivel: false, codigo: 'K3F9',
112
+ prazo: new Date(Date.now() + 3_600_000).toISOString(), acaoPadraoAoExpirar: 'esperar',
113
+ respostaAceita: { tipo: 'texto', maxCaracteres: 200 },
114
+ };
115
+ const antes = (0, ledger_1.lerLedger)(dir).length;
116
+ let confirmoRecusado = 'aceito';
117
+ try {
118
+ (0, hitl_gates_1.registrarPedidoHitl)(s.dir, confirmo);
119
+ }
120
+ catch (e) {
121
+ confirmoRecusado = e instanceof hitl_contract_1.SelecaoRecusada ? e.motivo : `outro: ${e.message}`;
122
+ }
123
+ const nadaGravadoNaRecusa = (0, ledger_1.lerLedger)(dir).length === antes;
124
+ const pulse = (0, pulse_1.montarPulse)(s.carregado, { consulta: { ok: true, sessoes: [], detalhe: 'runtime SIMULADO' } });
125
+ const parado = (0, ledger_stats_1.coletarEstatisticas)(s.dir, { desde: '1h', thread: t.id }).hitlDeConducao;
126
+ // No dist do OpenClaw a frase e uma concatenacao de literais: as emendas `' + '` saem antes da busca.
127
+ const umaLinha = (x) => x.replace(/'\s*\+\s*'/g, '').replace(/\s+/g, ' ');
128
+ const adaptadoresComARegra = exports.PROMPTS_DE_CONDUCAO.filter((rel) => {
129
+ const arquivo = path.join(ctx.catalogo, rel);
130
+ return fs.existsSync(arquivo) && umaLinha(fs.readFileSync(arquivo, 'utf8')).includes(exports.FRASE_DO_PEDIDO_COLADO);
131
+ }).length;
132
+ return {
133
+ simulado: true,
134
+ modoDoPedido: modo,
135
+ semPausaDoModo,
136
+ decisaoInformada: decisao.pedido.classe === 'decidido',
137
+ confirmoRecusado,
138
+ nadaGravadoNaRecusa,
139
+ humanosNoPulse: pulse.resumo.humanos,
140
+ perguntasDeConducao: parado.pedidos,
141
+ tempoParadoMs: parado.paradoMs,
142
+ adaptadoresComARegra,
143
+ };
144
+ }
145
+ finally {
146
+ s.limpar();
147
+ }
148
+ },
149
+ };
package/dist/canarios.js CHANGED
@@ -71,6 +71,7 @@ const canarios_pulse_1 = require("./canarios-pulse");
71
71
  const canarios_sensores_1 = require("./canarios-sensores");
72
72
  const canarios_hitl_1 = require("./canarios-hitl");
73
73
  const canarios_i43_1 = require("./canarios-i43");
74
+ const canarios_rm057_1 = require("./canarios-rm057");
74
75
  const objective_1 = require("./objective");
75
76
  const maestro_discovery_1 = require("./maestro-discovery");
76
77
  const maestro_cli_1 = require("./maestro-cli");
@@ -373,6 +374,7 @@ exports.CANARIOS = [
373
374
  canarios_sensores_1.CANARIO_SENSORES,
374
375
  ...canarios_hitl_1.CANARIOS_HITL,
375
376
  ...canarios_i43_1.CANARIOS_I43,
377
+ canarios_rm057_1.fxPedidoColado,
376
378
  ];
377
379
  /** Um canario por id, ou null quando a fixture aponta para um canario que nao existe. */
378
380
  function canarioPorId(id) {
package/dist/ci.js CHANGED
@@ -46,6 +46,8 @@ exports.prepararBundleCi = prepararBundleCi;
46
46
  exports.bundleDaBranch = bundleDaBranch;
47
47
  exports.executarCiDaBranch = executarCiDaBranch;
48
48
  exports.executarBundleCi = executarBundleCi;
49
+ /** GitHub CI como CHECK independente (I-12). */
50
+ const branch_de_estado_1 = require("./branch-de-estado");
49
51
  const util_1 = require("./util");
50
52
  const worktree_1 = require("./worktree");
51
53
  const verify_1 = require("./verify");
@@ -73,9 +75,13 @@ const CASOS_DE_VERIFICADOR_COM_INTEGRACAO_LOCAL = [
73
75
  /verify-check-c2-b3\.cjs\s+channel-offer(?:\s|$)/,
74
76
  // I-38: a prova da busca por significado le a memoria do tenant pela DSN do manifesto.
75
77
  /prova-busca-semantica\.sh(?:\s|$)/,
78
+ // RM-038: a prova do universo da busca tambem le a memoria do tenant pela DSN do manifesto.
79
+ /prova-universo-da-busca\.cjs(?:\s|$)/,
76
80
  // RM-051: o ensaio instala o tarball com npm --offline e resolve as dependencias pelo cache do npm
77
81
  // da estacao; o runner hospedado so tem os tarballs do npm ci, sem os metadados do registro.
78
82
  /testar-experiencia-e2e\.cjs(?:\s|$)/,
83
+ // RM-037: a suite local inteira, com as integracoes locais; o runner hospedado roda o test:ci.
84
+ /suite-local\.cjs(?:\s|$)/,
79
85
  ];
80
86
  /**
81
87
  * I-38: o runner hospedado nao oferece OrkMind nem a base do tenant. Claim que chama a memoria
@@ -133,7 +139,8 @@ function consultarCi(carregado, sha, remoto = 'origin', executor = executorPadra
133
139
  const context = ci.context || 'ork-verify';
134
140
  if (!ci.required_for_ship)
135
141
  return { schema: 'ork.ci-status/v1', required: false, ok: true, provider: 'github', repository: null, sha, context, state: 'disabled', url: null, detail: 'gate de CI não exigido pelo manifesto' };
136
- const remote = (0, util_1.exec)('git', ['remote', 'get-url', remoto], carregado.raiz);
142
+ // RM-047: o `--remoto` do `ork ci status` vem da linha de comando; so nome de remoto chega ao git.
143
+ const remote = (0, util_1.exec)('git', ['remote', 'get-url', '--', (0, branch_de_estado_1.exigirRemoto)(remoto, 'ci')], carregado.raiz);
137
144
  const repository = remote.ok ? repositorioGitHub(remote.stdout) : null;
138
145
  if (!repository)
139
146
  return { schema: 'ork.ci-status/v1', required: true, ok: false, provider: 'github', repository: null, sha, context, state: 'unavailable', url: null, detail: `remoto ${remoto} não é um repositório GitHub reconhecível` };
@@ -20,7 +20,9 @@ exports.analisarComando = analisarComando;
20
20
  exports.analisarComandos = analisarComandos;
21
21
  exports.linhaDoLintDeClaim = linhaDoLintDeClaim;
22
22
  const CORRECAO = {
23
- 'suite-inteira': 'use `npm --prefix core run test:ci` (a suite hermetica) ou `node --test` no arquivo do teste',
23
+ // Fatia 2 do ensaio da 0.5.0 (P6): a correcao vale para qualquer projeto; o script do Orkastery saiu daqui.
24
+ 'suite-inteira': 'rode só o teste da claim (`node --test` no arquivo do teste, ou o comando do projeto que roda um arquivo) ' +
25
+ 'ou um script hermético do projeto',
24
26
  'sha-intermediario': 'ancore na base (`git diff "$(git merge-base origin/main HEAD)" HEAD`) ou prove ancestralidade com `git merge-base --is-ancestor <sha> HEAD`',
25
27
  'contagem-de-commits': 'use `git merge-base --is-ancestor <commit> HEAD`: contagem de commits quebra com rebase e merge',
26
28
  };
package/dist/claims.js CHANGED
@@ -58,11 +58,14 @@ exports.anexarComando = anexarComando;
58
58
  exports.retirarClaim = retirarClaim;
59
59
  exports.carimbarEstado = carimbarEstado;
60
60
  exports.tabelaDeClaims = tabelaDeClaims;
61
+ const fs = __importStar(require("node:fs"));
61
62
  const path = __importStar(require("node:path"));
62
63
  const ledger_1 = require("./ledger");
63
64
  const manifest_1 = require("./manifest");
64
65
  const prova_minima_1 = require("./prova-minima");
65
66
  const thread_1 = require("./thread");
67
+ const policies_1 = require("./policies");
68
+ const verify_1 = require("./verify");
66
69
  const util_1 = require("./util");
67
70
  const claim_lint_1 = require("./claim-lint");
68
71
  /** Caminho do `claims.jsonl` da thread (append-only, como o ledger). */
@@ -165,7 +168,42 @@ function adicionarClaim(raiz, threadId, opcoes) {
165
168
  estado: claim.estado,
166
169
  ...(claim.lint?.length ? { lint: claim.lint.map((a) => a.regra) } : {}),
167
170
  });
168
- return claim;
171
+ const avisosDePolicy = opcoes.semProvaLocal ? [] : conferirProvaLocal(raiz, thread, claim, opcoes.executarProva ?? verify_1.executar);
172
+ return avisosDePolicy.length ? { ...claim, avisosDePolicy } : claim;
173
+ }
174
+ /**
175
+ * RM-008 (B8): com `claim_sem_prova_local` (ou `claims_failed`) declarada, o registro roda o comando da
176
+ * claim uma vez, na worktree da thread e no prazo do verify. A claim ja entrou: reprovacao ou estouro
177
+ * so gravam `policy_warn` no ledger e voltam como aviso. Sem a policy, nada roda.
178
+ */
179
+ function conferirProvaLocal(raiz, thread, claim, executarProva) {
180
+ const carregado = (0, manifest_1.carregarManifesto)(raiz);
181
+ if (!carregado || claim.verificar.length === 0 || !(0, policies_1.policyDeProvaLocal)(carregado.manifesto))
182
+ return [];
183
+ const prazoMs = carregado.manifesto.verify.timeout_ms ?? verify_1.TIMEOUT_VERIFY_MS;
184
+ const cwd = (0, verify_1.cwdDaThread)(raiz, thread);
185
+ let reprovada;
186
+ // Suspeitas da revisao de 03/10: sem a worktree (apagada), nada roda e o aviso diz por que, sem culpar a claim.
187
+ if (!fs.existsSync(cwd))
188
+ reprovada = { comando: claim.verificar[0], code: -1, estourou: false, semDiretorio: cwd };
189
+ for (const comando of reprovada ? [] : claim.verificar) {
190
+ const r = executarProva(`claim ${claim.id}`, comando, cwd, prazoMs);
191
+ if (!r.ok) {
192
+ reprovada = { comando, code: r.code, estourou: r.causa === 'timeout' };
193
+ break;
194
+ }
195
+ }
196
+ if (!reprovada)
197
+ return [];
198
+ const violacoes = (0, policies_1.avisos)((0, policies_1.avaliarPolicies)(carregado.manifesto, {
199
+ gate: 'claims.add', threadId: thread.id, modo: thread.modo, fase: claim.fase ?? undefined,
200
+ provaLocalReprovada: { claim: claim.id, ...reprovada, prazoMs },
201
+ }));
202
+ for (const v of violacoes) {
203
+ (0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, thread.id), thread.id, ledger_1.TIPOS_DE_EVENTO.politicaAviso, { gate: 'claims.add', claim: claim.id,
204
+ fase: claim.fase, policy: v.policy, motivo: v.motivo, detalhe: v.detalhe, correcao: v.correcao, modo: thread.modo });
205
+ }
206
+ return violacoes;
169
207
  }
170
208
  /** Prefixo do arquivo das claims de criterio, para o veredito dizer de onde veio. */
171
209
  exports.ARQUIVO_DONEWHEN = 'thread.json#doneWhen';