@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
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CRONTAB_DO_SISTEMA = exports.MARCA_DA_BATIDA = exports.ultimaRodadaDaVarredura = exports.ATRASO_DA_BATIDA_MIN = void 0;
|
|
37
|
+
exports.gravarCrontabDoSistema = gravarCrontabDoSistema;
|
|
38
|
+
exports.caminhoDaBatida = caminhoDaBatida;
|
|
39
|
+
exports.scriptDaBatida = scriptDaBatida;
|
|
40
|
+
exports.linhaDaBatida = linhaDaBatida;
|
|
41
|
+
exports.linhaGerenciada = linhaGerenciada;
|
|
42
|
+
exports.estadoDaBatida = estadoDaBatida;
|
|
43
|
+
exports.instalarBatida = instalarBatida;
|
|
44
|
+
exports.removerBatida = removerBatida;
|
|
45
|
+
exports.textoDoEstadoDaBatida = textoDoEstadoDaBatida;
|
|
46
|
+
exports.textoDoResultadoDaBatida = textoDoResultadoDaBatida;
|
|
47
|
+
/**
|
|
48
|
+
* RM-063 (F1): a batida da fabrica, instalada e vigiada pelo proprio `ork`.
|
|
49
|
+
*
|
|
50
|
+
* Incidente do maquina-b, de 03/10 a 12/10/2026 (P1 e P7 da pagina da RM-063): o cron da varredura do
|
|
51
|
+
* pulse nunca foi instalado, o `ork doctor` so conferia o crontab com `pulse-host.json` e, sem
|
|
52
|
+
* transporte, calava; a correcao (editar o crontab) foi barrada como persistencia nao autorizada. A
|
|
53
|
+
* maquina ficou nove dias sem batida e ninguem soube.
|
|
54
|
+
*
|
|
55
|
+
* `ork fabrica batida instalar|status|remover` e o comando que o dono autoriza uma vez: instala a linha
|
|
56
|
+
* do template `monitor/pulse.cron` com o checkout canonico e o PATH que acha o `node`, o `claude` e o
|
|
57
|
+
* transporte, preserva as outras entradas do crontab e grava o evento no ledger da maquina
|
|
58
|
+
* (`~/.orkastery/ledger.jsonl`). A linha e marcada (`# ork-batida`) e diz o projeto
|
|
59
|
+
* (`ORK_PULSE_PROJECT`): e por elas que o `remover` tira so a linha dela.
|
|
60
|
+
*
|
|
61
|
+
* O crontab nunca e gravado sem ter sido lido, e a gravacao so vale depois de relida. O executor e
|
|
62
|
+
* injetado: os testes usam um crontab falso e nunca tocam no da maquina.
|
|
63
|
+
*/
|
|
64
|
+
const fs = __importStar(require("node:fs"));
|
|
65
|
+
const path = __importStar(require("node:path"));
|
|
66
|
+
const node_child_process_1 = require("node:child_process");
|
|
67
|
+
const doctor_pulse_cron_1 = require("./doctor-pulse-cron");
|
|
68
|
+
var doctor_pulse_cron_2 = require("./doctor-pulse-cron");
|
|
69
|
+
Object.defineProperty(exports, "ATRASO_DA_BATIDA_MIN", { enumerable: true, get: function () { return doctor_pulse_cron_2.ATRASO_DA_BATIDA_MIN; } });
|
|
70
|
+
Object.defineProperty(exports, "ultimaRodadaDaVarredura", { enumerable: true, get: function () { return doctor_pulse_cron_2.ultimaRodadaDaVarredura; } });
|
|
71
|
+
const estado_thread_1 = require("./estado-thread");
|
|
72
|
+
const ledger_1 = require("./ledger");
|
|
73
|
+
const maquina_1 = require("./maquina");
|
|
74
|
+
const horario_1 = require("./horario");
|
|
75
|
+
const util_1 = require("./util");
|
|
76
|
+
const procedencia_1 = require("./procedencia");
|
|
77
|
+
/** O comentario no fim da linha que o `ork` instalou; o `sh` do cron o ignora. */
|
|
78
|
+
exports.MARCA_DA_BATIDA = '# ork-batida';
|
|
79
|
+
/** Os binarios que a varredura chama, alem do `node`: o runtime, a forja e o git. */
|
|
80
|
+
const BINARIOS_DA_VARREDURA = ['claude', 'codex', 'gh', 'git'];
|
|
81
|
+
const PATH_DO_SISTEMA = ['/usr/local/bin', '/usr/bin', '/bin'];
|
|
82
|
+
/** `crontab -` com o texto no stdin, sem shell e com prazo. */
|
|
83
|
+
function gravarCrontabDoSistema(texto) {
|
|
84
|
+
const r = (0, node_child_process_1.spawnSync)('crontab', ['-'], { input: texto, encoding: 'utf8', timeout: 5000 });
|
|
85
|
+
if (r.status === 0)
|
|
86
|
+
return { ok: true };
|
|
87
|
+
const erro = r.error ? r.error.code ?? r.error.message : null;
|
|
88
|
+
if (erro === 'ENOENT')
|
|
89
|
+
return { ok: false, motivo: 'comando crontab ausente nesta maquina' };
|
|
90
|
+
const primeira = `${r.stderr ?? ''}${r.stdout ?? ''}`.trim().split('\n')[0] ?? '';
|
|
91
|
+
return { ok: false, motivo: primeira ? `crontab - falhou: ${primeira}` : `crontab - saiu ${r.status ?? erro ?? 'sem codigo'}` };
|
|
92
|
+
}
|
|
93
|
+
exports.CRONTAB_DO_SISTEMA = { ler: doctor_pulse_cron_1.lerCrontabDoSistema, gravar: gravarCrontabDoSistema };
|
|
94
|
+
/** Caminho que entra na linha do cron: absoluto, sem `%` (o cron o troca por quebra de linha) e sem controle. */
|
|
95
|
+
function caminhoAceito(caminho) {
|
|
96
|
+
return path.isAbsolute(caminho) && !/[%\p{Cc}]/u.test(caminho);
|
|
97
|
+
}
|
|
98
|
+
/** Diretorio aceito no PATH da linha: alem do caminho aceito, sem `:`, o separador do PATH. */
|
|
99
|
+
function diretorioAceito(dir) {
|
|
100
|
+
return caminhoAceito(dir) && !dir.includes(':');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* O executavel do transporte, so do `pulse-host.json` local desta maquina (RM-047, P2): o versionado no git, ou o link,
|
|
104
|
+
* nao poe diretorio nenhum no PATH da batida.
|
|
105
|
+
*/
|
|
106
|
+
function transporteDoProjeto(raiz, dirMonitor) {
|
|
107
|
+
const arquivo = path.join(dirMonitor, 'pulse-host.json');
|
|
108
|
+
try {
|
|
109
|
+
(0, procedencia_1.exigirHostLocal)(raiz, arquivo);
|
|
110
|
+
const config = JSON.parse(fs.readFileSync(arquivo, 'utf8'));
|
|
111
|
+
return typeof config.executavel === 'string' && config.executavel.trim() ? config.executavel.trim() : null;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* O PATH da linha: o diretorio do `node` que roda este `ork`, os do `claude`, `codex`, `gh` e `git` achados
|
|
119
|
+
* agora, o do executavel do transporte (`pulse-host.json`) e o PATH minimo do sistema. O cron nao carrega o
|
|
120
|
+
* perfil do shell; sem isto a varredura nao acha o runtime nem o transporte (o template avisa).
|
|
121
|
+
*/
|
|
122
|
+
function caminhoDaBatida(opcoes = {}) {
|
|
123
|
+
const achar = opcoes.achar ?? ((bin) => (0, util_1.noPath)(bin));
|
|
124
|
+
const dirs = [];
|
|
125
|
+
const somar = (arquivo) => {
|
|
126
|
+
if (!arquivo || !path.isAbsolute(arquivo))
|
|
127
|
+
return;
|
|
128
|
+
const dir = path.dirname(arquivo);
|
|
129
|
+
if (diretorioAceito(dir) && !dirs.includes(dir))
|
|
130
|
+
dirs.push(dir);
|
|
131
|
+
};
|
|
132
|
+
somar(opcoes.node ?? process.execPath);
|
|
133
|
+
for (const bin of BINARIOS_DA_VARREDURA)
|
|
134
|
+
somar(achar(bin));
|
|
135
|
+
if (opcoes.transporte)
|
|
136
|
+
somar(path.isAbsolute(opcoes.transporte) ? opcoes.transporte : achar(opcoes.transporte));
|
|
137
|
+
for (const dir of PATH_DO_SISTEMA)
|
|
138
|
+
if (!dirs.includes(dir))
|
|
139
|
+
dirs.push(dir);
|
|
140
|
+
return dirs.join(':');
|
|
141
|
+
}
|
|
142
|
+
/** O script da varredura que a linha roda: o do checkout do projeto, senao o do `ork` instalado. */
|
|
143
|
+
function scriptDaBatida(raiz, scriptDoOrk = (0, doctor_pulse_cron_1.scriptDaVarreduraDoOrk)()) {
|
|
144
|
+
const doProjeto = path.join(raiz, 'monitor', doctor_pulse_cron_1.SCRIPT_DA_VARREDURA);
|
|
145
|
+
return fs.existsSync(doProjeto) ? doProjeto : scriptDoOrk;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* A linha que o `ork` instala: a batida do template (`*\/15`), o projeto alvo, o PATH e o script, com a
|
|
149
|
+
* marca no fim. `raiz` e a raiz canonica (o checkout principal, nunca a worktree de uma thread).
|
|
150
|
+
*/
|
|
151
|
+
function linhaDaBatida(raiz, opcoes = {}) {
|
|
152
|
+
const script = scriptDaBatida(raiz, opcoes.scriptDoOrk === undefined ? (0, doctor_pulse_cron_1.scriptDaVarreduraDoOrk)() : opcoes.scriptDoOrk);
|
|
153
|
+
if (!script) {
|
|
154
|
+
throw new Error(`fabrica.batida.sem-script: nem ${path.join(raiz, 'monitor', doctor_pulse_cron_1.SCRIPT_DA_VARREDURA)} nem o ` +
|
|
155
|
+
`${doctor_pulse_cron_1.SCRIPT_DA_VARREDURA} do ork instalado existem; reinstale o ork (npm i -g @orkastery/cli)`);
|
|
156
|
+
}
|
|
157
|
+
for (const caminho of [raiz, script]) {
|
|
158
|
+
if (!caminhoAceito(caminho)) {
|
|
159
|
+
throw new Error(`fabrica.batida.caminho-invalido: ${JSON.stringify(caminho)} nao cabe numa linha do cron ` +
|
|
160
|
+
'(precisa ser absoluto, sem % e sem caractere de controle)');
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const PATH = caminhoDaBatida({ node: opcoes.node, achar: opcoes.achar,
|
|
164
|
+
transporte: transporteDoProjeto(raiz, path.join(raiz, '.orkastery', 'monitor')) });
|
|
165
|
+
return `${doctor_pulse_cron_1.BATIDA_DO_TEMPLATE} ORK_PULSE_PROJECT=${(0, doctor_pulse_cron_1.citarNoShell)(raiz)} PATH=${(0, doctor_pulse_cron_1.citarNoShell)(PATH)} ` +
|
|
166
|
+
`${(0, doctor_pulse_cron_1.citarNoShell)(script)} ${exports.MARCA_DA_BATIDA}`;
|
|
167
|
+
}
|
|
168
|
+
/** A linha foi instalada pelo `ork fabrica batida instalar` (traz a marca no fim)? */
|
|
169
|
+
function linhaGerenciada(linha) {
|
|
170
|
+
return linha.trimEnd().endsWith(exports.MARCA_DA_BATIDA);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* As entradas da varredura DESTE projeto, separadas pela marca. O projeto efetivo considera a linha de ambiente do
|
|
174
|
+
* crontab acima da entrada: o template abaixo de `ORK_PULSE_PROJECT=/outro` e a batida do outro, e fica.
|
|
175
|
+
*/
|
|
176
|
+
function separar(texto, raiz) {
|
|
177
|
+
const doProjeto = (0, doctor_pulse_cron_1.entradasDaVarredura)(texto).filter((e) => (0, doctor_pulse_cron_1.entradaDoProjeto)(e, raiz)).map((e) => e.linha);
|
|
178
|
+
return { gerenciadas: doProjeto.filter(linhaGerenciada), manuais: doProjeto.filter((l) => !linhaGerenciada(l)) };
|
|
179
|
+
}
|
|
180
|
+
function ritmoDa(linha) {
|
|
181
|
+
const t = linha.trim();
|
|
182
|
+
const m = t.startsWith('@') ? /^(@\S+)\s/.exec(t) : /^(\S+\s+\S+\s+\S+\s+\S+\s+\S+)\s/.exec(t);
|
|
183
|
+
return m ? (0, doctor_pulse_cron_1.intervaloEmMinutos)(m[1]) : null;
|
|
184
|
+
}
|
|
185
|
+
/** `ork fabrica batida status`: o que o crontab desta maquina diz da batida deste projeto, e a ultima rodada. */
|
|
186
|
+
function estadoDaBatida(raizDoProjeto, opcoes = {}) {
|
|
187
|
+
const raiz = (0, estado_thread_1.raizDoEstado)(raizDoProjeto);
|
|
188
|
+
const executor = opcoes.executor ?? exports.CRONTAB_DO_SISTEMA;
|
|
189
|
+
const quando = opcoes.quando ?? new Date().toISOString();
|
|
190
|
+
const leitura = executor.ler();
|
|
191
|
+
const { gerenciadas, manuais } = leitura.ok ? separar(leitura.texto, raiz) : { gerenciadas: [], manuais: [] };
|
|
192
|
+
const ritmos = [...gerenciadas, ...manuais].map(ritmoDa).filter((r) => r !== null);
|
|
193
|
+
const rodada = (0, doctor_pulse_cron_1.ultimaRodadaDaVarredura)(path.join(raiz, '.orkastery', 'monitor'));
|
|
194
|
+
return {
|
|
195
|
+
projeto: raiz, maquina: (0, maquina_1.nomeDaMaquina)(),
|
|
196
|
+
leitura: leitura.ok ? { ok: true } : { ok: false, motivo: leitura.motivo },
|
|
197
|
+
gerenciada: gerenciadas[0]?.trim() ?? null, manuais: manuais.map((l) => l.trim()),
|
|
198
|
+
instalada: gerenciadas.length + manuais.length > 0,
|
|
199
|
+
intervaloMin: ritmos.length ? Math.min(...ritmos) : null,
|
|
200
|
+
ultimaRodada: rodada ? { ...rodada, haMin: Math.max(0, Math.floor((Date.parse(quando) - Date.parse(rodada.em)) / 60000)) } : null,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function lerParaEditar(executor) {
|
|
204
|
+
const leitura = executor.ler();
|
|
205
|
+
// Nunca gravar sem ter lido: um crontab que nao foi lido seria apagado pela gravacao.
|
|
206
|
+
if (!leitura.ok)
|
|
207
|
+
throw new Error(`fabrica.batida.sem-leitura: ${leitura.motivo}; nada foi gravado`);
|
|
208
|
+
return leitura.texto;
|
|
209
|
+
}
|
|
210
|
+
function gravarEConferir(executor, lido, texto, confere) {
|
|
211
|
+
// O crontab que mudou entre a leitura e a gravacao (um `crontab -e`, outro `instalar`) nao e sobrescrito.
|
|
212
|
+
const antes = executor.ler();
|
|
213
|
+
if (!antes.ok || antes.texto !== lido) {
|
|
214
|
+
throw new Error('fabrica.batida.concorrencia: o crontab mudou durante a operacao; nada foi gravado, rode de novo');
|
|
215
|
+
}
|
|
216
|
+
const gravacao = executor.gravar(texto);
|
|
217
|
+
if (!gravacao.ok)
|
|
218
|
+
throw new Error(`fabrica.batida.sem-gravacao: ${gravacao.motivo}`);
|
|
219
|
+
const relido = executor.ler();
|
|
220
|
+
if (!relido.ok || !confere(relido.texto)) {
|
|
221
|
+
throw new Error(`fabrica.batida.nao-confirmada: o crontab relido nao traz o que foi gravado` +
|
|
222
|
+
(relido.ok ? '' : ` (${relido.motivo})`) + '; confira com crontab -l');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** O texto do crontab sem as linhas pedidas, com o fim de linha que o cron exige. */
|
|
226
|
+
function semAsLinhas(texto, sair) {
|
|
227
|
+
const ficam = texto.split('\n').filter((l) => !sair.has(l));
|
|
228
|
+
while (ficam.length && ficam[ficam.length - 1].trim() === '')
|
|
229
|
+
ficam.pop();
|
|
230
|
+
return ficam.length ? `${ficam.join('\n')}\n` : '';
|
|
231
|
+
}
|
|
232
|
+
function noLedgerDaMaquina(tipo, dados) {
|
|
233
|
+
return (0, ledger_1.registrar)((0, maquina_1.pastaDoUsuario)(), 'maquina', tipo, { maquina: (0, maquina_1.nomeDaMaquina)(), ...dados }).eventId;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* `ork fabrica batida instalar`: idempotente. A linha igual ja instalada nao muda nada; a linha antiga do
|
|
237
|
+
* `ork` e a linha posta a mao da varredura deste projeto saem, e a linha do template entra no lugar. As
|
|
238
|
+
* outras entradas do crontab ficam como estavam.
|
|
239
|
+
*/
|
|
240
|
+
function instalarBatida(raizDoProjeto, opcoes = {}) {
|
|
241
|
+
const raiz = (0, estado_thread_1.raizDoEstado)(raizDoProjeto);
|
|
242
|
+
const executor = opcoes.executor ?? exports.CRONTAB_DO_SISTEMA;
|
|
243
|
+
const linha = linhaDaBatida(raiz, opcoes);
|
|
244
|
+
const texto = lerParaEditar(executor);
|
|
245
|
+
const { gerenciadas, manuais } = separar(texto, raiz);
|
|
246
|
+
if (manuais.length === 0 && gerenciadas.length === 1 && gerenciadas[0].trim() === linha) {
|
|
247
|
+
return { acao: 'ja-instalada', projeto: raiz, linha, retiradas: [], manuais: [], eventId: null };
|
|
248
|
+
}
|
|
249
|
+
const retiradas = [...gerenciadas, ...manuais];
|
|
250
|
+
const base = semAsLinhas(texto, new Set(retiradas));
|
|
251
|
+
gravarEConferir(executor, texto, `${base}${linha}\n`, (relido) => relido.split('\n').some((l) => l.trim() === linha));
|
|
252
|
+
const eventId = noLedgerDaMaquina(ledger_1.TIPOS_DE_EVENTO.batidaInstalada, {
|
|
253
|
+
projeto: raiz, linha, retiradas: retiradas.map((l) => l.trim()), por: opcoes.por ?? null,
|
|
254
|
+
evidencia: 'crontab -l relido depois da gravacao traz a linha',
|
|
255
|
+
});
|
|
256
|
+
return { acao: 'instalou', projeto: raiz, linha, retiradas: retiradas.map((l) => l.trim()), manuais: [], eventId };
|
|
257
|
+
}
|
|
258
|
+
/** `ork fabrica batida remover`: tira so a linha que o `ork` instalou para este projeto. */
|
|
259
|
+
function removerBatida(raizDoProjeto, opcoes = {}) {
|
|
260
|
+
const raiz = (0, estado_thread_1.raizDoEstado)(raizDoProjeto);
|
|
261
|
+
const executor = opcoes.executor ?? exports.CRONTAB_DO_SISTEMA;
|
|
262
|
+
const texto = lerParaEditar(executor);
|
|
263
|
+
const { gerenciadas, manuais } = separar(texto, raiz);
|
|
264
|
+
const ficam = manuais.map((l) => l.trim());
|
|
265
|
+
if (gerenciadas.length === 0)
|
|
266
|
+
return { acao: 'nao-instalada', projeto: raiz, linha: null, retiradas: [], manuais: ficam, eventId: null };
|
|
267
|
+
const sair = new Set(gerenciadas);
|
|
268
|
+
gravarEConferir(executor, texto, semAsLinhas(texto, sair), (relido) => separar(relido, raiz).gerenciadas.length === 0);
|
|
269
|
+
const eventId = noLedgerDaMaquina(ledger_1.TIPOS_DE_EVENTO.batidaRemovida, {
|
|
270
|
+
projeto: raiz, retiradas: gerenciadas.map((l) => l.trim()), manuaisQueFicaram: ficam, por: opcoes.por ?? null,
|
|
271
|
+
evidencia: 'crontab -l relido depois da gravacao nao traz a linha do ork',
|
|
272
|
+
});
|
|
273
|
+
return { acao: 'removeu', projeto: raiz, linha: null, retiradas: gerenciadas.map((l) => l.trim()), manuais: ficam, eventId };
|
|
274
|
+
}
|
|
275
|
+
function textoDoEstadoDaBatida(e, quando = new Date().toISOString()) {
|
|
276
|
+
const linhas = [`Batida da fábrica em ${e.maquina}, projeto ${e.projeto}`];
|
|
277
|
+
if (!e.leitura.ok)
|
|
278
|
+
linhas.push(` crontab: não lido (${e.leitura.motivo}); não dá para dizer se a batida está instalada`);
|
|
279
|
+
else if (!e.instalada)
|
|
280
|
+
linhas.push(' instalada: não; instale com: ork fabrica batida instalar');
|
|
281
|
+
else {
|
|
282
|
+
const ritmo = e.intervaloMin === null ? 'com horário que o ork não lê' : `a cada ${e.intervaloMin} min`;
|
|
283
|
+
linhas.push(` instalada: sim, ${ritmo}${e.gerenciada ? ', pelo ork fabrica batida instalar' : ', por linha posta à mão'}`);
|
|
284
|
+
for (const l of [...(e.gerenciada ? [e.gerenciada] : []), ...e.manuais])
|
|
285
|
+
linhas.push(` linha: ${l}`);
|
|
286
|
+
}
|
|
287
|
+
const r = e.ultimaRodada;
|
|
288
|
+
if (!r)
|
|
289
|
+
linhas.push(' última rodada: nenhuma registrada (.orkastery/monitor/hitl.log)');
|
|
290
|
+
else {
|
|
291
|
+
linhas.push(` última rodada: ${(0, horario_1.formatarHora)(r.em, { agora: quando })} (há ${r.haMin} min), ` +
|
|
292
|
+
`${r.code === 0 ? 'ok' : `código ${r.code ?? '?'}`}: ${r.detalhe || 'sem detalhe'}`);
|
|
293
|
+
if (e.instalada && r.haMin > doctor_pulse_cron_1.ATRASO_DA_BATIDA_MIN) {
|
|
294
|
+
linhas.push(` atrasada: nenhuma rodada há ${r.haMin} min com a batida instalada; confira crontab -l e o hitl.log`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
298
|
+
return linhas.join('\n');
|
|
299
|
+
}
|
|
300
|
+
function textoDoResultadoDaBatida(r) {
|
|
301
|
+
switch (r.acao) {
|
|
302
|
+
case 'ja-instalada': return `Batida já instalada para ${r.projeto}; nada mudou no crontab.\n linha: ${r.linha}`;
|
|
303
|
+
case 'instalou': return [`Batida instalada para ${r.projeto} (evento ${r.eventId} no ledger da máquina).`, ` linha: ${r.linha}`,
|
|
304
|
+
...r.retiradas.map((l) => ` saiu: ${l}`), ' confira com: ork fabrica batida status'].join('\n');
|
|
305
|
+
case 'removeu': return [`Batida removida de ${r.projeto} (evento ${r.eventId} no ledger da máquina).`,
|
|
306
|
+
...r.retiradas.map((l) => ` saiu: ${l}`), ...r.manuais.map((l) => ` ficou (posta à mão, não é do ork): ${l}`)].join('\n');
|
|
307
|
+
case 'nao-instalada': return [`Nenhuma batida do ork instalada para ${r.projeto}; nada mudou no crontab.`,
|
|
308
|
+
...r.manuais.map((l) => ` ficou (posta à mão, não é do ork): ${l}`)].join('\n');
|
|
309
|
+
}
|
|
310
|
+
}
|
package/dist/fabrica-estado.js
CHANGED
|
@@ -57,8 +57,9 @@ exports.painelDaFabricaEmMarkdown = painelDaFabricaEmMarkdown;
|
|
|
57
57
|
* GitHub. `ork board`, `ork fabrica` e o resumo do pulse leem as outras maquinas dali. Cada
|
|
58
58
|
* maquina so escreve o proprio arquivo: push recusado se resolve relendo a ponta.
|
|
59
59
|
*
|
|
60
|
-
* Publicar e empurrar para o remoto do projeto, entao so acontece sozinho com
|
|
61
|
-
* `fabrica
|
|
60
|
+
* Publicar e empurrar para o remoto do projeto, entao so acontece sozinho com a adesao da maquina
|
|
61
|
+
* (`ork fabrica entrar`); o `fabrica.compartilhada` do manifesto so pede (RM-047, P5), e
|
|
62
|
+
* `ork fabrica publicar` e o caminho explicito. Nada de
|
|
62
63
|
* credencial, prompt, log ou caminho local sai daqui: so identificadores, fase, status e o assunto
|
|
63
64
|
* da pausa que espera o dono.
|
|
64
65
|
*
|
|
@@ -81,6 +82,8 @@ const roadmap_reservas_1 = require("./roadmap-reservas");
|
|
|
81
82
|
const thread_1 = require("./thread");
|
|
82
83
|
const util_1 = require("./util");
|
|
83
84
|
const versao_1 = require("./versao");
|
|
85
|
+
const saida_segura_1 = require("./saida-segura");
|
|
86
|
+
const vida_da_thread_1 = require("./vida-da-thread");
|
|
84
87
|
exports.CONTRATO_MAQUINA = 'ork.fabrica-maquina/v1';
|
|
85
88
|
exports.BRANCH_DA_FABRICA = 'ork/fabrica-estado';
|
|
86
89
|
/** O diretorio dos retratos na branch; a leitura sem clone (RM-054) le o mesmo. */
|
|
@@ -161,17 +164,37 @@ function retratoDaMaquina(carregado, opcoes = {}) {
|
|
|
161
164
|
const linhas = new Map(monitor.linhas.map((l) => [l.thread, l]));
|
|
162
165
|
const entregas = entregasNaBase(raiz, carregado.manifesto.worktree.base_branch, remoto);
|
|
163
166
|
const itemDaThread = new Map((0, roadmap_reservas_1.reservasLocais)(raiz, remoto).filter((r) => r.thread).map((r) => [r.thread, r.item]));
|
|
167
|
+
let leitura;
|
|
168
|
+
const lerUmaVez = () => (leitura ??= (opcoes.runtime ?? (() => (0, vida_da_thread_1.lerRuntime)(raiz)))());
|
|
164
169
|
const threads = itens.map(({ thread: t, raiz: raizDoPerfil }) => {
|
|
165
170
|
const entregue = entregas.get(t.id) ?? null;
|
|
166
171
|
// RM-037 (fatia 4): o fim de turno sem pergunta e do condutor, e as outras maquinas nao o leem como espera
|
|
167
172
|
// do dono. Sai so a pausa que o observador abriu nele; outra pausa da thread continua contando.
|
|
168
173
|
let espera = null;
|
|
174
|
+
let eventos = [];
|
|
169
175
|
try {
|
|
170
|
-
|
|
176
|
+
eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raizDoPerfil, t.id));
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
eventos = [];
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
espera = (0, parado_no_condutor_1.esperaDoCondutor)(t, eventos, quando);
|
|
171
183
|
}
|
|
172
184
|
catch {
|
|
173
185
|
espera = null;
|
|
174
186
|
}
|
|
187
|
+
// RM-063 (F2): a fabrica so mostra a thread como andando com a sessao viva verificada no runtime.
|
|
188
|
+
let sessao = null;
|
|
189
|
+
if (!entregue) {
|
|
190
|
+
try {
|
|
191
|
+
const v = (0, vida_da_thread_1.vidaDaThread)(t, eventos, lerUmaVez, Date.parse(quando));
|
|
192
|
+
sessao = { viva: v.viva, desdeEm: v.desdeEm, motivo: v.motivo };
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
sessao = null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
175
198
|
const pausas = (linhas.get(t.id)?.pausas ?? []).filter((p) => !(espera && p.motivo === 'human.pending' && p.fonte === 'ledger' &&
|
|
176
199
|
p.fase === (espera.fase ?? t.faseAtual)));
|
|
177
200
|
const pausa = pausas[0];
|
|
@@ -183,6 +206,7 @@ function retratoDaMaquina(carregado, opcoes = {}) {
|
|
|
183
206
|
esperaVoce, pergunta: esperaVoce && pausa ? curto(pausa.pausaSobre || pausa.detalhe) : null,
|
|
184
207
|
paradaDesde: esperaVoce && pausa ? pausa.desdeEm : null,
|
|
185
208
|
...despachoDaThread((0, thread_1.dirThread)(raizDoPerfil, t.id)),
|
|
209
|
+
sessao,
|
|
186
210
|
};
|
|
187
211
|
}).sort((a, b) => a.id.localeCompare(b.id));
|
|
188
212
|
const eu = (0, roadmap_reservas_1.quemSouEu)(raiz, { por: opcoes.por, maquina: opcoes.maquina });
|
|
@@ -234,7 +258,8 @@ function gravarMarca(raiz, marca) {
|
|
|
234
258
|
*/
|
|
235
259
|
function publicarMaquina(carregado, opcoes = {}) {
|
|
236
260
|
const raiz = carregado.raiz;
|
|
237
|
-
|
|
261
|
+
// RM-047: antes do retrato e da marca, para o remoto invalido recusar mesmo sem mudanca a enviar.
|
|
262
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? carregado.manifesto.fabrica.remoto, PREFIXO);
|
|
238
263
|
const estado = retratoDaMaquina(carregado, { ...opcoes, remoto });
|
|
239
264
|
const assinatura = assinaturaDoRetrato(estado);
|
|
240
265
|
const marca = lerMarca(raiz);
|
|
@@ -274,7 +299,7 @@ function publicarMaquina(carregado, opcoes = {}) {
|
|
|
274
299
|
/** `ork fabrica sair`: tira o retrato desta maquina da branch. `null` quando nao havia retrato. */
|
|
275
300
|
function removerMaquina(carregado, opcoes = {}) {
|
|
276
301
|
const raiz = carregado.raiz;
|
|
277
|
-
const remoto = opcoes.remoto ?? carregado.manifesto.fabrica.remoto;
|
|
302
|
+
const remoto = (0, branch_de_estado_1.exigirRemoto)(opcoes.remoto ?? carregado.manifesto.fabrica.remoto, PREFIXO);
|
|
278
303
|
const maquina = (0, roadmap_reservas_1.quemSouEu)(raiz, { maquina: opcoes.maquina }).maquina;
|
|
279
304
|
for (let tentativa = 1; tentativa <= TENTATIVAS; tentativa++) {
|
|
280
305
|
const { ponta, atualizado } = (0, branch_de_estado_1.buscarBranch)(raiz, remoto, exports.BRANCH_DA_FABRICA, PREFIXO, 30000);
|
|
@@ -321,18 +346,29 @@ function tabela(cabecalho, linhas) {
|
|
|
321
346
|
const linha = (l) => ' ' + l.map((c, i) => c.padEnd(largura[i])).join(' ').trimEnd();
|
|
322
347
|
return [linha(cabecalho), linha(largura.map((n) => '-'.repeat(n))), ...linhas.map(linha)];
|
|
323
348
|
}
|
|
349
|
+
/** RM-063 (F2): a coluna da sessao: `viva`, `parada desde HH:MM: <motivo>`, ou `-` no retrato que nao a traz. */
|
|
350
|
+
function sessaoNaFabrica(t, teto) {
|
|
351
|
+
const v = (0, vida_da_thread_1.vidaDoRetrato)(t.sessao);
|
|
352
|
+
return v.viva ? 'viva' : v.motivo === null ? '-' : curto((0, vida_da_thread_1.paradaDesde)(v), teto);
|
|
353
|
+
}
|
|
324
354
|
function blocoDaMaquina(m, eu) {
|
|
325
355
|
const vivas = ativas(m), entregues = m.threads.length - vivas.length;
|
|
326
356
|
const cabeca = `${m.maquina}${m.maquina === eu ? ' (esta maquina)' : ''}, ${m.por}, publicado ${(0, horario_1.formatarDataHora)(m.publicadoEm)}: ` +
|
|
327
357
|
`${vivas.length} thread(s) ativa(s)` + (entregues ? `, ${entregues} entregue(s) sem MASTER` : '');
|
|
328
358
|
if (vivas.length === 0)
|
|
329
359
|
return [cabeca];
|
|
330
|
-
return [cabeca, ...tabela(['THREAD', 'MODO', 'FASE', 'RUNTIME', 'ITEM', 'ESPERA VOCE'], vivas.map((t) => [
|
|
360
|
+
return [cabeca, ...tabela(['THREAD', 'MODO', 'FASE', 'RUNTIME', 'ITEM', 'ESPERA VOCE', 'SESSAO'], vivas.map((t) => [
|
|
331
361
|
t.id, t.modo, t.fase, runtimeDaThread(t), t.roadmap ?? '-', t.esperaVoce ? `sim: ${curto(t.pergunta ?? 'veredito', 40)}` : '-',
|
|
362
|
+
sessaoNaFabrica(t, 70),
|
|
332
363
|
]))];
|
|
333
364
|
}
|
|
334
|
-
/**
|
|
335
|
-
|
|
365
|
+
/**
|
|
366
|
+
* `ork fabrica`: todas as maquinas. RM-053 (fatia 2): o painel vem do remoto, onde outras pessoas
|
|
367
|
+
* escrevem; cada valor dele (o `por`, o `projeto`, a pergunta) chega a tela numa linha so, sem nada
|
|
368
|
+
* que o terminal execute.
|
|
369
|
+
*/
|
|
370
|
+
function textoDaFabrica(painel, eu) {
|
|
371
|
+
const p = (0, saida_segura_1.valoresEmUmaLinha)(painel);
|
|
336
372
|
const linhas = [];
|
|
337
373
|
if (!p.atualizado)
|
|
338
374
|
linhas.push('AVISO: sem leitura nova do remoto; esta e a ultima copia lida nesta maquina.', '');
|
|
@@ -345,8 +381,9 @@ function textoDaFabrica(p, eu) {
|
|
|
345
381
|
linhas.push((0, horario_1.legendaDoFuso)());
|
|
346
382
|
return linhas.join('\n');
|
|
347
383
|
}
|
|
348
|
-
/** A secao de `ork board` com as outras maquinas
|
|
349
|
-
function textoDasOutrasMaquinas(
|
|
384
|
+
/** A secao de `ork board` com as outras maquinas, saneada como o `ork fabrica`. */
|
|
385
|
+
function textoDasOutrasMaquinas(painel, eu) {
|
|
386
|
+
const p = (0, saida_segura_1.valoresEmUmaLinha)(painel);
|
|
350
387
|
const outras = p.maquinas.filter((m) => m.maquina !== eu);
|
|
351
388
|
const origem = p.atualizado ? 'lido agora' : 'ultima copia local';
|
|
352
389
|
if (outras.length === 0)
|
|
@@ -364,17 +401,18 @@ function painelDaFabricaEmMarkdown(maquinas) {
|
|
|
364
401
|
'O que cada máquina está conduzindo agora. Gerado pelo `ork fabrica publicar`; não edite à mão.',
|
|
365
402
|
'Antes de pegar um item do roadmap: `ork roadmap reservas`.',
|
|
366
403
|
'',
|
|
367
|
-
'| Máquina | Thread | Modo | Fase | Runtime | Item | Espera você | Publicado |',
|
|
368
|
-
'| --- | --- | --- | --- | --- | --- | --- | --- |',
|
|
404
|
+
'| Máquina | Thread | Modo | Fase | Runtime | Item | Espera você | Publicado | Sessão |',
|
|
405
|
+
'| --- | --- | --- | --- | --- | --- | --- | --- | --- |',
|
|
369
406
|
];
|
|
370
407
|
const vivas = maquinas.flatMap((m) => ativas(m).map((t) => ({ m, t })));
|
|
371
408
|
if (vivas.length === 0)
|
|
372
|
-
linhas.push('| — | nenhuma thread ativa | — | — | | — | — | — |');
|
|
409
|
+
linhas.push('| — | nenhuma thread ativa | — | — | | — | — | — | — |');
|
|
373
410
|
for (const { m, t } of vivas) {
|
|
374
411
|
const pergunta = t.esperaVoce ? `sim: ${curto(t.pergunta ?? 'veredito', 60).replace(/\|/g, '/')}` : '—';
|
|
375
412
|
// RM-037 (sugestao 6 do CHECK 1): a celula sem despacho diz isso, sem travessao novo.
|
|
376
413
|
const runtime = t.runtime || t.modelo ? runtimeDaThread(t).replace(/\|/g, '/') : 'sem despacho';
|
|
377
|
-
|
|
414
|
+
const sessao = sessaoNaFabrica(t, 80).replace(/\|/g, '/').replace(/^-$/, '—');
|
|
415
|
+
linhas.push(`| ${m.maquina} | ${t.id} | ${t.modo} | ${t.fase} | ${runtime} | ${t.roadmap ?? '—'} | ${pergunta} | ${(0, horario_1.formatarDataHora)(m.publicadoEm)} | ${sessao} |`);
|
|
378
416
|
}
|
|
379
417
|
return [...linhas, '', (0, horario_1.legendaDoFuso)(), ''].join('\n');
|
|
380
418
|
}
|
package/dist/fabrica-publicar.js
CHANGED
|
@@ -39,18 +39,25 @@ exports.publicarEmSegundoPlano = publicarEmSegundoPlano;
|
|
|
39
39
|
*
|
|
40
40
|
* Modulo a parte, com o minimo de dependencias, porque quem chama (despacho de fase, entrega,
|
|
41
41
|
* thread nova) nao pode esperar rede nem arrastar o retrato inteiro para dentro de si.
|
|
42
|
+
*
|
|
43
|
+
* RM-053 (D9): o mesmo evento tambem dispara o retrato desta maquina na rede da pessoa, pela
|
|
44
|
+
* `rede-adesao` (tao leve quanto este modulo): so membro, no maximo uma vez a cada 14 minutos.
|
|
42
45
|
*/
|
|
43
46
|
const node_child_process_1 = require("node:child_process");
|
|
44
47
|
const fs = __importStar(require("node:fs"));
|
|
45
48
|
const path = __importStar(require("node:path"));
|
|
46
49
|
const maquina_1 = require("./maquina");
|
|
47
50
|
const manifest_1 = require("./manifest");
|
|
51
|
+
const projeto_alvo_1 = require("./projeto-alvo");
|
|
52
|
+
const rede_adesao_1 = require("./rede-adesao");
|
|
48
53
|
/**
|
|
49
54
|
* Publica sem segurar quem chamou (thread nova, despacho de fase, entrega). So com a fabrica
|
|
50
55
|
* compartilhada nesta maquina (`ork fabrica entrar`) ou no projeto; `ORK_FABRICA_PUBLICAR=0`
|
|
51
56
|
* desliga (testes e `ork eval`).
|
|
52
57
|
*/
|
|
53
58
|
function publicarEmSegundoPlano(raiz) {
|
|
59
|
+
// A rede decide por si (adesao, teto e ambiente); o retorno continua sendo o da fabrica.
|
|
60
|
+
(0, rede_adesao_1.publicarRedeEmSegundoPlano)({ diretorio: raiz });
|
|
54
61
|
if (process.env.ORK_FABRICA_PUBLICAR === '0')
|
|
55
62
|
return false;
|
|
56
63
|
let carregado;
|
|
@@ -66,7 +73,8 @@ function publicarEmSegundoPlano(raiz) {
|
|
|
66
73
|
if (!fs.existsSync(cli))
|
|
67
74
|
return false;
|
|
68
75
|
try {
|
|
69
|
-
|
|
76
|
+
// RM-052 (fatia 2, D2): o filho publica o projeto do proprio cwd; o modo host de quem chamou nao o segue.
|
|
77
|
+
const filho = (0, node_child_process_1.spawn)(process.execPath, [cli, 'fabrica', 'publicar', '--silencioso'], { cwd: carregado.raiz, detached: true, stdio: 'ignore', env: { ...process.env, ...projeto_alvo_1.AMBIENTE_SEM_PROJETO_HERDADO } });
|
|
70
78
|
filho.unref();
|
|
71
79
|
return true;
|
|
72
80
|
}
|
package/dist/fechamento.js
CHANGED
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
3
|
exports.liberarAoFechar = liberarAoFechar;
|
|
37
4
|
/**
|
|
@@ -43,61 +10,48 @@ exports.liberarAoFechar = liberarAoFechar;
|
|
|
43
10
|
* derruba. Cada parte roda isolada (achado A1 do CHECK 1): erro de E/S numa nao impede a outra, e o
|
|
44
11
|
* que nao saiu agora sai na poda do proximo pedido de regiao ou no `ork roadmap reservas --soltar-orfas`.
|
|
45
12
|
*/
|
|
46
|
-
const fs = __importStar(require("node:fs"));
|
|
47
|
-
const path = __importStar(require("node:path"));
|
|
48
|
-
const estado_thread_1 = require("./estado-thread");
|
|
49
13
|
const ledger_1 = require("./ledger");
|
|
50
14
|
const leases_1 = require("./leases");
|
|
51
15
|
const roadmap_reservas_1 = require("./roadmap-reservas");
|
|
16
|
+
const sessoes_1 = require("./sessoes");
|
|
52
17
|
const thread_1 = require("./thread");
|
|
53
18
|
function liberarAoFechar(raiz, threadId) {
|
|
54
|
-
const saida = { leases: [], fila: [], reservas: [], falhas: [] };
|
|
19
|
+
const saida = { leases: [], fila: [], reservas: [], sessoes: [], falhas: [] };
|
|
55
20
|
const falhou = (parte, e) => saida.falhas.push(`${parte}: ${e?.message ?? String(e)}`);
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
const real = (p) => { try {
|
|
59
|
-
return fs.realpathSync(p);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return path.resolve(p);
|
|
63
|
-
} };
|
|
64
|
-
const candidatos = [raiz];
|
|
21
|
+
// RM-036 (D6): os leases de regiao moram todos no estado canonico, chamado de qualquer checkout, e a
|
|
22
|
+
// soltura de la ja alcanca o legado que a versao anterior gravou nas worktrees. Uma soltura basta.
|
|
65
23
|
try {
|
|
66
|
-
|
|
24
|
+
const solto = (0, leases_1.soltarThreadFechada)(raiz, threadId, 'fechamento');
|
|
25
|
+
saida.leases.push(...solto.leases);
|
|
26
|
+
saida.fila.push(...solto.fila);
|
|
67
27
|
}
|
|
68
28
|
catch (e) {
|
|
69
|
-
falhou(
|
|
29
|
+
falhou(`leases em ${raiz}`, e);
|
|
70
30
|
}
|
|
71
31
|
try {
|
|
72
|
-
|
|
73
|
-
if (wt && fs.existsSync(wt))
|
|
74
|
-
candidatos.push(wt);
|
|
32
|
+
saida.reservas = (0, roadmap_reservas_1.soltarReservaDaThread)(raiz, threadId);
|
|
75
33
|
}
|
|
76
34
|
catch (e) {
|
|
77
|
-
falhou('
|
|
78
|
-
}
|
|
79
|
-
const checkouts = candidatos.filter((c, i) => candidatos.findIndex((x) => real(x) === real(c)) === i);
|
|
80
|
-
for (const checkout of checkouts) {
|
|
81
|
-
try {
|
|
82
|
-
const solto = (0, leases_1.soltarThreadFechada)(checkout, threadId, 'fechamento');
|
|
83
|
-
saida.leases.push(...solto.leases);
|
|
84
|
-
saida.fila.push(...solto.fila);
|
|
85
|
-
}
|
|
86
|
-
catch (e) {
|
|
87
|
-
falhou(`leases em ${checkout}`, e);
|
|
88
|
-
}
|
|
35
|
+
falhou('reserva', e);
|
|
89
36
|
}
|
|
37
|
+
// RM-056 (ao fechar): a sessao fantasma presa a thread fechada seguia no inventario e no doctor ate
|
|
38
|
+
// alguem rodar `ork sessions limpar-fantasmas` (624f65db e d38ae1d4, 03/10). So consulta o runtime
|
|
39
|
+
// quando o ledger tem sessao sem fim; nunca para nem remove nada no runtime, e sessao viva fica.
|
|
90
40
|
try {
|
|
91
|
-
|
|
41
|
+
if ((0, sessoes_1.sessoesSemFim)(raiz, threadId).length > 0) {
|
|
42
|
+
const r = (0, sessoes_1.limparFantasmas)(raiz, { thread: threadId, origem: 'fechamento' });
|
|
43
|
+
saida.sessoes = r.itens.filter((i) => i.acao === 'solto');
|
|
44
|
+
}
|
|
92
45
|
}
|
|
93
46
|
catch (e) {
|
|
94
|
-
falhou('
|
|
47
|
+
falhou('sessoes', e);
|
|
95
48
|
}
|
|
96
49
|
// Sugestao 2 do CHECK 2: a falha tambem vai ao ledger da thread, de melhor esforco.
|
|
97
50
|
if (saida.falhas.length > 0) {
|
|
98
51
|
try {
|
|
99
52
|
(0, ledger_1.registrarSeExiste)((0, thread_1.dirThread)(raiz, threadId), threadId, ledger_1.TIPOS_DE_EVENTO.solturaFalhou, { falhas: saida.falhas,
|
|
100
|
-
correcao: 'a poda do proximo pedido de regiao solta o que ficou; reserva: ork roadmap reservas --soltar-orfas'
|
|
53
|
+
correcao: 'a poda do proximo pedido de regiao solta o que ficou; reserva: ork roadmap reservas --soltar-orfas; ' +
|
|
54
|
+
'sessao fantasma: ork sessions limpar-fantasmas' });
|
|
101
55
|
}
|
|
102
56
|
catch { /* o ledger que nao grava ja esta nas falhas */ }
|
|
103
57
|
}
|