@orkastery/cli 0.5.1 → 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.
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/ork.md +9 -0
- package/adapters/codex/skills/ork/SKILL.md +18 -3
- package/adapters/hermes/README.md +1 -0
- package/adapters/hermes/bin/ork-network-status.sh +10 -0
- package/adapters/hermes/hermes.plugin.json +1 -0
- package/adapters/hermes/hitl-ingress/__init__.py +2 -2
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
- package/adapters/openclaw/README.md +24 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +46 -11
- package/adapters/openclaw/openclaw.plugin.json +5 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +2 -2
- package/adapters/openclaw/src/index.ts +49 -11
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +39 -5
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +5 -1
- package/dist/board.js +16 -14
- package/dist/branch-de-estado.js +66 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/ci.js +8 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +48 -9
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +89 -9
- package/dist/entrega-pr.js +20 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +14 -6
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/forja.js +31 -7
- package/dist/gates.js +5 -1
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +9 -0
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/horario.js +27 -0
- package/dist/hosts.js +52 -10
- package/dist/impedimento.js +205 -0
- package/dist/index.js +391 -74
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +17 -0
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +91 -8
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +3 -0
- package/dist/licoes.js +1 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +20 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +34 -3
- package/dist/mcp-git.js +20 -3
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +50 -4
- package/dist/mcp-server.js +14 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +191 -16
- package/dist/ocupacao.js +11 -3
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +12 -10
- package/dist/parado-no-condutor.js +188 -32
- package/dist/phase.js +68 -15
- package/dist/policies.js +52 -1
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +34 -2
- package/dist/pulse.js +49 -3
- package/dist/ratelimit.js +20 -4
- package/dist/recall.js +3 -1
- package/dist/rede-adesao.js +399 -0
- package/dist/rede-forja.js +289 -0
- package/dist/rede-projetos.js +239 -0
- package/dist/rede-status.js +336 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +69 -2
- package/dist/roadmap-status.js +23 -3
- package/dist/runtime-profiles.js +22 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-watcher-claude.js +113 -23
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship.js +85 -19
- package/dist/thread.js +192 -13
- package/dist/worktree.js +5 -2
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/skills/README.md +1 -1
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
package/dist/mcp-server.js
CHANGED
|
@@ -58,6 +58,7 @@ const hitl_contract_1 = require("./hitl-contract");
|
|
|
58
58
|
const hitl_presentation_1 = require("./hitl-presentation");
|
|
59
59
|
const roadmap_status_1 = require("./roadmap-status");
|
|
60
60
|
const network_roadmap_1 = require("./network-roadmap");
|
|
61
|
+
const rede_status_1 = require("./rede-status");
|
|
61
62
|
const hitl_sessions_1 = require("./hitl-sessions");
|
|
62
63
|
const hitl_local_1 = require("./hitl-local");
|
|
63
64
|
const mcp_artifacts_1 = require("./mcp-artifacts");
|
|
@@ -107,7 +108,9 @@ const nova = zod_1.z.object({ nome: zod_1.z.string().trim().min(1).max(200),
|
|
|
107
108
|
const fase = daThread.extend({ fase: zod_1.z.enum(['GOAL', 'PLAN', 'GO', 'CHECK', 'SHIP', 'MASTER']),
|
|
108
109
|
prompt: zod_1.z.string().min(1).max(65536), runtime: zod_1.z.enum(['claude-bg', 'codex']).optional(),
|
|
109
110
|
model: zod_1.z.string().trim().min(1).max(200).optional(),
|
|
110
|
-
effort: zod_1.z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),
|
|
111
|
+
effort: zod_1.z.enum(['low', 'medium', 'high', 'xhigh', 'max']).optional(),
|
|
112
|
+
// RM-056 (D1): o perfil pedido, validado contra o store pelo mesmo caminho do CLI.
|
|
113
|
+
perfil: zod_1.z.string().trim().regex(/^[a-z0-9][a-z0-9._-]{0,62}$/i).optional(), dryRun: zod_1.z.boolean().optional() }).strict();
|
|
111
114
|
// Limite de tipos do conversor externo: validacao continua no schema Zod strict.
|
|
112
115
|
const converterSchema = zod_to_json_schema_1.zodToJsonSchema;
|
|
113
116
|
const resposta = (valor) => ({ content: [{ type: 'text', text: JSON.stringify(valor) }] });
|
|
@@ -502,6 +505,16 @@ function criarServidorMcp(opcoes) {
|
|
|
502
505
|
const panorama = (0, network_roadmap_1.montarPanoramaDaRede)({ fixado: raiz });
|
|
503
506
|
return resposta({ texto: (0, network_roadmap_1.textoDoPanoramaDaRede)(panorama), panorama });
|
|
504
507
|
});
|
|
508
|
+
/**
|
|
509
|
+
* RM-054 (fatia 3): as maquinas da pessoa (RM-053, `ork.rede-status/v1`), com a fonte, a batida e as
|
|
510
|
+
* lacunas. O retrato de cada maquina fica so com o projeto servido (D5 da RM-052).
|
|
511
|
+
*/
|
|
512
|
+
registrarTool('ork_network_status', { description: 'Status da Orkastery Network, somente leitura: as maquinas da pessoa (casa privada na forja), com a batida de cada uma, a forja e o login, os runtimes e hosts com versao e o projeto servido em cada uma, mais a fonte e as lacunas. Transporte o texto como vem. Lacuna e "Nao consultado" sao o que nao foi lido: nunca conclua "nenhuma maquina" nem "rede vazia" a partir deles. Nao le roadmap nem threads: para isso, ork_network_roadmap.',
|
|
513
|
+
inputSchema: zod_1.z.object({}).strict(), annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: true } }, async () => {
|
|
514
|
+
carregar();
|
|
515
|
+
const status = (0, network_roadmap_1.redeDoProjetoFixado)(raiz);
|
|
516
|
+
return resposta({ texto: (0, rede_status_1.textoDaRede)(status), status: JSON.parse((0, rede_status_1.jsonDaRede)(status)) });
|
|
517
|
+
});
|
|
505
518
|
registrarTool('ork_observe', { description: 'Observa uma vez o progresso canonico e pedidos da thread. Nao cria monitor ou despacho.',
|
|
506
519
|
inputSchema: daThread, annotations: { readOnlyHint: true } }, async ({ threadId }) => {
|
|
507
520
|
return resposta(observar(threadId));
|
package/dist/memoria.js
CHANGED
|
@@ -172,7 +172,7 @@ function abrirMemoria(carregado, opcoes = {}) {
|
|
|
172
172
|
const { estado, driver } = (0, orkmind_1.resolverRegime)(carregado.manifesto, opcoes.driver ?? null);
|
|
173
173
|
const ativo = estado.efetivo === 'orkmind' && driver !== null;
|
|
174
174
|
const config = (0, orkmind_1.configDoManifesto)(carregado.manifesto);
|
|
175
|
-
const embeddings = (
|
|
175
|
+
const embeddings = (leitura = {}) => estadoDeEmbeddings(carregado.manifesto, ativo ? driver?.disponivel().saude ?? null : null, carregado.raiz, estado.tenant, config.dsn, leitura);
|
|
176
176
|
if (estado.pedido === 'orkmind')
|
|
177
177
|
estado.embeddings = embeddings();
|
|
178
178
|
const consultarRestrito = (collection, tags) => {
|
|
@@ -250,10 +250,30 @@ function abrirMemoria(carregado, opcoes = {}) {
|
|
|
250
250
|
return null;
|
|
251
251
|
return driver.exportar(colecao).find((e) => e.id === id) ?? null;
|
|
252
252
|
},
|
|
253
|
+
universo(tenant) {
|
|
254
|
+
// A fronteira do manifesto vale antes de qualquer leitura: tenant e so o configurado.
|
|
255
|
+
if (tenant !== estado.tenant)
|
|
256
|
+
throw new Error('memory.tenant.mismatch');
|
|
257
|
+
if (leituraRestrita)
|
|
258
|
+
throw new Error('memory.query.invalid');
|
|
259
|
+
if (!ativo || !driver)
|
|
260
|
+
throw new Error('memory.universo.indisponivel');
|
|
261
|
+
if (typeof driver.universo !== 'function')
|
|
262
|
+
throw new Error('memory.universo.unsupported');
|
|
263
|
+
return driver.universo(tenant);
|
|
264
|
+
},
|
|
253
265
|
};
|
|
254
|
-
//
|
|
266
|
+
// RM-038: a cobertura precisa do universo da busca (uma leitura pela ponte): so quando pedida. Falha
|
|
267
|
+
// de leitura (janela saturada, fronteira violada) vira motivo tipado no estado, nunca cobertura inventada.
|
|
255
268
|
if (opcoes.embeddings === 'detalhado' && ativo && !leituraRestrita) {
|
|
256
|
-
|
|
269
|
+
let leitura;
|
|
270
|
+
try {
|
|
271
|
+
leitura = { universo: (0, indice_vetorial_1.universoDaBusca)(memoria, estado.tenant) };
|
|
272
|
+
}
|
|
273
|
+
catch (erro) {
|
|
274
|
+
leitura = { falhaDoUniverso: (0, indice_vetorial_1.codigoDaFalha)(erro) };
|
|
275
|
+
}
|
|
276
|
+
estado.embeddings = embeddings(leitura);
|
|
257
277
|
}
|
|
258
278
|
return memoria;
|
|
259
279
|
}
|
|
@@ -300,6 +320,7 @@ function estadoDeEmbeddings(manifesto, saude, raiz, tenant, dsn, opcoes = {}) {
|
|
|
300
320
|
const estado = {
|
|
301
321
|
configurado, provider: config.provider, modelo: configurado ? config.model : null, dim: configurado ? config.dim : null,
|
|
302
322
|
variavelDaChave: variavel, chavePresente, fallback, indices: [], entradas: null, cobertura: null,
|
|
323
|
+
universo: null, aviso: null, falhaDoUniverso: null,
|
|
303
324
|
ativo: 'nenhum', sondado: saude !== null, motivo: null, detalhe: '', correcao: '',
|
|
304
325
|
};
|
|
305
326
|
if (!configurado) {
|
|
@@ -331,13 +352,24 @@ function estadoDeEmbeddings(manifesto, saude, raiz, tenant, dsn, opcoes = {}) {
|
|
|
331
352
|
estado.correcao = `exporte ${variavel} com a chave dedicada ao Orkastery; o valor nunca vai ao manifesto`;
|
|
332
353
|
}
|
|
333
354
|
if (opcoes.universo) {
|
|
334
|
-
|
|
355
|
+
// RM-038: o universo vem de universoDaBusca; a fronteira vale de novo antes de contar.
|
|
356
|
+
if (opcoes.universo.tenant !== tenant)
|
|
357
|
+
throw new Error('memory.query.scope-violation');
|
|
358
|
+
(0, indice_vetorial_1.conferirUniverso)(opcoes.universo.entradas, tenant, opcoes.universo.lidoEm);
|
|
359
|
+
const universo = opcoes.universo.entradas;
|
|
335
360
|
estado.indices = indicesDoTenant(raiz, tenant, base, universo);
|
|
336
361
|
estado.entradas = universo.length;
|
|
362
|
+
estado.universo = { porColecao: { ...opcoes.universo.porColecao }, foraDaBusca: opcoes.universo.foraDaBusca,
|
|
363
|
+
...(opcoes.universo.latenciaMs === undefined ? {} : { latenciaMs: opcoes.universo.latenciaMs }) };
|
|
337
364
|
const referencia = estado.ativo === 'fallback' ? { modelo: fallback.modelo, dim: fallback.dim } : { modelo: config.model, dim: config.dim };
|
|
338
365
|
const indice = estado.indices.find(i => i.modelo === referencia.modelo && i.dim === referencia.dim);
|
|
339
|
-
|
|
366
|
+
const coerentes = indice?.coerentes ?? 0;
|
|
367
|
+
estado.cobertura = universo.length === 0 ? 0 : Math.round((coerentes / universo.length) * 10_000) / 10_000;
|
|
368
|
+
// RM-038 (D7): o indice que a busca usa cobre menos do que ela enxerga: dito, nunca escondido.
|
|
369
|
+
estado.aviso = (0, indice_vetorial_1.avisoDeCobertura)(coerentes, universo, estado.ativo);
|
|
340
370
|
}
|
|
371
|
+
else if (opcoes.falhaDoUniverso)
|
|
372
|
+
estado.falhaDoUniverso = opcoes.falhaDoUniverso;
|
|
341
373
|
return estado;
|
|
342
374
|
}
|
|
343
375
|
/**
|
|
@@ -1098,12 +1130,22 @@ function textoDosEmbeddings(e) {
|
|
|
1098
1130
|
`dependencias ${e.fallback.dependencias ? 'ok' : e.sondado ? 'ausentes' : 'nao sondadas'}` : '(nao declarado)'}`);
|
|
1099
1131
|
linhas.push(` caminho ativo ${e.ativo}${e.sondado ? '' : ' (ponte nao sondada)'}`);
|
|
1100
1132
|
}
|
|
1133
|
+
if (e.universo) {
|
|
1134
|
+
const colecoes = Object.entries(e.universo.porColecao).map(([c, n]) => `${c} ${n}`).join(', ');
|
|
1135
|
+
linhas.push(` universo da busca ${e.entradas} entrada(s) do tenant: ${colecoes}`);
|
|
1136
|
+
linhas.push(` fora da busca ${(0, indice_vetorial_1.textoForaDaBusca)(e.universo.foraDaBusca)}`);
|
|
1137
|
+
}
|
|
1138
|
+
else if (e.falhaDoUniverso) {
|
|
1139
|
+
linhas.push(` universo da busca nao lido (${e.falhaDoUniverso}); cobertura nao calculada`);
|
|
1140
|
+
}
|
|
1101
1141
|
for (const i of e.indices) {
|
|
1102
1142
|
linhas.push(` indice ${i.modelo} / ${i.dim} dim: ${i.vetores} vetor(es), ${i.coerentes ?? '?'} coerente(s), ${i.desatualizados ?? '?'} desatualizado(s)`);
|
|
1103
1143
|
}
|
|
1104
1144
|
if (e.entradas !== null) {
|
|
1105
|
-
linhas.push(` cobertura ${e.cobertura === null ? '-' : `${Math.round(e.cobertura * 1000) / 10}%`} de ${e.entradas} entrada(s) do
|
|
1145
|
+
linhas.push(` cobertura ${e.cobertura === null ? '-' : `${Math.round(e.cobertura * 1000) / 10}%`} de ${e.entradas} entrada(s) do universo da busca`);
|
|
1106
1146
|
}
|
|
1147
|
+
if (e.aviso)
|
|
1148
|
+
linhas.push(` aviso ${e.aviso}`);
|
|
1107
1149
|
if (e.sonda) {
|
|
1108
1150
|
linhas.push(` sonda ${e.sonda.ok ? `${e.sonda.alvo} respondeu em ${e.sonda.latenciaMs} ms` : `sem resposta (${e.sonda.motivo ?? 'sem caminho ativo'})`}`);
|
|
1109
1151
|
}
|
package/dist/network-roadmap.js
CHANGED
|
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.ErroDoPedidoDeProjeto = exports.SAIDA_DO_PEDIDO = exports.LIMIAR_SEM_BATIDA_MS = exports.CONTRATO_REGISTRO_DE_PROJETOS = exports.CONTRATO_PANORAMA_DA_REDE = void 0;
|
|
37
37
|
exports.projetosConhecidos = projetosConhecidos;
|
|
38
38
|
exports.resolverProjeto = resolverProjeto;
|
|
39
|
+
exports.redeDoProjetoFixado = redeDoProjetoFixado;
|
|
39
40
|
exports.montarPanoramaDaRede = montarPanoramaDaRede;
|
|
40
41
|
exports.textoDoPanoramaDaRede = textoDoPanoramaDaRede;
|
|
41
42
|
/**
|
|
@@ -62,6 +63,11 @@ exports.textoDoPanoramaDaRede = textoDoPanoramaDaRede;
|
|
|
62
63
|
*
|
|
63
64
|
* Na fatia 2, os hosts chegam aqui por dois modos: `host` (gateway sem cwd de projeto, a regra da
|
|
64
65
|
* RM-052 no `--projeto` proprio do `network`) e `fixado` (o servidor MCP, que le so o projeto dele).
|
|
66
|
+
*
|
|
67
|
+
* Na fatia 3, a rede por pessoa da RM-053 (`ork.rede-status/v1`) entra como fonte: as maquinas da
|
|
68
|
+
* casa, com a batida de cada uma, os projetos que elas declaram (um projeto sem clone nem registro
|
|
69
|
+
* nesta maquina passa a ser conhecido pelo nome) e a maquina que esta na rede mas nao publicou na
|
|
70
|
+
* fabrica do projeto, dita como lacuna e nunca como "0 threads".
|
|
65
71
|
*/
|
|
66
72
|
const node_child_process_1 = require("node:child_process");
|
|
67
73
|
const fs = __importStar(require("node:fs"));
|
|
@@ -78,6 +84,9 @@ const manifest_1 = require("./manifest");
|
|
|
78
84
|
const maquina_1 = require("./maquina");
|
|
79
85
|
const modos_1 = require("./modos");
|
|
80
86
|
const projeto_alvo_1 = require("./projeto-alvo");
|
|
87
|
+
const rede_1 = require("./rede");
|
|
88
|
+
const rede_projetos_1 = require("./rede-projetos");
|
|
89
|
+
const rede_status_1 = require("./rede-status");
|
|
81
90
|
const roadmap_reservas_1 = require("./roadmap-reservas");
|
|
82
91
|
const roadmap_status_1 = require("./roadmap-status");
|
|
83
92
|
const thread_1 = require("./thread");
|
|
@@ -118,9 +127,8 @@ const lacuna = (tipo, parte, alvo, detalhe, correcao) => ({ tipo, parte, ...(alv
|
|
|
118
127
|
/**
|
|
119
128
|
* Nome de remoto do git, como `origin`. O valor vem do manifesto versionado (`fabrica.remoto`), e um
|
|
120
129
|
* valor que comece com `-` viraria opcao do `git fetch` (`--upload-pack=...`): so este formato chega
|
|
121
|
-
* ao git (achado 4 do CHECK).
|
|
130
|
+
* ao git (achado 4 do CHECK). O validador e o mesmo da branch de estado (RM-047).
|
|
122
131
|
*/
|
|
123
|
-
const REMOTO = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
124
132
|
/**
|
|
125
133
|
* Nome de branch base, como `main`. Tambem vem do manifesto (`worktree.base_branch`), e o `git log`
|
|
126
134
|
* da base o recebia cru: `--output=<arquivo>` gravava um arquivo (rodada 2 do CHECK).
|
|
@@ -128,7 +136,7 @@ const REMOTO = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
|
128
136
|
const baseValida = (base) => typeof base === 'string' && /^[A-Za-z0-9][A-Za-z0-9._/-]{0,99}$/.test(base) && !base.includes('..');
|
|
129
137
|
function projetoDoClone(c, origem) {
|
|
130
138
|
const remoto = c.manifesto.fabrica.remoto;
|
|
131
|
-
const url =
|
|
139
|
+
const url = (0, branch_de_estado_1.remotoValido)(remoto) ? (0, branch_de_estado_1.git)(c.raiz, ['remote', 'get-url', '--', remoto]) : null;
|
|
132
140
|
return { nome: c.manifesto.project.name, forja: url?.ok ? (0, forja_1.identidadeDaForja)(url.stdout.trim()) : null, raiz: c.raiz,
|
|
133
141
|
base: c.manifesto.worktree.base_branch, remoto, origem };
|
|
134
142
|
}
|
|
@@ -429,12 +437,12 @@ function maquinasDoPanorama(retratos, local, ctx, lacunas) {
|
|
|
429
437
|
}
|
|
430
438
|
saida.push({ maquina: m.maquina, por: m.por, publicadoEm: m.publicadoEm, idadeMin: Math.floor(idadeMs / 60000), semBatida,
|
|
431
439
|
estaMaquina: m.maquina === ctx.maquina, origem: 'retrato', versaoOrk: m.versaoOrk ?? null,
|
|
432
|
-
ativas: m.threads.filter((t) => !t.entregue), entreguesSemMaster: m.threads.filter((t) => t.entregue).length });
|
|
440
|
+
ativas: m.threads.filter((t) => !t.entregue), entreguesSemMaster: m.threads.filter((t) => t.entregue).length, threadsLidas: true });
|
|
433
441
|
}
|
|
434
442
|
if (local) {
|
|
435
443
|
saida.push({ maquina: local.maquina, por: local.por, publicadoEm: local.publicadoEm, idadeMin: 0, semBatida: false, estaMaquina: true,
|
|
436
444
|
origem: 'estado-local', versaoOrk: local.versaoOrk, ativas: local.threads.filter((t) => !t.entregue),
|
|
437
|
-
entreguesSemMaster: local.threads.filter((t) => t.entregue).length });
|
|
445
|
+
entreguesSemMaster: local.threads.filter((t) => t.entregue).length, threadsLidas: true });
|
|
438
446
|
}
|
|
439
447
|
return saida.sort((a, b) => a.maquina.localeCompare(b.maquina));
|
|
440
448
|
}
|
|
@@ -571,8 +579,8 @@ function lerProjetoDoClone(p, geral) {
|
|
|
571
579
|
const carregado = (0, manifest_1.carregarManifesto)(raiz);
|
|
572
580
|
// O fuso do dono deste projeto vale para o dia e os horarios dele (achado 5 do CHECK).
|
|
573
581
|
const ctx = { ...geral, fuso: carregado?.manifesto.owner?.timezone ?? geral.fuso };
|
|
574
|
-
if (!
|
|
575
|
-
lacunas.push(lacuna('projeto.remoto-invalido', 'projeto', raizParaExibir(raiz), `fabrica.remoto do manifesto (${
|
|
582
|
+
if (!(0, branch_de_estado_1.remotoValido)(remoto)) {
|
|
583
|
+
lacunas.push(lacuna('projeto.remoto-invalido', 'projeto', raizParaExibir(raiz), `fabrica.remoto do manifesto (${(0, branch_de_estado_1.remotoRedigido)(remoto)}) não é nome de remoto do git: nada foi lido pelo git`, 'corrija fabrica.remoto no orkastery.yaml (padrão: origin)'));
|
|
576
584
|
return montarProjeto(p, { nome: p.nome, docs: null, reservas: null, retratos: null, local: null, commits: [] }, ctx, fontes, lacunas);
|
|
577
585
|
}
|
|
578
586
|
if (!baseValida(p.base ?? 'main') || (carregado && !baseValida(carregado.manifesto.worktree.base_branch))) {
|
|
@@ -784,6 +792,134 @@ function lerProjeto(p, ctx) {
|
|
|
784
792
|
return vazio(lacuna('projeto.sem-leitura', 'projeto', p.raiz ? raizParaExibir(p.raiz) : p.nome, `a leitura de ${p.nome} parou: ${(0, forja_1.detalheSeguro)(e?.message ?? String(e))}`, 'confira o clone e o estado dele no próprio projeto; os outros projetos seguiram'));
|
|
785
793
|
}
|
|
786
794
|
}
|
|
795
|
+
// ---------------------------------------------------------------------------
|
|
796
|
+
// A rede por pessoa (fatia 3).
|
|
797
|
+
// ---------------------------------------------------------------------------
|
|
798
|
+
/** As lacunas do `ork.rede-status/v1` que sao da casa (forja, casa, retrato), e nao da fabrica de um projeto. */
|
|
799
|
+
const lacunaDaCasa = (tipo) => tipo.startsWith('forja.') || tipo.startsWith('rede.') || tipo === 'retrato.invalido' || tipo === 'maquina.nome-em-uso';
|
|
800
|
+
const CORRECAO_DA_CASA = {
|
|
801
|
+
'forja.ausente': 'instale o gh (ou o glab) nesta máquina',
|
|
802
|
+
'forja.sem-login': 'gh auth login (ou glab auth login) nesta máquina',
|
|
803
|
+
'rede.sem-repositorio': 'ork network entrar numa máquina da pessoa',
|
|
804
|
+
'maquina.nome-em-uso': 'ork network entrar --maquina NOME ou --forcar',
|
|
805
|
+
};
|
|
806
|
+
/** A rede lida para o panorama, ou o motivo de nao ter lido (vai ao `naoConsultado`). */
|
|
807
|
+
function lerRedeDoPanorama(opcoes, ctx, cwd) {
|
|
808
|
+
if (opcoes.rede === false)
|
|
809
|
+
return { status: null, motivo: 'não lida nesta chamada' };
|
|
810
|
+
if (opcoes.rede)
|
|
811
|
+
return { status: opcoes.rede, motivo: null };
|
|
812
|
+
if ((process.env.ORK_REDE_LER ?? '').trim() === '0')
|
|
813
|
+
return { status: null, motivo: 'leitura desligada (ORK_REDE_LER=0)' };
|
|
814
|
+
try {
|
|
815
|
+
// D-G6 da fatia 2: no host, o diretorio do gateway nao e projeto; a rede le so o registro e os retratos.
|
|
816
|
+
return { status: (0, rede_status_1.lerRede)({ semRemoto: ctx.semRemoto, maquina: opcoes.maquina, agora: ctx.quando, diretorio: opcoes.host ? null : cwd }),
|
|
817
|
+
motivo: null };
|
|
818
|
+
}
|
|
819
|
+
catch (e) {
|
|
820
|
+
return { status: null, motivo: `a leitura parou: ${(0, forja_1.detalheSeguro)(e?.message ?? String(e))}` };
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
/** O projeto que um retrato declara casa com o projeto do panorama: pela forja, ou pelo nome quando falta a forja. */
|
|
824
|
+
function declara(q, p, nome) {
|
|
825
|
+
const forja = q.remoto ? (0, forja_1.identidadeDaForja)(q.remoto) : null;
|
|
826
|
+
if (forja && p.forja)
|
|
827
|
+
return (0, forja_1.mesmaForja)(forja, p.forja);
|
|
828
|
+
return (0, rede_projetos_1.emUmaLinha)(q.nome) === nome;
|
|
829
|
+
}
|
|
830
|
+
/** Os projetos que as maquinas da rede declaram com remoto de forja e que esta maquina nao conhece. */
|
|
831
|
+
function projetosDaRede(status, conhecidos) {
|
|
832
|
+
const saida = [];
|
|
833
|
+
for (const m of status.membros) {
|
|
834
|
+
if (m.origem !== 'rede')
|
|
835
|
+
continue;
|
|
836
|
+
for (const q of m.projetos) {
|
|
837
|
+
const nome = (0, rede_projetos_1.emUmaLinha)(q.nome);
|
|
838
|
+
const forja = q.remoto ? (0, forja_1.identidadeDaForja)(q.remoto) : null;
|
|
839
|
+
if (!forja || !projeto_alvo_1.PADRAO_DO_NOME_DE_PROJETO.test(nome))
|
|
840
|
+
continue;
|
|
841
|
+
const p = { nome, forja, raiz: null, base: null, remoto: 'origin', origem: 'rede' };
|
|
842
|
+
if (![...conhecidos, ...saida].some((x) => mesmoProjeto(x, p)))
|
|
843
|
+
saida.push(p);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return saida;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Suspeitas da revisao de 03/10 (mesma raiz do defeito 3 da revisao): o retrato com o nome desta
|
|
850
|
+
* maquina e de outra instalacao quando o status diz `nomeEmUso`; entao nenhum retrato da rede e "esta
|
|
851
|
+
* maquina". `null` nesse caso; senao, o nome saneado desta maquina.
|
|
852
|
+
*/
|
|
853
|
+
function euNaRede(status, ctx) {
|
|
854
|
+
const eu = (0, rede_1.nomeSeguro)(ctx.maquina);
|
|
855
|
+
return status.estaMaquina.maquina === eu && status.estaMaquina.nomeEmUso ? null : eu;
|
|
856
|
+
}
|
|
857
|
+
/** A rede no panorama; no MCP fixado, os projetos de cada maquina ficam so o servido (D5 da RM-052). */
|
|
858
|
+
function redeNoPanorama(status, ctx, servido) {
|
|
859
|
+
const agora = Date.parse(ctx.quando);
|
|
860
|
+
const fonte = status.fontes.find((f) => f.fonte === 'rede');
|
|
861
|
+
const eu = euNaRede(status, ctx);
|
|
862
|
+
const membros = status.membros.filter((m) => m.origem === 'rede').map((m) => {
|
|
863
|
+
const idadeMs = agora - Date.parse(m.publicadoEm);
|
|
864
|
+
const idadeMin = Number.isFinite(idadeMs) ? Math.floor(Math.max(0, idadeMs) / 60000) : null;
|
|
865
|
+
const projetos = m.projetos.filter((q) => !servido || declara(q, servido.p, servido.nome)).map((q) => (0, rede_projetos_1.emUmaLinha)(q.nome));
|
|
866
|
+
return { maquina: (0, rede_projetos_1.emUmaLinha)(m.maquina), estaMaquina: m.maquina === eu, publicadoEm: m.publicadoEm, idadeMin,
|
|
867
|
+
semBatida: idadeMin === null || idadeMin * 60000 > fabrica_estado_1.LIMIAR_SEM_BATIDA_MS, versaoOrk: m.versaoOrk ? (0, rede_projetos_1.emUmaLinha)(m.versaoOrk) : null,
|
|
868
|
+
projetos: [...new Set(projetos)] };
|
|
869
|
+
});
|
|
870
|
+
return { casa: status.casa ? (0, rede_1.refDaCasa)(status.casa) : null, ponta: fonte?.ponta ?? null, atualizado: fonte ? fonte.atualizado : null,
|
|
871
|
+
lidoEm: status.consultadoEm, membros };
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* A maquina da rede que declara o projeto e nao publicou na fabrica dele entra na lista com as
|
|
875
|
+
* threads NAO lidas e uma lacuna: antes ela sumia, e a lista parecia completa.
|
|
876
|
+
*/
|
|
877
|
+
function completarComARede(x, p, status, ctx) {
|
|
878
|
+
if (x.maquinas === null)
|
|
879
|
+
return;
|
|
880
|
+
const agora = Date.parse(ctx.quando);
|
|
881
|
+
for (const m of status.membros) {
|
|
882
|
+
if (m.origem !== 'rede' || !m.projetos.some((q) => declara(q, p, x.projeto.nome)))
|
|
883
|
+
continue;
|
|
884
|
+
if (x.maquinas.some((y) => (0, rede_1.nomeSeguro)(y.maquina) === m.maquina))
|
|
885
|
+
continue;
|
|
886
|
+
const maquina = (0, rede_projetos_1.emUmaLinha)(m.maquina);
|
|
887
|
+
const idadeMs = agora - Date.parse(m.publicadoEm);
|
|
888
|
+
const legivel = Number.isFinite(idadeMs);
|
|
889
|
+
const idadeMin = legivel ? Math.floor(Math.max(0, idadeMs) / 60000) : 0;
|
|
890
|
+
const semBatida = !legivel || idadeMin * 60000 > fabrica_estado_1.LIMIAR_SEM_BATIDA_MS;
|
|
891
|
+
x.maquinas.push({ maquina, por: 'rede por pessoa', publicadoEm: m.publicadoEm, idadeMin, semBatida, estaMaquina: m.maquina === euNaRede(status, ctx),
|
|
892
|
+
origem: 'rede', versaoOrk: m.versaoOrk ? (0, rede_projetos_1.emUmaLinha)(m.versaoOrk) : null, ativas: [], entreguesSemMaster: 0, threadsLidas: false });
|
|
893
|
+
x.lacunas.push(lacuna('maquina.sem-fabrica', 'fabrica', maquina, `${maquina} está na rede por pessoa e declara ${x.projeto.nome}, mas não tem retrato em ${fabrica_estado_1.BRANCH_DA_FABRICA}: as threads dela neste projeto não foram lidas`, `na ${maquina}, rode ork fabrica entrar no clone de ${x.projeto.nome} (ou atualize o ork dela)`));
|
|
894
|
+
if (semBatida) {
|
|
895
|
+
x.lacunas.push(lacuna('maquina.sem-batida', 'rede', maquina, `${maquina} sem retrato novo na rede ${legivel
|
|
896
|
+
? `há ${(0, horario_1.duracaoCurta)(idadeMin)}` : '(batida ilegível)'}`, `confira a ${maquina}: ela publica na batida do pulse`));
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
x.maquinas.sort((a, b) => a.maquina.localeCompare(b.maquina));
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Fatia 3: o `ork network status` do servidor MCP fixado. A rede e da pessoa, mas o retrato de cada
|
|
903
|
+
* maquina lista todos os projetos dela: aqui fica so o projeto servido (D5 da RM-052), e o resto vai
|
|
904
|
+
* ao "nao consultado". Com `ORK_REDE_LER=0`, a casa e lida so da ultima copia desta maquina.
|
|
905
|
+
*/
|
|
906
|
+
function redeDoProjetoFixado(raiz, opcoes = {}) {
|
|
907
|
+
const c = (0, manifest_1.carregarManifesto)(raiz);
|
|
908
|
+
if (!c) {
|
|
909
|
+
throw new ErroDoPedidoDeProjeto('projeto.sem-manifesto', `a raiz fixada não tem ${manifest_1.NOME_MANIFESTO}`, [], 'confira a raiz fixada na instalação do servidor MCP (ork mcp install --project <raiz>)');
|
|
910
|
+
}
|
|
911
|
+
const p = projetoDoClone(c, 'instalacao');
|
|
912
|
+
const s = opcoes.status ?? (0, rede_status_1.lerRede)({ semRemoto: opcoes.semRemoto === true || (process.env.ORK_REDE_LER ?? '').trim() === '0', diretorio: c.raiz,
|
|
913
|
+
soRaiz: c.raiz });
|
|
914
|
+
const membros = s.membros.map((m) => ({ ...m, projetos: m.projetos.filter((q) => declara(q, p, p.nome)) }))
|
|
915
|
+
.filter((m) => m.origem === 'rede' || m.projetos.length > 0);
|
|
916
|
+
// Revisao de 03/10 (D5): a lacuna de uma maquina que saiu dos membros (vista so em outro projeto) sai junto.
|
|
917
|
+
const nomes = new Set(membros.map((m) => m.maquina));
|
|
918
|
+
return { ...s, membros, fontes: s.fontes.filter((f) => !f.projeto || f.projeto === p.nome),
|
|
919
|
+
lacunas: s.lacunas.filter((l) => (!l.projeto || l.projeto === p.nome) &&
|
|
920
|
+
(!l.maquina || l.tipo === 'maquina.nome-em-uso' || nomes.has(l.maquina))),
|
|
921
|
+
naoConsultado: [...s.naoConsultado, `outros projetos das máquinas (este servidor MCP mostra só ${p.nome}; os outros vêm do CLI ork network status)`] };
|
|
922
|
+
}
|
|
787
923
|
/**
|
|
788
924
|
* `ork network roadmap`: os projetos pedidos (ou todos os conhecidos), cada um com roadmap, reservas,
|
|
789
925
|
* threads por maquina, fontes e lacunas. Recusa o `--projeto` ambiguo ou desconhecido.
|
|
@@ -793,11 +929,21 @@ function montarPanoramaDaRede(opcoes = {}) {
|
|
|
793
929
|
const cwd = opcoes.cwd ?? process.cwd();
|
|
794
930
|
const ctx = { quando, maquina: (0, maquina_1.nomeDaMaquina)(opcoes.maquina), semRemoto: opcoes.semRemoto === true, executor: opcoes.executor,
|
|
795
931
|
fuso: (0, horario_1.fusoDoDono)().fuso };
|
|
796
|
-
const naoConsultado = [
|
|
797
|
-
'rede por pessoa (RM-053, ork.rede-status/v1): não lida nesta versão; as máquinas vêm da branch ork/fabrica-estado de cada projeto',
|
|
798
|
-
];
|
|
932
|
+
const naoConsultado = [];
|
|
799
933
|
const lacunas = [];
|
|
934
|
+
const lida = lerRedeDoPanorama(opcoes, ctx, cwd);
|
|
935
|
+
const status = lida.status;
|
|
936
|
+
if (!status)
|
|
937
|
+
naoConsultado.push(`rede por pessoa (RM-053, ork.rede-status/v1): ${lida.motivo}; as máquinas vêm da branch ${fabrica_estado_1.BRANCH_DA_FABRICA} de cada projeto`);
|
|
938
|
+
else {
|
|
939
|
+
for (const l of status.lacunas) {
|
|
940
|
+
if (!lacunaDaCasa(l.tipo) || l.projeto)
|
|
941
|
+
continue;
|
|
942
|
+
lacunas.push(lacuna(l.tipo, 'rede', l.maquina, (0, forja_1.detalheSeguro)((0, rede_projetos_1.emUmaLinha)(l.detalhe)), CORRECAO_DA_CASA[l.tipo] ?? 'confira com ork network status'));
|
|
943
|
+
}
|
|
944
|
+
}
|
|
800
945
|
let alvos;
|
|
946
|
+
let servido = null;
|
|
801
947
|
if (opcoes.fixado !== undefined) {
|
|
802
948
|
// D-G5 (fatia 2): o servidor MCP le so o projeto dele, em todas as maquinas; o registro nao e lido.
|
|
803
949
|
const c = (0, manifest_1.carregarManifesto)(opcoes.fixado);
|
|
@@ -805,6 +951,7 @@ function montarPanoramaDaRede(opcoes = {}) {
|
|
|
805
951
|
throw new ErroDoPedidoDeProjeto('projeto.sem-manifesto', `a raiz fixada não tem ${manifest_1.NOME_MANIFESTO}`, [], 'confira a raiz fixada na instalação do servidor MCP (ork mcp install --project <raiz>)');
|
|
806
952
|
}
|
|
807
953
|
alvos = [projetoDoClone(c, 'instalacao')];
|
|
954
|
+
servido = { p: alvos[0], nome: alvos[0].nome };
|
|
808
955
|
naoConsultado.push('outros projetos desta máquina: este servidor MCP lê só o projeto fixado na instalação; ' +
|
|
809
956
|
'os outros vêm do CLI `ork network roadmap`');
|
|
810
957
|
}
|
|
@@ -812,17 +959,19 @@ function montarPanoramaDaRede(opcoes = {}) {
|
|
|
812
959
|
const conhecidos = projetosConhecidos({ cwd, registro: opcoes.registro, host: opcoes.host });
|
|
813
960
|
naoConsultado.push(...conhecidos.naoConsultado);
|
|
814
961
|
lacunas.push(...conhecidos.lacunas);
|
|
962
|
+
// Fatia 3: o projeto que uma maquina da rede declara passa a ser conhecido, lido pela forja.
|
|
963
|
+
const todos = [...conhecidos.projetos, ...(status ? projetosDaRede(status, conhecidos.projetos) : [])];
|
|
815
964
|
if (opcoes.pedido !== undefined) {
|
|
816
965
|
if (opcoes.host)
|
|
817
|
-
exigirPedidoDoHost(opcoes.pedido,
|
|
818
|
-
const alvo = resolverProjeto(opcoes.pedido,
|
|
966
|
+
exigirPedidoDoHost(opcoes.pedido, todos);
|
|
967
|
+
const alvo = resolverProjeto(opcoes.pedido, todos, cwd);
|
|
819
968
|
alvos = [alvo];
|
|
820
|
-
for (const p of
|
|
969
|
+
for (const p of todos)
|
|
821
970
|
if (!mesmoProjeto(p, alvo))
|
|
822
971
|
naoConsultado.push(`projeto ${p.nome}: fora do pedido (--projeto)`);
|
|
823
972
|
}
|
|
824
973
|
else {
|
|
825
|
-
alvos =
|
|
974
|
+
alvos = todos;
|
|
826
975
|
}
|
|
827
976
|
}
|
|
828
977
|
if (alvos.length === 0) {
|
|
@@ -831,9 +980,15 @@ function montarPanoramaDaRede(opcoes = {}) {
|
|
|
831
980
|
: 'nenhum projeto conhecido nesta máquina: sem manifesto no diretório atual e sem registro', opcoes.host ? 'peça o projeto pela forja (--projeto github:dono/repo) ou registre o clone com `ork projetos registrar <caminho>`'
|
|
832
981
|
: 'peça o projeto: --projeto <caminho do clone> ou --projeto github:dono/repo'));
|
|
833
982
|
}
|
|
834
|
-
const projetos = alvos.map((p) =>
|
|
983
|
+
const projetos = alvos.map((p) => {
|
|
984
|
+
const x = lerProjeto(p, ctx);
|
|
985
|
+
if (status)
|
|
986
|
+
completarComARede(x, p, status, ctx);
|
|
987
|
+
return x;
|
|
988
|
+
});
|
|
835
989
|
return { contrato: exports.CONTRATO_PANORAMA_DA_REDE, consultadoEm: quando, maquina: ctx.maquina, pedido: opcoes.pedido ?? null,
|
|
836
|
-
limiarSemBatidaMin: fabrica_estado_1.LIMIAR_SEM_BATIDA_MS / 60000, fuso: projetos[0]?.projeto.fuso ?? ctx.fuso, projetos,
|
|
990
|
+
limiarSemBatidaMin: fabrica_estado_1.LIMIAR_SEM_BATIDA_MS / 60000, fuso: projetos[0]?.projeto.fuso ?? ctx.fuso, projetos,
|
|
991
|
+
rede: status ? redeNoPanorama(status, ctx, servido) : null, naoConsultado, lacunas };
|
|
837
992
|
}
|
|
838
993
|
// ---------------------------------------------------------------------------
|
|
839
994
|
// O texto.
|
|
@@ -859,6 +1014,11 @@ function linhasDasMaquinas(x, fuso) {
|
|
|
859
1014
|
return ['• nenhuma máquina publicou em ork/fabrica-estado'];
|
|
860
1015
|
return x.maquinas.flatMap((m) => {
|
|
861
1016
|
const quem = `${m.maquina}${m.estaMaquina ? ' (esta máquina)' : ''}`;
|
|
1017
|
+
// Fatia 3: a maquina so da rede por pessoa; as threads dela neste projeto nao foram lidas.
|
|
1018
|
+
if (m.origem === 'rede') {
|
|
1019
|
+
return [`• ${quem}: threads não lidas, na rede por pessoa (retrato de ${(0, horario_1.formatarDataHora)(m.publicadoEm, { fuso })}, ` +
|
|
1020
|
+
`há ${(0, horario_1.duracaoCurta)(m.idadeMin)}${m.semBatida ? ', SEM BATIDA' : ''}) e sem retrato em ${fabrica_estado_1.BRANCH_DA_FABRICA}`];
|
|
1021
|
+
}
|
|
862
1022
|
const batida = m.origem === 'estado-local' ? 'estado local lido agora'
|
|
863
1023
|
: `retrato de ${(0, horario_1.formatarDataHora)(m.publicadoEm, { fuso })} (há ${(0, horario_1.duracaoCurta)(m.idadeMin)})${m.semBatida ? ', SEM BATIDA' : ''}`;
|
|
864
1024
|
const cabeca = `• ${quem}: ${m.ativas.length} ativa(s)${m.entreguesSemMaster ? `, ${m.entreguesSemMaster} entregue(s) sem MASTER` : ''}, ${batida}`;
|
|
@@ -875,6 +1035,19 @@ function linhasDasReservas(x, fuso) {
|
|
|
875
1035
|
return ['• nenhuma reserva em ork/roadmap-reservas'];
|
|
876
1036
|
return x.reservas.map((r) => ` ${r.item} · ${r.maquina} · ${r.thread ?? 'sem thread'} · desde ${(0, horario_1.formatarDataHora)(r.desdeEm, { fuso })}`);
|
|
877
1037
|
}
|
|
1038
|
+
/** Fatia 3: a casa da rede por pessoa e as maquinas dela, com a batida e os projetos que declaram. */
|
|
1039
|
+
function linhasDaRede(r, quando, fuso) {
|
|
1040
|
+
const lido = r.lidoEm === quando ? 'lida agora' : `lida ${(0, horario_1.formatarDataHora)(r.lidoEm, { fuso })}`;
|
|
1041
|
+
const casa = !r.casa ? '• casa: nenhuma achada (veja as lacunas)'
|
|
1042
|
+
: r.atualizado === null ? `• casa: ${r.casa}, não lida (veja as lacunas)`
|
|
1043
|
+
: `• casa: ${r.casa} @ ${r.ponta ? r.ponta.slice(0, 7) : 'sem commit'}, ${r.atualizado ? lido : 'última cópia desta máquina, sem leitura nova'}`;
|
|
1044
|
+
if (r.membros.length === 0)
|
|
1045
|
+
return [casa, '• nenhum retrato lido na casa; isso não quer dizer que não há máquinas: veja as lacunas'];
|
|
1046
|
+
return [casa, ...r.membros.map((m) => `• ${m.maquina}${m.estaMaquina ? ' (esta máquina)' : ''}: retrato de ` +
|
|
1047
|
+
`${(0, horario_1.formatarDataHora)(m.publicadoEm, { fuso })}${m.idadeMin === null ? ' (batida ilegível)' : ` (há ${(0, horario_1.duracaoCurta)(m.idadeMin)})`}` +
|
|
1048
|
+
`${m.semBatida ? ', SEM BATIDA' : ''}${m.versaoOrk ? `, ork ${m.versaoOrk}` : ''}, ` +
|
|
1049
|
+
(m.projetos.length ? `projetos: ${m.projetos.join(', ')}` : 'nenhum projeto declarado aqui'))];
|
|
1050
|
+
}
|
|
878
1051
|
const linhaDaLacuna = (l) => `• ${l.tipo}${l.alvo ? ` (${l.alvo})` : ''}: ${l.detalhe}. O que fazer: ${l.correcao}.`;
|
|
879
1052
|
/** O texto de `ork network roadmap`: o consultado e o nao consultado no alto, e cada parte com a fonte e a hora. */
|
|
880
1053
|
function textoDoPanoramaDaRede(p) {
|
|
@@ -886,6 +1059,8 @@ function textoDoPanoramaDaRede(p) {
|
|
|
886
1059
|
p.projetos.length ? `Consultado: ${p.projetos.map((x) => descreverProjeto(x.projeto)).join('; ')}` : 'Consultado: nenhum projeto.',
|
|
887
1060
|
'Não consultado:', ...(p.naoConsultado.length ? p.naoConsultado.map((n) => `• ${n}`) : ['• nada fora do pedido']),
|
|
888
1061
|
];
|
|
1062
|
+
if (p.rede)
|
|
1063
|
+
linhas.push('', 'Rede por pessoa (RM-053)', ...linhasDaRede(p.rede, p.consultadoEm, p.fuso));
|
|
889
1064
|
if (p.lacunas.length)
|
|
890
1065
|
linhas.push('', 'Lacunas da consulta', ...p.lacunas.map(linhaDaLacuna));
|
|
891
1066
|
for (const x of p.projetos) {
|
package/dist/ocupacao.js
CHANGED
|
@@ -28,6 +28,7 @@ exports.faseTemPausaPrevista = faseTemPausaPrevista;
|
|
|
28
28
|
exports.sessaoLivreDaVaga = sessaoLivreDaVaga;
|
|
29
29
|
exports.avaliarOcupacao = avaliarOcupacao;
|
|
30
30
|
const ledger_1 = require("./ledger");
|
|
31
|
+
const impedimento_1 = require("./impedimento");
|
|
31
32
|
const sessoes_adopt_1 = require("./sessoes-adopt");
|
|
32
33
|
/** Estado que o `ork phase run` grava quando o bloco despachado pausa ao fim. */
|
|
33
34
|
exports.PAUSA_PREVISTA = 'prevista ao fim do bloco';
|
|
@@ -126,7 +127,8 @@ function pausaHumanaAberta(thread, eventos) {
|
|
|
126
127
|
for (let i = 0; i < eventos.length; i++) {
|
|
127
128
|
const e = eventos[i];
|
|
128
129
|
const prevista = ehPausaPrevista(e);
|
|
129
|
-
|
|
130
|
+
// RM-055: o impedimento do despacho que so o dono resolve tambem e pausa humana: nao ocupa vaga.
|
|
131
|
+
const escalada = (0, impedimento_1.ehEsperaDoDono)(e, ledger_1.TIPOS_DE_EVENTO.gateBloqueado);
|
|
130
132
|
if (!prevista && !escalada)
|
|
131
133
|
continue;
|
|
132
134
|
const iFase = indiceDaFase(e.fase);
|
|
@@ -143,11 +145,16 @@ function pausaHumanaAberta(thread, eventos) {
|
|
|
143
145
|
});
|
|
144
146
|
if (resolvida)
|
|
145
147
|
continue;
|
|
148
|
+
// Ensaio de 03/10/2026 (RM-049): a escalada traz a correcao gravada no gate (no impedimento do dono,
|
|
149
|
+
// o comando dele e o `ork retry run`); o board a mostra, em vez de um `ork gate request` que o
|
|
150
|
+
// modo sem pausa prevista recusa.
|
|
151
|
+
const correcao = escalada && typeof e.correcao === 'string' && e.correcao !== '' ? e.correcao : undefined;
|
|
146
152
|
return {
|
|
147
153
|
desdeEm: e.ts,
|
|
148
154
|
evidencia: prevista
|
|
149
155
|
? `ledger ${ledger_1.TIPOS_DE_EVENTO.pausaHumana} (${exports.PAUSA_PREVISTA}) em ${e.ts}`
|
|
150
|
-
: `ledger ${ledger_1.TIPOS_DE_EVENTO.gateBloqueado} (
|
|
156
|
+
: `ledger ${ledger_1.TIPOS_DE_EVENTO.gateBloqueado} (${String(e.motivo)}) em ${e.ts}`,
|
|
157
|
+
...(correcao ? { correcao } : {}),
|
|
151
158
|
};
|
|
152
159
|
}
|
|
153
160
|
return null;
|
|
@@ -162,7 +169,7 @@ function impedimentoAberto(eventos) {
|
|
|
162
169
|
continue;
|
|
163
170
|
const motivo = e.motivo;
|
|
164
171
|
// `human.pending` ja e pausa humana; `claims.unverifiable` avisa mas nao bloqueia.
|
|
165
|
-
if (motivo === 'human.pending' || motivo === 'claims.unverifiable')
|
|
172
|
+
if (motivo === 'human.pending' || motivo === 'claims.unverifiable' || (0, impedimento_1.ehImpedimentoDoDono)(motivo))
|
|
166
173
|
continue;
|
|
167
174
|
const resolvido = eventos
|
|
168
175
|
.slice(i + 1)
|
|
@@ -248,6 +255,7 @@ function avaliarOcupacao(thread, doLedger, opcoes) {
|
|
|
248
255
|
detalhe: `pausa humana aberta ha ${minutos(pausa.desdeEm, opcoes.agora)} min: ` +
|
|
249
256
|
'esperar veredito humano nao ocupa vaga da maquina',
|
|
250
257
|
evidencia: pausa.evidencia,
|
|
258
|
+
...(pausa.correcao ? { correcao: pausa.correcao } : {}),
|
|
251
259
|
};
|
|
252
260
|
}
|
|
253
261
|
if (registro)
|