@orkastery/cli 0.5.3 → 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/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/hermes/skills/orkastery-devmaster/SKILL.md +1 -1
- package/adapters/openclaw/README.md +2 -1
- package/adapters/openclaw/openclaw.plugin.json +1 -1
- package/adapters/openclaw/package.json +1 -1
- 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/dist/adapters/claude-bg.js +77 -13
- package/dist/adapters/codex.js +10 -1
- package/dist/agents-md.js +24 -15
- package/dist/auditrun.js +17 -2
- package/dist/board.js +4 -3
- package/dist/branch-de-estado.js +23 -1
- package/dist/catalogo.js +33 -0
- package/dist/ci.js +13 -7
- package/dist/claims-conferir.js +342 -0
- package/dist/claims.js +3 -1
- package/dist/company-brain-client.js +36 -1
- 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 +22 -8
- package/dist/doctor-pulse-cron.js +182 -27
- package/dist/doctor-rede.js +18 -17
- package/dist/doctor.js +115 -111
- package/dist/entrega-pr.js +22 -21
- package/dist/escopo-escrita.js +10 -1
- package/dist/estado-thread.js +23 -1
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/fabrica-batida.js +310 -0
- package/dist/fabrica-estado.js +38 -8
- package/dist/fabrica-publicar.js +3 -1
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +3 -2
- package/dist/forja.js +1 -1
- package/dist/gates.js +3 -28
- package/dist/handoff.js +10 -6
- package/dist/hitl-local-receipt.js +2 -0
- package/dist/hitl-resumo.js +29 -3
- package/dist/hitl-tempo-parado.js +4 -4
- package/dist/hitl.js +29 -33
- package/dist/horario.js +14 -7
- package/dist/hosts.js +52 -1
- package/dist/impedimento.js +108 -14
- package/dist/index.js +623 -521
- package/dist/indice.js +7 -1
- package/dist/init.js +43 -47
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +92 -21
- package/dist/intelligence-graph-contexto.js +56 -17
- 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-query.js +66 -19
- package/dist/ledger.js +15 -1
- 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/manifest.js +129 -3
- package/dist/maquina.js +23 -4
- package/dist/master-digest.js +6 -1
- package/dist/master-nota.js +4 -6
- package/dist/master.js +21 -24
- package/dist/mcp-artifacts.js +11 -2
- package/dist/mcp-git.js +23 -6
- package/dist/mcp-grafo.js +7 -4
- package/dist/mcp-server.js +8 -2
- package/dist/mcp-ship.js +3 -1
- package/dist/mcp-verify.js +6 -1
- package/dist/modos.js +3 -6
- package/dist/network-roadmap.js +5 -2
- 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 +29 -2
- package/dist/onboarding.js +40 -21
- package/dist/orkmind.js +9 -2
- package/dist/orquestracao.js +13 -12
- package/dist/parado-no-condutor.js +34 -9
- package/dist/phase.js +94 -39
- package/dist/policies.js +4 -4
- package/dist/portfolio.js +4 -2
- package/dist/postura-local.js +234 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +225 -0
- package/dist/projeto-alvo.js +127 -4
- package/dist/prompts.js +6 -2
- package/dist/pulse-delivery.js +13 -2
- package/dist/pulse.js +52 -19
- package/dist/ratelimit.js +4 -2
- package/dist/redacao-saida.js +63 -0
- package/dist/rede-status.js +3 -2
- package/dist/retry.js +232 -148
- package/dist/roadmap-reservas.js +20 -3
- package/dist/roadmap-status.js +129 -33
- package/dist/runtime-context.js +181 -3
- package/dist/runtimes.js +2 -1
- package/dist/session-events.js +7 -3
- package/dist/session-watcher-claude.js +7 -1
- package/dist/session-watcher.js +185 -33
- package/dist/sessoes-contas.js +1 -1
- package/dist/ship-publicar.js +800 -0
- package/dist/ship.js +84 -81
- package/dist/steal.js +77 -0
- package/dist/thread-close.js +3 -2
- package/dist/thread.js +153 -82
- 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 +20 -0
- package/dist/yaml.js +27 -8
- package/package.json +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +2 -1
package/dist/handoff.js
CHANGED
|
@@ -73,6 +73,7 @@ const phase_1 = require("./phase");
|
|
|
73
73
|
const thread_1 = require("./thread");
|
|
74
74
|
const memoria_1 = require("./memoria");
|
|
75
75
|
const util_1 = require("./util");
|
|
76
|
+
const procedencia_1 = require("./procedencia");
|
|
76
77
|
/** sha256 de um arquivo em disco, a prova de proveniencia de cada item. */
|
|
77
78
|
function sha256DoArquivo(caminho) {
|
|
78
79
|
if (!fs.existsSync(caminho))
|
|
@@ -98,7 +99,8 @@ function caminhoDoArtefato(raiz, thread, arquivo) {
|
|
|
98
99
|
? [path.resolve(thread.worktree, arquivo), path.resolve(raiz, arquivo)]
|
|
99
100
|
: [path.resolve(raiz, arquivo)];
|
|
100
101
|
for (const c of candidatos) {
|
|
101
|
-
|
|
102
|
+
// RM-047 (P2): o arquivo da claim vem do estado; fora da raiz e da worktree registrada, não vira ponteiro.
|
|
103
|
+
if (fs.existsSync(c) && fs.statSync(c).isFile() && (0, procedencia_1.caminhoContidoOuNulo)(raiz, thread, c))
|
|
102
104
|
return c;
|
|
103
105
|
}
|
|
104
106
|
return null;
|
|
@@ -222,7 +224,7 @@ function exportarHandoff(carregado, threadId, opcoes = {}) {
|
|
|
222
224
|
if (s.origem === 'adocao')
|
|
223
225
|
continue;
|
|
224
226
|
const caminhoPrompt = path.resolve(raiz, s.promptPath);
|
|
225
|
-
if (!fs.existsSync(caminhoPrompt))
|
|
227
|
+
if (!fs.existsSync(caminhoPrompt) || !(0, procedencia_1.caminhoContidoOuNulo)(raiz, thread, caminhoPrompt))
|
|
226
228
|
continue;
|
|
227
229
|
addPonteiro(`Prompt da sessao ${s.slug} (fase ${s.fase})`, caminhoPrompt, 'pedido-do-builder', s.fase);
|
|
228
230
|
}
|
|
@@ -261,7 +263,7 @@ function exportarHandoff(carregado, threadId, opcoes = {}) {
|
|
|
261
263
|
for (const e of anteriores) {
|
|
262
264
|
const arquivo = (0, memoria_1.arquivoDoHandoff)(e);
|
|
263
265
|
const emDisco = arquivo ? path.resolve(raiz, arquivo) : '';
|
|
264
|
-
if (!emDisco || !fs.existsSync(emDisco))
|
|
266
|
+
if (!emDisco || !fs.existsSync(emDisco) || !(0, procedencia_1.caminhoContidoOuNulo)(raiz, thread, emDisco))
|
|
265
267
|
continue;
|
|
266
268
|
addPonteiro(`Handoff anterior desta thread (${arquivo})`, emDisco, 'tudo', proximaFase, `orkmind://handoff/${e.id}`);
|
|
267
269
|
}
|
|
@@ -270,7 +272,7 @@ function exportarHandoff(carregado, threadId, opcoes = {}) {
|
|
|
270
272
|
for (const e of (0, memoria_1.licoesDoProduto)(memoria, manifesto, threadId)) {
|
|
271
273
|
const postmortem = (0, memoria_1.postmortemDaLicao)(e);
|
|
272
274
|
const emDisco = postmortem ? path.resolve(raiz, postmortem) : '';
|
|
273
|
-
if (!emDisco || !fs.existsSync(emDisco))
|
|
275
|
+
if (!emDisco || !fs.existsSync(emDisco) || !(0, procedencia_1.caminhoContidoOuNulo)(raiz, thread, emDisco))
|
|
274
276
|
continue;
|
|
275
277
|
addPonteiro(`Licao da thread ${(0, memoria_1.threadDaEntrada)(e) ?? '(anterior)'}`, emDisco, 'json:resumo', 'MASTER', `orkmind://learning/${e.id}`);
|
|
276
278
|
}
|
|
@@ -398,9 +400,11 @@ function recall(carregado, threadId, ponteiro) {
|
|
|
398
400
|
if (!fs.existsSync(caminho) || !fs.statSync(caminho).isFile()) {
|
|
399
401
|
throw new Error(`ponteiro nao resolve: arquivo "${bruto}" nao existe a partir de ${raiz}`);
|
|
400
402
|
}
|
|
401
|
-
|
|
403
|
+
// RM-047 (P2): o `location` vem do handoff.json (estado, talvez versionado); só lê dentro do projeto.
|
|
404
|
+
const real = (0, procedencia_1.exigirCaminhoContido)(raiz, (0, thread_1.lerThread)(raiz, threadId), caminho, bruto);
|
|
405
|
+
const conteudoBruto = fs.readFileSync(real, 'utf8');
|
|
402
406
|
const linhas = conteudoBruto.split('\n');
|
|
403
|
-
const sha = sha256DoArquivo(
|
|
407
|
+
const sha = sha256DoArquivo(real);
|
|
404
408
|
const base = { location: `${bruto}#${ancora}`, caminho, ancora, sha256: sha };
|
|
405
409
|
const registrarRecall = (r) => {
|
|
406
410
|
(0, ledger_1.registrar)((0, thread_1.dirThread)(raiz, threadId), threadId, ledger_1.TIPOS_DE_EVENTO.handoffRecuperado, {
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.chaveLocal = chaveLocal;
|
|
36
37
|
exports.gravarEvidenciaLocal = gravarEvidenciaLocal;
|
|
37
38
|
exports.gravarEvidenciaLocalSessao = gravarEvidenciaLocalSessao;
|
|
38
39
|
exports.validarEvidenciaLocalSessao = validarEvidenciaLocalSessao;
|
|
@@ -70,6 +71,7 @@ function diretorioPrivado(file) {
|
|
|
70
71
|
}
|
|
71
72
|
return validarDiretorio(file, 0o700);
|
|
72
73
|
}
|
|
74
|
+
/** RM-058 (N1): exportada só para o arco #Noctum derivar a subchave dele (`noctum-arco.ts`). */
|
|
73
75
|
function chaveLocal(raiz, criar) {
|
|
74
76
|
const estado = path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery');
|
|
75
77
|
const stEstado = fs.lstatSync(estado);
|
package/dist/hitl-resumo.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SEM_PERGUNTA_NO_RESUMO = exports.TETO_DE_DECISOES_DETALHADAS = exports.TETO_DE_ESPERAS_POR_MAQUINA = exports.TETO_DE_PARADOS_NO_CONDUTOR = exports.TETO_DE_THREADS_NOMEADAS = exports.PERGUNTA_DO_RESUMO = exports.CONTRATO_RESUMO = void 0;
|
|
3
|
+
exports.SEM_PERGUNTA_COM_IMPEDIMENTO = exports.SEM_PERGUNTA_NO_RESUMO = exports.TETO_DE_DECISOES_DETALHADAS = exports.TETO_DE_ESPERAS_POR_MAQUINA = exports.TETO_DE_IMPEDIMENTOS = exports.TETO_DE_PARADOS_NO_CONDUTOR = exports.TETO_DE_THREADS_NOMEADAS = exports.PERGUNTA_DO_RESUMO = exports.CONTRATO_RESUMO = void 0;
|
|
4
4
|
exports.resumirHitl = resumirHitl;
|
|
5
5
|
exports.linhaDoParadoNoCondutor = linhaDoParadoNoCondutor;
|
|
6
6
|
exports.linhasDoCondutor = linhasDoCondutor;
|
|
7
|
+
exports.linhasDosImpedimentos = linhasDosImpedimentos;
|
|
7
8
|
exports.linhaDosTecnicos = linhaDosTecnicos;
|
|
8
9
|
exports.linhasDasOutrasMaquinas = linhasDasOutrasMaquinas;
|
|
9
10
|
exports.linhasDasDecisoes = linhasDasDecisoes;
|
|
@@ -29,6 +30,7 @@ exports.textoDoResumo = textoDoResumo;
|
|
|
29
30
|
* mensagem do canal. Quem entrega chama a segunda.
|
|
30
31
|
*/
|
|
31
32
|
const horario_1 = require("./horario");
|
|
33
|
+
const locale_1 = require("./locale");
|
|
32
34
|
const hitl_tempo_parado_1 = require("./hitl-tempo-parado");
|
|
33
35
|
const decisao_autonoma_1 = require("./decisao-autonoma");
|
|
34
36
|
const hitl_classificacao_1 = require("./hitl-classificacao");
|
|
@@ -60,6 +62,8 @@ function resumirHitl(itens, opcoes) {
|
|
|
60
62
|
threadsTecnicas: [...new Set(tecnicos.map(i => i.thread).filter((t) => !!t))].sort(),
|
|
61
63
|
...(opcoes.paradosNoCondutor?.length ? { paradosNoCondutor: opcoes.paradosNoCondutor.map(p => ({ thread: p.thread, caso: p.caso,
|
|
62
64
|
desdeEm: p.desdeEm, proximoPasso: p.proximoPasso })) } : {}),
|
|
65
|
+
...(opcoes.impedimentosDoDono?.length ? { impedimentosDoDono: opcoes.impedimentosDoDono.map(i => ({ thread: i.thread,
|
|
66
|
+
fase: i.fase, comando: i.comando, retry: i.retry })) } : {}),
|
|
63
67
|
...(opcoes.hitlDeConducao?.acimaDaMeta ? { hitlDeConducao: opcoes.hitlDeConducao } : {}),
|
|
64
68
|
};
|
|
65
69
|
}
|
|
@@ -71,7 +75,7 @@ exports.TETO_DE_PARADOS_NO_CONDUTOR = 5;
|
|
|
71
75
|
*/
|
|
72
76
|
function linhaDoParadoNoCondutor(p, opcoes) {
|
|
73
77
|
const { desdeEm: desde } = p;
|
|
74
|
-
return
|
|
78
|
+
return (0, locale_1.msg)().pulse.linhaDoCondutor(p.thread, (0, horario_1.formatarHora)(desde, opcoes), p.proximoPasso);
|
|
75
79
|
}
|
|
76
80
|
/** As linhas do condutor no resumo, uma por thread, com o resto contado. */
|
|
77
81
|
function linhasDoCondutor(r, marcador, recuo) {
|
|
@@ -80,6 +84,24 @@ function linhasDoCondutor(r, marcador, recuo) {
|
|
|
80
84
|
return [...mostradas.map(p => `${marcador}${linhaDoParadoNoCondutor(p, { agora: r.consultadoEm })}`),
|
|
81
85
|
...(sobra > 0 ? [`${recuo}e mais ${sobra}: ork pulse`] : [])];
|
|
82
86
|
}
|
|
87
|
+
/** Quantos impedimentos do dono o resumo detalha antes de contar o resto. */
|
|
88
|
+
exports.TETO_DE_IMPEDIMENTOS = 5;
|
|
89
|
+
/** Uma linha so, sem caractere de controle e sem corte: o comando precisa chegar inteiro para ser copiado. */
|
|
90
|
+
const semQuebra = (texto) => String(texto).replace(/\p{Cc}/gu, ' ').replace(/\s+/g, ' ').trim();
|
|
91
|
+
/**
|
|
92
|
+
* RM-055 (continuacao, D3): o titulo e uma linha por impedimento do dono, iguais nos dois canais (so o
|
|
93
|
+
* marcador e o recuo mudam). Cada linha diz a thread, a fase, o comando exato e o retry que vem depois.
|
|
94
|
+
*/
|
|
95
|
+
function linhasDosImpedimentos(r, marcador, recuo) {
|
|
96
|
+
const impedimentos = r.impedimentosDoDono ?? [];
|
|
97
|
+
if (!impedimentos.length)
|
|
98
|
+
return [];
|
|
99
|
+
const mostrados = impedimentos.slice(0, exports.TETO_DE_IMPEDIMENTOS), sobra = impedimentos.length - mostrados.length;
|
|
100
|
+
return [`${marcador}Só você destrava, no terminal: ${impedimentos.length}`,
|
|
101
|
+
...mostrados.map(i => `${recuo}• ${semQuebra(i.thread)}${i.fase ? ` ${semQuebra(i.fase)}` : ''}: ` +
|
|
102
|
+
`rode \`${semQuebra(i.comando)}\`; depois \`${semQuebra(i.retry)}\``),
|
|
103
|
+
...(sobra > 0 ? [`${recuo}e mais ${sobra}: ork pulse`] : [])];
|
|
104
|
+
}
|
|
83
105
|
/** RM-057 (fatia 3): a linha do tempo parado por HITL de conducao, a mesma nos dois canais. */
|
|
84
106
|
function linhaDoHitlParado(r) {
|
|
85
107
|
const linha = (0, hitl_tempo_parado_1.linhaDoHitlAcimaDaMeta)(r.hitlDeConducao, { agora: r.consultadoEm });
|
|
@@ -143,6 +165,8 @@ function linhasDasDecisoes(r, marcador, recuo) {
|
|
|
143
165
|
}
|
|
144
166
|
/** Quando nao ha pergunta, o resumo diz isso em vez de pedir licenca para mandar nada. */
|
|
145
167
|
exports.SEM_PERGUNTA_NO_RESUMO = 'Nada aqui pede resposta sua por este canal agora.';
|
|
168
|
+
/** RM-055 (continuacao, D3): sem pergunta, mas com impedimento do dono: o que fazer esta no bloco acima. */
|
|
169
|
+
exports.SEM_PERGUNTA_COM_IMPEDIMENTO = 'Nada aqui pede resposta sua por este canal agora; o que só você destrava está acima, no terminal.';
|
|
146
170
|
/** A linha das perguntas prontas, uma so para os dois canais, pelo mesmo motivo da de baixo. */
|
|
147
171
|
function linhaDasPerguntas(n) {
|
|
148
172
|
return `Perguntas para você: ${n}`;
|
|
@@ -192,7 +216,7 @@ function abertura(r, codigo, marca, resposta) {
|
|
|
192
216
|
return r.pergunta ? [`${marca}${r.pergunta}`, ...linhaDeResposta(codigo).map(l => `${resposta}${l}`), ''] : [];
|
|
193
217
|
}
|
|
194
218
|
function fecho(r) {
|
|
195
|
-
return r.pergunta ? [] : ['', exports.SEM_PERGUNTA_NO_RESUMO];
|
|
219
|
+
return r.pergunta ? [] : ['', r.impedimentosDoDono?.length ? exports.SEM_PERGUNTA_COM_IMPEDIMENTO : exports.SEM_PERGUNTA_NO_RESUMO];
|
|
196
220
|
}
|
|
197
221
|
function textoTelegram(r, codigo) {
|
|
198
222
|
const quando = (0, horario_1.formatarDataHoraRotulada)(r.consultadoEm, { agora: r.consultadoEm });
|
|
@@ -209,6 +233,7 @@ function textoTelegram(r, codigo) {
|
|
|
209
233
|
...(r.tecnicos ? [`🔧 ${linhaDosTecnicos(r)}`] : []),
|
|
210
234
|
...(r.consertos ? [`🔧 ${linhaDosConsertos(r.consertos)}`] : []),
|
|
211
235
|
...linhaDoHitlParado(r).map(l => `⏳ ${l}`),
|
|
236
|
+
...(r.impedimentosDoDono?.length ? ['', ...linhasDosImpedimentos(r, '🔑 ', ' ')] : []),
|
|
212
237
|
...(r.paradosNoCondutor?.length ? ['', ...linhasDoCondutor(r, '🚧 ', ' ')] : []),
|
|
213
238
|
...(r.acumuladas ? ['', `📥 ${linhaDoLoteGuardado(r.acumuladas)}`] : []),
|
|
214
239
|
...(r.decisoes.length || r.acimaDoLimiar.length ? ['', ...linhasDasDecisoes(r, '🧭 ', ' ')] : []),
|
|
@@ -241,6 +266,7 @@ function textoTerminal(r, codigo) {
|
|
|
241
266
|
...(r.tecnicos ? ['', ` ${linhaDosTecnicos(r)}`] : []),
|
|
242
267
|
...(r.consertos ? ['', ` ${linhaDosConsertos(r.consertos)}`] : []),
|
|
243
268
|
...linhaDoHitlParado(r).flatMap(l => ['', ` ${l}`]),
|
|
269
|
+
...(r.impedimentosDoDono?.length ? ['', ...linhasDosImpedimentos(r, ' ', ' ')] : []),
|
|
244
270
|
...(r.paradosNoCondutor?.length ? ['', ...linhasDoCondutor(r, ' ', ' ')] : []),
|
|
245
271
|
...(r.acumuladas ? ['', ` ${linhaDoLoteGuardado(r.acumuladas)}`] : []),
|
|
246
272
|
...(r.decisoes.length || r.acimaDoLimiar.length ? ['', ...linhasDasDecisoes(r, '', ' ').map(l => l.startsWith(' ') ? l : ` ${l}`)] : []),
|
|
@@ -42,6 +42,7 @@ const hitl_contract_1 = require("./hitl-contract");
|
|
|
42
42
|
const horario_1 = require("./horario");
|
|
43
43
|
const ledger_1 = require("./ledger");
|
|
44
44
|
const thread_1 = require("./thread");
|
|
45
|
+
const locale_1 = require("./locale");
|
|
45
46
|
/** A meta da RM-057: mediana de resposta abaixo de 5 minutos. */
|
|
46
47
|
exports.META_DA_MEDIANA_DE_RESPOSTA_MS = 5 * 60_000;
|
|
47
48
|
const RESPOSTAS = ['human_gate', 'session_answered'];
|
|
@@ -178,13 +179,12 @@ const emMinutos = (ms) => `${(ms / 60_000).toFixed(1)} min`;
|
|
|
178
179
|
function textoDaMediana(h) {
|
|
179
180
|
const s = h.seteDias;
|
|
180
181
|
if (s.medianaRespostaMs === null)
|
|
181
|
-
return
|
|
182
|
-
return
|
|
183
|
-
`${s.respondidos} resposta(s))`;
|
|
182
|
+
return (0, locale_1.msg)().pulse.medianaSemResposta;
|
|
183
|
+
return (0, locale_1.msg)().pulse.mediana(emMinutos(s.medianaRespostaMs), s.dentroDaMeta, s.respondidos);
|
|
184
184
|
}
|
|
185
185
|
/** "<thread> (<fase>) parada ha 12min, desde 01:02": a hora no fuso do dono (RM-035). */
|
|
186
186
|
function linhaDaPerguntaParada(p, opcoes) {
|
|
187
|
-
return
|
|
187
|
+
return (0, locale_1.msg)().pulse.perguntaParada(p.thread, p.fase, (0, horario_1.duracaoRelativa)(p.paradaHaMin), (0, horario_1.formatarHora)(p.desdeEm, opcoes));
|
|
188
188
|
}
|
|
189
189
|
/**
|
|
190
190
|
* A linha unica do resumo do pulse, so quando passou da meta: quantas abertas, a mais antiga e a
|
package/dist/hitl.js
CHANGED
|
@@ -88,6 +88,8 @@ const horario_1 = require("./horario");
|
|
|
88
88
|
Object.defineProperty(exports, "duracaoCurta", { enumerable: true, get: function () { return horario_1.duracaoCurta; } });
|
|
89
89
|
const hitl_estado_1 = require("./hitl-estado");
|
|
90
90
|
const redacao_url_1 = require("./redacao-url");
|
|
91
|
+
const locale_1 = require("./locale");
|
|
92
|
+
const locale_pulse_1 = require("./locale-pulse");
|
|
91
93
|
/** Limite de atencao padrao, em minutos, igual ao do monitor de orquestracao. */
|
|
92
94
|
exports.ATENCAO_PADRAO_MIN = 30;
|
|
93
95
|
function redigirSegredos(texto) {
|
|
@@ -110,28 +112,29 @@ function contextoSeguro(texto, linhas = 20) {
|
|
|
110
112
|
* `stopped` NAO pede humano: a sessao foi parada por decisao de alguem. `failed` pede,
|
|
111
113
|
* porque alguem precisa decidir entre retomar, corrigir ou abandonar.
|
|
112
114
|
*/
|
|
115
|
+
// RM-061 (F2b): o detalhe de cada estado tem a fonte no catalogo pt-BR (`locale-pulse.ts`), com o ingles ao lado.
|
|
113
116
|
const REGRA_POR_ESTADO = {
|
|
114
117
|
blocked: {
|
|
115
118
|
classe: 'hitl',
|
|
116
119
|
precisaDeHumano: true,
|
|
117
|
-
detalhe:
|
|
120
|
+
detalhe: locale_pulse_1.PULSE_PT_BR.sessao.blocked,
|
|
118
121
|
},
|
|
119
122
|
failed: {
|
|
120
123
|
classe: 'falha',
|
|
121
124
|
precisaDeHumano: true,
|
|
122
|
-
detalhe:
|
|
125
|
+
detalhe: locale_pulse_1.PULSE_PT_BR.sessao.failed,
|
|
123
126
|
},
|
|
124
|
-
working: { classe: 'trabalhando', precisaDeHumano: false, detalhe:
|
|
125
|
-
done: { classe: 'concluida', precisaDeHumano: false, detalhe:
|
|
127
|
+
working: { classe: 'trabalhando', precisaDeHumano: false, detalhe: locale_pulse_1.PULSE_PT_BR.sessao.working },
|
|
128
|
+
done: { classe: 'concluida', precisaDeHumano: false, detalhe: locale_pulse_1.PULSE_PT_BR.sessao.done },
|
|
126
129
|
stopped: {
|
|
127
130
|
classe: 'interrompida',
|
|
128
131
|
precisaDeHumano: false,
|
|
129
|
-
detalhe:
|
|
132
|
+
detalhe: locale_pulse_1.PULSE_PT_BR.sessao.stopped,
|
|
130
133
|
},
|
|
131
134
|
idle: {
|
|
132
135
|
classe: 'interativa',
|
|
133
136
|
precisaDeHumano: false,
|
|
134
|
-
detalhe:
|
|
137
|
+
detalhe: locale_pulse_1.PULSE_PT_BR.sessao.idle,
|
|
135
138
|
},
|
|
136
139
|
};
|
|
137
140
|
/** Estado cru da sessao: `state` manda, `status` e o fallback historico. */
|
|
@@ -142,14 +145,13 @@ function estadoBruto(s) {
|
|
|
142
145
|
/** Classifica o estado cru do runtime. Estado que nao esta no mapa avisa a mais. */
|
|
143
146
|
function classificarEstado(estado) {
|
|
144
147
|
const regra = REGRA_POR_ESTADO[estado];
|
|
148
|
+
// RM-061 (F2b, G2): o detalhe vem do catalogo (o mesmo pt-BR da tabela) e o pulse o remonta no locale.
|
|
145
149
|
if (regra)
|
|
146
|
-
return regra;
|
|
150
|
+
return { ...regra, detalhe: (0, locale_1.textoDoCatalogo)((m) => m.pulse.sessao[estado] ?? regra.detalhe) };
|
|
147
151
|
return {
|
|
148
152
|
classe: 'desconhecida',
|
|
149
153
|
precisaDeHumano: true,
|
|
150
|
-
detalhe: estado === ''
|
|
151
|
-
? 'runtime nao informou estado desta sessao: tratada como possivel parada'
|
|
152
|
-
: `estado "${estado}" nao esta no catalogo do ork: tratado como possivel parada`,
|
|
154
|
+
detalhe: (0, locale_1.textoDoCatalogo)((m) => estado === '' ? m.pulse.sessaoSemEstado : m.pulse.sessaoEstadoForaDoCatalogo(estado)),
|
|
153
155
|
};
|
|
154
156
|
}
|
|
155
157
|
/** Resposta do `claude logs` quando o job da sessao ja saiu do runtime. */
|
|
@@ -279,28 +281,22 @@ function lerPerguntaDaTela(textoLimpo) {
|
|
|
279
281
|
* inventa opcao que a sessao nao deu.
|
|
280
282
|
*/
|
|
281
283
|
function recomendarPara(classe, tipo, id) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
'coloque-o na allowlist de permissoes para nao parar de novo pelo mesmo motivo.');
|
|
299
|
-
case 'hitl.pergunta':
|
|
300
|
-
return `abra a sessao (\`claude attach ${id}\`) e escolha entre as opcoes que ela listou.`;
|
|
301
|
-
default:
|
|
302
|
-
return `veja o que a sessao pede com \`ork sessions logs ${id}\` antes de responder.`;
|
|
303
|
-
}
|
|
284
|
+
// RM-061 (F2b, G2): nasce em pt-BR pelo catalogo (o --json guarda) e o pulse a remonta no locale.
|
|
285
|
+
return (0, locale_1.textoDoCatalogo)((m) => {
|
|
286
|
+
const r = m.pulse.recomendacaoDoRadar;
|
|
287
|
+
if (classe === 'abandonada')
|
|
288
|
+
return r.abandonada;
|
|
289
|
+
if (classe === 'falha')
|
|
290
|
+
return r.falha(id);
|
|
291
|
+
if (classe === 'desconhecida')
|
|
292
|
+
return r.desconhecida(id);
|
|
293
|
+
switch (tipo) {
|
|
294
|
+
case 'hitl.credencial': return r.credencial(id);
|
|
295
|
+
case 'hitl.permissao': return r.permissao(id);
|
|
296
|
+
case 'hitl.pergunta': return r.pergunta(id);
|
|
297
|
+
default: return r.outra(id);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
304
300
|
}
|
|
305
301
|
/** Minutos inteiros entre um epoch em ms e um carimbo ISO (nunca negativo). */
|
|
306
302
|
function idadeEmMinutos(inicioMs, ateEm) {
|
|
@@ -440,7 +436,7 @@ function varrerSessoes(opcoes = {}) {
|
|
|
440
436
|
}
|
|
441
437
|
const consultaClaude = opcoes.consulta ?? (adapter.disponivel()
|
|
442
438
|
? adapter.consultarSessoes(opcoes.soDaRaiz && raiz ? raiz : undefined, true)
|
|
443
|
-
: { ok: false, sessoes: [], detalhe:
|
|
439
|
+
: { ok: false, sessoes: [], detalhe: (0, locale_1.textoDoCatalogo)((m) => m.pulse.adapterIndisponivel) });
|
|
444
440
|
const consulta = { ...consultaClaude, ok: consultaClaude.ok || nativas.size > 0,
|
|
445
441
|
sessoes: [...consultaClaude.sessoes, ...nativas.values()] };
|
|
446
442
|
if (!consulta.ok) {
|
package/dist/horario.js
CHANGED
|
@@ -34,6 +34,7 @@ exports.formatarPrazo = formatarPrazo;
|
|
|
34
34
|
exports.formatarDesde = formatarDesde;
|
|
35
35
|
exports.localizarTexto = localizarTexto;
|
|
36
36
|
exports.localizarTextoRotulado = localizarTextoRotulado;
|
|
37
|
+
const locale_1 = require("./locale");
|
|
37
38
|
exports.CHAVE_DO_FUSO = 'owner.timezone';
|
|
38
39
|
/** Único fuso com nome próprio no rótulo; exemplo da documentação e do `ork init`. */
|
|
39
40
|
exports.FUSO_DE_BRASILIA = 'America/Sao_Paulo';
|
|
@@ -194,11 +195,11 @@ function duracaoCurta(minutos) {
|
|
|
194
195
|
}
|
|
195
196
|
/** Duração até ou desde agora: abaixo de 1 min diz `menos de 1 min`, nunca `0min`. */
|
|
196
197
|
function duracaoRelativa(minutos) {
|
|
197
|
-
return minutos < 1 ?
|
|
198
|
+
return minutos < 1 ? (0, locale_1.msg)().horario.menosDeUmMin : duracaoCurta(minutos);
|
|
198
199
|
}
|
|
199
|
-
function sigla(fuso, ms) {
|
|
200
|
+
function sigla(fuso, ms, locale = (0, locale_1.localeAtivo)()) {
|
|
200
201
|
try {
|
|
201
|
-
return new Intl.DateTimeFormat('pt-BR', { timeZone: fuso, timeZoneName: 'short' })
|
|
202
|
+
return new Intl.DateTimeFormat(locale === 'en' ? 'en-US' : 'pt-BR', { timeZone: fuso, timeZoneName: 'short' })
|
|
202
203
|
.formatToParts(new Date(ms)).find(p => p.type === 'timeZoneName')?.value ?? '';
|
|
203
204
|
}
|
|
204
205
|
catch {
|
|
@@ -208,7 +209,7 @@ function sigla(fuso, ms) {
|
|
|
208
209
|
/** Como o fuso aparece entre parênteses: `horário de Brasília`, `UTC`, `Europe/Lisbon, GMT+1`. */
|
|
209
210
|
function rotuloDoFuso(fuso = fusoDoDono().fuso, quando) {
|
|
210
211
|
if (fuso === exports.FUSO_DE_BRASILIA)
|
|
211
|
-
return
|
|
212
|
+
return (0, locale_1.msg)().horario.brasilia;
|
|
212
213
|
if (fuso === 'UTC')
|
|
213
214
|
return 'UTC';
|
|
214
215
|
const ms = instante(quando);
|
|
@@ -218,16 +219,22 @@ function rotuloDoFuso(fuso = fusoDoDono().fuso, quando) {
|
|
|
218
219
|
/** Legenda de mensagem com vários horários: `Horários de Brasília.` */
|
|
219
220
|
function legendaDoFuso(fuso = fusoDoDono().fuso, quando) {
|
|
220
221
|
if (fuso === exports.FUSO_DE_BRASILIA)
|
|
221
|
-
return
|
|
222
|
-
return
|
|
222
|
+
return (0, locale_1.msg)().horario.legendaBrasilia;
|
|
223
|
+
return (0, locale_1.msg)().horario.legenda(rotuloDoFuso(fuso, quando));
|
|
223
224
|
}
|
|
224
|
-
/**
|
|
225
|
+
/**
|
|
226
|
+
* `19/09 15:16`; `19/09/2025 15:16` quando o ano não é o corrente do dono. Em `en`, sempre
|
|
227
|
+
* `2026-09-19 15:16` (EN6). Inválido volta como veio.
|
|
228
|
+
*/
|
|
225
229
|
function formatarDataHora(quando, opcoes = {}) {
|
|
226
230
|
const ms = instante(quando ?? null);
|
|
227
231
|
if (!Number.isFinite(ms))
|
|
228
232
|
return quando === null || quando === undefined ? '' : String(quando);
|
|
229
233
|
const fuso = opcoes.fuso ?? fusoDoDono().fuso;
|
|
230
234
|
const p = partesLocais(ms, fuso), a = partesLocais(instante(opcoes.agora), fuso);
|
|
235
|
+
if ((opcoes.locale ?? (0, locale_1.localeAtivo)()) === 'en') {
|
|
236
|
+
return `${p.ano}-${p.mes}-${p.dia} ${p.hora}:${p.minuto}` + (opcoes.segundos ? `:${p.segundo}` : '');
|
|
237
|
+
}
|
|
231
238
|
return `${p.dia}/${p.mes}${p.ano !== a.ano ? `/${p.ano}` : ''} ${p.hora}:${p.minuto}` +
|
|
232
239
|
(opcoes.segundos ? `:${p.segundo}` : '');
|
|
233
240
|
}
|
package/dist/hosts.js
CHANGED
|
@@ -354,7 +354,7 @@ function instalarAdaptador(host, opcoes = {}) {
|
|
|
354
354
|
let planoExperiencia = null;
|
|
355
355
|
if (preferencias && hostComBloco && !avisoExperiencia) {
|
|
356
356
|
try {
|
|
357
|
-
planoExperiencia = (0, experiencia_instalacao_1.planejarExperiencia)(projeto, host, preferencias.experience ? diretorioExperiencia : null);
|
|
357
|
+
planoExperiencia = (0, experiencia_instalacao_1.planejarExperiencia)(projeto, host, preferencias.experience ? diretorioExperiencia : null, opcoes.locale);
|
|
358
358
|
}
|
|
359
359
|
catch (e) {
|
|
360
360
|
const motivo = e.message;
|
|
@@ -421,6 +421,7 @@ function instalarAdaptador(host, opcoes = {}) {
|
|
|
421
421
|
estado,
|
|
422
422
|
});
|
|
423
423
|
}
|
|
424
|
+
const removidos = sobrasDeMods(destino, recibo, arquivos);
|
|
424
425
|
const conflitos = arquivos.filter((a) => a.estado === 'sobrescrito');
|
|
425
426
|
/**
|
|
426
427
|
* I-43 (D5): a divergencia continua sendo DETECTADA; ela deixa de BARRAR quando e
|
|
@@ -458,6 +459,7 @@ function instalarAdaptador(host, opcoes = {}) {
|
|
|
458
459
|
...(preferencias || avisoExperiencia ? { experiencia: { ativa: host !== 'openclaw' && !!preferencias?.experience && !avisoExperiencia,
|
|
459
460
|
arquivos: planoExperiencia?.mudancas.map(m => path.relative(planoExperiencia.projeto, m.arquivo)) ?? [], skill: preferencias?.skill ?? '',
|
|
460
461
|
...(avisoExperiencia ? { aviso: avisoExperiencia } : {}) } } : {}),
|
|
462
|
+
...(removidos.length ? { removidos } : {}),
|
|
461
463
|
};
|
|
462
464
|
if (opcoes.dryRun === true || barrado)
|
|
463
465
|
return resultado;
|
|
@@ -477,6 +479,17 @@ function instalarAdaptador(host, opcoes = {}) {
|
|
|
477
479
|
if (arquivo.executavel)
|
|
478
480
|
fs.chmodSync(arquivo.destino, 0o755);
|
|
479
481
|
}
|
|
482
|
+
// RM-059 (T0.7, A1 do CHECK): o que saiu do catalogo em `mods/` sai da copia, com a pasta que ficar vazia.
|
|
483
|
+
for (const relativo of removidos) {
|
|
484
|
+
const alvo = path.join(destino, relativo);
|
|
485
|
+
fs.unlinkSync(alvo);
|
|
486
|
+
const raizDoMod = path.join(destino, ...relativo.split('/').slice(0, 2));
|
|
487
|
+
for (let dir = path.dirname(alvo); dir.startsWith(raizDoMod); dir = path.dirname(dir)) {
|
|
488
|
+
if (fs.readdirSync(dir).length)
|
|
489
|
+
break;
|
|
490
|
+
fs.rmdirSync(dir);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
480
493
|
// O recibo: com ele da para saber, depois, se alguem editou a copia instalada em vez do
|
|
481
494
|
// catalogo. Sem ele a instalacao e um monte de arquivo sem procedencia.
|
|
482
495
|
fs.writeFileSync(path.join(destino, 'INSTALADO.json'), JSON.stringify({
|
|
@@ -497,6 +510,41 @@ function instalarAdaptador(host, opcoes = {}) {
|
|
|
497
510
|
(0, experiencia_instalacao_1.aplicarExperiencia)(planoExperiencia);
|
|
498
511
|
return resultado;
|
|
499
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* RM-059 (T0.7, A1 do CHECK): os arquivos de `mods/` do recibo anterior que nao estao mais no catalogo e que a
|
|
515
|
+
* copia guarda como foram instalados (sha256 do recibo), os de cada mod e os comuns da raiz de `mods/` (N2 da
|
|
516
|
+
* rodada 2). Arquivo editado, link ou caminho fora do destino fica: o despacho continua recusando com o motivo,
|
|
517
|
+
* e a decisao e de quem editou.
|
|
518
|
+
*/
|
|
519
|
+
function sobrasDeMods(destino, recibo, arquivos) {
|
|
520
|
+
if (!recibo)
|
|
521
|
+
return [];
|
|
522
|
+
const novos = new Set(arquivos.map((a) => a.relativo));
|
|
523
|
+
let base;
|
|
524
|
+
try {
|
|
525
|
+
base = fs.realpathSync(destino);
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
return [];
|
|
529
|
+
}
|
|
530
|
+
return recibo.arquivos.flatMap((a) => {
|
|
531
|
+
const rel = typeof a.arquivo === 'string' ? a.arquivo : '';
|
|
532
|
+
if (!/^mods\/[^/]+(?:$|\/.)/.test(rel) || novos.has(rel) || path.isAbsolute(rel) || rel.split('/').includes('..'))
|
|
533
|
+
return [];
|
|
534
|
+
const alvo = path.join(destino, rel);
|
|
535
|
+
const st = fs.lstatSync(alvo, { throwIfNoEntry: false });
|
|
536
|
+
if (!st || !st.isFile() || st.nlink !== 1)
|
|
537
|
+
return [];
|
|
538
|
+
try {
|
|
539
|
+
if (!fs.realpathSync(path.dirname(alvo)).startsWith(base + path.sep))
|
|
540
|
+
return [];
|
|
541
|
+
}
|
|
542
|
+
catch {
|
|
543
|
+
return [];
|
|
544
|
+
}
|
|
545
|
+
return sha256(fs.readFileSync(alvo)) === a.sha256 ? [rel] : [];
|
|
546
|
+
});
|
|
547
|
+
}
|
|
500
548
|
/** Caminho real do maior ancestral existente, com o resto como está: o destino pode não existir ainda. */
|
|
501
549
|
function caminhoReal(alvo) {
|
|
502
550
|
let existente = path.resolve(alvo);
|
|
@@ -592,6 +640,9 @@ function textoDaInstalacao(r) {
|
|
|
592
640
|
const porque = a.divergencia ? ` (${a.divergencia})` : '';
|
|
593
641
|
linhas.push(` ${marca} ${a.relativo}${porque}`);
|
|
594
642
|
}
|
|
643
|
+
// RM-059 (T0.7): arquivo de mod que saiu do catalogo sai da copia, para o despacho nao recusar o mod.
|
|
644
|
+
for (const rel of r.removidos ?? [])
|
|
645
|
+
linhas.push(` - ${rel} (saiu do catalogo${r.dryRun ? ', seria removido' : ', removido'})`);
|
|
595
646
|
// I-43 (D5): o `--dir` na raiz avisa, em vez de reportar "tudo novo" com saida 0.
|
|
596
647
|
if (r.reciboVizinho) {
|
|
597
648
|
linhas.push('');
|
package/dist/impedimento.js
CHANGED
|
@@ -79,6 +79,17 @@ function ehEsperaDoDono(e, tipoGateBloqueado = 'gate_blocked') {
|
|
|
79
79
|
function citar(caminho) {
|
|
80
80
|
return /^[A-Za-z0-9_./:@+-]+$/.test(caminho) ? caminho : `'${caminho.replace(/'/g, `'\\''`)}'`;
|
|
81
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* RM-055 (continuacao, D4): frases que dizem "Workspace not trusted" mas que aceitar a confianca NAO
|
|
84
|
+
* resolve. No claude 2.1.296 o veredito do `--bg` tem tres saidas: o diretorio que nao existe mais no
|
|
85
|
+
* disco, o diretorio home (que so confia uma sessao por vez) e a recusa de confianca de verdade. As duas
|
|
86
|
+
* primeiras ficam no caminho generico (`runtime.unavailable`), com o stderr gravado no despacho falho:
|
|
87
|
+
* mandar o dono rodar `cd <dir> && claude` ali nao destrava nada.
|
|
88
|
+
*/
|
|
89
|
+
const FRASES_QUE_NAO_SAO_DO_DONO = [
|
|
90
|
+
/could not be resolved on disk/i,
|
|
91
|
+
/home directory is trusted one session at a time/i,
|
|
92
|
+
];
|
|
82
93
|
const FRASES_DE_CONFIANCA = [
|
|
83
94
|
/workspace not trusted/i,
|
|
84
95
|
/accept the trust (?:prompt|dialog)/i,
|
|
@@ -86,10 +97,32 @@ const FRASES_DE_CONFIANCA = [
|
|
|
86
97
|
/(?:folder|directory|workspace) (?:is )?not trusted/i,
|
|
87
98
|
];
|
|
88
99
|
const FRASES_DE_CONSENTIMENTO = [
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
100
|
+
// claude 2.1.296, modo print: o aviso que bloqueia e sai com 1. O aviso de carencia ("will take effect
|
|
101
|
+
// ... Run `claude` to review the updated terms") nao bloqueia e nao casa aqui.
|
|
102
|
+
{ regra: /\[ACTION REQUIRED\][^\n]*(?:terms|policy)/i, aceita: 'revisar e aceitar os termos novos',
|
|
103
|
+
feito: 'aceite os termos e saia' },
|
|
104
|
+
// claude 2.1.296: o portao do `--bg` que vem antes da confianca (gateCause "disclaimer").
|
|
105
|
+
{ regra: /requires accepting the disclaimer first/i, aceita: 'aceitar o aviso do modo sem permissões (bypass)',
|
|
106
|
+
feito: 'aceite o aviso e saia' },
|
|
107
|
+
{ regra: /requires opting in first/i, aceita: 'ativar o modo auto uma vez', feito: 'confirme o modo auto e saia' },
|
|
108
|
+
// Fatia 1 (02/10/2026): frases genericas de termos novos.
|
|
109
|
+
{ regra: /accept (?:the )?(?:updated |new )?(?:terms|consumer terms|privacy policy|usage policy)/i,
|
|
110
|
+
aceita: 'aceitar termos novos', feito: 'aceite os termos e saia' },
|
|
111
|
+
{ regra: /(?:terms|policy) (?:have|has) (?:been )?updated[^\n]*accept/i, aceita: 'aceitar termos novos',
|
|
112
|
+
feito: 'aceite os termos e saia' },
|
|
113
|
+
{ regra: /consent (?:is )?required/i, aceita: 'aceitar termos novos', feito: 'aceite os termos e saia' },
|
|
92
114
|
];
|
|
115
|
+
/** A forma fechada de um comando que o runtime manda rodar: o binario e opcoes `--nome` com valor simples. */
|
|
116
|
+
const FORMA_DO_COMANDO = /^(?:claude|codex)(?: --[a-z][a-z-]*(?: [a-z][a-z0-9-]*)?)*$/;
|
|
117
|
+
/**
|
|
118
|
+
* RM-055 (continuacao, D4): o comando que a propria frase do runtime manda rodar ("Run `claude
|
|
119
|
+
* --permission-mode auto` once interactively"). So na forma fechada e so do binario do runtime: a saida
|
|
120
|
+
* do runtime nunca chega ao dono como comando arbitrario. Fora disso, o binario puro.
|
|
121
|
+
*/
|
|
122
|
+
function comandoDaFrase(trecho, bin) {
|
|
123
|
+
const pedido = /\brun `([^`]{1,120})`/i.exec(trecho)?.[1].replace(/\s+/g, ' ').trim();
|
|
124
|
+
return pedido && FORMA_DO_COMANDO.test(pedido) && pedido.split(' ')[0] === bin ? pedido : bin;
|
|
125
|
+
}
|
|
93
126
|
function trechoDa(texto, regra) {
|
|
94
127
|
const linha = texto.split(/\r?\n/).find(l => regra.test(l)) ?? texto;
|
|
95
128
|
return linha.replace(/\s+/g, ' ').trim().slice(0, 240);
|
|
@@ -103,6 +136,8 @@ function binarioDo(runtime) {
|
|
|
103
136
|
*/
|
|
104
137
|
function classificarImpedimento(saida, ctx) {
|
|
105
138
|
const texto = saida ?? '';
|
|
139
|
+
if (FRASES_QUE_NAO_SAO_DO_DONO.some(r => r.test(texto)))
|
|
140
|
+
return null;
|
|
106
141
|
const bin = binarioDo(ctx.runtime);
|
|
107
142
|
const depois = `depois, \`ork retry run ${ctx.thread}\` re-despacha ${ctx.fase} com o mesmo prompt gravado`;
|
|
108
143
|
const confianca = FRASES_DE_CONFIANCA.find(r => r.test(texto));
|
|
@@ -115,23 +150,77 @@ function classificarImpedimento(saida, ctx) {
|
|
|
115
150
|
trecho: trechoDa(texto, confianca),
|
|
116
151
|
};
|
|
117
152
|
}
|
|
118
|
-
const consentimento = FRASES_DE_CONSENTIMENTO.find(
|
|
153
|
+
const consentimento = FRASES_DE_CONSENTIMENTO.find(c => c.regra.test(texto));
|
|
119
154
|
if (consentimento) {
|
|
155
|
+
const trecho = trechoDa(texto, consentimento.regra);
|
|
120
156
|
return {
|
|
121
157
|
motivo: 'runtime.consent-pending',
|
|
122
|
-
trava: `o ${bin} espera você
|
|
123
|
-
comando: bin,
|
|
124
|
-
depois:
|
|
125
|
-
trecho
|
|
158
|
+
trava: `o ${bin} espera você ${consentimento.aceita} e recusou o despacho de ${ctx.fase}`,
|
|
159
|
+
comando: comandoDaFrase(trecho, bin),
|
|
160
|
+
depois: `${consentimento.feito}; ${depois}`,
|
|
161
|
+
trecho,
|
|
126
162
|
};
|
|
127
163
|
}
|
|
128
164
|
return null;
|
|
129
165
|
}
|
|
166
|
+
/** O caminho como o claude o compara: o real, sem link; o resolvido quando ele nao existe no disco. */
|
|
167
|
+
function caminhoReal(caminho) {
|
|
168
|
+
try {
|
|
169
|
+
return fs.realpathSync.native(caminho);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return path.resolve(caminho);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/** A raiz git do diretorio: o ancestral mais proximo, ele incluido, com `.git` (arquivo ou diretorio). */
|
|
176
|
+
function raizGit(dir) {
|
|
177
|
+
for (let d = dir;; d = path.dirname(d)) {
|
|
178
|
+
try {
|
|
179
|
+
const st = fs.lstatSync(path.join(d, '.git'));
|
|
180
|
+
if (st.isFile() || st.isDirectory())
|
|
181
|
+
return d;
|
|
182
|
+
}
|
|
183
|
+
catch { /* sem `.git` aqui: sobe */ }
|
|
184
|
+
if (path.dirname(d) === d)
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* A raiz canonica de uma raiz git, conferida como o claude 2.1.296 confere: numa worktree vinculada (o
|
|
190
|
+
* arquivo `.git` aponta `gitdir:` para `<comum>/worktrees/<nome>`, que tem `commondir` e um `gitdir` de
|
|
191
|
+
* volta para `<raiz>/.git`), e o repositorio principal, o diretorio de cima do `<comum>` chamado `.git`.
|
|
192
|
+
* Qualquer conferencia que falha devolve a propria raiz, e um repositorio comum (`.git` diretorio) tambem.
|
|
193
|
+
*/
|
|
194
|
+
function raizCanonica(raiz) {
|
|
195
|
+
try {
|
|
196
|
+
const conteudo = fs.readFileSync(path.join(raiz, '.git'), 'utf8').trim();
|
|
197
|
+
if (!conteudo.startsWith('gitdir:'))
|
|
198
|
+
return raiz;
|
|
199
|
+
const gitdir = path.resolve(raiz, conteudo.slice('gitdir:'.length).trim());
|
|
200
|
+
const comum = path.resolve(gitdir, fs.readFileSync(path.join(gitdir, 'commondir'), 'utf8').trim());
|
|
201
|
+
if (path.dirname(gitdir) !== path.join(comum, 'worktrees'))
|
|
202
|
+
return raiz;
|
|
203
|
+
const deVolta = path.resolve(gitdir, fs.readFileSync(path.join(gitdir, 'gitdir'), 'utf8').trim());
|
|
204
|
+
if (caminhoReal(deVolta) !== path.join(caminhoReal(raiz), '.git'))
|
|
205
|
+
return raiz;
|
|
206
|
+
if (path.basename(comum) !== '.git')
|
|
207
|
+
return fs.existsSync(path.join(comum, '.git')) ? raiz : comum;
|
|
208
|
+
return path.dirname(comum);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return raiz;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
130
214
|
/**
|
|
131
215
|
* O impedimento ja foi resolvido? So o de confianca do diretorio tem prova local: o `claude` grava
|
|
132
|
-
* `hasTrustDialogAccepted` por projeto no `.claude.json` da conta (o do perfil, com `CLAUDE_CONFIG_DIR`)
|
|
133
|
-
*
|
|
134
|
-
*
|
|
216
|
+
* `hasTrustDialogAccepted` por projeto no `.claude.json` da conta (o do perfil, com `CLAUDE_CONFIG_DIR`).
|
|
217
|
+
* `null` e "nao sei": o retry despacha e o runtime decide; se recusar de novo, a mesma pausa volta.
|
|
218
|
+
*
|
|
219
|
+
* RM-055 (continuacao, D1): a regra e a que o claude 2.1.296 aplica no `--bg`, medida com worktrees git
|
|
220
|
+
* reais: vale a confianca do proprio diretorio e dos de cima ate a raiz git, inclusive, e a da raiz
|
|
221
|
+
* canonica de uma worktree vinculada (o repositorio principal), more a worktree dentro ou fora dele. Acima
|
|
222
|
+
* da raiz git nada vale: com so o diretorio de cima do repositorio confiado, o claude recusa a worktree.
|
|
223
|
+
* Fora de git, qualquer diretorio de cima vale, como no claude.
|
|
135
224
|
*/
|
|
136
225
|
function impedimentoResolvido(motivo, ctx) {
|
|
137
226
|
if (motivo !== 'runtime.workspace-untrusted' || ctx.runtime !== 'claude-bg')
|
|
@@ -149,10 +238,15 @@ function impedimentoResolvido(motivo, ctx) {
|
|
|
149
238
|
catch {
|
|
150
239
|
return null;
|
|
151
240
|
}
|
|
152
|
-
|
|
153
|
-
|
|
241
|
+
const confia = (dir) => projetos[dir]?.hasTrustDialogAccepted === true;
|
|
242
|
+
const cwd = caminhoReal(ctx.cwd);
|
|
243
|
+
const raiz = raizGit(cwd);
|
|
244
|
+
if (raiz && confia(raizCanonica(raiz)))
|
|
245
|
+
return true;
|
|
246
|
+
for (let dir = cwd;; dir = path.dirname(dir)) {
|
|
247
|
+
if (confia(dir))
|
|
154
248
|
return true;
|
|
155
|
-
if (path.dirname(dir) === dir)
|
|
249
|
+
if (dir === raiz || path.dirname(dir) === dir)
|
|
156
250
|
return false;
|
|
157
251
|
}
|
|
158
252
|
}
|