@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
|
@@ -33,17 +33,24 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.LIMITE_DE_RECENTES = exports.LIMITE_DE_PRS = exports.VALIDADE_DO_RETRATO_MIN = exports.LIMIAR_PARADO_NO_CONDUTOR_MIN = exports.CONTRATO_PRS = void 0;
|
|
36
|
+
exports.CONTRATO_FORJA_SEM_LEITURA = exports.ghPadrao = exports.FORJA_SEM_LEITURA = exports.LIMITE_DE_RECENTES = exports.LIMITE_DE_PRS = exports.VALIDADE_DO_RETRATO_MIN = exports.LIMIAR_PARADO_NO_CONDUTOR_MIN = exports.CONTRATO_PRS = void 0;
|
|
37
37
|
exports.nomeDeCheck = nomeDeCheck;
|
|
38
|
+
exports.prDaForja = prDaForja;
|
|
39
|
+
exports.githubDoRemoto = githubDoRemoto;
|
|
38
40
|
exports.repositorioDoRemoto = repositorioDoRemoto;
|
|
39
41
|
exports.lerPrsDaForja = lerPrsDaForja;
|
|
40
42
|
exports.gravarRetratoDePrs = gravarRetratoDePrs;
|
|
43
|
+
exports.avisarForjaSemLeitura = avisarForjaSemLeitura;
|
|
44
|
+
exports.esquecerForjaSemLeitura = esquecerForjaSemLeitura;
|
|
45
|
+
exports.forjaSemLeituraDoRemoto = forjaSemLeituraDoRemoto;
|
|
41
46
|
exports.lerRetratoDePrs = lerRetratoDePrs;
|
|
42
47
|
exports.perguntaAberta = perguntaAberta;
|
|
43
48
|
exports.fimDoTurno = fimDoTurno;
|
|
44
49
|
exports.pendenciaDoDono = pendenciaDoDono;
|
|
50
|
+
exports.conducaoAgora = conducaoAgora;
|
|
45
51
|
exports.esperaDoCondutor = esperaDoCondutor;
|
|
46
52
|
exports.sessaoSemPergunta = sessaoSemPergunta;
|
|
53
|
+
exports.refsLocais = refsLocais;
|
|
47
54
|
exports.entregasDoProjeto = entregasDoProjeto;
|
|
48
55
|
/**
|
|
49
56
|
* RM-037 (fatia 4): o trabalho parado no condutor.
|
|
@@ -72,6 +79,7 @@ exports.entregasDoProjeto = entregasDoProjeto;
|
|
|
72
79
|
const fs = __importStar(require("node:fs"));
|
|
73
80
|
const path = __importStar(require("node:path"));
|
|
74
81
|
const node_child_process_1 = require("node:child_process");
|
|
82
|
+
const branch_de_estado_1 = require("./branch-de-estado");
|
|
75
83
|
const conducao_1 = require("./conducao");
|
|
76
84
|
const estado_thread_1 = require("./estado-thread");
|
|
77
85
|
const forja_1 = require("./forja");
|
|
@@ -102,7 +110,8 @@ const PRAZO_DO_GH_MS = 30000;
|
|
|
102
110
|
/** A leitura inteira da forja numa batida: cabe com folga nos 240 s que a varredura da ao subprocesso do pulse. */
|
|
103
111
|
const ORCAMENTO_DA_LEITURA_MS = 60000;
|
|
104
112
|
const CAMPOS_DOS_RECENTES = 'number,state,headRefName,headRefOid,baseRefName,isDraft,isCrossRepository,url,createdAt,mergedAt';
|
|
105
|
-
|
|
113
|
+
/** RM-059 (F7, D11 da ork-rm059pista): o estado de merge do PR aberto, que a pista de entrega mostra como conflito. */
|
|
114
|
+
const CAMPOS_DO_GH = `${CAMPOS_DOS_RECENTES},statusCheckRollup,mergeable`;
|
|
106
115
|
/** Quantas branches candidatas a "sem PR" sao conferidas uma a uma por batida; o resto fica "PR nao lido". */
|
|
107
116
|
const LIMITE_DE_CANDIDATAS = 10;
|
|
108
117
|
/** A conferencia de uma candidata so comeca com este tempo de sobra no orcamento; com menos, a branch fica sem conferir. */
|
|
@@ -111,6 +120,8 @@ const MINIMO_DA_CONFERENCIA_MS = 5000;
|
|
|
111
120
|
const FASES_ANTES_DA_ENTREGA = ['GOAL', 'PLAN', 'GO', 'CHECK'];
|
|
112
121
|
/** Os modos em que a #TAG ja autoriza o push (`autorizacaoDePush`, `core/src/ship.ts`). */
|
|
113
122
|
const MODOS_COM_PUSH_AUTORIZADO = ['auto', 'maestro'];
|
|
123
|
+
/** RM-037 (fatia 5, A5): o que as linhas e o resumo dizem quando a forja nao tem leitura de PR. */
|
|
124
|
+
exports.FORJA_SEM_LEITURA = 'forja sem leitura de PR';
|
|
114
125
|
/** O ambiente do `gh`: sem cor, sem prompt e sem host ou repositorio herdados (o host vai no `--repo`). */
|
|
115
126
|
function ambienteDoGh() {
|
|
116
127
|
const env = { ...process.env, GH_PROMPT_DISABLED: '1', NO_COLOR: '1', CLICOLOR: '0', CLICOLOR_FORCE: '0' };
|
|
@@ -123,11 +134,14 @@ const ghPadrao = (args, timeoutMs) => {
|
|
|
123
134
|
const r = (0, node_child_process_1.spawnSync)('gh', [...args], { encoding: 'utf8', timeout: timeoutMs, maxBuffer: 16 * 1024 * 1024, env: ambienteDoGh() });
|
|
124
135
|
return { status: r.status, stdout: r.stdout ?? '', stderr: r.error ? r.error.message : (r.stderr ?? '') };
|
|
125
136
|
};
|
|
137
|
+
exports.ghPadrao = ghPadrao;
|
|
126
138
|
/** Git local sem rede escondida: clone parcial nunca busca objeto durante uma leitura daqui. */
|
|
127
139
|
const git = (raiz, args) => (0, util_1.exec)('git', args, raiz, 60000, { ...process.env, GIT_NO_LAZY_FETCH: '1' });
|
|
128
140
|
const SHA = /^[0-9a-f]{40}$/;
|
|
129
141
|
const BRANCH = /^[A-Za-z0-9._/-]{1,200}$/;
|
|
130
142
|
const REPOSITORIO = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
143
|
+
/** O host do GitHub Enterprise guardado no retrato: rotulos alfanumericos separados por ponto, como na forja. */
|
|
144
|
+
const HOST = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/;
|
|
131
145
|
/** Texto curto vindo de fora: sem controle, num teto. */
|
|
132
146
|
function curto(v, teto = 120) {
|
|
133
147
|
if (typeof v !== 'string')
|
|
@@ -212,33 +226,95 @@ function prDaForja(bruto, base) {
|
|
|
212
226
|
}
|
|
213
227
|
}
|
|
214
228
|
const url = typeof p.url === 'string' && /^https:\/\/[^\s]+$/.test(p.url) ? curto(p.url, 300) : null;
|
|
229
|
+
// RM-059 (F7): o estado de merge so vale do PR aberto, e so quando a leitura pediu o campo.
|
|
230
|
+
const conflito = estado !== 'aberto' || p.mergeable === undefined ? undefined
|
|
231
|
+
: p.mergeable === 'CONFLICTING' ? true : p.mergeable === 'MERGEABLE' ? false : null;
|
|
215
232
|
return { numero: numero, branch: p.headRefName, head, estado, rascunho: p.isDraft, url,
|
|
216
|
-
criadoEm: instante(p.createdAt), mescladoEm: instante(p.mergedAt), checks: [...porChave.values()].map((x) => x.check)
|
|
233
|
+
criadoEm: instante(p.createdAt), mescladoEm: instante(p.mergedAt), checks: [...porChave.values()].map((x) => x.check),
|
|
234
|
+
...(conflito !== undefined ? { conflito } : {}) };
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* RM-037 (fatia 5, A5): o host e o `dono/nome` do remoto quando ele pode ser um GitHub (o github.com ou um host
|
|
238
|
+
* proprio), so pelo git local, sem rede nem `gh`. O GitLab fica de fora.
|
|
239
|
+
*/
|
|
240
|
+
function githubDoRemoto(raiz, remoto) {
|
|
241
|
+
// RM-047: o remoto vem do manifesto versionado; so nome de remoto chega ao git, e depois do `--`.
|
|
242
|
+
if (!(0, branch_de_estado_1.remotoValido)(remoto))
|
|
243
|
+
return null;
|
|
244
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
245
|
+
const forja = url.ok ? (0, forja_1.repositorioGithubNoHost)(url.stdout.trim()) : null;
|
|
246
|
+
// `ssh.github.com` e o SSH do github.com pela porta 443, e nao um GitHub Enterprise (sugestao da rodada 1 do CHECK).
|
|
247
|
+
return forja && REPOSITORIO.test(forja.repo) ? { host: forja.host === 'ssh.github.com' ? 'github.com' : forja.host, repositorio: forja.repo }
|
|
248
|
+
: null;
|
|
217
249
|
}
|
|
218
250
|
/** O repositorio `dono/nome` do remoto, so quando ele e do github.com (o host ancorado, nao so citado no caminho). */
|
|
219
251
|
function repositorioDoRemoto(raiz, remoto) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
252
|
+
const github = githubDoRemoto(raiz, remoto);
|
|
253
|
+
return github && github.host === 'github.com' ? github.repositorio : null;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* RM-037 (fatia 5, A5): de onde o pulse le os PRs do remoto. O github.com, como sempre; o host proprio em que o `gh`
|
|
257
|
+
* esta autenticado, que e um GitHub Enterprise (`gh auth status --hostname <host>`); ou nenhum: GitLab, caminho local,
|
|
258
|
+
* ou host em que o `gh` nao tem login. Ficar sem leitura nao e falha desta batida (o "PR nao lido"): e o estado da
|
|
259
|
+
* forja, que o pulse diz uma vez.
|
|
260
|
+
*/
|
|
261
|
+
function forjaDosPrs(raiz, remoto, executor, prazoMs) {
|
|
262
|
+
// RM-047: remoto que nao e nome de remoto nao chega ao git; para o pulse, e forja sem leitura.
|
|
263
|
+
if (!(0, branch_de_estado_1.remotoValido)(remoto)) {
|
|
264
|
+
return { leitura: false, host: null, motivo: `o remoto ${(0, branch_de_estado_1.remotoRedigido)(remoto)} não é nome de remoto do git`, semLeitura: true };
|
|
265
|
+
}
|
|
266
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
267
|
+
if (!url.ok)
|
|
268
|
+
return { leitura: false, host: null, motivo: `o remoto ${remoto} não está configurado neste checkout`, semLeitura: true };
|
|
269
|
+
const endereco = (0, forja_1.enderecoDoRemoto)(url.stdout.trim());
|
|
270
|
+
// Caminho local, ou apelido de SSH sem dominio (`git@github-trabalho:dono/repo.git`): nao ha host para ler.
|
|
271
|
+
if (!endereco) {
|
|
272
|
+
return { leitura: false, host: null, motivo: `o remoto ${remoto} não tem host de forja (caminho local ou apelido de SSH)`, semLeitura: true };
|
|
273
|
+
}
|
|
274
|
+
if ((0, forja_1.identidadeDaForja)(url.stdout.trim())?.tipo === 'gitlab') {
|
|
275
|
+
return { leitura: false, host: endereco.host, motivo: `a forja de ${remoto} (${endereco.host}) é um GitLab, e o ork só lê PR do GitHub`,
|
|
276
|
+
semLeitura: true };
|
|
277
|
+
}
|
|
278
|
+
const github = githubDoRemoto(raiz, remoto);
|
|
279
|
+
if (!github) {
|
|
280
|
+
return { leitura: false, host: endereco.host, motivo: `o remoto ${remoto} (${endereco.host}) não aponta um repositório dono/nome`,
|
|
281
|
+
semLeitura: true };
|
|
282
|
+
}
|
|
283
|
+
if (github.host === 'github.com')
|
|
284
|
+
return { leitura: true, ...github };
|
|
285
|
+
const auth = executor(['auth', 'status', '--hostname', github.host], prazoMs);
|
|
286
|
+
if (auth.status === 0)
|
|
287
|
+
return { leitura: true, ...github };
|
|
288
|
+
// So a resposta de login ausente (o `gh` 2.46 diz "You are not logged into any accounts on <host>") e o estado da
|
|
289
|
+
// forja; prazo estourado, `gh` ausente ou host fora do ar sao falha desta batida.
|
|
290
|
+
const semLogin = auth.status === 1 && /\bnot logged in/i.test(`${auth.stdout}\n${auth.stderr}`);
|
|
291
|
+
return { leitura: false, host: github.host, semLeitura: semLogin, motivo: semLogin
|
|
292
|
+
? `o gh não está autenticado em ${github.host}, a forja de ${remoto}`
|
|
293
|
+
: `gh auth status --hostname ${github.host} falhou (${auth.status === null ? 'sem código de saída' : `código ${auth.status}`}): ` +
|
|
294
|
+
(curto((0, hitl_1.redigirSegredos)(auth.stderr || auth.stdout || ''), 120) ?? 'sem detalhe') };
|
|
223
295
|
}
|
|
224
296
|
/**
|
|
225
297
|
* Le os PRs da base do repositorio do remoto em duas chamadas: os abertos (ate `LIMITE_DE_PRS`; e so a
|
|
226
298
|
* lista deles que pode dizer "sem PR") e os recentes de qualquer estado (para achar o mesclado e o fechado).
|
|
227
|
-
* O `gh` usa a autenticacao dele; nenhum token passa por aqui.
|
|
299
|
+
* O `gh` usa a autenticacao dele; nenhum token passa por aqui. RM-037 (fatia 5, A5): no GitHub Enterprise, o host
|
|
300
|
+
* vai no `--repo`; forja sem leitura de PR nao chama o `gh pr list`.
|
|
228
301
|
*/
|
|
229
302
|
function lerPrsDaForja(carregado, opcoes = {}) {
|
|
230
303
|
const lidoEm = opcoes.quando ?? new Date().toISOString();
|
|
231
304
|
const remoto = opcoes.remoto ?? carregado.manifesto.fabrica.remoto;
|
|
232
305
|
const base = carregado.manifesto.worktree.base_branch;
|
|
233
|
-
const repositorio = repositorioDoRemoto(carregado.raiz, remoto);
|
|
234
|
-
if (!repositorio)
|
|
235
|
-
return { ok: false, lidoEm, erro: `o remoto ${remoto} não é um repositório do github.com` };
|
|
236
306
|
const orcamento = opcoes.orcamentoMs ?? ORCAMENTO_DA_LEITURA_MS, fimDaLeitura = Date.now() + orcamento;
|
|
237
307
|
const resta = () => fimDaLeitura - Date.now();
|
|
308
|
+
const executor = opcoes.executor ?? exports.ghPadrao;
|
|
309
|
+
const forja = opcoes.forja ? { leitura: true, ...opcoes.forja }
|
|
310
|
+
: forjaDosPrs(carregado.raiz, remoto, executor, Math.min(PRAZO_DO_GH_MS, Math.max(1, resta())));
|
|
311
|
+
if (!forja.leitura)
|
|
312
|
+
return { ok: false, lidoEm, erro: forja.motivo, ...(forja.semLeitura ? { semLeitura: { remoto, host: forja.host } } : {}) };
|
|
313
|
+
const { host, repositorio } = forja;
|
|
238
314
|
const pedir = (args) => {
|
|
239
315
|
if (resta() <= 0)
|
|
240
316
|
return `gh pr list: orçamento de ${Math.round(orcamento / 1000)} s da leitura esgotado`;
|
|
241
|
-
const r =
|
|
317
|
+
const r = executor(['pr', 'list', `--repo=${host}/${repositorio}`, `--base=${base}`, ...args], Math.min(PRAZO_DO_GH_MS, resta()));
|
|
242
318
|
if (r.status !== 0) {
|
|
243
319
|
const detalhe = curto((0, hitl_1.redigirSegredos)(r.stderr || r.stdout || ''), 160) ?? 'sem detalhe';
|
|
244
320
|
return `gh pr list falhou (${r.status === null ? 'sem código de saída' : `código ${r.status}`}): ${detalhe}`;
|
|
@@ -296,8 +372,8 @@ function lerPrsDaForja(carregado, opcoes = {}) {
|
|
|
296
372
|
semConferir.push(branch);
|
|
297
373
|
}
|
|
298
374
|
}
|
|
299
|
-
return { ok: true, retrato: { contrato: exports.CONTRATO_PRS, lidoEm, repositorio,
|
|
300
|
-
...(semConferir.length ? { semConferir } : {}), prs: [...porNumero.values()] } };
|
|
375
|
+
return { ok: true, retrato: { contrato: exports.CONTRATO_PRS, lidoEm, repositorio, ...(host !== 'github.com' ? { host } : {}), base,
|
|
376
|
+
parcial: abertos.length >= exports.LIMITE_DE_PRS, ...(semConferir.length ? { semConferir } : {}), prs: [...porNumero.values()] } };
|
|
301
377
|
}
|
|
302
378
|
catch (e) {
|
|
303
379
|
return { ok: false, lidoEm, erro: `resposta do gh pr list fora do formato: ${curto((0, hitl_1.redigirSegredos)(e.message), 120) ?? 'sem detalhe'}` };
|
|
@@ -321,6 +397,64 @@ function gravarRetratoDePrs(raiz, retrato) {
|
|
|
321
397
|
throw e;
|
|
322
398
|
}
|
|
323
399
|
}
|
|
400
|
+
const ARQUIVO_DA_FORJA_SEM_LEITURA = 'forja-sem-leitura.json';
|
|
401
|
+
exports.CONTRATO_FORJA_SEM_LEITURA = 'ork.forja-sem-leitura/v1';
|
|
402
|
+
function lerAvisoDeForjaSemLeitura(raiz) {
|
|
403
|
+
try {
|
|
404
|
+
const a = JSON.parse(fs.readFileSync(path.join(dirDoMonitor(raiz), ARQUIVO_DA_FORJA_SEM_LEITURA), 'utf8'));
|
|
405
|
+
const ditoEm = instante(a.ditoEm), motivo = curto(a.motivo, 200);
|
|
406
|
+
if (a.contrato !== exports.CONTRATO_FORJA_SEM_LEITURA || typeof a.remoto !== 'string' || !/^[A-Za-z0-9._-]{1,100}$/.test(a.remoto) ||
|
|
407
|
+
!(a.host === null || (typeof a.host === 'string' && HOST.test(a.host))) || !ditoEm || !motivo)
|
|
408
|
+
return null;
|
|
409
|
+
return { contrato: exports.CONTRATO_FORJA_SEM_LEITURA, remoto: a.remoto, host: a.host, motivo, ditoEm };
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* RM-037 (fatia 5, A5): a forja sem leitura de PR e dita uma vez por remoto e host. Com o remoto fora do github.com,
|
|
417
|
+
* o pulse dizia "PR nao lido" a cada batida, para um estado que nao muda de uma batida para a outra. A marca em
|
|
418
|
+
* `.orkastery/monitor/` guarda o que ja foi dito; devolve true quando e novidade (e grava a marca).
|
|
419
|
+
*/
|
|
420
|
+
function avisarForjaSemLeitura(raiz, semLeitura, motivo, quando) {
|
|
421
|
+
const atual = lerAvisoDeForjaSemLeitura(raiz);
|
|
422
|
+
if (atual && atual.remoto === semLeitura.remoto && atual.host === semLeitura.host)
|
|
423
|
+
return false;
|
|
424
|
+
const dir = dirDoMonitor(raiz);
|
|
425
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
426
|
+
const arquivo = path.join(dir, ARQUIVO_DA_FORJA_SEM_LEITURA), tmp = `${arquivo}.${process.pid}.${Date.now()}.tmp`;
|
|
427
|
+
const aviso = { contrato: exports.CONTRATO_FORJA_SEM_LEITURA, ...semLeitura, motivo: curto(motivo, 200) ?? exports.FORJA_SEM_LEITURA,
|
|
428
|
+
ditoEm: quando };
|
|
429
|
+
try {
|
|
430
|
+
fs.writeFileSync(tmp, JSON.stringify(aviso, null, 2) + '\n', { mode: 0o600, flag: 'wx' });
|
|
431
|
+
fs.renameSync(tmp, arquivo);
|
|
432
|
+
}
|
|
433
|
+
catch (e) {
|
|
434
|
+
try {
|
|
435
|
+
fs.unlinkSync(tmp);
|
|
436
|
+
}
|
|
437
|
+
catch { /* ja saiu */ }
|
|
438
|
+
throw e;
|
|
439
|
+
}
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
/** A leitura voltou: a marca sai, e a forja que perder a leitura de novo volta a ser dita. */
|
|
443
|
+
function esquecerForjaSemLeitura(raiz) {
|
|
444
|
+
fs.rmSync(path.join(dirDoMonitor(raiz), ARQUIVO_DA_FORJA_SEM_LEITURA), { force: true });
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* A forja sem leitura que o pulse ja disse, so quando ela e a do remoto de agora (mesmo nome e mesmo host): o status
|
|
448
|
+
* do roadmap a le sem rede e sem `gh`.
|
|
449
|
+
*/
|
|
450
|
+
function forjaSemLeituraDoRemoto(raiz, remoto) {
|
|
451
|
+
const aviso = lerAvisoDeForjaSemLeitura(raiz);
|
|
452
|
+
if (!aviso || aviso.remoto !== remoto || !(0, branch_de_estado_1.remotoValido)(remoto))
|
|
453
|
+
return null;
|
|
454
|
+
const url = git(raiz, ['remote', 'get-url', '--', remoto]);
|
|
455
|
+
const host = url.ok ? (0, forja_1.enderecoDoRemoto)(url.stdout.trim())?.host ?? null : null;
|
|
456
|
+
return host === aviso.host ? aviso : null;
|
|
457
|
+
}
|
|
324
458
|
/** O ultimo retrato gravado pelo pulse, conferido campo a campo e com os nomes de check limpos de novo. */
|
|
325
459
|
function lerRetratoDePrs(raiz) {
|
|
326
460
|
try {
|
|
@@ -328,6 +462,7 @@ function lerRetratoDePrs(raiz) {
|
|
|
328
462
|
const lidoEm = instante(r.lidoEm);
|
|
329
463
|
if (r.contrato !== exports.CONTRATO_PRS || !lidoEm || typeof r.repositorio !== 'string' || !REPOSITORIO.test(r.repositorio) ||
|
|
330
464
|
typeof r.base !== 'string' || typeof r.parcial !== 'boolean' || !Array.isArray(r.prs) ||
|
|
465
|
+
(r.host !== undefined && !(typeof r.host === 'string' && HOST.test(r.host))) ||
|
|
331
466
|
(r.semConferir !== undefined && !(Array.isArray(r.semConferir) && r.semConferir.every((b) => typeof b === 'string' && BRANCH.test(b)))))
|
|
332
467
|
return null;
|
|
333
468
|
const opcional = (v) => (v === null || v === undefined ? null : instante(v) ?? undefined);
|
|
@@ -351,8 +486,8 @@ function lerRetratoDePrs(raiz) {
|
|
|
351
486
|
prs.push({ numero: p.numero, branch: p.branch, head: p.head, estado, rascunho: p.rascunho,
|
|
352
487
|
url: typeof p.url === 'string' && /^https:\/\/[^\s]+$/.test(p.url) ? curto(p.url, 300) : null, criadoEm, mescladoEm, checks });
|
|
353
488
|
}
|
|
354
|
-
return { contrato: exports.CONTRATO_PRS, lidoEm, repositorio: r.repositorio,
|
|
355
|
-
...(Array.isArray(r.semConferir) && r.semConferir.length ? { semConferir: r.semConferir } : {}), prs };
|
|
489
|
+
return { contrato: exports.CONTRATO_PRS, lidoEm, repositorio: r.repositorio, ...(typeof r.host === 'string' ? { host: r.host } : {}),
|
|
490
|
+
base: r.base, parcial: r.parcial, ...(Array.isArray(r.semConferir) && r.semConferir.length ? { semConferir: r.semConferir } : {}), prs };
|
|
356
491
|
}
|
|
357
492
|
catch {
|
|
358
493
|
return null;
|
|
@@ -411,13 +546,25 @@ const doRadar = (e) => e.tipo === 'sessao_bloqueada' && e.fonte === 'ork session
|
|
|
411
546
|
* intervalo do despacho. A prova do ork no SHIP e so o `ship_done` (`provaDoOrk`): o que falta e mergear o PR
|
|
412
547
|
* ou registrar a entrega, e isso e do condutor, como o fim de turno em `blocked`. Dos 4 `human.pending` do SHIP
|
|
413
548
|
* nos ledgers de 30/09, 2 tem este formato (ork-rm037noite e ork-pacotedeexpe). O CHECK em `done` sem o veredito
|
|
414
|
-
* e outra coisa
|
|
549
|
+
* e outra coisa: `checkSemVeredito`.
|
|
415
550
|
*/
|
|
416
551
|
function shipSemRegistro(e) {
|
|
417
552
|
const { ok: provou } = (e.provaOrk ?? {});
|
|
418
553
|
return e.motivo === 'human.pending' && e.origem === 'sessions.watch' && e.fase === 'SHIP' && e.estadoNativo === 'done' &&
|
|
419
554
|
!!e.stop && provou === false;
|
|
420
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* RM-037 (fatia 5, A3): o CHECK que o observador viu terminar em `done`, com o Stop, sem exatamente um veredito
|
|
558
|
+
* legivel no `docs/check.md` (`provaDoOrk`). No #Auto, com o bloco sem pausa ao fim, ninguem perguntou nada ao dono:
|
|
559
|
+
* o passo e do condutor, que redespacha o CHECK. Nos dois casos reais (ork-i35horariodo em 20/09 e ork-pacotedeexpe
|
|
560
|
+
* em 30/09, as duas #Auto) o condutor seguiu sozinho minutos depois, sem pergunta ao dono. Fora do #Auto, segue com
|
|
561
|
+
* o dono, como antes.
|
|
562
|
+
*/
|
|
563
|
+
function checkSemVeredito(e) {
|
|
564
|
+
const { ok: provou } = (e.provaOrk ?? {});
|
|
565
|
+
return e.motivo === 'human.pending' && e.origem === 'sessions.watch' && e.fase === 'CHECK' && e.estadoNativo === 'done' &&
|
|
566
|
+
!!e.stop && provou === false;
|
|
567
|
+
}
|
|
421
568
|
/**
|
|
422
569
|
* O bloqueio que pede o dono: o prompt de permissao do hook e o que o radar leu com pergunta na tela. O
|
|
423
570
|
* carimbo do radar no fim de turno (`blocked` lido sem menu nem pergunta) nao e prompt nenhum.
|
|
@@ -473,7 +620,8 @@ function atividadeDaSessao(e) {
|
|
|
473
620
|
return !(e.sensor === 'notification' && e.notificationType === 'idle_prompt');
|
|
474
621
|
return e.tipo === 'commit' || e.tipo === 'runtime_stop' || (e.tipo === 'sessao_bloqueada' && !doRadar(e));
|
|
475
622
|
}
|
|
476
|
-
|
|
623
|
+
/** `modo`: o da thread. Sem ele, o CHECK sem o veredito fica com o dono, como fora do #Auto. */
|
|
624
|
+
function fimDoTurno(eventos, despacho, modo) {
|
|
477
625
|
const i = eventos.lastIndexOf(despacho);
|
|
478
626
|
const depois = eventos.slice(i + 1);
|
|
479
627
|
const sid = texto(despacho.sessionId);
|
|
@@ -497,12 +645,13 @@ function fimDoTurno(eventos, despacho) {
|
|
|
497
645
|
// S-a do CHECK (rodada 3): no bloco com pausa ao fim, todo `human.pending` do resultado e a fase entregue ao dono.
|
|
498
646
|
return { em: resultado.ts, tipo: 'pausa-do-bloco', sessionId: sid, fase, comProva: true };
|
|
499
647
|
}
|
|
500
|
-
else if (resultado.motivo === 'human.pending' && resultado.stop && (resultado.estadoNativo === 'blocked' || shipSemRegistro(resultado)
|
|
648
|
+
else if (resultado.motivo === 'human.pending' && resultado.stop && (resultado.estadoNativo === 'blocked' || shipSemRegistro(resultado) ||
|
|
649
|
+
(modo === 'auto' && checkSemVeredito(resultado)))) {
|
|
501
650
|
if (!retomou) {
|
|
502
651
|
const { ts: doStop } = resultado.stop;
|
|
503
652
|
const { ok: provou } = (resultado.provaOrk ?? {});
|
|
504
|
-
return { em: instante(doStop) ?? resultado.ts, tipo: 'espera-do-observador',
|
|
505
|
-
comProva: typeof provou === 'boolean' ? provou : null };
|
|
653
|
+
return { em: instante(doStop) ?? resultado.ts, tipo: checkSemVeredito(resultado) ? 'check-sem-veredito' : 'espera-do-observador',
|
|
654
|
+
sessionId: sid, fase, comProva: typeof provou === 'boolean' ? provou : null };
|
|
506
655
|
}
|
|
507
656
|
}
|
|
508
657
|
else
|
|
@@ -544,17 +693,17 @@ function pendenciaDoDono(t, eventos, quando) {
|
|
|
544
693
|
return 'prompt de permissão pendente';
|
|
545
694
|
// Aviso da rodada 6 do CHECK: o gate do observador so muda de dono com o fim de turno provado. A sessao que voltou a
|
|
546
695
|
// trabalhar depois do resultado, sem Stop novo, segue do dono, e a thread nao sai tambem como linha do condutor.
|
|
547
|
-
const fim = fimDoTurno(eventos, despacho);
|
|
696
|
+
const fim = fimDoTurno(eventos, despacho, t.modo);
|
|
548
697
|
const turnoEncerrado = !!fim && fim.tipo !== 'outro';
|
|
549
698
|
for (let k = 0; k < depois.length; k++) {
|
|
550
699
|
const e = depois[k];
|
|
551
700
|
if (e.tipo !== 'gate_blocked')
|
|
552
701
|
continue;
|
|
553
702
|
const motivo = String(e.motivo ?? '');
|
|
554
|
-
// O fim de turno que o observador viu em `blocked`,
|
|
555
|
-
// escalacao: sao justamente o que muda de dono.
|
|
703
|
+
// O fim de turno que o observador viu em `blocked`, o SHIP em `done` sem o `ship_done` (B1 da rodada 5) e, no #Auto,
|
|
704
|
+
// o CHECK em `done` sem o veredito (A3, fatia 5) nao sao escalacao: sao justamente o que muda de dono.
|
|
556
705
|
if (turnoEncerrado && motivo === 'human.pending' && e.origem === 'sessions.watch' &&
|
|
557
|
-
(e.estadoNativo === 'blocked' || shipSemRegistro(e)))
|
|
706
|
+
(e.estadoNativo === 'blocked' || shipSemRegistro(e) || (t.modo === 'auto' && checkSemVeredito(e))))
|
|
558
707
|
continue;
|
|
559
708
|
const doDono = motivo === 'human.pending' ||
|
|
560
709
|
(hitl_gates_1.MOTIVOS_DE_ESCALACAO_HUMANA.includes(motivo) && (0, hitl_classificacao_1.quemDecide)(motivo) === 'dono');
|
|
@@ -564,13 +713,26 @@ function pendenciaDoDono(t, eventos, quando) {
|
|
|
564
713
|
}
|
|
565
714
|
return null;
|
|
566
715
|
}
|
|
716
|
+
/**
|
|
717
|
+
* Quem conduz a thread agora, ou `null`. P7: a sessao que ja encerrou o turno nao conduz mais nada, mesmo com o lease
|
|
718
|
+
* de pe. RM-059 (F7): a mesma regra do pulse decide se o `ork ship publicar` pode publicar a branch.
|
|
719
|
+
*/
|
|
720
|
+
function conducaoAgora(raiz, t, eventos, quando) {
|
|
721
|
+
const conducao = (0, conducao_1.conducaoDaThread)(raiz, t.id, { agora: new Date(quando) });
|
|
722
|
+
if (!conducao)
|
|
723
|
+
return null;
|
|
724
|
+
const despacho = ultimoDespacho(eventos);
|
|
725
|
+
const fim = despacho ? fimDoTurno(eventos, despacho, t.modo) : null;
|
|
726
|
+
const terminou = !!fim && fim.tipo !== 'outro';
|
|
727
|
+
return conducao.dono.tipo === 'sessao' && terminou && conducao.dono.sessionId === fim.sessionId ? null : conducao;
|
|
728
|
+
}
|
|
567
729
|
function esperaDoCondutor(t, eventos, quando) {
|
|
568
730
|
if (t.status === 'fechada')
|
|
569
731
|
return null;
|
|
570
732
|
const despacho = ultimoDespacho(eventos);
|
|
571
733
|
if (!despacho || despacho.pausaAoFim !== false)
|
|
572
734
|
return null;
|
|
573
|
-
const fim = fimDoTurno(eventos, despacho);
|
|
735
|
+
const fim = fimDoTurno(eventos, despacho, t.modo);
|
|
574
736
|
if (!fim || fim.tipo === 'outro' || fim.tipo === 'pausa-do-bloco' || pendenciaDoDono(t, eventos, quando))
|
|
575
737
|
return null;
|
|
576
738
|
return { thread: t.id, fase: fim.fase, sessionId: fim.sessionId, fimDoTurnoEm: fim.em, tipo: fim.tipo, comProva: fim.comProva };
|
|
@@ -699,9 +861,13 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
699
861
|
// R4-4 do CHECK (rodada 4): o `ship_done` cobre a entrega do mesmo head (`shaDe`) ou do mesmo merge; a entrega
|
|
700
862
|
// nova depois dele ainda nao foi registrada. O legado sem o sha cobre tudo, como antes.
|
|
701
863
|
const cobre = (campo, sha) => ships.some((e) => typeof e[campo] !== 'string' || !SHA.test(e[campo]) || e[campo] === sha);
|
|
864
|
+
// RM-037 (fatia 5, A1): ate esta fatia, o `ork ship` com a branch ja incorporada gravava a ponta da base no
|
|
865
|
+
// `mergeSha`. Esse `ship_done` registra o merge `ship(<thread>)` que a ponta gravada contem.
|
|
866
|
+
const contemOMerge = (sha) => ships.some((e) => typeof e.mergeSha === 'string' && SHA.test(e.mergeSha) &&
|
|
867
|
+
e.mergeSha !== sha && git(raiz, ['merge-base', '--is-ancestor', sha, e.mergeSha]).code === 0);
|
|
702
868
|
return { t, eventos, branch: cabeca ? branch : null, cabeca, comProduto, publicada, temRemota: !!remota,
|
|
703
869
|
shipNoLedger: ships.length > 0, entregueNaPonta: cabeca ? cobre('shaDe', cabeca) : ships.length > 0,
|
|
704
|
-
mergeRegistrado: !!merge && cobre('mergeSha', merge.sha), merge };
|
|
870
|
+
mergeRegistrado: !!merge && (cobre('mergeSha', merge.sha) || contemOMerge(merge.sha)), merge };
|
|
705
871
|
});
|
|
706
872
|
// D2: a forja so e lida quando alguma thread tem o que mostrar la: produto numa branch que ja foi ao remoto
|
|
707
873
|
// (inteira, ou com commit novo ainda sem push, que pode ter PR aberto).
|
|
@@ -710,11 +876,15 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
710
876
|
if (opcoes.lerPrs && candidatas.length)
|
|
711
877
|
prs = opcoes.lerPrs(candidatas);
|
|
712
878
|
// O retrato so vale do repositorio e da base de agora, e lido ha menos de `VALIDADE_DO_RETRATO_MIN`.
|
|
713
|
-
|
|
879
|
+
// RM-037 (fatia 5, A5): a forja sem leitura de PR e o estado dela, dito uma vez pelo pulse; a linha nunca diz "PR nao lido".
|
|
880
|
+
const semLeituraDaForja = !!prs && !prs.ok && !!prs.semLeitura;
|
|
881
|
+
let retrato = null, semRetrato = prs && !prs.ok ? (semLeituraDaForja ? exports.FORJA_SEM_LEITURA : prs.erro) : 'sem leitura dos PRs';
|
|
714
882
|
if (prs?.ok) {
|
|
715
|
-
const r = prs.retrato;
|
|
716
|
-
|
|
883
|
+
const r = prs.retrato, atual = githubDoRemoto(raiz, remoto);
|
|
884
|
+
// O retrato vale do mesmo host: o do GitHub Enterprise (`host`) ou, sem ele, o github.com.
|
|
885
|
+
if (r.base !== baseBranch || !atual || r.repositorio !== atual.repositorio || (r.host ?? 'github.com') !== atual.host) {
|
|
717
886
|
semRetrato = 'retrato de PRs de outro repositório ou base';
|
|
887
|
+
}
|
|
718
888
|
else if (minutosDesde(r.lidoEm, quando) > exports.VALIDADE_DO_RETRATO_MIN)
|
|
719
889
|
semRetrato = 'retrato de PRs velho';
|
|
720
890
|
else if (Date.parse(r.lidoEm) - Date.parse(quando) > FOLGA_DO_RELOGIO_MIN * 60000)
|
|
@@ -727,7 +897,7 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
727
897
|
for (const f of fatos) {
|
|
728
898
|
const { t, eventos } = f;
|
|
729
899
|
const despacho = ultimoDespacho(eventos);
|
|
730
|
-
const fim = despacho ? fimDoTurno(eventos, despacho) : null;
|
|
900
|
+
const fim = despacho ? fimDoTurno(eventos, despacho, t.modo) : null;
|
|
731
901
|
const terminou = !!fim && fim.tipo !== 'outro';
|
|
732
902
|
const fimEm = terminou ? fim.em : null;
|
|
733
903
|
// A1 do CHECK (rodada 3): o fim de turno vem do ledger (Stop sem atividade depois); a tela da sessao depois
|
|
@@ -740,9 +910,9 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
740
910
|
doCondutor.turnosEncerrados.add(espera.sessionId);
|
|
741
911
|
}
|
|
742
912
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
const conduzidaAgora =
|
|
913
|
+
// A mesma regra do `ork ship publicar` (RM-059): quem conduz agora, ou ninguem.
|
|
914
|
+
const conducao = conducaoAgora(raiz, t, eventos, quando);
|
|
915
|
+
const conduzidaAgora = conducao !== null;
|
|
746
916
|
const doDono = pendenciaDoDono(t, eventos, quando);
|
|
747
917
|
// A2 do CHECK (rodada 3): depois do veredito do dono, o tempo do condutor conta a partir dele.
|
|
748
918
|
const aprovacao = despacho ? eventos.slice(eventos.lastIndexOf(despacho) + 1).filter(ocupacao_1.ehAprovacaoHumana).at(-1) : undefined;
|
|
@@ -771,7 +941,15 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
771
941
|
let caso = null, desde = null, passo = '', peloGit = false;
|
|
772
942
|
const evidencia = [];
|
|
773
943
|
if (!conduzidaAgora && !doDono) {
|
|
774
|
-
if (
|
|
944
|
+
if (espera?.tipo === 'check-sem-veredito') {
|
|
945
|
+
// RM-037 (fatia 5, A3): antes de qualquer caso de entrega. Publicar ou mergear sem o veredito do CHECK pularia
|
|
946
|
+
// a revisao; e o `ork retry run` nao redespacha `human.pending` (`escalar-humano`), entao o passo e o despacho.
|
|
947
|
+
caso = 'check-sem-veredito';
|
|
948
|
+
desde = espera.fimDoTurnoEm;
|
|
949
|
+
passo = `redespachar o CHECK (ork phase run ${t.id} CHECK --prompt "<pedido da fase>")`;
|
|
950
|
+
evidencia.push('ledger: CHECK em done com o Stop, sem exatamente um veredito no docs/check.md');
|
|
951
|
+
}
|
|
952
|
+
else if (f.comProduto && publicada === false && terminou) {
|
|
775
953
|
desde = fimOuVeredito;
|
|
776
954
|
if (antesDaEntrega && !aberto) {
|
|
777
955
|
caso = 'fase-seguinte';
|
|
@@ -782,7 +960,8 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
782
960
|
// N2 da seguranca (rodada 2): branch que ja foi ao remoto pode ter PR; sem a leitura, nunca "abrir o PR". A4 da
|
|
783
961
|
// rodada 5: publicar e abrir o PR pedem a mesma autorizacao de push que o merge.
|
|
784
962
|
passo = (aberto ? `publicar os commits novos da branch ${f.branch} no PR #${aberto.numero}`
|
|
785
|
-
:
|
|
963
|
+
// RM-037 (fatia 5, A5): a forja sem leitura de PR ja foi dita uma vez; a linha so diz o passo.
|
|
964
|
+
: f.temRemota && !prSabido ? `publicar os commits novos da branch ${f.branch}${semLeituraDaForja ? '' : ' (PR não lido)'}`
|
|
786
965
|
: `publicar a branch ${f.branch} e abrir o PR`) + autorizacao;
|
|
787
966
|
}
|
|
788
967
|
evidencia.push(`refs/heads/${f.branch} tem commit fora de refs/remotes/${remoto}/${f.branch}`);
|
|
@@ -850,7 +1029,8 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
850
1029
|
caso = 'sessao-sem-pergunta';
|
|
851
1030
|
passo = f.shipNoLedger && !f.comProduto ? `fechar o MASTER da thread (ork master ${t.id})`
|
|
852
1031
|
: aberto ? `acompanhar os checks do PR #${aberto.numero}, que seguem em andamento`
|
|
853
|
-
: precisaDePr && !usouPr ? `conferir o PR da branch ${f.branch}
|
|
1032
|
+
: precisaDePr && !usouPr ? (semLeituraDaForja ? `conferir na forja o PR da branch ${f.branch} e seguir`
|
|
1033
|
+
: `conferir o PR da branch ${f.branch} (PR não lido) e seguir`)
|
|
854
1034
|
: `ler o fim da sessão ${id} (ork sessions logs ${id}) e seguir a thread`;
|
|
855
1035
|
}
|
|
856
1036
|
}
|
|
@@ -880,11 +1060,12 @@ function entregasDoProjeto(carregado, opcoes) {
|
|
|
880
1060
|
: daBranch.mesclado && !f.entregueNaPonta ? (f.merge && !f.mergeRegistrado ? `PR #${daBranch.mesclado.numero} mesclado, falta registrar a entrega (${registrar})`
|
|
881
1061
|
: `PR #${daBranch.mesclado.numero} mesclado sem o assunto ship(${t.id}), falta registrar a entrega`)
|
|
882
1062
|
: !f.comProduto && f.merge && !f.mergeRegistrado ? `merge ${f.merge.sha.slice(0, 7)} na base, falta registrar a entrega (${registrar})`
|
|
883
|
-
: precisaDePr ? (!usouPr ? 'branch publicada, PR não lido'
|
|
1063
|
+
: precisaDePr ? (!usouPr ? (semLeituraDaForja ? `branch publicada, ${exports.FORJA_SEM_LEITURA}` : 'branch publicada, PR não lido')
|
|
884
1064
|
: daBranch.fechado ? `branch publicada, PR #${daBranch.fechado.numero} fechado sem merge` : 'branch publicada sem PR')
|
|
885
1065
|
: null;
|
|
886
1066
|
estados.push({ thread: t.id, branch: f.branch, comProduto: f.comProduto, publicada, pr: prDaEntrega,
|
|
887
|
-
prLidoEm: prLido && (usouPr || aberto) ? prLido.lidoEm : null, prNaoLido, conduzidaAgora,
|
|
1067
|
+
prLidoEm: prLido && (usouPr || aberto) ? prLido.lidoEm : null, prNaoLido, conduzidaAgora,
|
|
1068
|
+
donoDaConducao: conduzidaAgora && conducao ? conducao.dono.tipo : null, espera, parado, resumo });
|
|
888
1069
|
}
|
|
889
1070
|
// As sessoes `blocked` sem pergunta que sobraram: de thread fechada, ou de despacho antigo de thread aberta.
|
|
890
1071
|
// A do despacho corrente fica com o predicado do ledger (`esperaDoCondutor`). Sem o carimbo do radar nao
|