@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/master.js
CHANGED
|
@@ -49,7 +49,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
49
49
|
};
|
|
50
50
|
})();
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
-
exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.ORDEM_DAS_CLASSES = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
|
|
52
|
+
exports.AUTOR_DA_OMISSAO = exports.CONTRATO_MASTER_PENDENTE = exports.FASE_DO_TIPO = exports.ORDEM_DAS_CLASSES = exports.CLASSE_DO_MOTIVO = exports.CLASSES_DE_FALHA = exports.VERSAO_MASTER_LOG = exports.CONTRATO_MASTER_LOG = void 0;
|
|
53
|
+
exports.classesPelosGates = classesPelosGates;
|
|
54
|
+
exports.sincronizacoesComABase = sincronizacoesComABase;
|
|
53
55
|
exports.parseClasse = parseClasse;
|
|
54
56
|
exports.caminhoPostmortem = caminhoPostmortem;
|
|
55
57
|
exports.caminhoMasterLog = caminhoMasterLog;
|
|
@@ -72,6 +74,8 @@ exports.aceitosPorOmissao = aceitosPorOmissao;
|
|
|
72
74
|
exports.pendentesDeScore = pendentesDeScore;
|
|
73
75
|
exports.tabelaDeEntregas = tabelaDeEntregas;
|
|
74
76
|
exports.aceitarPendentesPorOmissao = aceitarPendentesPorOmissao;
|
|
77
|
+
exports.entregasParaOmissao = entregasParaOmissao;
|
|
78
|
+
exports.motivoForaDaOmissao = motivoForaDaOmissao;
|
|
75
79
|
exports.textoDoMaster = textoDoMaster;
|
|
76
80
|
exports.tabelaDeClasses = tabelaDeClasses;
|
|
77
81
|
const path = __importStar(require("node:path"));
|
|
@@ -83,6 +87,7 @@ const modos_1 = require("./modos");
|
|
|
83
87
|
const thread_1 = require("./thread");
|
|
84
88
|
const types_1 = require("./types");
|
|
85
89
|
const util_1 = require("./util");
|
|
90
|
+
const locale_1 = require("./locale");
|
|
86
91
|
const fs = __importStar(require("node:fs"));
|
|
87
92
|
const horario_1 = require("./horario");
|
|
88
93
|
const indice_1 = require("./indice");
|
|
@@ -105,6 +110,65 @@ exports.CLASSES_DE_FALHA = {
|
|
|
105
110
|
'scope-creep': 'a entrega cresceu alem do que o GOAL prometia',
|
|
106
111
|
outra: 'nao cabe em nenhuma classe acima (descreva na justificativa)',
|
|
107
112
|
};
|
|
113
|
+
/**
|
|
114
|
+
* RM-008 (classe pelo gate): a classe que cada motivo tipado do gate sustenta quando ninguem informa
|
|
115
|
+
* `--classe`. Antes, todo gate virava "outra", a classe que o `ork licoes` ignora: 8 POSTMORTEMs de
|
|
116
|
+
* 03/10 fecharam assim por aceite por omissao. Motivo fora da tabela (prazo, falta de veredito,
|
|
117
|
+
* runtime, conta, custo, espera humana) nao cabe numa classe fixa e segue "outra".
|
|
118
|
+
*/
|
|
119
|
+
exports.CLASSE_DO_MOTIVO = {
|
|
120
|
+
'artifact.missing': 'processo',
|
|
121
|
+
'claims.failed': 'processo',
|
|
122
|
+
'claims.unverifiable': 'processo',
|
|
123
|
+
'policy.violation': 'processo',
|
|
124
|
+
'runtime.autoconferencia': 'processo',
|
|
125
|
+
'verify.regression': 'processo',
|
|
126
|
+
'verify.failed': 'processo',
|
|
127
|
+
'ci.failed': 'processo',
|
|
128
|
+
'hitl.formato': 'processo',
|
|
129
|
+
'runtime.rate-limited': 'rate-limit',
|
|
130
|
+
'runtime.quota-exhausted': 'rate-limit',
|
|
131
|
+
'lease.busy': 'conflito',
|
|
132
|
+
'conducao.em-andamento': 'conflito',
|
|
133
|
+
'tree.blocked': 'conflito',
|
|
134
|
+
};
|
|
135
|
+
/** As classes que os motivos dos gates sustentam, na ordem canonica e sem repetir. */
|
|
136
|
+
function classesPelosGates(motivos) {
|
|
137
|
+
const achadas = new Set();
|
|
138
|
+
for (const m of motivos)
|
|
139
|
+
achadas.add(exports.CLASSE_DO_MOTIVO[m] ?? 'outra');
|
|
140
|
+
if (achadas.size === 0)
|
|
141
|
+
achadas.add('sem-falha');
|
|
142
|
+
return exports.ORDEM_DAS_CLASSES.filter((c) => achadas.has(c));
|
|
143
|
+
}
|
|
144
|
+
/** Teto de merges conferidos por entrega: a branch de 03/10 com mais sincronizacoes trouxe 16. */
|
|
145
|
+
const TETO_DE_MERGES_POR_ENTREGA = 200;
|
|
146
|
+
/**
|
|
147
|
+
* RM-008 (base-avancou): quantas vezes a thread precisou trazer a base para dentro da branch. Conta os
|
|
148
|
+
* `worktree_synced` do ledger e, em cada entrega com merge, os merges da branch (entre o primeiro e o
|
|
149
|
+
* segundo pai do merge) cujo pai trazido ja estava na base. Em 03/10/2026, 29 de 35 entregas trouxeram
|
|
150
|
+
* a `origin/main` antes do merge, e nenhuma fechou com `base-avancou`. Git sem resposta conta 0 e nunca
|
|
151
|
+
* derruba o MASTER.
|
|
152
|
+
*/
|
|
153
|
+
function sincronizacoesComABase(raiz, eventos, mergeShas) {
|
|
154
|
+
let total = eventos.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.worktreeSincronizada).length;
|
|
155
|
+
for (const sha of new Set(mergeShas)) {
|
|
156
|
+
if (!/^[0-9a-f]{40}$/.test(sha))
|
|
157
|
+
continue;
|
|
158
|
+
const r = (0, util_1.exec)('git', ['rev-list', '--merges', '--parents', `--max-count=${TETO_DE_MERGES_POR_ENTREGA}`,
|
|
159
|
+
`${sha}^1..${sha}^2`], raiz, 30000);
|
|
160
|
+
if (!r.ok)
|
|
161
|
+
continue;
|
|
162
|
+
for (const linha of r.stdout.split('\n')) {
|
|
163
|
+
const pais = linha.trim().split(/\s+/).slice(1);
|
|
164
|
+
// O pai trazido (o segundo em diante) ja estava na base: e a base entrando na branch.
|
|
165
|
+
if (pais.slice(1).some((p) => /^[0-9a-f]{40}$/.test(p) &&
|
|
166
|
+
(0, util_1.exec)('git', ['merge-base', '--is-ancestor', p, `${sha}^1`], raiz, 30000).ok))
|
|
167
|
+
total += 1;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return total;
|
|
171
|
+
}
|
|
108
172
|
/** Ordem canonica das classes na saida do CLI. */
|
|
109
173
|
exports.ORDEM_DAS_CLASSES = [
|
|
110
174
|
'sem-falha',
|
|
@@ -138,6 +202,19 @@ function caminhoPostmortem(raiz, id) {
|
|
|
138
202
|
function caminhoMasterLog(raiz, id) {
|
|
139
203
|
return path.join((0, thread_1.dirThread)(raiz, id), 'master-log.json');
|
|
140
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* RM-008 (fases pelo tipo): a fase dos eventos que o nucleo grava sem o campo `fase`. O `verify_run`
|
|
207
|
+
* e o `ship_done` nunca trouxeram fase, e 34 dos 35 POSTMORTEM de 03/10 sairam sem o CHECK, e 33 sem o
|
|
208
|
+
* SHIP, embora o ledger os tivesse (`ork-rm037testesi`: 6 `verify_run`, 1 `ship_done`, "GOAL GO MASTER").
|
|
209
|
+
* So vale quando o evento nao traz `fase`: o campo explicito continua vencendo.
|
|
210
|
+
*/
|
|
211
|
+
exports.FASE_DO_TIPO = {
|
|
212
|
+
[ledger_1.TIPOS_DE_EVENTO.verificacao]: 'CHECK',
|
|
213
|
+
[ledger_1.TIPOS_DE_EVENTO.reverifyConcluido]: 'CHECK',
|
|
214
|
+
[ledger_1.TIPOS_DE_EVENTO.shipIniciado]: 'SHIP',
|
|
215
|
+
[ledger_1.TIPOS_DE_EVENTO.shipConcluido]: 'SHIP',
|
|
216
|
+
[ledger_1.TIPOS_DE_EVENTO.shipBloqueado]: 'SHIP',
|
|
217
|
+
};
|
|
141
218
|
/**
|
|
142
219
|
* As fases que a thread realmente percorreu, reconstruidas do LEDGER.
|
|
143
220
|
*
|
|
@@ -148,7 +225,7 @@ function fasesPercorridas(raiz, id) {
|
|
|
148
225
|
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
|
|
149
226
|
const porFase = new Map();
|
|
150
227
|
for (const e of eventos) {
|
|
151
|
-
const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : null;
|
|
228
|
+
const bruta = typeof e.fase === 'string' ? e.fase.toUpperCase() : (exports.FASE_DO_TIPO[e.tipo] ?? null);
|
|
152
229
|
if (!bruta || !types_1.FASES.includes(bruta))
|
|
153
230
|
continue;
|
|
154
231
|
const atual = porFase.get(bruta) ?? {
|
|
@@ -244,7 +321,8 @@ function prepararDocumentos(raiz, id, opcoes) {
|
|
|
244
321
|
sincronizarReversao(raiz, id);
|
|
245
322
|
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, id));
|
|
246
323
|
const gatesBloqueados = eventos
|
|
247
|
-
|
|
324
|
+
// Ensaio de 03/10/2026 (RM-049): o gate barrado por um `ork ship --dry-run` e ensaio, nao reprovacao.
|
|
325
|
+
.filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.gateBloqueado && e.dryRun !== true)
|
|
248
326
|
.map((e) => ({
|
|
249
327
|
ts: e.ts,
|
|
250
328
|
motivo: String(e.motivo ?? '(sem motivo)'),
|
|
@@ -264,11 +342,20 @@ function prepararDocumentos(raiz, id, opcoes) {
|
|
|
264
342
|
let classes = opcoes.classes ?? [];
|
|
265
343
|
if (classes.length === 0) {
|
|
266
344
|
classesInferidas = true;
|
|
267
|
-
classes = gatesBloqueados.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
345
|
+
classes = classesPelosGates(gatesBloqueados.map((g) => g.motivo));
|
|
346
|
+
const motivos = [...new Set(gatesBloqueados.map((g) => g.motivo))];
|
|
347
|
+
const sincronizacoes = sincronizacoesComABase(raiz, eventos, entregas.map((e) => e.mergeSha));
|
|
348
|
+
if (sincronizacoes > 0) {
|
|
349
|
+
classes = exports.ORDEM_DAS_CLASSES.filter((c) => c === 'base-avancou' || (c !== 'sem-falha' && classes.includes(c)));
|
|
350
|
+
}
|
|
351
|
+
const pelaBase = sincronizacoes > 0
|
|
352
|
+
? ` A branch trouxe a base ${sincronizacoes} vez(es) antes da entrega: o \`ork\` juntou "base-avancou".` : '';
|
|
353
|
+
avisos.push((gatesBloqueados.length > 0
|
|
354
|
+
? `a thread levou ${gatesBloqueados.length} reprovacao(oes) tipada(s) (${motivos.join(', ')}) e nenhuma --classe foi ` +
|
|
355
|
+
`informada: o \`ork\` inferiu "${classes.join('", "')}" pelo motivo do gate.${pelaBase} Corrija com --classe <classe> --refazer.`
|
|
356
|
+
: sincronizacoes > 0
|
|
357
|
+
? `nenhuma --classe informada e nenhum gate reprovou.${pelaBase} Corrija com --classe <classe> --refazer.`
|
|
358
|
+
: 'nenhuma --classe informada e nenhum gate reprovou: o `ork` gravou "sem-falha".'));
|
|
272
359
|
}
|
|
273
360
|
// I-43 (D3): o indice e DERIVADO do ledger no momento do registro, e acompanha o
|
|
274
361
|
// score como o que a maquina achava antes de o dono falar. Quando as duas existem,
|
|
@@ -351,7 +438,7 @@ function autoriaHumana(por) {
|
|
|
351
438
|
}
|
|
352
439
|
function exigirAutoriaHumana(por) {
|
|
353
440
|
if (!autoriaHumana(por))
|
|
354
|
-
throw new Error('ratificação exige --por humano explícito; agente ou autoria pendente não pode pontuar');
|
|
441
|
+
throw new Error('ratificação exige --por humano explícito (ex.: --por "seu-nome"); agente ou autoria pendente não pode pontuar');
|
|
355
442
|
}
|
|
356
443
|
function masterRatificado(raiz, id) {
|
|
357
444
|
const t = (0, thread_1.lerThread)(raiz, id);
|
|
@@ -646,6 +733,7 @@ function pendentesDeScore(raiz, todas = false) {
|
|
|
646
733
|
* inteiro, e a nota humana continua sobrescrevendo o indice quando o dono reclama.
|
|
647
734
|
*/
|
|
648
735
|
function tabelaDeEntregas(raiz, todas = false) {
|
|
736
|
+
const m = (0, locale_1.msg)().master;
|
|
649
737
|
const pendentes = pendentesDeScore(raiz, todas);
|
|
650
738
|
const omissoes = aceitosPorOmissao(raiz);
|
|
651
739
|
// A1: o indice da coluna e o de AGORA; `SCORE GRAVADO` e o que o MASTER log congelou.
|
|
@@ -653,23 +741,18 @@ function tabelaDeEntregas(raiz, todas = false) {
|
|
|
653
741
|
const caiuDepoisDeAceita = omissoes.filter((o) => typeof o.scoreGravado === 'number' && o.indice.valor < o.scoreGravado);
|
|
654
742
|
const secaoOmissao = omissoes.length === 0
|
|
655
743
|
? []
|
|
656
|
-
: ['',
|
|
657
|
-
(0, util_1.tabela)([
|
|
744
|
+
: ['', m.aceitasTitulo(omissoes.length), '',
|
|
745
|
+
(0, util_1.tabela)([...m.colunasAceitas], omissoes.map((o) => [o.thread, `${o.indice.valor}/${o.indice.base}`,
|
|
658
746
|
typeof o.scoreGravado === 'number' ? `${o.scoreGravado}/5` : '-',
|
|
659
747
|
(0, horario_1.formatarDataHora)(o.aceitoEm)])),
|
|
660
748
|
(0, horario_1.legendaDoFuso)(),
|
|
661
749
|
...(caiuDepoisDeAceita.length === 0 ? [] : ['',
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
' registro humano alcancar o fato; o registro da omissao permanece no ledger.']),
|
|
666
|
-
'', 'Discordou de alguma? A nota humana sobrescreve, e o registro da omissao permanece:',
|
|
667
|
-
' ork master <thread-id> --score <0-5> --justificativa "<por que>" --por <humano>'];
|
|
750
|
+
m.caiuDepois(caiuDepoisDeAceita.length, caiuDepoisDeAceita.map((o) => o.thread).join(', ')),
|
|
751
|
+
m.caiuDepoisLinha1, m.caiuDepoisLinha2]),
|
|
752
|
+
'', m.discordouDeAlguma, m.pontuar];
|
|
668
753
|
if (pendentes.length === 0) {
|
|
669
754
|
return [
|
|
670
|
-
todas
|
|
671
|
-
? 'Nenhuma thread aberta sem score.'
|
|
672
|
-
: 'Nenhuma entrega esperando decisao. Para ver tambem as que ainda nao entregaram: ork master --todas',
|
|
755
|
+
todas ? m.semEntregaTodas : m.semEntrega,
|
|
673
756
|
...secaoOmissao,
|
|
674
757
|
].join('\n');
|
|
675
758
|
}
|
|
@@ -680,22 +763,23 @@ function tabelaDeEntregas(raiz, todas = false) {
|
|
|
680
763
|
p.thread.slug,
|
|
681
764
|
(0, modos_1.tagDoModo)(p.thread.modo),
|
|
682
765
|
p.thread.faseAtual,
|
|
683
|
-
p.thread.status,
|
|
684
|
-
p.entregou
|
|
766
|
+
(0, locale_1.msg)().thread.status(p.thread.status),
|
|
767
|
+
m.simNao(p.entregou),
|
|
685
768
|
`${indice.valor}/${indice.base}`,
|
|
686
|
-
indice.parcelas.length === 0 ?
|
|
769
|
+
indice.parcelas.length === 0 ? m.semTropeco : indice.parcelas.map((x) => `${x.evento} x${x.ocorrencias}`).join(', '),
|
|
687
770
|
];
|
|
688
771
|
});
|
|
689
772
|
return [
|
|
690
|
-
|
|
773
|
+
m.entregas(pendentes.length),
|
|
691
774
|
'',
|
|
692
|
-
(0, util_1.tabela)([
|
|
775
|
+
(0, util_1.tabela)([...m.colunas], linhas),
|
|
693
776
|
'',
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
777
|
+
m.entregueEAceito,
|
|
778
|
+
m.aceitarEsta,
|
|
779
|
+
m.aceitarTodas,
|
|
780
|
+
m.reclamar,
|
|
697
781
|
'',
|
|
698
|
-
|
|
782
|
+
m.classesFixas(exports.ORDEM_DAS_CLASSES.join(', ')),
|
|
699
783
|
...secaoOmissao,
|
|
700
784
|
].join('\n');
|
|
701
785
|
}
|
|
@@ -706,10 +790,40 @@ function tabelaDeEntregas(raiz, todas = false) {
|
|
|
706
790
|
* ENTREGOU: uma thread que nunca chegou ao ship nao tem entrega para aceitar, e
|
|
707
791
|
* aceita-la seria inventar um fato.
|
|
708
792
|
*/
|
|
709
|
-
function aceitarPendentesPorOmissao(raiz) {
|
|
793
|
+
function aceitarPendentesPorOmissao(raiz, opcoes = {}) {
|
|
794
|
+
return entregasParaOmissao(raiz, opcoes.thread).map((p) => aceitarPorOmissao(raiz, p.thread.id));
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* RM-008 (03/10/2026): o que `ork master --aceitar-omissao` fecharia, sem gravar nada.
|
|
798
|
+
*
|
|
799
|
+
* Na madrugada de 03/10, tres vezes, um condutor rodou `ork master --aceitar-omissao` para fechar
|
|
800
|
+
* a PROPRIA thread, e o comando fechou tambem as entregues de outras frentes paralelas. A CLI nao
|
|
801
|
+
* deixava indicar a thread. Com `thread`, o alvo e so ela; sem, continua sendo toda entrega que
|
|
802
|
+
* espera decisao (o padrao nao mudou). Thread inexistente recusa pelo `lerThread`.
|
|
803
|
+
*/
|
|
804
|
+
function entregasParaOmissao(raiz, thread) {
|
|
805
|
+
if (thread !== undefined)
|
|
806
|
+
(0, thread_1.lerThread)(raiz, thread);
|
|
710
807
|
return pendentesDeScore(raiz)
|
|
711
808
|
.filter((p) => p.entregou)
|
|
712
|
-
.
|
|
809
|
+
.filter((p) => thread === undefined || p.thread.id === thread);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Por que a thread indicada nao entra no aceite por omissao, ou `null` quando entra.
|
|
813
|
+
* `ja-fechada` e idempotencia (nada a fazer); `fechamento-admin` e `sem-entrega` sao recusa.
|
|
814
|
+
*/
|
|
815
|
+
function motivoForaDaOmissao(raiz, id) {
|
|
816
|
+
const thread = (0, thread_1.lerThread)(raiz, id);
|
|
817
|
+
if (thread.fechamentoAdmin) {
|
|
818
|
+
return { motivo: 'fechamento-admin', texto: (0, locale_1.msg)().master.foraAdmin(id, thread.fechamentoAdmin.motivo) };
|
|
819
|
+
}
|
|
820
|
+
if (masterRatificado(raiz, id)) {
|
|
821
|
+
return { motivo: 'ja-fechada', texto: (0, locale_1.msg)().master.foraJaFechada(id) };
|
|
822
|
+
}
|
|
823
|
+
if (!entregou(raiz, id)) {
|
|
824
|
+
return { motivo: 'sem-entrega', texto: (0, locale_1.msg)().master.foraSemEntrega(id) };
|
|
825
|
+
}
|
|
826
|
+
return null;
|
|
713
827
|
}
|
|
714
828
|
/** Texto de `ork master <thread-id> --score`. */
|
|
715
829
|
function textoDoMaster(r) {
|
package/dist/mcp-artifacts.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.diagnosticoNomeForaDeUtf8 = diagnosticoNomeForaDeUtf8;
|
|
36
37
|
exports.validarArquivosEstadoMcp = validarArquivosEstadoMcp;
|
|
37
38
|
exports.lerArtefatoMcp = lerArtefatoMcp;
|
|
38
39
|
exports.escreverArtefatoMcp = escreverArtefatoMcp;
|
|
@@ -49,6 +50,14 @@ const claims_1 = require("./claims");
|
|
|
49
50
|
const fases = { goal: 'GOAL', plan: 'PLAN', check: 'CHECK' };
|
|
50
51
|
const limite = 128 * 1024;
|
|
51
52
|
const hash = (bytes) => (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
|
|
53
|
+
/** Diagnostico relativo, sem perda de bytes nem controles de terminal; nao e um comando shell. */
|
|
54
|
+
function diagnosticoNomeForaDeUtf8(raiz, pasta, nome) {
|
|
55
|
+
const pai = path.relative(raiz, pasta);
|
|
56
|
+
const entrada = Buffer.concat([Buffer.from(pai ? pai + path.sep : ''), nome]);
|
|
57
|
+
const rotulo = Array.from(entrada, byte => byte >= 0x20 && byte <= 0x7e && byte !== 0x5c
|
|
58
|
+
? String.fromCharCode(byte) : '\\x' + byte.toString(16).padStart(2, '0')).join('');
|
|
59
|
+
return `nome fora de UTF-8 em ${rotulo}\nRenomeie a entrada pelo shell para um nome UTF-8 valido e repita a operacao.`;
|
|
60
|
+
}
|
|
52
61
|
/** Core legado usa nomes de arquivos: este preflight recusa links existentes, nao promete CAS contra writers hostis. */
|
|
53
62
|
function validarArquivosEstadoMcp(raiz, id) {
|
|
54
63
|
validarId(id);
|
|
@@ -150,8 +159,39 @@ function comEscrita(raiz, id, executar) {
|
|
|
150
159
|
if (st) {
|
|
151
160
|
if (!st.isDirectory() || st.isSymbolicLink() || fs.realpathSync(pastaLeases) !== pastaLeases)
|
|
152
161
|
throw Error('mcp.state.unsafe: leases');
|
|
153
|
-
for (const
|
|
154
|
-
const
|
|
162
|
+
for (const nomeBytes of fs.readdirSync(pastaLeases, { encoding: 'buffer' })) {
|
|
163
|
+
const nome = nomeBytes.toString('utf8');
|
|
164
|
+
// Antes do lstat: uma decodificacao com perda nao prova que a entrada desapareceu.
|
|
165
|
+
if (!Buffer.from(nome, 'utf8').equals(nomeBytes))
|
|
166
|
+
throw Error('mcp.state.unsafe: ' + diagnosticoNomeForaDeUtf8(raiz, pastaLeases, nomeBytes));
|
|
167
|
+
const entrada = path.join(pastaLeases, nome), s = fs.lstatSync(entrada, { throwIfNoEntry: false });
|
|
168
|
+
if (!s)
|
|
169
|
+
continue; // Uma retomada pode ter acabado durante o preflight.
|
|
170
|
+
if (s.isDirectory() && nome.endsWith('.json.retomadas')) {
|
|
171
|
+
const base = nome.slice(0, -'.json.retomadas'.length);
|
|
172
|
+
if (!base || encodeURIComponent(decodeURIComponent(base)) !== base)
|
|
173
|
+
throw Error('mcp.state.unsafe: fila de retomada');
|
|
174
|
+
let candidatos;
|
|
175
|
+
try {
|
|
176
|
+
candidatos = fs.readdirSync(entrada, { encoding: 'buffer' });
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
if (e.code === 'ENOENT')
|
|
180
|
+
continue;
|
|
181
|
+
throw e;
|
|
182
|
+
}
|
|
183
|
+
for (const candidatoBytes of candidatos) {
|
|
184
|
+
const candidato = candidatoBytes.toString('utf8');
|
|
185
|
+
if (!Buffer.from(candidato, 'utf8').equals(candidatoBytes))
|
|
186
|
+
throw Error('mcp.state.unsafe: ' + diagnosticoNomeForaDeUtf8(raiz, entrada, candidatoBytes));
|
|
187
|
+
const c = fs.lstatSync(path.join(entrada, candidato), { throwIfNoEntry: false });
|
|
188
|
+
if (!c)
|
|
189
|
+
continue;
|
|
190
|
+
if (!/^\d+-[a-f0-9-]+\.json(?:\.tmp)?$/.test(candidato) || !c.isFile() || c.nlink !== 1)
|
|
191
|
+
throw Error('mcp.state.unsafe: candidato de retomada');
|
|
192
|
+
}
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
155
195
|
if (!s.isFile() || s.isSymbolicLink() || s.nlink !== 1)
|
|
156
196
|
throw Error('mcp.state.unsafe: lease ou fila');
|
|
157
197
|
}
|
|
@@ -231,6 +271,6 @@ function adicionarClaimMcp(raiz, id, entrada) {
|
|
|
231
271
|
if ((0, thread_1.lerThread)(raiz, id).status === 'fechada')
|
|
232
272
|
throw Error('mcp.claim.closed');
|
|
233
273
|
// Strings sao dados da claim; a reexecucao MCP deve usar o executor confinado.
|
|
234
|
-
return (0, claims_1.adicionarClaim)(raiz, id, entrada);
|
|
274
|
+
return (0, claims_1.adicionarClaim)(raiz, id, { ...entrada, semProvaLocal: true });
|
|
235
275
|
}));
|
|
236
276
|
}
|
package/dist/mcp-git.js
CHANGED
|
@@ -195,7 +195,9 @@ function arvoreMetadados(root, alvo, opcoes = {}) {
|
|
|
195
195
|
? '; empacote os objetos soltos sem perda com git repack -d (git count-objects -v mostra quantos)' : ''));
|
|
196
196
|
if (profundidade > 32)
|
|
197
197
|
falha(`metadata.unsupported: mais de 32 niveis em ${rotulo(alvo)}`);
|
|
198
|
-
const st = fs.lstatSync(f);
|
|
198
|
+
const st = fs.lstatSync(f, { throwIfNoEntry: false });
|
|
199
|
+
if (!st)
|
|
200
|
+
return; // Uma retomada pode remover a fila ou o candidato depois da enumeracao.
|
|
199
201
|
if (st.isSymbolicLink())
|
|
200
202
|
falha(`metadata.unsafe: link simbolico em ${rotulo(f)}`);
|
|
201
203
|
if (!st.isDirectory() && !st.isFile())
|
|
@@ -205,9 +207,24 @@ function arvoreMetadados(root, alvo, opcoes = {}) {
|
|
|
205
207
|
`tire o vinculo sem perder conteudo: cp -p ${rotulo(f)} ${rotulo(f + '.tmp')} && mv ${rotulo(f + '.tmp')} ${rotulo(f)}`);
|
|
206
208
|
if (f !== root && !dentro(root, f))
|
|
207
209
|
falha(`metadata.unsafe: ${rotulo(f)} fora de ${path.basename(root)}`);
|
|
208
|
-
if (st.isDirectory())
|
|
209
|
-
|
|
210
|
+
if (st.isDirectory()) {
|
|
211
|
+
let entradas;
|
|
212
|
+
try {
|
|
213
|
+
entradas = fs.readdirSync(f, { encoding: 'buffer' });
|
|
214
|
+
}
|
|
215
|
+
catch (e) {
|
|
216
|
+
if (e.code === 'ENOENT')
|
|
217
|
+
return;
|
|
218
|
+
throw e;
|
|
219
|
+
}
|
|
220
|
+
for (const bytes of entradas) {
|
|
221
|
+
const n = bytes.toString('utf8');
|
|
222
|
+
// Perda de bytes nao e ENOENT transitorio: o nome decodificado pode nem apontar para esta entrada.
|
|
223
|
+
if (!Buffer.from(n, 'utf8').equals(bytes))
|
|
224
|
+
falha('metadata.unsafe: ' + (0, mcp_artifacts_1.diagnosticoNomeForaDeUtf8)(opcoes.relativoA ?? path.dirname(root), f, bytes));
|
|
210
225
|
visitar(path.join(f, n), profundidade + 1);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
211
228
|
};
|
|
212
229
|
if (fs.realpathSync(alvo) !== alvo)
|
|
213
230
|
falha(`metadata.unsafe: ${rotulo(alvo)} passa por link simbolico`);
|
|
@@ -337,7 +354,7 @@ function estadoGitMcp(raiz, threadId) {
|
|
|
337
354
|
scope: 'local-only', observedAt: new Date().toISOString() };
|
|
338
355
|
}
|
|
339
356
|
/** Somente o worker dedicado chama este corpo; não altera env do servidor. */
|
|
340
|
-
function executar(raiz, p) {
|
|
357
|
+
function executar(raiz, p, dispatchId) {
|
|
341
358
|
const proprias = [];
|
|
342
359
|
let commit = null, estadoAuditado = false;
|
|
343
360
|
try {
|
|
@@ -347,6 +364,23 @@ function executar(raiz, p) {
|
|
|
347
364
|
fisico(raiz, (0, thread_1.dirThread)(raiz, p.threadId));
|
|
348
365
|
(0, mcp_artifacts_1.validarArquivosEstadoMcp)(raiz, p.threadId);
|
|
349
366
|
const t = (0, thread_1.lerThread)(raiz, p.threadId), wt = t.worktree;
|
|
367
|
+
// Identidade vem do startup do servidor, nunca dos argumentos públicos da tool.
|
|
368
|
+
// Sem vínculo conhecido, o recibo continua sem atribuição de sessão.
|
|
369
|
+
let vinculo;
|
|
370
|
+
if (dispatchId !== undefined) {
|
|
371
|
+
if (!/^[a-f0-9-]{36}$/.test(dispatchId))
|
|
372
|
+
falha('session.invalid');
|
|
373
|
+
const despachos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)).filter(e => e.tipo === 'phase_dispatch');
|
|
374
|
+
const despacho = despachos.filter(e => e.identidade?.dispatchId === dispatchId).at(-1);
|
|
375
|
+
const proximo = despacho ? despachos[despachos.indexOf(despacho) + 1] : undefined;
|
|
376
|
+
const sessoes = despacho ? t.sessoes.filter(s => s.sessionId === despacho.sessionId && s.origem !== 'adocao' &&
|
|
377
|
+
s.fase === despacho.fase && s.promptSha256 === despacho.promptSha256 && typeof s.despachadaEm === 'string' &&
|
|
378
|
+
Date.parse(s.despachadaEm) >= Date.parse(despacho.ts) &&
|
|
379
|
+
(!proximo || Date.parse(s.despachadaEm) < Date.parse(proximo.ts))) : [];
|
|
380
|
+
if (sessoes.length !== 1)
|
|
381
|
+
falha('session.invalid');
|
|
382
|
+
vinculo = { sessionId: sessoes[0].sessionId, despachoEm: sessoes[0].despachadaEm };
|
|
383
|
+
}
|
|
350
384
|
if (!wt || t.status === 'fechada' || !(0, thread_1.blocoDaThread)(t, t.faseAtual).fases.includes('GO') || wt === raiz)
|
|
351
385
|
falha('thread.invalid');
|
|
352
386
|
// I-42 (D7): ciclo sem PLAN nem CHECK nao commita contrato publico; a mudanca vira iniciativa.
|
|
@@ -428,7 +462,7 @@ function executar(raiz, p) {
|
|
|
428
462
|
const alterados = git(wt, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', commit]).split('\0').filter(Boolean);
|
|
429
463
|
if (!alterados.length || alterados.some(f => !p.paths.includes(f)))
|
|
430
464
|
falha('commit.paths-invalid');
|
|
431
|
-
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, t.id), t.id, 'mcp_git_committed', { commit, paths: alterados, origem: 'mcp.git', estadoAuditado });
|
|
465
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, t.id), t.id, 'mcp_git_committed', { commit, paths: alterados, origem: 'mcp.git', estadoAuditado, ...vinculo });
|
|
432
466
|
return { ok: true, commit, erro: null, estadoAuditado };
|
|
433
467
|
}
|
|
434
468
|
catch (e) {
|
|
@@ -442,7 +476,7 @@ function executar(raiz, p) {
|
|
|
442
476
|
}
|
|
443
477
|
}
|
|
444
478
|
/** Entrada do servidor: argumentos nunca escolhem executável/env/cwd/opções Git. */
|
|
445
|
-
async function commitMcp(raiz, pedido, signal) {
|
|
479
|
+
async function commitMcp(raiz, pedido, signal, dispatchId) {
|
|
446
480
|
validar(pedido);
|
|
447
481
|
if (signal?.aborted)
|
|
448
482
|
return { ok: false, commit: null, erro: 'mcp.git.cancelled', estadoAuditado: false };
|
|
@@ -466,7 +500,7 @@ async function commitMcp(raiz, pedido, signal) {
|
|
|
466
500
|
erro = true;
|
|
467
501
|
child.stdin.end();
|
|
468
502
|
return;
|
|
469
|
-
} child.stdin.end(JSON.stringify({ raiz, pedido })); });
|
|
503
|
+
} child.stdin.end(JSON.stringify({ raiz, pedido, dispatchId })); });
|
|
470
504
|
child.stdin.on('error', () => { erro = true; });
|
|
471
505
|
child.on('error', () => { erro = true; });
|
|
472
506
|
child.stdout.on('data', (b) => { if (Buffer.byteLength(stdout) + b.length > LIMITE)
|
|
@@ -499,7 +533,7 @@ if (require.main === module && process.argv[2] === '--worker') {
|
|
|
499
533
|
if (Buffer.byteLength(raw) > LIMITE)
|
|
500
534
|
falha('request.invalid');
|
|
501
535
|
const p = JSON.parse(raw);
|
|
502
|
-
process.stdout.write(JSON.stringify(executar(p.raiz, p.pedido)));
|
|
536
|
+
process.stdout.write(JSON.stringify(executar(p.raiz, p.pedido, p.dispatchId)));
|
|
503
537
|
}
|
|
504
538
|
catch {
|
|
505
539
|
process.stdout.write(JSON.stringify({ ok: false, commit: null, erro: 'mcp.git.worker.invalid', estadoAuditado: false }));
|
package/dist/mcp-grafo-worker.js
CHANGED
|
@@ -38,7 +38,7 @@ exports.rodarConsulta = rodarConsulta;
|
|
|
38
38
|
* RM-031 KG5 (D3, D8): o worker da consulta do grafo pelo MCP.
|
|
39
39
|
*
|
|
40
40
|
* Roda num processo filho, aberto pelo `mcp-grafo.ts` com o ambiente minimo do MCP. Le `{raiz, argv}`
|
|
41
|
-
* do stdin, confere que o cwd e a raiz, aceita so as
|
|
41
|
+
* do stdin, confere que o cwd e a raiz, aceita so as cinco consultas no argv que as tools montam (com
|
|
42
42
|
* `--json` e `--teto-bytes`), carrega o manifesto da raiz (a worktree da thread) e chama o
|
|
43
43
|
* `executarGrafo` com o argv que a CLI receberia: a resposta e a do `ork grafo`, byte a byte. O `main` do
|
|
44
44
|
* `ork` nao roda aqui, entao nada do argv vira `--projeto`, `--version` ou `--help`.
|
|
@@ -52,7 +52,8 @@ const zod_1 = require("zod");
|
|
|
52
52
|
const intelligence_graph_cli_1 = require("./intelligence-graph-cli");
|
|
53
53
|
const manifest_1 = require("./manifest");
|
|
54
54
|
const estado_thread_1 = require("./estado-thread");
|
|
55
|
-
const
|
|
55
|
+
const mcp_grafo_1 = require("./mcp-grafo");
|
|
56
|
+
const CONSULTAS = Object.freeze({ vizinhos: 1, chamadores: 1, importadores: 1, caminho: 2, contexto: 1 });
|
|
56
57
|
const OPCAO = /^--(profundidade|sentido|tipo|limite|teto-bytes)=[a-z0-9_,]{1,120}$/;
|
|
57
58
|
const PEDIDO = zod_1.z.object({
|
|
58
59
|
raiz: zod_1.z.string().min(1).max(4096).refine((p) => path.isAbsolute(p), 'raiz absoluta'),
|
|
@@ -78,7 +79,8 @@ function rodarConsulta(entrada, cwd, escrever) {
|
|
|
78
79
|
const carregado = (0, manifest_1.exigirManifesto)(raiz);
|
|
79
80
|
if (fs.realpathSync(carregado.raiz) !== fs.realpathSync(raiz))
|
|
80
81
|
throw Error('grafo.mcp.worker: o manifesto nao e o da raiz pedida');
|
|
81
|
-
return (0, intelligence_graph_cli_1.executarGrafo)(argv, { raiz: carregado.raiz, estado: (0, estado_thread_1.raizDoEstado)(carregado.raiz), repositorio: carregado.manifesto.project.name,
|
|
82
|
+
return (0, intelligence_graph_cli_1.executarGrafo)(argv, { raiz: carregado.raiz, estado: (0, estado_thread_1.raizDoEstado)(carregado.raiz), repositorio: carregado.manifesto.project.name,
|
|
83
|
+
contextoDaThread: (id) => (0, mcp_grafo_1.lerEntradaDaThread)(carregado.raiz, id), escrever });
|
|
82
84
|
}
|
|
83
85
|
if (require.main === module) {
|
|
84
86
|
try {
|
package/dist/mcp-grafo.js
CHANGED
|
@@ -35,16 +35,18 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.LIMITE_MAXIMO_DO_MCP = exports.PROFUNDIDADE_MAXIMA_DO_MCP = exports.TIPOS_DE_ARESTA_DO_MCP = exports.PRAZO_DA_CONSULTA_MS = exports.TETO_MAXIMO = exports.TETO_MINIMO = exports.TETO_PADRAO = exports.TOOLS_DO_GRAFO = void 0;
|
|
37
37
|
exports.grafoLigado = grafoLigado;
|
|
38
|
+
exports.lerEntradaDaThread = lerEntradaDaThread;
|
|
38
39
|
exports.argvDaTool = argvDaTool;
|
|
39
40
|
exports.consultarPeloWorker = consultarPeloWorker;
|
|
40
41
|
exports.registrarConsultasDoGrafo = registrarConsultasDoGrafo;
|
|
41
42
|
/**
|
|
42
43
|
* RM-031 KG5: a consulta do grafo de codigo pelas fases, pelo MCP do projeto.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
+
* Cinco tools de leitura com o contrato do `ork grafo` (D6): cada uma roda, na worktree da thread, o
|
|
45
46
|
* argv que a CLI receberia (`<consulta> ... --json --teto-bytes N`) e devolve o que ela escreve, sem
|
|
46
47
|
* transformar: a resposta e JSON `ork.code-graph-query/v0` com a evidencia de cada aresta e no maximo
|
|
47
|
-
* `tetoBytes` bytes (D4);
|
|
48
|
+
* `tetoBytes` bytes (D4); contexto usa ork.thread-graph-context/v2. A recusa nao passa pelo teto. Desde a
|
|
49
|
+
* fatia 5, a resposta traz as fontes (sha256 e blob) e diz por aresta se elas conferem com a arvore.
|
|
48
50
|
*
|
|
49
51
|
* Desligadas por padrao (D2): so existem com `grafo.mcp: true` no manifesto da raiz, lido no startup, e
|
|
50
52
|
* cada chamada confere a flag de novo. A consulta roda num worker (D3), um processo filho por chamada,
|
|
@@ -58,7 +60,10 @@ const path = __importStar(require("node:path"));
|
|
|
58
60
|
const node_child_process_1 = require("node:child_process");
|
|
59
61
|
const zod_1 = require("zod");
|
|
60
62
|
const mcp_git_1 = require("./mcp-git");
|
|
61
|
-
|
|
63
|
+
const mcp_artifacts_1 = require("./mcp-artifacts");
|
|
64
|
+
const thread_1 = require("./thread");
|
|
65
|
+
const estado_thread_1 = require("./estado-thread");
|
|
66
|
+
exports.TOOLS_DO_GRAFO = ['ork_grafo_vizinhos', 'ork_grafo_chamadores', 'ork_grafo_importadores', 'ork_grafo_caminho', 'ork_grafo_contexto'];
|
|
62
67
|
/** D4: o teto das respostas, em bytes do JSON. */
|
|
63
68
|
exports.TETO_PADRAO = 32768;
|
|
64
69
|
exports.TETO_MINIMO = 4096;
|
|
@@ -71,7 +76,7 @@ const TETO_DO_STDOUT = 1024 * 1024;
|
|
|
71
76
|
* O vocabulario e os limites da consulta do KG3, repetidos aqui porque este modulo nao importa a
|
|
72
77
|
* familia do grafo (D8); o teste confere que sao os mesmos do contrato v1 e da consulta.
|
|
73
78
|
*/
|
|
74
|
-
exports.TIPOS_DE_ARESTA_DO_MCP = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from'];
|
|
79
|
+
exports.TIPOS_DE_ARESTA_DO_MCP = ['contains', 'declares', 'imports', 'calls', 'references', 'derived_from', 'cites'];
|
|
75
80
|
exports.PROFUNDIDADE_MAXIMA_DO_MCP = 5;
|
|
76
81
|
exports.LIMITE_MAXIMO_DO_MCP = 10_000;
|
|
77
82
|
/** D2: so o booleano `true` do manifesto da raiz liga as tools. */
|
|
@@ -94,7 +99,8 @@ const tipos = zod_1.z.array(zod_1.z.enum(exports.TIPOS_DE_ARESTA_DO_MCP)).min(1)
|
|
|
94
99
|
const tetoBytes = zod_1.z.number().int().min(exports.TETO_MINIMO).max(exports.TETO_MAXIMO).optional()
|
|
95
100
|
.describe(`teto da resposta em bytes (padrao ${exports.TETO_PADRAO}); acima, saem as arestas mais longe`);
|
|
96
101
|
const COMUM = 'Leitura do grafo do HEAD da worktree da thread (o do ork grafo): so o que o extrator prova. '
|
|
97
|
-
+ 'Resposta JSON ork.code-graph-query/v0 de ate tetoBytes; sem indice do HEAD, recusa com a correcao ork grafo indexar.'
|
|
102
|
+
+ 'Resposta JSON ork.code-graph-query/v0 de ate tetoBytes; sem indice do HEAD, recusa com a correcao ork grafo indexar. '
|
|
103
|
+
+ 'Cada aresta traz arvore (modificada quando uma fonte dela mudou depois do HEAD) e a resposta traz fontes, com o sha256 e o blob de cada arquivo citado.';
|
|
98
104
|
/** As opcoes da CLI, na ordem dela, com `=`: o valor nunca vira outro argumento. */
|
|
99
105
|
function opcoes(a) {
|
|
100
106
|
const r = [];
|
|
@@ -134,7 +140,50 @@ const DEFINICOES = [
|
|
|
134
140
|
schema: zod_1.z.object({ threadId, de: no(`origem: ${DESCRICAO_DO_NO}`), para: no('destino, na mesma forma'), sentido, tipos, tetoBytes }).strict(),
|
|
135
141
|
argv: (a) => ['caminho', a.de, a.para, ...opcoes(a)],
|
|
136
142
|
},
|
|
143
|
+
{
|
|
144
|
+
nome: 'ork_grafo_contexto',
|
|
145
|
+
descricao: 'Pacote deterministico da thread: diff da worktree contra base (ignorado sem worktree), GOAL, PLAN e claims; fan-in agregado e evidencias compactas. '
|
|
146
|
+
+ 'JSON ork.thread-graph-context/v2 limitado em bytes, refs locais, prioridade entre arquivos e por proximidade ao diff. Citacoes literais cites; segundo salto marcado usa a sobra apos ligacoes diretas. '
|
|
147
|
+
+ 'Grupo com fonte que mudou depois do HEAD traz arvore: modificada. Sem indice do HEAD, recusa com ork grafo indexar.',
|
|
148
|
+
schema: zod_1.z.object({ threadId, tetoBytes }).strict(),
|
|
149
|
+
argv: (a) => ['contexto', a.threadId, ...opcoes(a)],
|
|
150
|
+
},
|
|
137
151
|
];
|
|
152
|
+
/** Leitura compartilhada por CLI e worker, fora da familia do grafo. Nunca escreve estado. */
|
|
153
|
+
function lerEntradaDaThread(raiz, id) {
|
|
154
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(id))
|
|
155
|
+
throw Error('grafo.contexto.thread-invalida: id invalido');
|
|
156
|
+
const projeto = fs.realpathSync((0, estado_thread_1.raizDoEstado)(raiz));
|
|
157
|
+
(0, mcp_artifacts_1.validarArquivosEstadoMcp)(projeto, id);
|
|
158
|
+
const t = (0, thread_1.lerThread)(projeto, id);
|
|
159
|
+
const cwd = fs.realpathSync(t.worktree ?? projeto);
|
|
160
|
+
if (cwd !== projeto && !cwd.startsWith(projeto + path.sep))
|
|
161
|
+
throw Error('grafo.contexto.escopo: worktree fora do projeto');
|
|
162
|
+
if (fs.realpathSync((0, estado_thread_1.raizDoEstado)(cwd)) !== projeto)
|
|
163
|
+
throw Error('grafo.contexto.escopo: worktree de outro repositorio');
|
|
164
|
+
// Em uma WT, consultar outra thread daria um pacote de outra arvore silenciosamente.
|
|
165
|
+
const origem = fs.realpathSync(raiz);
|
|
166
|
+
if (origem !== projeto && origem !== cwd)
|
|
167
|
+
throw Error('grafo.contexto.escopo: thread de outra worktree');
|
|
168
|
+
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(t.base.commit))
|
|
169
|
+
throw Error('grafo.contexto.base-invalida: thread sem commit base');
|
|
170
|
+
const git = (args) => {
|
|
171
|
+
const r = (0, node_child_process_1.spawnSync)('git', ['-c', 'core.fsmonitor=false', ...args], {
|
|
172
|
+
cwd, env: { ...(0, mcp_git_1.ambienteGitMcp)(), GIT_OPTIONAL_LOCKS: '0' }, encoding: 'utf8', timeout: 10000, maxBuffer: 8 * 1024 * 1024,
|
|
173
|
+
});
|
|
174
|
+
if (r.error || r.status !== 0)
|
|
175
|
+
throw Error('grafo.contexto.git-falhou: nao foi possivel ler HEAD/base/diff da thread');
|
|
176
|
+
return r.stdout;
|
|
177
|
+
};
|
|
178
|
+
const head = git(['rev-parse', '--verify', 'HEAD']).trim();
|
|
179
|
+
const diff = !t.worktree || cwd === projeto ? [] : git(['diff', '--no-ext-diff', '--no-textconv', '--no-renames', '--name-only', '-z', t.base.commit, '--']).split('\0').filter(Boolean);
|
|
180
|
+
const goal = (0, mcp_artifacts_1.lerArtefatoMcp)(projeto, id, 'goal').conteudo;
|
|
181
|
+
const plan = (0, mcp_artifacts_1.lerArtefatoMcp)(projeto, id, 'plan').conteudo;
|
|
182
|
+
const claims = (0, mcp_artifacts_1.listarClaimsMcp)(projeto, id).filter((c) => c.estado !== 'retirada').map(({ id, arquivo }) => ({ id, arquivo }));
|
|
183
|
+
if (head !== git(['rev-parse', '--verify', 'HEAD']).trim())
|
|
184
|
+
throw Error('grafo.contexto.revisao-mudou: HEAD mudou durante a leitura; repita');
|
|
185
|
+
return { raiz: cwd, head, entrada: { thread: id, base: t.base.commit, diff, diffEstado: !t.worktree || cwd === projeto ? 'ignorado-sem-worktree' : 'coletado-na-worktree', goal, plan, claims } };
|
|
186
|
+
}
|
|
138
187
|
/** D9: o argv que a tool monta para os argumentos dados; a medida offline usa o mesmo. */
|
|
139
188
|
function argvDaTool(nome, args) {
|
|
140
189
|
const d = DEFINICOES.find((x) => x.nome === nome);
|
|
@@ -204,7 +253,7 @@ function consultarPeloWorker(raiz, argv, opcoesDoWorker = {}) {
|
|
|
204
253
|
}
|
|
205
254
|
const texto = (t, isError = false) => ({ content: [{ type: 'text', text: t }], ...(isError ? { isError: true } : {}) });
|
|
206
255
|
/**
|
|
207
|
-
* As
|
|
256
|
+
* As cinco tools, chamadas pelo servidor so com a flag ligada no startup. `carregar` e `thread` sao os
|
|
208
257
|
* do servidor: o projeto fixado e a thread conferida (escopo da sessao filha e worktree confinada).
|
|
209
258
|
*/
|
|
210
259
|
function registrarConsultasDoGrafo(registrar, contexto) {
|