@orkastery/cli 0.5.1 → 0.5.6
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/README.md +158 -0
- 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/claude-code/mods/autoridade.json +56 -0
- package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
- package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
- package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
- package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
- package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
- package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
- package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
- package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
- package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -0
- package/adapters/claude-code/mods/ork-mesa/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
- package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
- package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +117 -0
- package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
- package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
- package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
- package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
- package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
- package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
- package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
- package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
- package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
- package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
- package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
- package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
- package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
- package/adapters/claude-code/mods/ork-sentinela/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
- package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
- package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
- package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
- package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
- package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
- package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
- package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
- package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -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 +7 -6
- package/adapters/openclaw/README.md +26 -5
- 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/docs-en/markdownlint-cli2.jsonc +22 -0
- package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
- package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
- package/assets/docs-en/produto/README.md +14 -0
- package/assets/docs-en/produto/_modelo-feature.md +62 -0
- package/assets/docs-en/roadmap/README.md +14 -0
- package/assets/docs-en/roadmap/_modelo-item.md +75 -0
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +116 -18
- package/dist/adapters/codex.js +14 -4
- package/dist/agents-md.js +24 -14
- package/dist/auditrun.js +22 -3
- package/dist/board.js +20 -17
- package/dist/branch-de-estado.js +88 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/catalogo.js +33 -0
- package/dist/ci.js +21 -8
- package/dist/claims-conferir.js +342 -0
- package/dist/claims.js +41 -1
- package/dist/company-brain-client.js +36 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/company-brain-journal.js +2 -1
- package/dist/company-brain-migration.js +36 -1
- package/dist/conducao-sentinela.js +388 -0
- package/dist/conducao-texto.js +12 -18
- package/dist/conducao.js +122 -30
- package/dist/conhecimento.js +490 -0
- package/dist/docs.js +70 -17
- package/dist/doctor-pulse-cron.js +349 -0
- package/dist/doctor-rede.js +150 -0
- package/dist/doctor.js +195 -111
- package/dist/entrega-pr.js +42 -29
- package/dist/escopo-escrita.js +10 -1
- package/dist/esgotamentos.js +181 -0
- package/dist/estado-thread.js +23 -1
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-batida.js +310 -0
- package/dist/fabrica-estado.js +52 -14
- package/dist/fabrica-publicar.js +9 -1
- package/dist/fechamento.js +20 -66
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +3 -2
- package/dist/forja.js +31 -7
- package/dist/gates.js +3 -24
- package/dist/handoff.js +10 -6
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-local-receipt.js +2 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +38 -3
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/hitl.js +29 -33
- package/dist/horario.js +41 -7
- package/dist/hosts.js +104 -11
- package/dist/impedimento.js +299 -0
- package/dist/index.js +961 -542
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +9 -1
- package/dist/init.js +56 -43
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +170 -16
- package/dist/intelligence-graph-contexto.js +254 -0
- package/dist/intelligence-graph-contract.js +2 -1
- package/dist/intelligence-graph-extract-md.js +56 -4
- package/dist/intelligence-graph-extract-ts.js +71 -3
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-query.js +66 -19
- package/dist/leases.js +664 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +18 -1
- package/dist/licoes.js +1 -0
- package/dist/liveness.js +6 -3
- package/dist/locale-ajuda.js +761 -0
- package/dist/locale-gerados.js +160 -0
- package/dist/locale-master.js +99 -0
- package/dist/locale-onboarding.js +92 -0
- package/dist/locale-phase.js +151 -0
- package/dist/locale-pulse.js +211 -0
- package/dist/locale-retry.js +385 -0
- package/dist/locale-roadmap.js +102 -0
- package/dist/locale-ship.js +494 -0
- package/dist/locale-thread.js +277 -0
- package/dist/locale-verify.js +125 -0
- package/dist/locale.js +714 -0
- package/dist/maestro-runtime.js +4 -1
- package/dist/manifest.js +149 -4
- package/dist/maquina.js +23 -4
- package/dist/master-digest.js +6 -1
- package/dist/master-nota.js +18 -11
- package/dist/master.js +145 -31
- package/dist/mcp-artifacts.js +43 -3
- package/dist/mcp-git.js +42 -8
- package/dist/mcp-grafo-worker.js +5 -3
- package/dist/mcp-grafo.js +55 -6
- package/dist/mcp-server.js +22 -3
- package/dist/mcp-ship.js +3 -1
- package/dist/mcp-verify.js +6 -1
- package/dist/memoria.js +48 -6
- package/dist/modos.js +3 -6
- package/dist/network-roadmap.js +196 -18
- package/dist/noctum-arco.js +911 -0
- package/dist/noctum-capacidade.js +141 -0
- package/dist/noctum-envelope.js +810 -0
- package/dist/noctum-execucao.js +304 -0
- package/dist/noctum-fila.js +280 -0
- package/dist/ocupacao.js +40 -5
- package/dist/onboarding.js +40 -21
- package/dist/orkmind.js +99 -7
- package/dist/orquestracao.js +24 -21
- package/dist/parado-no-condutor.js +219 -38
- package/dist/phase.js +160 -52
- package/dist/policies.js +56 -5
- package/dist/portfolio.js +8 -3
- package/dist/postura-local.js +234 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +225 -0
- package/dist/projeto-alvo.js +132 -5
- package/dist/prompts.js +40 -1
- package/dist/prova-ativacao.js +75 -6
- package/dist/pulse-delivery.js +47 -4
- package/dist/pulse.js +98 -19
- package/dist/ratelimit.js +24 -6
- package/dist/recall.js +3 -1
- package/dist/redacao-saida.js +63 -0
- 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 +337 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +291 -140
- package/dist/roadmap-reservas.js +20 -3
- package/dist/roadmap-status.js +150 -34
- package/dist/runtime-context.js +181 -3
- package/dist/runtime-profiles.js +22 -1
- package/dist/runtimes.js +2 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-events.js +7 -3
- package/dist/session-watcher-claude.js +120 -24
- package/dist/session-watcher.js +185 -33
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -18
- package/dist/sessoes.js +83 -2
- package/dist/ship-publicar.js +800 -0
- package/dist/ship.js +157 -88
- package/dist/steal.js +77 -0
- package/dist/thread-close.js +3 -2
- package/dist/thread.js +299 -49
- package/dist/util.js +8 -1
- package/dist/verify.js +141 -52
- package/dist/vida-da-thread.js +254 -0
- package/dist/worktree-local.js +165 -0
- package/dist/worktree.js +25 -2
- package/dist/yaml.js +27 -8
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +2 -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/roadmap-reservas.js
CHANGED
|
@@ -48,6 +48,7 @@ exports.soltarItem = soltarItem;
|
|
|
48
48
|
exports.reservasOrfas = reservasOrfas;
|
|
49
49
|
exports.soltarReservaDaThread = soltarReservaDaThread;
|
|
50
50
|
exports.soltarReservasOrfas = soltarReservasOrfas;
|
|
51
|
+
exports.leituraDasReservas = leituraDasReservas;
|
|
51
52
|
exports.textoDasReservas = textoDasReservas;
|
|
52
53
|
/**
|
|
53
54
|
* I-47: reservas de item do roadmap entre maquinas, como documentacao em codigo.
|
|
@@ -71,6 +72,7 @@ const os = __importStar(require("node:os"));
|
|
|
71
72
|
const path = __importStar(require("node:path"));
|
|
72
73
|
const branch_de_estado_1 = require("./branch-de-estado");
|
|
73
74
|
const horario_1 = require("./horario");
|
|
75
|
+
const locale_1 = require("./locale");
|
|
74
76
|
const ledger_1 = require("./ledger");
|
|
75
77
|
const maquina_1 = require("./maquina");
|
|
76
78
|
const thread_1 = require("./thread");
|
|
@@ -101,15 +103,16 @@ const PREFIXO = 'roadmap';
|
|
|
101
103
|
/** O item precisa existir no roadmap do projeto (`docs/roadmap/RM-NNN-*.md`). */
|
|
102
104
|
function exigirItem(raiz, item) {
|
|
103
105
|
const id = item.trim().toUpperCase();
|
|
106
|
+
// RM-061 (D14): `thread new --roadmap` chama isto no escopo pt-BR da reserva; a entrada do CLI remonta no locale dele.
|
|
104
107
|
if (!ITEM.test(id))
|
|
105
|
-
throw new
|
|
108
|
+
throw new locale_1.ErroDoCatalogo((m) => m.thread.roadmapItemInvalido(item));
|
|
106
109
|
const dir = path.join(raiz, 'docs', 'roadmap');
|
|
107
110
|
const doItem = (f) => path.basename(f).startsWith(`${id}-`) && f.endsWith('.md');
|
|
108
111
|
const naArvore = fs.existsSync(dir) && fs.readdirSync(dir).some(doItem);
|
|
109
112
|
// O checkout pode estar numa branch antiga, sem o item: vale tambem o que a main ja tem.
|
|
110
113
|
const naBase = !naArvore && ['main', 'origin/main'].some((ref) => (0, branch_de_estado_1.git)(raiz, ['ls-tree', '--name-only', ref, '--', 'docs/roadmap/']).stdout.split('\n').some(doItem));
|
|
111
114
|
if (!naArvore && !naBase)
|
|
112
|
-
throw new
|
|
115
|
+
throw new locale_1.ErroDoCatalogo((m) => m.thread.roadmapItemInexistente(id));
|
|
113
116
|
return id;
|
|
114
117
|
}
|
|
115
118
|
/** Quem esta pegando: `--por`, senao o `user.name` do git, senao o usuario do sistema. */
|
|
@@ -458,8 +461,22 @@ function soltarReservasOrfas(raiz, opcoes = {}) {
|
|
|
458
461
|
}
|
|
459
462
|
});
|
|
460
463
|
}
|
|
464
|
+
function leituraDasReservas(p, temRemoto) {
|
|
465
|
+
if (!temRemoto)
|
|
466
|
+
return 'sem-remoto';
|
|
467
|
+
return p.atualizado ? 'lido-agora' : p.ponta ? 'copia-local' : 'sem-copia';
|
|
468
|
+
}
|
|
461
469
|
/** O texto de `ork roadmap reservas` para o terminal, no fuso do dono. */
|
|
462
|
-
function textoDasReservas(p, orfas = []) {
|
|
470
|
+
function textoDasReservas(p, orfas = [], lida = {}) {
|
|
471
|
+
const remoto = lida.remoto ?? exports.REMOTO_PADRAO;
|
|
472
|
+
const leitura = leituraDasReservas(p, lida.temRemoto !== false);
|
|
473
|
+
if (leitura === 'sem-remoto') {
|
|
474
|
+
const projeto = lida.projeto ? `o projeto ${lida.projeto}` : 'o projeto';
|
|
475
|
+
return `Reservas do roadmap: ${projeto} não tem o remoto ${remoto}; nada foi lido de ${exports.BRANCH_DE_RESERVAS}.`;
|
|
476
|
+
}
|
|
477
|
+
if (leitura === 'sem-copia') {
|
|
478
|
+
return `Reservas do roadmap: o remoto ${remoto} não respondeu e esta máquina não tem cópia de ${exports.BRANCH_DE_RESERVAS}; nada foi lido.`;
|
|
479
|
+
}
|
|
463
480
|
const linhas = [];
|
|
464
481
|
if (!p.atualizado)
|
|
465
482
|
linhas.push('AVISO: sem acesso ao remoto; esta e a ultima copia lida nesta maquina.', '');
|
package/dist/roadmap-status.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TETO_DO_FECHO = exports.GRUPO_DO_CICLO = exports.GRUPOS_DO_ROADMAP = exports.CONTRATO_STATUS_DO_ROADMAP = void 0;
|
|
4
4
|
exports.esperaDoDono = esperaDoDono;
|
|
5
|
+
exports.esperaVoce = esperaVoce;
|
|
5
6
|
exports.fatosLocais = fatosLocais;
|
|
6
7
|
exports.batidaDaFabrica = batidaDaFabrica;
|
|
7
8
|
exports.montarStatusDoRoadmap = montarStatusDoRoadmap;
|
|
@@ -26,6 +27,11 @@ exports.textoDoStatusDoRoadmap = textoDoStatusDoRoadmap;
|
|
|
26
27
|
* RM-054: o montador recebe FATOS de thread (`FatoDeThread`), nao so as threads deste disco. O
|
|
27
28
|
* relatorio local continua com os fatos locais; o panorama da rede soma os retratos das outras
|
|
28
29
|
* maquinas, e so ai o fecho diz entre parenteses em que maquina a thread anda.
|
|
30
|
+
*
|
|
31
|
+
* RM-063 (F2): o fecho so diz "sigo <thread> na fase <F>" com sessao viva verificada no runtime
|
|
32
|
+
* (`vida-da-thread.ts`) ou com o processo do condutor conduzindo agora; sessao fantasma, despacho falho ou
|
|
33
|
+
* nenhuma sessao viram "<thread> parada desde HH:MM: <motivo>". E "O que precisa de voce" le a MESMA fila do `ork pulse` (`precisaDeHumanoAgora`),
|
|
34
|
+
* que o CLI e o MCP passam: com item do dono na fila, o fecho nunca diz "Nada agora".
|
|
29
35
|
*/
|
|
30
36
|
const docs_1 = require("./docs");
|
|
31
37
|
const ledger_1 = require("./ledger");
|
|
@@ -37,10 +43,15 @@ const horario_1 = require("./horario");
|
|
|
37
43
|
const projeto_alvo_1 = require("./projeto-alvo");
|
|
38
44
|
const fabrica_estado_1 = require("./fabrica-estado");
|
|
39
45
|
const hitl_resumo_1 = require("./hitl-resumo");
|
|
46
|
+
const hitl_tempo_parado_1 = require("./hitl-tempo-parado");
|
|
40
47
|
const manifest_1 = require("./manifest");
|
|
41
48
|
const maquina_1 = require("./maquina");
|
|
42
49
|
const parado_no_condutor_1 = require("./parado-no-condutor");
|
|
43
50
|
const util_1 = require("./util");
|
|
51
|
+
const impedimento_1 = require("./impedimento");
|
|
52
|
+
const ocupacao_1 = require("./ocupacao");
|
|
53
|
+
const locale_1 = require("./locale");
|
|
54
|
+
const vida_da_thread_1 = require("./vida-da-thread");
|
|
44
55
|
exports.CONTRATO_STATUS_DO_ROADMAP = 'ork.roadmap-status/v1';
|
|
45
56
|
/** Os grupos, na ordem e com os icones que o dono aprovou. */
|
|
46
57
|
exports.GRUPOS_DO_ROADMAP = Object.freeze([
|
|
@@ -116,21 +127,44 @@ function esperaDoDono(raiz, t, quando) {
|
|
|
116
127
|
}
|
|
117
128
|
return undefined;
|
|
118
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* R3 (RM-049): a thread espera o dono, pela regra de `esperaDoDono` ou pela do monitor e do pulse
|
|
132
|
+
* (`ehEsperaDoDono`): a escalada `human.pending` ou o impedimento do despacho que so o dono resolve,
|
|
133
|
+
* ainda sem evento que destrave. O fim de turno sem pergunta continua do condutor. Leitura pura.
|
|
134
|
+
*/
|
|
135
|
+
function esperaVoce(raiz, t, quando) {
|
|
136
|
+
if (t.status === 'fechada')
|
|
137
|
+
return false;
|
|
138
|
+
if (esperaDoDono(raiz, t, quando))
|
|
139
|
+
return true;
|
|
140
|
+
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id));
|
|
141
|
+
const doCondutor = (0, parado_no_condutor_1.esperaDoCondutor)(t, eventos, quando) !== null;
|
|
142
|
+
return eventos.some((e, i) => (0, impedimento_1.ehEsperaDoDono)(e) && !(doCondutor && e.motivo === 'human.pending') &&
|
|
143
|
+
!eventos.slice(i + 1).some(p => ocupacao_1.EVENTOS_QUE_DESTRAVAM.includes(p.tipo) || (0, ocupacao_1.ehAprovacaoHumana)(p)));
|
|
144
|
+
}
|
|
119
145
|
/**
|
|
120
146
|
* Os fatos das threads deste disco: `ship_done` do dia e espera do dono lidos do ledger local.
|
|
121
147
|
* `fuso`: o do projeto consultado, na visao da rede; sem ele, o do dono deste processo.
|
|
122
148
|
*/
|
|
123
|
-
function fatosLocais(raiz, quando, fuso) {
|
|
149
|
+
function fatosLocais(raiz, quando, fuso, opcoes = {}) {
|
|
124
150
|
const hoje = (0, horario_1.dataLocal)(quando, fuso);
|
|
125
151
|
const fatos = [];
|
|
152
|
+
// RM-063 (F2): o runtime e consultado uma vez por relatorio, e so quando alguma thread tem sessao a conferir.
|
|
153
|
+
let leitura;
|
|
154
|
+
const lerUmaVez = () => (leitura ??= (opcoes.runtime ?? (() => (0, vida_da_thread_1.lerRuntime)(raiz)))());
|
|
126
155
|
// RM-037 (fatia 4): o estado das entregas sai uma vez, sob demanda, do git local e do retrato de PRs do pulse.
|
|
127
156
|
let entregas;
|
|
128
157
|
const lerEntregas = () => {
|
|
129
158
|
if (entregas !== undefined)
|
|
130
159
|
return entregas;
|
|
131
160
|
try {
|
|
132
|
-
const
|
|
133
|
-
|
|
161
|
+
const carregado = (0, manifest_1.exigirManifesto)(raiz);
|
|
162
|
+
// RM-037 (fatia 5, A5): a forja sem leitura que o pulse ja disse vale sobre o retrato, que e de antes dela (a
|
|
163
|
+
// leitura boa apaga a marca), e a linha nao diz "PR nao lido".
|
|
164
|
+
const aviso = (0, parado_no_condutor_1.forjaSemLeituraDoRemoto)(raiz, carregado.manifesto.fabrica.remoto);
|
|
165
|
+
const retrato = aviso ? null : (0, parado_no_condutor_1.lerRetratoDePrs)(raiz);
|
|
166
|
+
entregas = (0, parado_no_condutor_1.entregasDoProjeto)(carregado, { quando, lerPrs: () => (retrato ? { ok: true, retrato }
|
|
167
|
+
: aviso ? { ok: false, lidoEm: aviso.ditoEm, erro: aviso.motivo, semLeitura: { remoto: aviso.remoto, host: aviso.host } } : null) });
|
|
134
168
|
}
|
|
135
169
|
catch {
|
|
136
170
|
entregas = null;
|
|
@@ -154,7 +188,19 @@ function fatosLocais(raiz, quando, fuso) {
|
|
|
154
188
|
id: t.id, roadmap: t.roadmap ?? null, aberta: t.status !== 'fechada', fase: t.faseAtual,
|
|
155
189
|
entregueHoje: () => (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)).some(e => e.tipo === 'ship_done' && (0, horario_1.dataLocal)(e.ts, fuso) === hoje),
|
|
156
190
|
espera: () => esperaDoDono(raiz, t, quando),
|
|
191
|
+
esperaVoce: () => esperaVoce(raiz, t, quando),
|
|
157
192
|
entrega: () => (t.status === 'fechada' ? undefined : entrega(t.id)),
|
|
193
|
+
vida: () => {
|
|
194
|
+
if (t.status === 'fechada')
|
|
195
|
+
return undefined;
|
|
196
|
+
try {
|
|
197
|
+
return (0, vida_da_thread_1.vidaDaThread)(t, (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)), lerUmaVez, Date.parse(quando));
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
const causa = { tipo: 'naoLida', detalhe: e.message.slice(0, 80) };
|
|
201
|
+
return { viva: false, sessionId: null, desdeEm: null, motivo: (0, vida_da_thread_1.motivoDaCausa)(causa), causa };
|
|
202
|
+
}
|
|
203
|
+
},
|
|
158
204
|
});
|
|
159
205
|
}
|
|
160
206
|
return fatos;
|
|
@@ -163,7 +209,8 @@ function fatosLocais(raiz, quando, fuso) {
|
|
|
163
209
|
function entregaNoStatus(e) {
|
|
164
210
|
if (!e || (!e.resumo && !e.parado))
|
|
165
211
|
return undefined;
|
|
166
|
-
|
|
212
|
+
// RM-063 (F2): o lease de sessao nao prova trabalho (a K7 morta seguia com ele); quem diz e a vida da sessao no runtime.
|
|
213
|
+
return { estado: e.resumo, ...(e.conduzidaAgora && e.donoDaConducao !== 'sessao' ? { conduzida: true } : {}),
|
|
167
214
|
...(e.parado ? { parado: { desdeEm: e.parado.desdeEm, proximoPasso: e.parado.proximoPasso,
|
|
168
215
|
...(e.parado.prLidoEm ? { prLidoEm: e.parado.prLidoEm } : {}) } } : {}),
|
|
169
216
|
...(e.prLidoEm ? { prLidoEm: e.prLidoEm } : {}) };
|
|
@@ -179,7 +226,7 @@ function batidaDaFabrica(carregado, quando) {
|
|
|
179
226
|
// a 2.45 ignora o GIT_NO_LAZY_FETCH, entao o clone parcial nem e lido aqui (N4 da seguranca, rodada 2).
|
|
180
227
|
// N4 da seguranca (rodada 3): o git novo registra o clone parcial no `remote.<r>.promisor`, o velho no `extensions`.
|
|
181
228
|
if ((0, util_1.exec)('git', ['config', '--get-regexp', '^(extensions\\.partialclone|remote\\..+\\.promisor)$'], carregado.raiz).stdout.trim()) {
|
|
182
|
-
return { lido: false, motivo:
|
|
229
|
+
return { lido: false, motivo: (0, locale_1.textoDoCatalogo)((m) => m.roadmap.fabricaClone(fabrica_estado_1.BRANCH_DA_FABRICA)), semBatida: [] };
|
|
183
230
|
}
|
|
184
231
|
const antes = process.env.GIT_NO_LAZY_FETCH;
|
|
185
232
|
process.env.GIT_NO_LAZY_FETCH = '1';
|
|
@@ -188,7 +235,7 @@ function batidaDaFabrica(carregado, quando) {
|
|
|
188
235
|
painel = (0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto: carregado.manifesto.fabrica.remoto, semRemoto: true });
|
|
189
236
|
}
|
|
190
237
|
catch {
|
|
191
|
-
return { lido: false, motivo:
|
|
238
|
+
return { lido: false, motivo: (0, locale_1.textoDoCatalogo)((m) => m.roadmap.fabricaIlegivel(fabrica_estado_1.BRANCH_DA_FABRICA)), semBatida: [] };
|
|
192
239
|
}
|
|
193
240
|
finally {
|
|
194
241
|
if (antes === undefined)
|
|
@@ -221,8 +268,27 @@ function montarStatusDoRoadmap(raiz, opcoes = {}) {
|
|
|
221
268
|
catch {
|
|
222
269
|
fabrica = undefined;
|
|
223
270
|
}
|
|
224
|
-
|
|
225
|
-
|
|
271
|
+
// RM-057 (fatia 3): leitura pura do ledger; sem ela o relatorio sai como antes.
|
|
272
|
+
let hitlDeConducao;
|
|
273
|
+
try {
|
|
274
|
+
const h = (0, hitl_tempo_parado_1.lerHitlDeConducaoAgora)(raiz, quando);
|
|
275
|
+
if (h.abertas.length || h.seteDias.pedidos || h.seteDias.respondidos)
|
|
276
|
+
hitlDeConducao = h;
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
hitlDeConducao = undefined;
|
|
280
|
+
}
|
|
281
|
+
let fila;
|
|
282
|
+
if (opcoes.fila) {
|
|
283
|
+
try {
|
|
284
|
+
fila = opcoes.fila(quando);
|
|
285
|
+
}
|
|
286
|
+
catch (e) {
|
|
287
|
+
fila = { lida: false, detalhe: e.message.slice(0, 160), itens: [] };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return montarStatusDeFatos((0, docs_1.carregarDocs)(raiz).docs, fatosLocais(raiz, quando, undefined, { runtime: opcoes.runtime }), { quando, projeto: opcoes.projeto, consulta: opcoes.consulta,
|
|
291
|
+
...(fabrica ? { fabrica } : {}), ...(hitlDeConducao ? { hitlDeConducao } : {}), ...(fila ? { fila } : {}) });
|
|
226
292
|
}
|
|
227
293
|
/** O relatorio a partir das paginas do roadmap e dos fatos das threads, de onde quer que venham. */
|
|
228
294
|
function montarStatusDeFatos(docs, fatos, opcoes) {
|
|
@@ -248,8 +314,11 @@ function montarStatusDeFatos(docs, fatos, opcoes) {
|
|
|
248
314
|
}
|
|
249
315
|
// RM-037 (fatia 4): a thread que diz o estado real vem primeiro: a parada no condutor, depois a entrega em curso.
|
|
250
316
|
const entregas = new Map(abertas.map(f => [f.id, f.entrega?.()]));
|
|
251
|
-
|
|
317
|
+
// RM-063 (F2): sem parada nem entrega a dizer, a thread com sessao viva vem antes das paradas.
|
|
318
|
+
const conduz = abertas.find(f => entregas.get(f.id)?.parado) ?? abertas.find(f => entregas.get(f.id)?.estado) ??
|
|
319
|
+
abertas.find(f => f.vida?.()?.viva) ?? abertas[0];
|
|
252
320
|
const entrega = conduz ? entregas.get(conduz.id) : undefined;
|
|
321
|
+
const vida = conduz?.vida?.();
|
|
253
322
|
const emAberto = exports.GRUPO_DO_CICLO[ciclo] === 'disponiveis' ? [
|
|
254
323
|
...(texto(estado.exposicao) && texto(estado.exposicao) !== 'Geral' ? [`exposição ${texto(estado.exposicao)}`] : []),
|
|
255
324
|
...(texto(estado.habilitacao) && texto(estado.habilitacao) !== 'Concluída' ? [`habilitação ${texto(estado.habilitacao)}`] : []),
|
|
@@ -259,18 +328,36 @@ function montarStatusDeFatos(docs, fatos, opcoes) {
|
|
|
259
328
|
grupo: entregueHoje ? 'hoje' : exports.GRUPO_DO_CICLO[ciclo] ?? 'proposto',
|
|
260
329
|
emAberto, threads: ligadas,
|
|
261
330
|
...(conduz ? { conduzindo: { thread: conduz.id, fase: conduz.fase, ...(conduz.maquina ? { maquina: conduz.maquina } : {}),
|
|
262
|
-
...(entrega ? { entrega } : {}) } } : {}),
|
|
331
|
+
...(entrega ? { entrega } : {}), ...(vida ? { vida } : {}) } } : {}),
|
|
263
332
|
...(hitl ? { hitl } : {}),
|
|
264
333
|
});
|
|
265
334
|
}
|
|
266
335
|
const grupos = exports.GRUPOS_DO_ROADMAP.map(g => ({ ...g, itens: itens.filter(i => i.grupo === g.id) }));
|
|
336
|
+
// R3 (RM-049): a thread aberta que nao conduz item nenhum e espera o dono. O relatorio continua por item;
|
|
337
|
+
// isto so evita que "O que precisa de voce" negue o que o pulse mostra.
|
|
338
|
+
const doRoadmap = new Set(itens.flatMap(i => i.threads));
|
|
339
|
+
const fora = fatos.filter(f => f.aberta && !doRoadmap.has(f.id) && (f.esperaVoce ? f.esperaVoce() : !!f.espera()))
|
|
340
|
+
.map(f => f.id).sort();
|
|
341
|
+
const precisaDeVoce = itens.filter(i => i.hitl).map(i => ({ item: i.id, espera: i.hitl }));
|
|
342
|
+
// RM-063 (F2): a fila do pulse entra no fecho com o que ele ainda nao dizia; a thread que espera o dono sai do "sigo".
|
|
343
|
+
const ditas = new Set([...precisaDeVoce.map(x => x.espera.thread), ...fora]);
|
|
344
|
+
const itemDaThread = new Map(itens.flatMap(i => i.threads.map(t => [t, i.id])));
|
|
345
|
+
const daFila = (opcoes.fila?.itens ?? []).filter(x => !(x.thread && ditas.has(x.thread)))
|
|
346
|
+
.map(x => (x.thread && itemDaThread.has(x.thread) ? { ...x, item: itemDaThread.get(x.thread) } : x));
|
|
347
|
+
const esperamODono = new Set(daFila.map(x => x.thread).filter((t) => !!t));
|
|
348
|
+
const fila = opcoes.fila;
|
|
267
349
|
return {
|
|
268
350
|
contrato: exports.CONTRATO_STATUS_DO_ROADMAP, consultadoEm: quando,
|
|
269
351
|
projeto: opcoes.projeto ?? 'projeto', grupos,
|
|
270
|
-
precisaDeVoce
|
|
271
|
-
emSeguida: itens.filter(i => i.conduzindo && !i.hitl
|
|
352
|
+
precisaDeVoce,
|
|
353
|
+
emSeguida: itens.filter(i => i.conduzindo && !i.hitl && !esperamODono.has(i.conduzindo.thread))
|
|
354
|
+
.map(i => ({ item: i.id, ...i.conduzindo })),
|
|
272
355
|
...(opcoes.consulta ? { consulta: opcoes.consulta } : {}),
|
|
273
356
|
...(opcoes.fabrica ? { fabrica: opcoes.fabrica } : {}),
|
|
357
|
+
...(opcoes.hitlDeConducao ? { hitlDeConducao: opcoes.hitlDeConducao } : {}),
|
|
358
|
+
...(fora.length ? { foraDoRoadmap: { threads: fora } } : {}),
|
|
359
|
+
...(fila && (!fila.lida || daFila.length) ? { filaDoDono: { lida: fila.lida,
|
|
360
|
+
...(!fila.lida && fila.detalhe ? { detalhe: fila.detalhe } : {}), itens: daFila } } : {}),
|
|
274
361
|
};
|
|
275
362
|
}
|
|
276
363
|
/** "orkastery" vira "Orkastery": o titulo diz o nome do projeto como gente escreve. */
|
|
@@ -282,35 +369,52 @@ const naMaquina = (maquina) => maquina ? ` (${maquina})` : '';
|
|
|
282
369
|
* proximo passo; entrega em curso, com o estado do PR e a hora em que ele foi lido; sem nada disso, a fase.
|
|
283
370
|
*/
|
|
284
371
|
function linhaDoQueVem(x, agora, fuso) {
|
|
372
|
+
const m = (0, locale_1.msg)().roadmap;
|
|
285
373
|
const e = x.entrega;
|
|
286
374
|
if (e?.parado) {
|
|
287
375
|
const { prLidoEm: lido } = e.parado;
|
|
288
376
|
return `• ${x.item}: ${(0, hitl_resumo_1.linhaDoParadoNoCondutor)({ thread: x.thread, ...e.parado }, { agora, fuso })}${naMaquina(x.maquina)}` +
|
|
289
|
-
`${lido ?
|
|
377
|
+
`${lido ? m.prLido((0, horario_1.formatarHora)(lido, { agora, fuso })) : ''}.`;
|
|
290
378
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
379
|
+
const daLeitura = e?.estado && e.prLidoEm ? m.prLido((0, horario_1.formatarHora)(e.prLidoEm, { agora, fuso })) : '';
|
|
380
|
+
const maquina = naMaquina(x.maquina);
|
|
381
|
+
const linha = (sigo) => e?.estado
|
|
382
|
+
? (sigo ? m.sigoComEstado(x.item, x.thread, x.fase, maquina, e.estado, daLeitura) : m.comEstado(x.item, x.thread, x.fase, maquina, e.estado, daLeitura))
|
|
383
|
+
: (sigo ? m.sigo(x.item, x.thread, x.fase, maquina) : m.semSessaoVerificada(x.item, x.thread, x.fase, maquina));
|
|
384
|
+
const v = x.vida;
|
|
385
|
+
// Sem `vida` (status montado sem ela), a linha de antes: "sigo" sem entrega, ou com o processo do condutor.
|
|
386
|
+
if (!v)
|
|
387
|
+
return linha(!e?.estado || !!e.conduzida);
|
|
388
|
+
// RM-063 (F2): "sigo" so com a sessao viva verificada no runtime ou com o processo do condutor conduzindo agora; sem
|
|
389
|
+
// isso, a parada com o desde e o motivo; sem motivo (retrato que nao publica a sessao), nada foi verificado.
|
|
390
|
+
if (v.viva || e?.conduzida)
|
|
391
|
+
return linha(true);
|
|
392
|
+
if (!v.motivo)
|
|
393
|
+
return linha(false);
|
|
394
|
+
return m.parada(x.item, x.thread, maquina, v.desdeEm && Number.isFinite(Date.parse(v.desdeEm)) ? (0, horario_1.formatarHora)(v.desdeEm, { agora, fuso }) : null, v.causa ? (0, vida_da_thread_1.motivoDaCausa)(v.causa, m.motivoDaParada) : v.motivo, e?.estado ? `${e.estado}${daLeitura}` : null);
|
|
395
|
+
}
|
|
396
|
+
/** RM-063 (F2): um item da fila do pulse no fecho, numa linha: quem, a pergunta e o que responder. */
|
|
397
|
+
function linhaDaFila(x) {
|
|
398
|
+
const m = (0, locale_1.msg)().roadmap;
|
|
399
|
+
const quem = x.item ? `${x.item} (${x.thread}${x.fase ? `, ${x.fase}` : ''})`
|
|
400
|
+
: x.thread ? `${x.thread}${x.fase ? ` (${x.fase})` : ''}` : m.sessaoSemThread((x.sessionId ?? '?').slice(0, 8));
|
|
401
|
+
const pergunta = x.pergunta.trim();
|
|
402
|
+
return `• ${quem}: ${pergunta}${/[.?!…]$/u.test(pergunta) ? '' : '.'}${x.comando ? m.responder(x.comando) : ''}`;
|
|
298
403
|
}
|
|
299
404
|
/** RM-037 (fatia 4, D8): uma linha so para a fabrica, e so quando ha o que avisar. */
|
|
300
405
|
function linhaDaFabrica(f, agora, fuso) {
|
|
301
406
|
if (!f)
|
|
302
407
|
return [];
|
|
408
|
+
const m = (0, locale_1.msg)().roadmap;
|
|
303
409
|
if (!f.lido)
|
|
304
|
-
return [
|
|
410
|
+
return [m.fabricaNaoLida(f.motivo !== undefined ? (0, locale_1.remontar)(f.motivo) : m.fabricaSemCopia(fabrica_estado_1.BRANCH_DA_FABRICA))];
|
|
305
411
|
if (f.copiaVelha) {
|
|
306
412
|
const { ultimoDestaMaquina: ultimo } = f.copiaVelha;
|
|
307
|
-
return [
|
|
308
|
-
`${(0, horario_1.formatarDataHora)(ultimo, { agora, fuso })}` : 'esta máquina não aparece nela'}); não dá para dizer quem está sem batida.`];
|
|
413
|
+
return [m.fabricaVelha(fabrica_estado_1.BRANCH_DA_FABRICA, ultimo ? (0, horario_1.formatarDataHora)(ultimo, { agora, fuso }) : null)];
|
|
309
414
|
}
|
|
310
415
|
if (!f.semBatida.length)
|
|
311
416
|
return [];
|
|
312
|
-
return [
|
|
313
|
-
`(último retrato ${(0, horario_1.formatarDataHora)(m.publicadoEm, { agora, fuso })})`).join('; ')}, pela cópia local de ${fabrica_estado_1.BRANCH_DA_FABRICA}.`];
|
|
417
|
+
return [m.fabricaSemBatida(f.semBatida.map(x => m.semBatida(x.maquina, (0, horario_1.duracaoCurta)(x.idadeMin), (0, horario_1.formatarDataHora)(x.publicadoEm, { agora, fuso }))).join('; '), fabrica_estado_1.BRANCH_DA_FABRICA)];
|
|
314
418
|
}
|
|
315
419
|
/**
|
|
316
420
|
* O texto do relatorio, igual em todo canal: os icones sao parte do formato aprovado. `fuso`: o do
|
|
@@ -329,20 +433,32 @@ function textoDoStatusDoRoadmap(s, fuso, opcoes = {}) {
|
|
|
329
433
|
? ` (${i.conduzindo.fase}${i.conduzindo.maquina ? `, ${i.conduzindo.maquina}` : ''})` : '';
|
|
330
434
|
return `• ${i.id} ${i.titulo}${detalhe}${i.hitl ? ' #HITL' : ''}`;
|
|
331
435
|
};
|
|
332
|
-
const
|
|
436
|
+
const m = (0, locale_1.msg)().roadmap;
|
|
437
|
+
const cortar = (lista, f) => [...lista.slice(0, exports.TETO_DO_FECHO).map(f), ...(lista.length > exports.TETO_DO_FECHO ? [m.eMais(lista.length - exports.TETO_DO_FECHO)] : [])];
|
|
333
438
|
return [
|
|
334
|
-
|
|
439
|
+
m.titulo(capitalizar(s.projeto), p),
|
|
335
440
|
...(opcoes.legenda === false ? [] : [(0, horario_1.legendaDoFuso)(fuso, s.consultadoEm)]),
|
|
336
441
|
// RM-052: logo abaixo do titulo aprovado (e do fuso), qual projeto foi lido e o que nao foi.
|
|
337
442
|
...(s.consulta ? (0, projeto_alvo_1.linhasDaConsulta)(s.consulta) : []),
|
|
338
443
|
...linhaDaFabrica(s.fabrica, s.consultadoEm, fuso),
|
|
339
|
-
|
|
340
|
-
'', '
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
444
|
+
// RM-061 (F2b, D4): o titulo do grupo e dado do contrato; a impressao o traduz pelo id.
|
|
445
|
+
...s.grupos.filter(g => g.itens.length).flatMap(g => ['', `${g.icone} ${(0, locale_1.localeAtivo)() === 'pt-BR' ? g.titulo : m.grupos[g.id] ?? g.titulo}`,
|
|
446
|
+
...g.itens.map(linhaDoItem)]),
|
|
447
|
+
'', m.precisaDeVoce,
|
|
448
|
+
...cortar(s.precisaDeVoce, x => `• ${x.item}${naMaquina(x.espera.maquina)}: ${x.espera.pergunta}` +
|
|
449
|
+
(x.espera.codigo ? m.responda(x.espera.codigo, x.espera.recomendada ?? 'a') : m.chegaNoResumo)),
|
|
450
|
+
// RM-063 (F2): a fila do pulse, com o que ainda nao foi dito; a que nao foi lida inteira e dita, nunca "Nada agora".
|
|
451
|
+
...cortar(s.filaDoDono?.itens ?? [], linhaDaFila),
|
|
452
|
+
...(s.filaDoDono && !s.filaDoDono.lida ? [m.filaNaoLida(s.filaDoDono.detalhe ?? null)] : []),
|
|
453
|
+
// R3 (RM-049): so quando ha; o detalhe de cada thread esta no `ork pulse`.
|
|
454
|
+
...(s.foraDoRoadmap?.threads.length ? [m.foraDoRoadmap(s.foraDoRoadmap.threads.length)] : []),
|
|
455
|
+
// RM-063 (F2): "Nada agora" so quando nada do dono foi dito acima (substitui a alternativa a da R3).
|
|
456
|
+
...(!s.precisaDeVoce.length && !s.filaDoDono && !s.foraDoRoadmap?.threads.length ? [m.nadaAgora] : []),
|
|
457
|
+
// RM-057 (fatia 3): ha quanto tempo cada pergunta de conducao parou a thread, e a mediana da semana.
|
|
458
|
+
...(s.hitlDeConducao ? [m.hitlDeConducao(s.hitlDeConducao.abertas.length, (0, hitl_tempo_parado_1.textoDaMediana)(s.hitlDeConducao)),
|
|
459
|
+
...cortar(s.hitlDeConducao.abertas, a => ` ${(0, hitl_tempo_parado_1.linhaDaPerguntaParada)(a, { agora: s.consultadoEm, fuso })}.`)] : []),
|
|
460
|
+
'', m.emSeguida,
|
|
345
461
|
...(s.emSeguida.length ? cortar(s.emSeguida, x => linhaDoQueVem(x, s.consultadoEm, fuso))
|
|
346
|
-
: [
|
|
462
|
+
: [m.nadaEmAndamento]),
|
|
347
463
|
].join('\n');
|
|
348
464
|
}
|
package/dist/runtime-context.js
CHANGED
|
@@ -36,6 +36,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.novaIdentidadeDeDespacho = novaIdentidadeDeDespacho;
|
|
37
37
|
exports.contextoDoProjeto = contextoDoProjeto;
|
|
38
38
|
exports.validarContextoRuntime = validarContextoRuntime;
|
|
39
|
+
exports.lerDeclaracaoDeMod = lerDeclaracaoDeMod;
|
|
40
|
+
exports.modsDeFaseInstalados = modsDeFaseInstalados;
|
|
39
41
|
/** Contexto interno opt-in: configuracao M4 existente + catalogo instalado, nunca args do modelo. */
|
|
40
42
|
const fs = __importStar(require("node:fs"));
|
|
41
43
|
const path = __importStar(require("node:path"));
|
|
@@ -193,27 +195,203 @@ function validarContextoRuntime(contexto, cwd) {
|
|
|
193
195
|
if (recibo.contrato !== 'ork.adapter-install/v1' || recibo.host !== contexto.host || !Array.isArray(recibo.arquivos) || recibo.arquivos.length > 512)
|
|
194
196
|
throw Error('runtime.context.installation: recibo instalado invalido');
|
|
195
197
|
const arquivos = new Map();
|
|
198
|
+
// RM-059 (T0.7): os bytes ja conferidos da declaracao e do manifesto de cada mod, lidos uma vez so.
|
|
199
|
+
const conferidos = new Map();
|
|
196
200
|
for (const item of recibo.arquivos) {
|
|
197
201
|
const a = objeto(item);
|
|
198
202
|
if (typeof a.arquivo !== 'string' || path.isAbsolute(a.arquivo) || a.arquivo.split(/[\\/]/).includes('..') ||
|
|
199
203
|
typeof a.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(a.sha256) || arquivos.has(a.arquivo))
|
|
200
204
|
throw Error('runtime.context.installation: arquivo do recibo invalido');
|
|
201
205
|
const file = path.join(instalacao, a.arquivo);
|
|
202
|
-
if (!dentro(raiz, file).startsWith(instalacao + path.sep)
|
|
206
|
+
if (!dentro(raiz, file).startsWith(instalacao + path.sep))
|
|
207
|
+
throw Error('runtime.context.installation: bytes instalados divergentes');
|
|
208
|
+
const bytes = ler(raiz, file, 1048576);
|
|
209
|
+
if ((0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex') !== a.sha256)
|
|
203
210
|
throw Error('runtime.context.installation: bytes instalados divergentes');
|
|
204
211
|
arquivos.set(a.arquivo, file);
|
|
212
|
+
if (DECLARACAO_OU_MANIFESTO_DE_MOD.test(a.arquivo))
|
|
213
|
+
conferidos.set(a.arquivo, bytes);
|
|
205
214
|
}
|
|
206
215
|
const bootstrap = arquivos.get('skills/core/orkastery-bootstrap/SKILL.md');
|
|
207
216
|
if (!bootstrap || (contexto.host === 'claude-code' && !arquivos.has('.claude-plugin/plugin.json')))
|
|
208
217
|
throw Error('runtime.context.installation: catalogo ou plugin incompleto');
|
|
218
|
+
const modsDeFase = contexto.host === 'claude-code' ? modsDeFaseInstalados(raiz, instalacao, arquivos, conferidos) : [];
|
|
209
219
|
// Capacidade derivada do bloco atual, nunca aceita como entrada do modelo.
|
|
210
220
|
const permiteEditarProduto = permissoesFilho === 'worktree' && (0, thread_1.blocoDaThread)(thread, thread.faseAtual).fases.includes('GO');
|
|
211
221
|
// RM-031 KG5 (D2, D7): as tools do grafo seguem a flag do manifesto da raiz, que o servidor do filho tambem le;
|
|
212
222
|
// o manifesto da worktree da thread e o pedido do modelo nao ligam nada.
|
|
213
|
-
const
|
|
223
|
+
const manifestoDaRaiz = (0, manifest_1.exigirManifesto)(raiz).manifesto;
|
|
224
|
+
const grafoMcp = (0, mcp_grafo_1.grafoLigado)(manifestoDaRaiz);
|
|
225
|
+
// RM-059 (T10.4, D11 da thread ork-rm059portao): os tetos do piloto de agent teams so vao ao despacho do Claude Code
|
|
226
|
+
// quando o bloco da fase atual tem o GO, a mesma regra da edicao de produto; o manifesto da raiz decide, nunca o
|
|
227
|
+
// pedido do modelo. Quem liga de fato e o `montarComando`, e so com o Portao de Tarefas na sessao.
|
|
228
|
+
const tetos = contexto.host === 'claude-code' ? manifestoDaRaiz.runtime.agent_teams : undefined;
|
|
229
|
+
const agentTeams = tetos && (0, thread_1.blocoDaThread)(thread, thread.faseAtual).fases.includes('GO') ? { ...tetos } : null;
|
|
214
230
|
const publicVerifiers = (0, hitl_public_receipt_1.publicHitlVerifiers)();
|
|
215
231
|
const servidor = { ...(0, mcp_install_1.configuracaoServidorMcp)(raiz, contexto.host, contexto.threadId, transporteShip, permissoesFilho, contexto.identidade?.dispatchId),
|
|
216
232
|
...(publicVerifiers ? { env: { [hitl_public_receipt_1.ENV_HITL_VERIFIERS]: publicVerifiers } } : {}),
|
|
217
233
|
...(contexto.host === 'codex' && permissoesFilho === 'worktree' ? (0, mcp_install_1.politicasFilhoCodex)(perfil.politicasCodex ?? {}) : {}) };
|
|
218
|
-
return { projeto: raiz, instalacao, bootstrap, permissoesFilho, permiteEditarProduto, grafoMcp, servidor };
|
|
234
|
+
return { projeto: raiz, instalacao, bootstrap, permissoesFilho, permiteEditarProduto, grafoMcp, servidor, modsDeFase, agentTeams };
|
|
235
|
+
}
|
|
236
|
+
const DECLARACAO_OU_MANIFESTO_DE_MOD = /^mods\/[^/]+\/(?:orkastery-mod\.json|\.claude-plugin\/plugin\.json)$/;
|
|
237
|
+
const DECLARACAO_DE_MOD = /^mods\/([^/]+)\/orkastery-mod\.json$/;
|
|
238
|
+
const NOME_DE_MOD = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
239
|
+
/** A declaracao de papel de um mod; o erro diz o que esta fora da convencao. */
|
|
240
|
+
function lerDeclaracaoDeMod(texto) {
|
|
241
|
+
let bruto;
|
|
242
|
+
try {
|
|
243
|
+
bruto = JSON.parse(texto);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
throw Error('orkastery-mod.json nao e JSON');
|
|
247
|
+
}
|
|
248
|
+
if (!bruto || typeof bruto !== 'object' || Array.isArray(bruto))
|
|
249
|
+
throw Error('orkastery-mod.json precisa ser objeto');
|
|
250
|
+
const d = bruto;
|
|
251
|
+
if (d.formato !== 'ork.mod/v1')
|
|
252
|
+
throw Error('orkastery-mod.json com formato diferente de ork.mod/v1');
|
|
253
|
+
const papeis = d.papeis;
|
|
254
|
+
if (!Array.isArray(papeis) || papeis.length === 0 || papeis.some((p) => p !== 'dono' && p !== 'fase') ||
|
|
255
|
+
new Set(papeis).size !== papeis.length)
|
|
256
|
+
throw Error('orkastery-mod.json com papeis fora de dono e fase, vazios ou repetidos');
|
|
257
|
+
if (typeof d.claudeCodeMinimo !== 'string' || !/^\d+\.\d+\.\d+$/.test(d.claudeCodeMinimo))
|
|
258
|
+
throw Error('orkastery-mod.json com claudeCodeMinimo fora do formato X.Y.Z');
|
|
259
|
+
return { formato: 'ork.mod/v1', papeis: papeis, claudeCodeMinimo: d.claudeCodeMinimo };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* RM-059 (T0.7, D3): os nomes que o `dependencies` do `plugin.json` de um mod cita, em melhor esforco:
|
|
263
|
+
* lista de nomes (com ou sem `@marketplace`), objeto com os nomes nas chaves, ou lista de objetos com `name`.
|
|
264
|
+
*/
|
|
265
|
+
function dependenciasDoManifesto(texto) {
|
|
266
|
+
let manifesto;
|
|
267
|
+
try {
|
|
268
|
+
manifesto = JSON.parse(texto);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
throw Error('.claude-plugin/plugin.json nao e JSON');
|
|
272
|
+
}
|
|
273
|
+
if (!manifesto || typeof manifesto !== 'object' || Array.isArray(manifesto))
|
|
274
|
+
throw Error('.claude-plugin/plugin.json precisa ser objeto');
|
|
275
|
+
const deps = manifesto.dependencies;
|
|
276
|
+
const itens = Array.isArray(deps) ? deps : deps && typeof deps === 'object' ? Object.keys(deps) : [];
|
|
277
|
+
return itens.flatMap((item) => {
|
|
278
|
+
const nome = typeof item === 'string' ? item : item && typeof item === 'object' ? item.name : undefined;
|
|
279
|
+
return typeof nome === 'string' && nome ? [nome.split('@')[0]] : [];
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
/** Os tipos que o proprio Claude Code escreve na pasta do mod que ele carrega: declaracoes, nunca codigo. */
|
|
283
|
+
function tipoDoMotor(relativo) {
|
|
284
|
+
return relativo.startsWith('.claude-plugin/types/') && (relativo.endsWith('.d.ts') || path.posix.basename(relativo) === 'tsconfig.json');
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* RM-059 (T0.7, D1): a pasta instalada de um mod de fase tem exatamente os arquivos do recibo. O
|
|
288
|
+
* `--plugin-dir` carrega o que estiver nela (comandos, agentes e skills sao descobertos), entao arquivo
|
|
289
|
+
* fora do recibo entraria na sessao de fase sem prova. Link e arquivo especial recusam sempre.
|
|
290
|
+
*/
|
|
291
|
+
function conferirPastaDoMod(raiz, instalacao, nome, arquivos) {
|
|
292
|
+
const dir = path.join(instalacao, 'mods', nome);
|
|
293
|
+
const recusa = (motivo, correcao = 'reinstale com ork adapter install claude-code') => Error(`runtime.context.installation: mod ${nome}: ${motivo}; ${correcao}`);
|
|
294
|
+
if (!fs.lstatSync(dir, { throwIfNoEntry: false })?.isDirectory() || dentro(raiz, dir) !== dir)
|
|
295
|
+
throw recusa('pasta instalada ausente ou fora da instalacao');
|
|
296
|
+
const visitar = (atual, prefixo) => {
|
|
297
|
+
for (const entrada of fs.readdirSync(atual, { withFileTypes: true })) {
|
|
298
|
+
const relativo = prefixo ? `${prefixo}/${entrada.name}` : entrada.name;
|
|
299
|
+
if (entrada.isSymbolicLink())
|
|
300
|
+
throw recusa(`link em ${relativo}`);
|
|
301
|
+
if (entrada.isDirectory()) {
|
|
302
|
+
visitar(path.join(atual, entrada.name), relativo);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
if (!entrada.isFile())
|
|
306
|
+
throw recusa(`arquivo especial em ${relativo}`);
|
|
307
|
+
if (!arquivos.has(`mods/${nome}/${relativo}`) && !tipoDoMotor(relativo)) {
|
|
308
|
+
throw recusa(`arquivo fora do INSTALADO.json (${relativo})`, 'se ele saiu do catalogo, ork adapter install claude-code o tira da copia; ' +
|
|
309
|
+
`se foi editado ou acrescentado a mao, apague ${path.join(dir, relativo)}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
visitar(dir, '');
|
|
314
|
+
return dir;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* RM-059 (rodada 2 do CHECK, N2): o arquivo comum da raiz de `mods/` tambem so vale com prova. A ponte le a lista
|
|
318
|
+
* de autoridade em `../autoridade.json` antes da propria pasta, entao uma copia velha ou escrita a mao ali mudaria o
|
|
319
|
+
* que a sessao de fase aceita. Com mod de fase no despacho, todo arquivo direto em `mods/` esta no recibo (que ja
|
|
320
|
+
* conferiu os bytes); link e arquivo especial recusam. Pastas sao os mods, conferidos um a um.
|
|
321
|
+
*/
|
|
322
|
+
function conferirRaizDosMods(raiz, instalacao, arquivos) {
|
|
323
|
+
const dir = path.join(instalacao, 'mods');
|
|
324
|
+
const recusa = (motivo, correcao = 'reinstale com ork adapter install claude-code') => Error(`runtime.context.installation: mods/: ${motivo}; ${correcao}`);
|
|
325
|
+
if (!fs.lstatSync(dir, { throwIfNoEntry: false })?.isDirectory() || dentro(raiz, dir) !== dir)
|
|
326
|
+
throw recusa('pasta instalada ausente ou fora da instalacao');
|
|
327
|
+
for (const entrada of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
328
|
+
if (entrada.isSymbolicLink())
|
|
329
|
+
throw recusa(`link em ${entrada.name}`);
|
|
330
|
+
if (entrada.isDirectory())
|
|
331
|
+
continue;
|
|
332
|
+
if (!entrada.isFile())
|
|
333
|
+
throw recusa(`arquivo especial em ${entrada.name}`);
|
|
334
|
+
if (!arquivos.has(`mods/${entrada.name}`)) {
|
|
335
|
+
throw recusa(`arquivo fora do INSTALADO.json (${entrada.name})`, 'se ele saiu do catalogo, ork adapter install claude-code o tira da copia; ' +
|
|
336
|
+
`se foi editado ou acrescentado a mao, apague ${path.join(dir, entrada.name)}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* RM-059 (T0.7): os mods de papel `fase` da instalacao, lidos do recibo ja conferido e na ordem da D3:
|
|
342
|
+
* a dependencia antes de quem depende, depois o nome. Declaracao ou manifesto invalidos recusam como
|
|
343
|
+
* um byte divergente (D2): e instalacao corrompida, e o CI do catalogo ja reprova esse caso.
|
|
344
|
+
*/
|
|
345
|
+
function modsDeFaseInstalados(raiz, instalacao, arquivos, conferidos) {
|
|
346
|
+
const achados = [];
|
|
347
|
+
const nomes = [...arquivos.keys()].flatMap((arquivo) => DECLARACAO_DE_MOD.exec(arquivo)?.[1] ?? []).sort();
|
|
348
|
+
const daInstalacao = new Set(nomes);
|
|
349
|
+
for (const nome of nomes) {
|
|
350
|
+
const arquivo = `mods/${nome}/orkastery-mod.json`;
|
|
351
|
+
const recusa = (motivo) => Error(`runtime.context.installation: mod ${nome}: ${motivo}; reinstale com ork adapter install claude-code`);
|
|
352
|
+
if (!NOME_DE_MOD.test(nome))
|
|
353
|
+
throw recusa('nome fora de letras minusculas, digitos e hifen');
|
|
354
|
+
let declaracao;
|
|
355
|
+
try {
|
|
356
|
+
declaracao = lerDeclaracaoDeMod(conferidos.get(arquivo).toString('utf8'));
|
|
357
|
+
}
|
|
358
|
+
catch (e) {
|
|
359
|
+
throw recusa(e.message);
|
|
360
|
+
}
|
|
361
|
+
if (!declaracao.papeis.includes('fase'))
|
|
362
|
+
continue;
|
|
363
|
+
const manifesto = conferidos.get(`mods/${nome}/.claude-plugin/plugin.json`);
|
|
364
|
+
if (!manifesto)
|
|
365
|
+
throw recusa('.claude-plugin/plugin.json fora do recibo');
|
|
366
|
+
let dependencias;
|
|
367
|
+
try {
|
|
368
|
+
dependencias = dependenciasDoManifesto(manifesto.toString('utf8')).filter((d) => daInstalacao.has(d) && d !== nome);
|
|
369
|
+
}
|
|
370
|
+
catch (e) {
|
|
371
|
+
throw recusa(e.message);
|
|
372
|
+
}
|
|
373
|
+
achados.push({ nome, dir: conferirPastaDoMod(raiz, instalacao, nome, arquivos), claudeCodeMinimo: declaracao.claudeCodeMinimo, dependencias });
|
|
374
|
+
}
|
|
375
|
+
if (achados.length)
|
|
376
|
+
conferirRaizDosMods(raiz, instalacao, arquivos);
|
|
377
|
+
const porNome = new Map(achados.map((m) => [m.nome, m]));
|
|
378
|
+
const ordem = [];
|
|
379
|
+
const feitos = new Set(), abertos = new Set();
|
|
380
|
+
// Busca em profundidade: a dependencia sai antes; num ciclo, a aresta de volta e ignorada (melhor esforco).
|
|
381
|
+
const visitar = (m) => {
|
|
382
|
+
if (feitos.has(m.nome) || abertos.has(m.nome))
|
|
383
|
+
return;
|
|
384
|
+
abertos.add(m.nome);
|
|
385
|
+
for (const dep of [...m.dependencias].sort()) {
|
|
386
|
+
const alvo = porNome.get(dep);
|
|
387
|
+
if (alvo)
|
|
388
|
+
visitar(alvo);
|
|
389
|
+
}
|
|
390
|
+
abertos.delete(m.nome);
|
|
391
|
+
feitos.add(m.nome);
|
|
392
|
+
ordem.push(m);
|
|
393
|
+
};
|
|
394
|
+
for (const m of achados)
|
|
395
|
+
visitar(m);
|
|
396
|
+
return ordem;
|
|
219
397
|
}
|