@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/entrega-pr.js
CHANGED
|
@@ -16,12 +16,15 @@ exports.registrarEntregasPorPr = registrarEntregasPorPr;
|
|
|
16
16
|
* remota (ancestralidade conferida contra a ponta que o `ls-remote` devolve) e o check do CI no
|
|
17
17
|
* head do PR. Sem CI verde, nao registra: merge sem prova independente nao e entrega.
|
|
18
18
|
*/
|
|
19
|
+
const branch_de_estado_1 = require("./branch-de-estado");
|
|
19
20
|
const ci_1 = require("./ci");
|
|
21
|
+
const docs_1 = require("./docs");
|
|
20
22
|
const fabrica_publicar_1 = require("./fabrica-publicar");
|
|
21
23
|
const ledger_1 = require("./ledger");
|
|
22
24
|
const modos_1 = require("./modos");
|
|
23
25
|
const thread_1 = require("./thread");
|
|
24
26
|
const util_1 = require("./util");
|
|
27
|
+
const locale_1 = require("./locale");
|
|
25
28
|
/** O merge `ship(<thread>)` mais recente na base remota, com o head do PR (segundo pai). */
|
|
26
29
|
function mergeDaEntrega(raiz, thread, remoto, base) {
|
|
27
30
|
const r = (0, util_1.exec)('git', ['log', `refs/remotes/${remoto}/${base}`, '--first-parent', '--format=%H%x09%P%x09%s', `--grep=^ship(${thread})`], raiz);
|
|
@@ -49,7 +52,7 @@ function avancarParaShip(raiz, threadId) {
|
|
|
49
52
|
(0, thread_1.gravarThread)(raiz, atualizada);
|
|
50
53
|
}
|
|
51
54
|
function resultado(thread, acao, motivo, extra = {}) {
|
|
52
|
-
return { thread, acao, motivo, mergeSha: null, headSha: null, ci: null, ...extra };
|
|
55
|
+
return { thread, acao, motivo, mergeSha: null, headSha: null, ci: null, docsPendentes: [], ...extra };
|
|
53
56
|
}
|
|
54
57
|
/**
|
|
55
58
|
* `ork ship registrar-pr <thread>`: grava o `ship_done` da entrega feita por PR. Idempotente:
|
|
@@ -57,39 +60,46 @@ function resultado(thread, acao, motivo, extra = {}) {
|
|
|
57
60
|
*/
|
|
58
61
|
function registrarEntregaPorPr(carregado, threadId, opcoes = {}) {
|
|
59
62
|
const raiz = carregado.raiz;
|
|
60
|
-
|
|
63
|
+
// RM-047: o `--remoto` vem da linha de comando; so nome de remoto chega ao git, e depois do `--`.
|
|
64
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
|
|
61
65
|
const base = carregado.manifesto.worktree.base_branch;
|
|
62
66
|
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
63
67
|
if (thread.status === 'fechada')
|
|
64
|
-
return resultado(threadId, 'ja-registrada',
|
|
68
|
+
return resultado(threadId, 'ja-registrada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prThreadFechada));
|
|
65
69
|
if (opcoes.buscar !== false)
|
|
66
|
-
(0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], raiz);
|
|
67
|
-
const
|
|
68
|
-
if (!
|
|
69
|
-
return resultado(threadId, 'sem-merge',
|
|
70
|
+
(0, util_1.exec)('git', ['fetch', '-q', '--', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], raiz);
|
|
71
|
+
const encontrado = mergeDaEntrega(raiz, threadId, remoto, base);
|
|
72
|
+
if (!encontrado)
|
|
73
|
+
return resultado(threadId, 'sem-merge', (0, locale_1.textoDoCatalogo)((m) => m.ship.prSemMerge(threadId, remoto, base)));
|
|
74
|
+
// RM-044 (A3): o condutor roda o registrar-pr logo depois do merge; e aqui que ele fica sabendo da pagina que
|
|
75
|
+
// vai deixar o push da base vermelho, lida da base remota que o fetch acabou de trazer.
|
|
76
|
+
const merge = { ...encontrado, docsPendentes: (0, docs_1.docsPendentesDoMerge)(raiz, threadId, `refs/remotes/${remoto}/${base}`) };
|
|
70
77
|
const dir = (0, thread_1.dirThread)(raiz, threadId);
|
|
71
78
|
const jaTem = (0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido && e.mergeSha === merge.mergeSha);
|
|
72
79
|
if (jaTem)
|
|
73
|
-
return resultado(threadId, 'ja-registrada',
|
|
80
|
+
return resultado(threadId, 'ja-registrada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prJaTemShipDone), merge);
|
|
74
81
|
// A ponta do remoto AGORA, e o merge dentro dela: e o que torna o push provado, nao presumido.
|
|
75
|
-
const remotoAgora = (0, util_1.exec)('git', ['ls-remote', remoto, `refs/heads/${base}`], raiz);
|
|
82
|
+
const remotoAgora = (0, util_1.exec)('git', ['ls-remote', '--', remoto, `refs/heads/${base}`], raiz);
|
|
76
83
|
const ponta = remotoAgora.ok ? remotoAgora.stdout.split('\t')[0].trim() : '';
|
|
77
84
|
if (!ponta || !(0, util_1.exec)('git', ['merge-base', '--is-ancestor', merge.mergeSha, ponta], raiz).ok) {
|
|
78
|
-
return resultado(threadId, 'recusada',
|
|
85
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prForaDaPonta(merge.mergeSha.slice(0, 7), remoto, base)), merge);
|
|
79
86
|
}
|
|
80
87
|
const ci = (0, ci_1.consultarCi)(carregado, merge.headSha ?? merge.mergeSha, remoto, opcoes.executorCi);
|
|
81
88
|
if (ci.required && !ci.ok) {
|
|
82
|
-
return resultado(threadId, 'recusada',
|
|
89
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prSemCiVerde((0, locale_1.remontar)(ci.detail))), { ...merge, ci });
|
|
83
90
|
}
|
|
84
91
|
// RM-037 (fatia 3, defeito 6): o ensaio confere tudo e para aqui, sem ledger, fase nem fabrica.
|
|
85
92
|
if (opcoes.dryRun) {
|
|
86
|
-
return resultado(threadId, 'registraria',
|
|
93
|
+
return resultado(threadId, 'registraria', (0, locale_1.textoDoCatalogo)((m) => m.ship.prRegistraria(merge.mergeSha.slice(0, 7))), { ...merge, ci });
|
|
87
94
|
}
|
|
88
95
|
(0, ledger_1.registrar)(dir, threadId, ledger_1.TIPOS_DE_EVENTO.shipConcluido, {
|
|
89
96
|
de: thread.base?.branch ?? null,
|
|
90
97
|
para: base,
|
|
91
98
|
shaDe: merge.headSha,
|
|
92
99
|
mergeSha: merge.mergeSha,
|
|
100
|
+
// RM-037 (fatia 5, A1): a ponta que o ls-remote provou vai em campo proprio; o recibo do Maestro confere o push
|
|
101
|
+
// contra ela quando a base andou depois do merge.
|
|
102
|
+
pontaDaBase: ponta,
|
|
93
103
|
jaIncorporado: true,
|
|
94
104
|
remoto,
|
|
95
105
|
shaRemoto: ponta,
|
|
@@ -105,7 +115,7 @@ function registrarEntregaPorPr(carregado, threadId, opcoes = {}) {
|
|
|
105
115
|
avancarParaShip(raiz, threadId);
|
|
106
116
|
if (opcoes.publicar !== false)
|
|
107
117
|
(0, fabrica_publicar_1.publicarEmSegundoPlano)(raiz);
|
|
108
|
-
return resultado(threadId, 'registrou',
|
|
118
|
+
return resultado(threadId, 'registrou', (0, locale_1.textoDoCatalogo)((m) => m.ship.prRegistrou(merge.mergeSha.slice(0, 7))), { ...merge, ci });
|
|
109
119
|
}
|
|
110
120
|
const ghApi = (caminho) => (0, util_1.exec)('gh', ['api', caminho, '-H', 'Accept: application/vnd.github+json'], process.cwd(), 120000);
|
|
111
121
|
function lerJson(r) {
|
|
@@ -130,25 +140,25 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
|
|
|
130
140
|
const gh = opcoes.executorGitHub ?? ghApi;
|
|
131
141
|
const declarados = carregado.manifesto.ci.external_repositories;
|
|
132
142
|
if (!Object.hasOwn(declarados, repo)) {
|
|
133
|
-
return resultado(threadId, 'recusada',
|
|
143
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prRepoNaoDeclarado(repo)));
|
|
134
144
|
}
|
|
135
145
|
if (!Number.isSafeInteger(n) || n < 1)
|
|
136
|
-
return resultado(threadId, 'recusada',
|
|
146
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prNumeroInvalido(String(n))));
|
|
137
147
|
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
138
148
|
if (thread.status === 'fechada')
|
|
139
|
-
return resultado(threadId, 'ja-registrada',
|
|
149
|
+
return resultado(threadId, 'ja-registrada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prThreadFechada));
|
|
140
150
|
const dir = (0, thread_1.dirThread)(raiz, threadId);
|
|
141
151
|
if ((0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido && e.repositorio === repo && e.pr === n)) {
|
|
142
|
-
return resultado(threadId, 'ja-registrada',
|
|
152
|
+
return resultado(threadId, 'ja-registrada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prExternoJaTem(n, repo)));
|
|
143
153
|
}
|
|
144
154
|
const pr = lerJson(gh(`repos/${repo}/pulls/${n}`));
|
|
145
155
|
if (!pr)
|
|
146
|
-
return resultado(threadId, 'recusada',
|
|
156
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prConsultaFalhou(n, repo)));
|
|
147
157
|
const mergeSha = typeof pr.merge_commit_sha === 'string' && /^[0-9a-f]{40}$/.test(pr.merge_commit_sha) ? pr.merge_commit_sha : null;
|
|
148
158
|
const headSha = typeof pr.head?.sha === 'string' && /^[0-9a-f]{40}$/.test(pr.head.sha) ? pr.head.sha : null;
|
|
149
159
|
const base = typeof pr.base?.ref === 'string' && /^[A-Za-z0-9._/-]{1,200}$/.test(pr.base.ref) ? pr.base.ref : null;
|
|
150
160
|
if (pr.merged !== true || !mergeSha || !headSha || !base) {
|
|
151
|
-
return resultado(threadId, 'sem-merge',
|
|
161
|
+
return resultado(threadId, 'sem-merge', (0, locale_1.textoDoCatalogo)((m) => m.ship.prNaoMesclado(n, repo)));
|
|
152
162
|
}
|
|
153
163
|
// Achado A4 do CHECK: o PR precisa ser DESTA thread e ter entrado na branch padrao do repositorio. Sem o
|
|
154
164
|
// vinculo, qualquer PR mesclado do repositorio viraria entrega de qualquer thread; sem a base, um PR
|
|
@@ -158,28 +168,28 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
|
|
|
158
168
|
// letra ou digito colado nao (outro id). Sem diferenciar maiusculas.
|
|
159
169
|
.some((x) => new RegExp(`(^|[^a-z0-9-])${threadId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![a-z0-9])`, 'i').test(x));
|
|
160
170
|
if (!vinculo) {
|
|
161
|
-
return resultado(threadId, 'recusada',
|
|
171
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prNaoCitaThread(n, repo, threadId)), { mergeSha, headSha });
|
|
162
172
|
}
|
|
163
173
|
const repositorio = lerJson(gh(`repos/${repo}`));
|
|
164
174
|
if (!repositorio)
|
|
165
|
-
return resultado(threadId, 'recusada',
|
|
175
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prRepoFalhou(repo)), { mergeSha, headSha });
|
|
166
176
|
if (repositorio.default_branch !== base) {
|
|
167
|
-
return resultado(threadId, 'recusada',
|
|
177
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prOutraBase(n, base, repo, repositorio.default_branch)), { mergeSha, headSha });
|
|
168
178
|
}
|
|
169
179
|
// A ponta da base AGORA, e o merge dentro dela: o push provado, pela mesma pergunta do ls-remote.
|
|
170
180
|
const ramo = lerJson(gh(`repos/${repo}/branches/${encodeURIComponent(base)}`));
|
|
171
181
|
const ponta = typeof ramo?.commit?.sha === 'string' && /^[0-9a-f]{40}$/.test(ramo.commit.sha) ? ramo.commit.sha : '';
|
|
172
182
|
const comparacao = ponta ? lerJson(gh(`repos/${repo}/compare/${mergeSha}...${ponta}`)) : null;
|
|
173
183
|
if (!ponta || !comparacao || !['ahead', 'identical'].includes(String(comparacao.status))) {
|
|
174
|
-
return resultado(threadId, 'recusada',
|
|
184
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prExternoForaDaPonta(mergeSha.slice(0, 7), repo, base)), { mergeSha, headSha });
|
|
175
185
|
}
|
|
176
186
|
const check = declarados[repo];
|
|
177
187
|
const ci = check ? (0, ci_1.consultarCiDoRepositorio)(repo, headSha, check, opcoes.executorCi) : null;
|
|
178
188
|
if (ci && !ci.ok) {
|
|
179
|
-
return resultado(threadId, 'recusada',
|
|
189
|
+
return resultado(threadId, 'recusada', (0, locale_1.textoDoCatalogo)((m) => m.ship.prSemCiVerde((0, locale_1.remontar)(ci.detail))), { mergeSha, headSha, ci });
|
|
180
190
|
}
|
|
181
191
|
if (opcoes.dryRun) {
|
|
182
|
-
return resultado(threadId, 'registraria',
|
|
192
|
+
return resultado(threadId, 'registraria', (0, locale_1.textoDoCatalogo)((m) => m.ship.prExternoRegistraria(mergeSha.slice(0, 7), n, repo)), { mergeSha, headSha, ci });
|
|
183
193
|
}
|
|
184
194
|
(0, ledger_1.registrar)(dir, threadId, ledger_1.TIPOS_DE_EVENTO.shipConcluido, {
|
|
185
195
|
de: thread.base?.branch ?? null,
|
|
@@ -189,6 +199,9 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
|
|
|
189
199
|
url: pr.html_url ?? `https://github.com/${repo}/pull/${n}`,
|
|
190
200
|
shaDe: headSha,
|
|
191
201
|
mergeSha,
|
|
202
|
+
// RM-037 (fatia 5, A1; aviso da rodada 1 do CHECK): a ponta conferida vai em campo proprio, como no PR local; a
|
|
203
|
+
// comparacao aceita `ahead`, e o recibo do Maestro confere o push contra ela.
|
|
204
|
+
pontaDaBase: ponta,
|
|
192
205
|
jaIncorporado: true,
|
|
193
206
|
remoto: `github:${repo}`,
|
|
194
207
|
shaRemoto: ponta,
|
|
@@ -203,13 +216,13 @@ function registrarEntregaExternaPorPr(carregado, threadId, opcoes) {
|
|
|
203
216
|
avancarParaShip(raiz, threadId);
|
|
204
217
|
if (opcoes.publicar !== false)
|
|
205
218
|
(0, fabrica_publicar_1.publicarEmSegundoPlano)(raiz);
|
|
206
|
-
return resultado(threadId, 'registrou',
|
|
219
|
+
return resultado(threadId, 'registrou', (0, locale_1.textoDoCatalogo)((m) => m.ship.prExternoRegistrou(mergeSha.slice(0, 7), n, repo)), { mergeSha, headSha, ci });
|
|
207
220
|
}
|
|
208
221
|
/** `ork ship registrar-pr --todas`: toda thread aberta que ja tem merge `ship(<thread>)` na base. */
|
|
209
222
|
function registrarEntregasPorPr(carregado, opcoes = {}) {
|
|
210
|
-
const remoto = opcoes.remoto ?? 'origin';
|
|
223
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? 'origin', 'ship');
|
|
211
224
|
const base = carregado.manifesto.worktree.base_branch;
|
|
212
|
-
(0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], carregado.raiz);
|
|
225
|
+
(0, util_1.exec)('git', ['fetch', '-q', '--', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], carregado.raiz);
|
|
213
226
|
const r = (0, thread_1.listarIds)(carregado.raiz)
|
|
214
227
|
.filter((id) => (0, thread_1.lerThread)(carregado.raiz, id).status !== 'fechada')
|
|
215
228
|
.filter((id) => mergeDaEntrega(carregado.raiz, id, remoto, base) !== null)
|
|
@@ -218,7 +231,7 @@ function registrarEntregasPorPr(carregado, opcoes = {}) {
|
|
|
218
231
|
return registrarEntregaPorPr(carregado, id, { ...opcoes, buscar: false, publicar: false });
|
|
219
232
|
}
|
|
220
233
|
catch (e) {
|
|
221
|
-
return resultado(id, 'recusada', e.message);
|
|
234
|
+
return resultado(id, 'recusada', e instanceof locale_1.ErroDoCatalogo ? (0, locale_1.textoDoCatalogo)(e.montar) : e.message);
|
|
222
235
|
}
|
|
223
236
|
});
|
|
224
237
|
// Uma publicacao so para o lote inteiro, nao uma por thread.
|
package/dist/escopo-escrita.js
CHANGED
|
@@ -60,7 +60,16 @@ function exigirEscopoDeEscrita(threads) {
|
|
|
60
60
|
/** Um nome autorizado nao pode ser alias de outra thread ou de estado externo. */
|
|
61
61
|
function validarDiretorioDeThread(raiz, id) {
|
|
62
62
|
validarThreadDeEscrita(id);
|
|
63
|
-
|
|
63
|
+
let dir;
|
|
64
|
+
// RM-047: o estadoCanonico já recusa link (estado.link); aqui a recusa mantém o código do escopo.
|
|
65
|
+
try {
|
|
66
|
+
dir = (0, estado_thread_1.estadoCanonico)(raiz, id);
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
if (e.message.startsWith('estado.link'))
|
|
70
|
+
throw new Error('scope.thread.alias');
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
64
73
|
for (const candidato of [path.dirname(path.dirname(dir)), path.dirname(dir), dir]) {
|
|
65
74
|
const stat = fs.lstatSync(candidato, { throwIfNoEntry: false });
|
|
66
75
|
if (!stat)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* RM-040 (B7): `ork accounts esgotamentos`, a medida da metrica do item.
|
|
4
|
+
*
|
|
5
|
+
* A metrica da RM-040 e "zero despacho numa conta que outro projeto do mesmo usuario ja viu
|
|
6
|
+
* esgotada, dentro do prazo dela". Este relatorio so le: as marcas do registro compartilhado
|
|
7
|
+
* (`~/.orkastery/private/contas.json`) e os `phase_dispatch` com perfil dos ledgers de cada projeto
|
|
8
|
+
* registrado nesta maquina (`~/.orkastery/projetos.json`). Conta o despacho que caiu na conta de
|
|
9
|
+
* uma marca, dentro da janela dela, vindo de projeto diferente do que marcou.
|
|
10
|
+
*
|
|
11
|
+
* A saida nunca leva diretorio de conta: a conta vira um id opaco (sha256 da chave, 12 hex), o
|
|
12
|
+
* projeto sai pelo nome registrado e o perfil, pelo id.
|
|
13
|
+
*
|
|
14
|
+
* Limite declarado: o registro so guarda as marcas vivas. Uso bem sucedido, login reconferido e
|
|
15
|
+
* prazo vencido apagam a marca na gravacao seguinte; por isso o numero e um piso, e a leitura vale
|
|
16
|
+
* enquanto a marca existe.
|
|
17
|
+
*/
|
|
18
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
21
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
22
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
23
|
+
}
|
|
24
|
+
Object.defineProperty(o, k2, desc);
|
|
25
|
+
}) : (function(o, m, k, k2) {
|
|
26
|
+
if (k2 === undefined) k2 = k;
|
|
27
|
+
o[k2] = m[k];
|
|
28
|
+
}));
|
|
29
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
30
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
31
|
+
}) : function(o, v) {
|
|
32
|
+
o["default"] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
35
|
+
var ownKeys = function(o) {
|
|
36
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
37
|
+
var ar = [];
|
|
38
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
39
|
+
return ar;
|
|
40
|
+
};
|
|
41
|
+
return ownKeys(o);
|
|
42
|
+
};
|
|
43
|
+
return function (mod) {
|
|
44
|
+
if (mod && mod.__esModule) return mod;
|
|
45
|
+
var result = {};
|
|
46
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
47
|
+
__setModuleDefault(result, mod);
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
})();
|
|
51
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.NAO_REGISTRADO = exports.LIMITE_DO_RELATORIO = exports.CONTRATO_ESGOTAMENTOS = void 0;
|
|
53
|
+
exports.contaOpaca = contaOpaca;
|
|
54
|
+
exports.fimDaJanela = fimDaJanela;
|
|
55
|
+
exports.relatorioDeEsgotamentos = relatorioDeEsgotamentos;
|
|
56
|
+
exports.textoDosEsgotamentos = textoDosEsgotamentos;
|
|
57
|
+
const node_crypto_1 = require("node:crypto");
|
|
58
|
+
const fs = __importStar(require("node:fs"));
|
|
59
|
+
const horario_1 = require("./horario");
|
|
60
|
+
const ledger_1 = require("./ledger");
|
|
61
|
+
const ledger_stats_1 = require("./ledger-stats");
|
|
62
|
+
const projeto_alvo_1 = require("./projeto-alvo");
|
|
63
|
+
const runtime_profiles_1 = require("./runtime-profiles");
|
|
64
|
+
const thread_1 = require("./thread");
|
|
65
|
+
const util_1 = require("./util");
|
|
66
|
+
exports.CONTRATO_ESGOTAMENTOS = 'ork.esgotamentos/v1';
|
|
67
|
+
exports.LIMITE_DO_RELATORIO = 'o registro guarda so as marcas vivas (uso bem sucedido, login reconferido e prazo vencido ' +
|
|
68
|
+
'apagam a marca): o total e um piso, valido enquanto a marca existe';
|
|
69
|
+
exports.NAO_REGISTRADO = 'nao registrado';
|
|
70
|
+
function contaOpaca(chave) {
|
|
71
|
+
return (0, node_crypto_1.createHash)('sha256').update(chave).digest('hex').slice(0, 12);
|
|
72
|
+
}
|
|
73
|
+
function caminhoReal(p) {
|
|
74
|
+
try {
|
|
75
|
+
return fs.realpathSync(p);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return p;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Fim da janela da marca: o prazo para cota esgotada; sem prazo (login, credencial paga), aberta. */
|
|
82
|
+
function fimDaJanela(m) {
|
|
83
|
+
if (m.estado !== 'esgotado')
|
|
84
|
+
return Number.POSITIVE_INFINITY;
|
|
85
|
+
const ate = m.esgotadoAte === null ? NaN : Date.parse(m.esgotadoAte);
|
|
86
|
+
return Number.isFinite(ate) ? ate : Number.NEGATIVE_INFINITY;
|
|
87
|
+
}
|
|
88
|
+
function relatorioDeEsgotamentos(opcoes = {}) {
|
|
89
|
+
const agoraMs = opcoes.agoraMs ?? Date.now();
|
|
90
|
+
const desdeMs = (0, ledger_stats_1.parsePeriodo)(opcoes.desde ?? '7d', agoraMs);
|
|
91
|
+
if (desdeMs >= agoraMs)
|
|
92
|
+
throw Error('ledger.period.order');
|
|
93
|
+
// Um projeto por raiz real: o registro pode trazer a mesma copia por dois caminhos.
|
|
94
|
+
const vistos = new Set();
|
|
95
|
+
const projetos = (0, projeto_alvo_1.listarProjetos)().filter((p) => {
|
|
96
|
+
const real = caminhoReal(p.raiz);
|
|
97
|
+
if (vistos.has(real))
|
|
98
|
+
return false;
|
|
99
|
+
vistos.add(real);
|
|
100
|
+
return true;
|
|
101
|
+
}).map((p) => ({ ...p, real: caminhoReal(p.raiz) }));
|
|
102
|
+
const nomeDaRaiz = (raiz) => projetos.find((p) => p.real === caminhoReal(raiz))?.nome ?? exports.NAO_REGISTRADO;
|
|
103
|
+
const contas = (0, runtime_profiles_1.lerContasCompartilhadas)();
|
|
104
|
+
const marcas = contas.map((c) => ({ c, real: caminhoReal(c.projeto), inicio: Date.parse(c.em), fim: fimDaJanela(c) }));
|
|
105
|
+
const despachos = [];
|
|
106
|
+
const lidos = [];
|
|
107
|
+
for (const p of projetos) {
|
|
108
|
+
let comPerfil = 0;
|
|
109
|
+
let ids = [];
|
|
110
|
+
try {
|
|
111
|
+
ids = p.presente ? (0, thread_1.listarIds)(p.raiz) : [];
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
ids = [];
|
|
115
|
+
}
|
|
116
|
+
for (const id of ids) {
|
|
117
|
+
let eventos = [];
|
|
118
|
+
try {
|
|
119
|
+
eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(p.raiz, id));
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
for (const e of eventos) {
|
|
125
|
+
if (e.tipo !== 'phase_dispatch' || e.perfil === undefined || e.perfil === null)
|
|
126
|
+
continue;
|
|
127
|
+
const t = Date.parse(String(e.ts));
|
|
128
|
+
if (!Number.isFinite(t) || t < desdeMs || t >= agoraMs)
|
|
129
|
+
continue;
|
|
130
|
+
let perfil, chave;
|
|
131
|
+
try {
|
|
132
|
+
perfil = (0, runtime_profiles_1.validarPerfilDeDespacho)(e.perfil);
|
|
133
|
+
chave = (0, runtime_profiles_1.chaveDaConta)(perfil);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
comPerfil++;
|
|
139
|
+
const marca = marcas.find((m) => m.c.chave === chave && m.real !== p.real && t >= m.inicio && t < m.fim);
|
|
140
|
+
if (!marca)
|
|
141
|
+
continue;
|
|
142
|
+
despachos.push({ em: new Date(t).toISOString(), projeto: p.nome, thread: String(e.thread ?? id),
|
|
143
|
+
fase: typeof e.fase === 'string' ? e.fase : null, runtime: perfil.runtime, perfil: perfil.id,
|
|
144
|
+
conta: contaOpaca(chave), marcadaPor: nomeDaRaiz(marca.c.projeto) });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
lidos.push({ nome: p.nome, presente: p.presente, despachosComPerfil: comPerfil });
|
|
148
|
+
}
|
|
149
|
+
despachos.sort((a, b) => a.em.localeCompare(b.em));
|
|
150
|
+
return {
|
|
151
|
+
contrato: exports.CONTRATO_ESGOTAMENTOS,
|
|
152
|
+
periodo: { desde: new Date(desdeMs).toISOString(), ate: new Date(agoraMs).toISOString(), intervalo: '[desde,ate)' },
|
|
153
|
+
marcas: contas.map((c) => ({ conta: contaOpaca(c.chave), runtime: c.chave.slice(0, c.chave.indexOf(':')), estado: c.estado,
|
|
154
|
+
motivo: c.motivo, em: c.em, esgotadoAte: c.esgotadoAte, projeto: nomeDaRaiz(c.projeto) })),
|
|
155
|
+
projetos: lidos,
|
|
156
|
+
despachos,
|
|
157
|
+
total: despachos.length,
|
|
158
|
+
limite: exports.LIMITE_DO_RELATORIO,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/** Texto para o terminal, com o horario do dono e o fuso uma vez no fim. */
|
|
162
|
+
function textoDosEsgotamentos(r) {
|
|
163
|
+
const linhas = [
|
|
164
|
+
`Esgotamentos de conta ${(0, horario_1.formatarDataHora)(r.periodo.desde)} ate ${(0, horario_1.formatarDataHora)(r.periodo.ate)} ${r.periodo.intervalo}`,
|
|
165
|
+
` marcas vivas no registro: ${r.marcas.length}`,
|
|
166
|
+
];
|
|
167
|
+
for (const m of r.marcas) {
|
|
168
|
+
const ate = m.estado === 'esgotado' ? `ate ${(0, horario_1.formatarDataHora)(m.esgotadoAte)}` : 'sem prazo';
|
|
169
|
+
linhas.push(` conta ${m.conta} ${m.runtime} ${m.estado} desde ${(0, horario_1.formatarDataHora)(m.em)}, ${ate} visto em ${m.projeto} (${m.motivo})`);
|
|
170
|
+
}
|
|
171
|
+
linhas.push(` projetos lidos: ${r.projetos.length === 0 ? 'nenhum registrado'
|
|
172
|
+
: r.projetos.map((p) => `${p.nome} (${p.presente ? `${p.despachosComPerfil} despacho(s) com perfil` : 'fora do disco'})`).join(', ')}`);
|
|
173
|
+
linhas.push(` despachos em conta marcada por outro projeto: ${r.total}`);
|
|
174
|
+
if (r.despachos.length > 0) {
|
|
175
|
+
linhas.push((0, util_1.tabela)(['QUANDO', 'PROJETO', 'THREAD', 'FASE', 'PERFIL', 'CONTA', 'MARCADA POR'], r.despachos.map((d) => [(0, horario_1.formatarDataHora)(d.em), d.projeto, d.thread, d.fase ?? '-', d.perfil, d.conta, d.marcadaPor]))
|
|
176
|
+
.split('\n').map((l) => ` ${l}`).join('\n'));
|
|
177
|
+
}
|
|
178
|
+
linhas.push(` limite: ${r.limite}`);
|
|
179
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
180
|
+
return linhas.join('\n');
|
|
181
|
+
}
|
package/dist/estado-thread.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.raizDoEstado = raizDoEstado;
|
|
37
37
|
exports.estadoCanonico = estadoCanonico;
|
|
38
|
+
exports.exigirEstadoSemLink = exigirEstadoSemLink;
|
|
38
39
|
exports.vincularEstado = vincularEstado;
|
|
39
40
|
exports.comEstadoParaGit = comEstadoParaGit;
|
|
40
41
|
exports.auditarEstado = auditarEstado;
|
|
@@ -66,7 +67,28 @@ function raizDoEstado(raiz) {
|
|
|
66
67
|
function estadoCanonico(raiz, id) {
|
|
67
68
|
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(id))
|
|
68
69
|
throw new Error('id de thread inválido');
|
|
69
|
-
|
|
70
|
+
const principal = raizDoEstado(raiz);
|
|
71
|
+
exigirEstadoSemLink(principal, ['.orkastery', 'threads', id]);
|
|
72
|
+
return path.join(principal, '.orkastery', 'threads', id);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* RM-047 (fronteira de confiança): na árvore principal, `.orkastery`, `threads` e o diretório da thread
|
|
76
|
+
* são pastas de verdade. Um link versionado no clone levaria ledger, claims e thread.json para fora da
|
|
77
|
+
* raiz, e o `ork` anexaria linhas em arquivo alheio. O link que o próprio `ork` cria fica na worktree
|
|
78
|
+
* (`vincularEstado`) e aponta para cá; ele nunca é um destes componentes.
|
|
79
|
+
*/
|
|
80
|
+
function exigirEstadoSemLink(principal, componentes) {
|
|
81
|
+
let atual = principal;
|
|
82
|
+
for (const nome of componentes) {
|
|
83
|
+
atual = path.join(atual, nome);
|
|
84
|
+
const stat = fs.lstatSync(atual, { throwIfNoEntry: false });
|
|
85
|
+
if (!stat)
|
|
86
|
+
return;
|
|
87
|
+
if (stat.isSymbolicLink()) {
|
|
88
|
+
throw new Error(`estado.link: ${path.relative(principal, atual)} é link simbólico; o estado do ork fica em ` +
|
|
89
|
+
'pastas de verdade dentro da raiz (um link versionado levaria a escrita para fora dela). Remova o link.');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
70
92
|
}
|
|
71
93
|
function mesmoArquivo(a, b) {
|
|
72
94
|
return fs.existsSync(a) && fs.existsSync(b) && fs.realpathSync(a) === fs.realpathSync(b);
|
|
@@ -41,10 +41,14 @@ exports.aplicarExperiencia = aplicarExperiencia;
|
|
|
41
41
|
const fs = __importStar(require("node:fs"));
|
|
42
42
|
const path = __importStar(require("node:path"));
|
|
43
43
|
const node_crypto_1 = require("node:crypto");
|
|
44
|
+
const locale_1 = require("./locale");
|
|
44
45
|
exports.INICIO_EXPERIENCIA = '<!-- orkastery:experiencia:begin -->';
|
|
45
46
|
exports.FIM_EXPERIENCIA = '<!-- orkastery:experiencia:end -->';
|
|
46
47
|
const CONTRATO = 'ork.experiencia-install/v1';
|
|
47
|
-
|
|
48
|
+
/** RM-061 (F3a, D8): as linguas em que o bloco e escrito e, sem recibo, reconhecido. */
|
|
49
|
+
const LOCALES_DO_BLOCO = ['pt-BR', 'en'];
|
|
50
|
+
/** Marca do diretorio no molde da linha: o texto antes e depois dela reconhece a linha em cada lingua. */
|
|
51
|
+
const MARCA_DO_DIRETORIO = '{{diretorio}}';
|
|
48
52
|
const conflito = () => { throw Error('experiencia.bloco.conflict: bloco ou recibo alterado/duplicado; preserve os arquivos e revise a instalação'); };
|
|
49
53
|
/** Recusa symlinks e hardlinks em qualquer componente antes da leitura/escrita. */
|
|
50
54
|
function caminhoSeguro(projeto, arquivo) {
|
|
@@ -83,18 +87,35 @@ function decodificar(s) {
|
|
|
83
87
|
return b;
|
|
84
88
|
}
|
|
85
89
|
const eolDe = (b) => b.includes('\r\n') ? '\r\n' : '\n';
|
|
86
|
-
/**
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
/**
|
|
91
|
+
* O caminho vai relativo ao projeto: o arquivo de instruções costuma ser versionado. RM-061 (F3a, D1 e D2): o texto
|
|
92
|
+
* sai na língua pedida, pela família `gerados` do catálogo; os marcadores são os mesmos nas duas línguas.
|
|
93
|
+
*/
|
|
94
|
+
function nucleoDoBloco(skill, eol, locale) {
|
|
95
|
+
const t = (0, locale_1.msg)(locale).gerados.experiencia;
|
|
96
|
+
return Buffer.from([exports.INICIO_EXPERIENCIA, `## ${t.titulo}`, t.consulte, t.diretorio(JSON.stringify(skill)), t.preferencias,
|
|
93
97
|
exports.FIM_EXPERIENCIA, ''].join(eol));
|
|
94
98
|
}
|
|
99
|
+
/** O diretório escrito na linha do bloco de uma língua, ou null se a linha não é a dessa língua. */
|
|
100
|
+
function diretorioDaLinha(linha, locale) {
|
|
101
|
+
const molde = (0, locale_1.msg)(locale).gerados.experiencia.diretorio(MARCA_DO_DIRETORIO);
|
|
102
|
+
const corte = molde.indexOf(MARCA_DO_DIRETORIO);
|
|
103
|
+
const antes = molde.slice(0, corte), depois = molde.slice(corte + MARCA_DO_DIRETORIO.length);
|
|
104
|
+
if (linha.length < antes.length + depois.length || !linha.startsWith(antes) || !linha.endsWith(depois))
|
|
105
|
+
return null;
|
|
106
|
+
let skill;
|
|
107
|
+
try {
|
|
108
|
+
skill = JSON.parse(linha.slice(antes.length, linha.length - depois.length));
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
return typeof skill === 'string' && !/[\r\n`]/.test(skill) ? skill : null;
|
|
114
|
+
}
|
|
95
115
|
/**
|
|
96
116
|
* Bloco sem recibo (clone novo, `.orkastery/` apagado) só é adotado quando é exatamente o texto
|
|
97
|
-
* que esta versão ou a anterior geram, com qualquer diretório
|
|
117
|
+
* que esta versão ou a anterior geram, com qualquer diretório e em qualquer das duas línguas (RM-061,
|
|
118
|
+
* F3a, D8); qualquer outra edição é conflito.
|
|
98
119
|
*/
|
|
99
120
|
function reconhecerBloco(antes) {
|
|
100
121
|
if (contar(antes, exports.INICIO_EXPERIENCIA) !== 1 || contar(antes, exports.FIM_EXPERIENCIA) !== 1)
|
|
@@ -108,18 +129,14 @@ function reconhecerBloco(antes) {
|
|
|
108
129
|
fim += eol.length;
|
|
109
130
|
const texto = antes.subarray(inicio, fim);
|
|
110
131
|
const linha = texto.toString('utf8').split(eol)[3] ?? '';
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (typeof skill !== 'string' || /[\r\n`]/.test(skill))
|
|
120
|
-
return null;
|
|
121
|
-
const esperado = nucleoDoBloco(skill, eol);
|
|
122
|
-
if (!texto.equals(esperado) && !texto.equals(esperado.subarray(0, esperado.length - eol.length)))
|
|
132
|
+
const reconhecido = LOCALES_DO_BLOCO.some((locale) => {
|
|
133
|
+
const skill = diretorioDaLinha(linha, locale);
|
|
134
|
+
if (skill === null)
|
|
135
|
+
return false;
|
|
136
|
+
const esperado = nucleoDoBloco(skill, eol, locale);
|
|
137
|
+
return texto.equals(esperado) || texto.equals(esperado.subarray(0, esperado.length - eol.length));
|
|
138
|
+
});
|
|
139
|
+
if (!reconhecido)
|
|
123
140
|
return null;
|
|
124
141
|
// Uma linha em branco antes do bloco é o separador que a instalação põe depois de uma linha.
|
|
125
142
|
const sep = Buffer.from(eol);
|
|
@@ -144,8 +161,11 @@ function removerBloco(antes, bloco) {
|
|
|
144
161
|
const juncao = prefixo.length && prefixo.at(-1) !== 10 && sufixo.length ? Buffer.from(bloco.eol) : Buffer.alloc(0);
|
|
145
162
|
return Buffer.concat([prefixo, juncao, sufixo]);
|
|
146
163
|
}
|
|
147
|
-
/**
|
|
148
|
-
|
|
164
|
+
/**
|
|
165
|
+
* Planejamento puro em relação ao disco: dry-run e preflight usam o mesmo contrato. O bloco sai no `locale` pedido
|
|
166
|
+
* (RM-061, F3a), pt-BR por omissão: só o `ork adapter install` passa a língua do dono (D2).
|
|
167
|
+
*/
|
|
168
|
+
function planejarExperiencia(projeto, host, skill, locale = locale_1.LOCALE_PADRAO) {
|
|
149
169
|
projeto = fs.realpathSync(path.resolve(projeto));
|
|
150
170
|
if (!['claude-code', 'codex'].includes(host))
|
|
151
171
|
throw Error('experiencia.host.unsupported');
|
|
@@ -189,7 +209,7 @@ function planejarExperiencia(projeto, host, skill) {
|
|
|
189
209
|
let separador, nucleo, anterior;
|
|
190
210
|
if (antes && bloco) {
|
|
191
211
|
// Atualização no lugar: o que está antes e depois do bloco, inclusive edição externa, fica.
|
|
192
|
-
nucleo = nucleoDoBloco(skill, bloco.eol);
|
|
212
|
+
nucleo = nucleoDoBloco(skill, bloco.eol, locale);
|
|
193
213
|
separador = bloco.separador;
|
|
194
214
|
depois = Buffer.concat([antes.subarray(0, bloco.inicio), nucleo, antes.subarray(bloco.fim)]);
|
|
195
215
|
// Adotado sem recibo: se só havia o bloco, o arquivo conta como criado pelo pacote.
|
|
@@ -198,7 +218,7 @@ function planejarExperiencia(projeto, host, skill) {
|
|
|
198
218
|
}
|
|
199
219
|
else {
|
|
200
220
|
const base = antes ?? Buffer.alloc(0), eol = eolDe(base);
|
|
201
|
-
nucleo = nucleoDoBloco(skill, eol);
|
|
221
|
+
nucleo = nucleoDoBloco(skill, eol, locale);
|
|
202
222
|
separador = Buffer.from(base.length ? (base.at(-1) === 10 ? eol : eol + eol) : '');
|
|
203
223
|
depois = Buffer.concat([base, separador, nucleo]);
|
|
204
224
|
anterior = antes?.toString('base64') ?? null;
|
package/dist/experiencia.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IDIOMA_PADRAO = void 0;
|
|
3
4
|
exports.normalizarIdioma = normalizarIdioma;
|
|
4
5
|
exports.validarPreferencias = validarPreferencias;
|
|
5
6
|
exports.idiomaDoSistema = idiomaDoSistema;
|
|
@@ -44,6 +45,11 @@ function validarPreferencias(valor) {
|
|
|
44
45
|
}
|
|
45
46
|
return resultado;
|
|
46
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Ensaio de 03/10 (R2): sem idioma escolhido, vale a língua da CLI. Antes era en-US, e uma máquina com
|
|
50
|
+
* LANG=C.UTF-8 (contêiner, CI, servidor) recebia a experiência em inglês de uma CLI que fala português.
|
|
51
|
+
*/
|
|
52
|
+
exports.IDIOMA_PADRAO = 'pt-BR';
|
|
47
53
|
/** C, POSIX e und (raiz do ICU) dizem que o sistema não escolheu idioma: vale o padrão. */
|
|
48
54
|
const SEM_IDIOMA = new Set(['c', 'posix', 'und']);
|
|
49
55
|
function idiomaEscolhido(valor) {
|
|
@@ -52,11 +58,15 @@ function idiomaEscolhido(valor) {
|
|
|
52
58
|
}
|
|
53
59
|
function idiomaDoSistema(env = process.env, doIntl = () => Intl.DateTimeFormat().resolvedOptions().locale) {
|
|
54
60
|
const locale = env.LC_ALL || env.LC_MESSAGES || env.LANG;
|
|
55
|
-
|
|
61
|
+
if (locale) {
|
|
62
|
+
// Com C ou POSIX explícito, o Intl do Node cai no en-US do ICU: ele não diz a escolha de ninguém.
|
|
63
|
+
return idiomaEscolhido(locale.split(/[.@]/)[0].replace(/_/g, '-')) ?? exports.IDIOMA_PADRAO;
|
|
64
|
+
}
|
|
65
|
+
return idiomaEscolhido(doIntl()) ?? exports.IDIOMA_PADRAO;
|
|
56
66
|
}
|
|
57
67
|
function resolverExperiencia(owner = {}, sistema = { language: idiomaDoSistema(), timezone: (0, horario_1.fusoDoSistema)() }) {
|
|
58
68
|
const p = validarPreferencias(owner);
|
|
59
|
-
const language = p.language ?? normalizarIdioma(sistema.language) ??
|
|
69
|
+
const language = p.language ?? normalizarIdioma(sistema.language) ?? exports.IDIOMA_PADRAO;
|
|
60
70
|
return {
|
|
61
71
|
language, timezone: p.timezone ?? (0, horario_1.normalizarFuso)(sistema.timezone) ?? 'UTC',
|
|
62
72
|
depth: p.depth ?? 'curta', experience: p.experience ?? true,
|