@orkastery/cli 0.5.0 → 0.5.3
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 +11 -2
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/onboarding.md +3 -2
- package/adapters/claude-code/commands/ork.md +9 -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 +6 -5
- package/adapters/openclaw/README.md +35 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +47 -12
- 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 +50 -12
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +59 -11
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +6 -2
- package/dist/board.js +16 -14
- package/dist/branch-de-estado.js +66 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/ci.js +8 -1
- package/dist/claim-lint.js +3 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +110 -3
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +294 -37
- package/dist/entrega-pr.js +27 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +35 -9
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/fix.js +3 -3
- package/dist/forja.js +31 -7
- package/dist/gates.js +5 -1
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +33 -1
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/horario.js +27 -0
- package/dist/hosts.js +59 -13
- package/dist/impedimento.js +205 -0
- package/dist/index.js +433 -88
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +28 -5
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +267 -30
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-contract.js +71 -12
- package/dist/intelligence-graph-extract-md.js +41 -23
- package/dist/intelligence-graph-extract-ts.js +181 -11
- package/dist/intelligence-graph-extract.js +186 -9
- package/dist/intelligence-graph-index.js +205 -24
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-repo.js +10 -0
- package/dist/leases.js +680 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +12 -0
- package/dist/licoes.js +6 -4
- package/dist/liveness.js +2 -1
- package/dist/maestro-runtime.js +7 -1
- package/dist/manifest.js +44 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +36 -3
- package/dist/mcp-git.js +80 -15
- package/dist/mcp-grafo-worker.js +93 -0
- package/dist/mcp-grafo.js +279 -0
- package/dist/mcp-install.js +2 -1
- package/dist/mcp-server.js +23 -1
- package/dist/mcp-ship.js +2 -0
- package/dist/mcp-verify.js +3 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +195 -20
- package/dist/ocupacao.js +17 -5
- package/dist/onboarding.js +9 -4
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +14 -11
- package/dist/parado-no-condutor.js +1089 -0
- package/dist/phase.js +68 -15
- package/dist/policies.js +79 -3
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +414 -0
- package/dist/pulse-delivery.js +60 -7
- package/dist/pulse.js +99 -3
- package/dist/ratelimit.js +20 -4
- package/dist/recall.js +3 -1
- 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 +336 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +69 -2
- package/dist/roadmap-status.js +162 -7
- package/dist/runtime-context.js +5 -1
- package/dist/runtime-profiles.js +22 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-watcher-claude.js +113 -23
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -12
- package/dist/sessoes.js +87 -3
- package/dist/ship.js +110 -20
- package/dist/thread.js +212 -14
- package/dist/util.js +71 -4
- package/dist/verify.js +2 -2
- package/dist/worktree.js +34 -8
- package/eval/casos/onboarding.json +1 -1
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/skills/README.md +1 -1
- package/skills/core/onboarding/SKILL.md +3 -2
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
- package/skills/phases/ship-release/SKILL.md +6 -3
|
@@ -0,0 +1,414 @@
|
|
|
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.ENTRADAS = exports.HOSTS_DA_PROVA = void 0;
|
|
37
|
+
exports.transcriptDoClaude = transcriptDoClaude;
|
|
38
|
+
exports.transcriptDoOpenclaw = transcriptDoOpenclaw;
|
|
39
|
+
exports.transcriptDoCodex = transcriptDoCodex;
|
|
40
|
+
exports.extrairSnapshot = extrairSnapshot;
|
|
41
|
+
exports.conferirProva = conferirProva;
|
|
42
|
+
exports.redigir = redigir;
|
|
43
|
+
exports.redigirObjeto = redigirObjeto;
|
|
44
|
+
/**
|
|
45
|
+
* RM-032: conferência da prova de ativação por host, sem host.
|
|
46
|
+
*
|
|
47
|
+
* O roteiro `core/scripts/prova-ativacao.cjs` abre uma sessão nova e não interativa no host
|
|
48
|
+
* (Claude Code, OpenClaw ou Codex), diz `orkastery maestro` e entrega aqui o transcript. Esta
|
|
49
|
+
* conferência olha só o que é determinístico: qual ferramenta o modelo chamou, o resultado que
|
|
50
|
+
* ela devolveu (contra o contrato da entrada) e o projeto lido. Da resposta final em texto
|
|
51
|
+
* livre, exige apenas que cite o projeto e não repita o incidente de 29/09 ("roadmap vazio").
|
|
52
|
+
*/
|
|
53
|
+
const fs = __importStar(require("node:fs"));
|
|
54
|
+
const path = __importStar(require("node:path"));
|
|
55
|
+
const maestro_contract_1 = require("./maestro-contract");
|
|
56
|
+
exports.HOSTS_DA_PROVA = ['claude-code', 'openclaw', 'codex'];
|
|
57
|
+
/**
|
|
58
|
+
* As entradas da frase em cada host. No Claude, a tool MCP do servidor `orkastery` fixado no
|
|
59
|
+
* projeto (MAESTRO_HOST_SURFACES em hosts.ts). No OpenClaw 0.5.0 (RM-054, fatia 2), a frase sem
|
|
60
|
+
* projeto vai a `ork_network_roadmap`, a única tool da extensão no perfil `coding`; com projeto
|
|
61
|
+
* nomeado, a `ork_maestro`. No Codex (B11), a tool `ork_maestro` do servidor `orkastery` que o
|
|
62
|
+
* `ork mcp install --host codex` grava no projeto; o nome segue o padrão `mcp__<servidor>__<tool>`.
|
|
63
|
+
* `ork maestro` pelo shell do host é desvio: o CLI resolve o projeto pelo diretório atual, a classe
|
|
64
|
+
* de erro do incidente.
|
|
65
|
+
*/
|
|
66
|
+
exports.ENTRADAS = {
|
|
67
|
+
'claude-code': [{ ferramenta: 'mcp__orkastery__ork_maestro', contrato: 'maestro' }],
|
|
68
|
+
openclaw: [{ ferramenta: 'ork_network_roadmap', contrato: 'rede' }, { ferramenta: 'ork_maestro', contrato: 'maestro' }],
|
|
69
|
+
codex: [{ ferramenta: 'mcp__orkastery__ork_maestro', contrato: 'maestro' }],
|
|
70
|
+
};
|
|
71
|
+
const SHELL_DO_HOST = { 'claude-code': 'Bash', openclaw: 'exec', codex: 'command_execution' };
|
|
72
|
+
// B11: o shell do Codex chega embrulhado (`bash -lc 'ork maestro'`), então aspas também abrem o comando.
|
|
73
|
+
// Suspeitas da revisão de 03/10: o mesmo CLI roda também pelo caminho do binário (`$(which ork)`), pelo
|
|
74
|
+
// node (`core/dist/index.js`), pelo npx (`@orkastery/cli`) e com o projeto entre aspas. É desvio a
|
|
75
|
+
// invocação do ork cujo subcomando, depois só de opções (com valor, até entre aspas), é `maestro`;
|
|
76
|
+
// `maestro` dentro do argumento de outro subcomando não é.
|
|
77
|
+
const INVOCACAO_DO_ORK = String.raw `(?:(?:^|[^\w.@-])ork|@orkastery\/cli(?:@[\w.-]+)?|\bdist\/index\.js)(?![\w.-])[)\x60]?`;
|
|
78
|
+
const VALOR = String.raw `(?:"[^"]*"|'[^']*'|[^\s"'-][^\s"']*)`;
|
|
79
|
+
const OPCOES = String.raw `(?:\s+-[\w-]*(?:=(?:"[^"]*"|'[^']*'|[^\s"']+))?(?:\s+${VALOR})?)*`;
|
|
80
|
+
const ORK_MAESTRO_NO_SHELL = new RegExp(String.raw `${INVOCACAO_DO_ORK}${OPCOES}\s+maestro(?![\w.-])`);
|
|
81
|
+
function linhasJson(texto) {
|
|
82
|
+
const eventos = [];
|
|
83
|
+
for (const linha of texto.split('\n')) {
|
|
84
|
+
const limpa = linha.trim();
|
|
85
|
+
if (!limpa.startsWith('{'))
|
|
86
|
+
continue;
|
|
87
|
+
try {
|
|
88
|
+
eventos.push(JSON.parse(limpa));
|
|
89
|
+
}
|
|
90
|
+
catch { /* linha de log do host, não evento */ }
|
|
91
|
+
}
|
|
92
|
+
return eventos;
|
|
93
|
+
}
|
|
94
|
+
function textoDoConteudo(conteudo) {
|
|
95
|
+
if (typeof conteudo === 'string')
|
|
96
|
+
return conteudo;
|
|
97
|
+
if (!Array.isArray(conteudo))
|
|
98
|
+
return null;
|
|
99
|
+
const partes = conteudo.filter((c) => !!c && typeof c === 'object' && c.type === 'text' && typeof c.text === 'string');
|
|
100
|
+
return partes.length ? partes.map(p => p.text).join('\n') : null;
|
|
101
|
+
}
|
|
102
|
+
function classificar(host, ferramenta, argumentos) {
|
|
103
|
+
const entrada = exports.ENTRADAS[host].find(e => e.ferramenta === ferramenta);
|
|
104
|
+
if (entrada)
|
|
105
|
+
return { via: 'entrada', contrato: entrada.contrato };
|
|
106
|
+
const comando = argumentos?.command;
|
|
107
|
+
if (ferramenta === SHELL_DO_HOST[host] && typeof comando === 'string' && ORK_MAESTRO_NO_SHELL.test(comando))
|
|
108
|
+
return { via: 'shell', contrato: null };
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
/** Transcript `claude -p --output-format stream-json --verbose`. */
|
|
112
|
+
function transcriptDoClaude(streamJson) {
|
|
113
|
+
const eventos = linhasJson(streamJson);
|
|
114
|
+
let ferramentasExpostas = null;
|
|
115
|
+
let respostaFinal = null;
|
|
116
|
+
const pedidas = new Map();
|
|
117
|
+
const chamadas = [];
|
|
118
|
+
for (const e of eventos) {
|
|
119
|
+
if (e.type === 'system' && e.subtype === 'init' && Array.isArray(e.tools))
|
|
120
|
+
ferramentasExpostas = e.tools.filter((t) => typeof t === 'string');
|
|
121
|
+
const mensagem = e.message;
|
|
122
|
+
const blocos = Array.isArray(mensagem?.content) ? mensagem.content : [];
|
|
123
|
+
if (e.type === 'assistant') {
|
|
124
|
+
for (const b of blocos) {
|
|
125
|
+
if (b?.type !== 'tool_use' || typeof b.name !== 'string' || typeof b.id !== 'string')
|
|
126
|
+
continue;
|
|
127
|
+
const tipo = classificar('claude-code', b.name, b.input);
|
|
128
|
+
if (!tipo)
|
|
129
|
+
continue;
|
|
130
|
+
const chamada = { ferramenta: b.name, ...tipo, argumentos: b.input ?? null, resultado: null, erro: false };
|
|
131
|
+
pedidas.set(b.id, chamada);
|
|
132
|
+
chamadas.push(chamada);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (e.type === 'user') {
|
|
136
|
+
for (const b of blocos) {
|
|
137
|
+
if (b?.type !== 'tool_result' || typeof b.tool_use_id !== 'string')
|
|
138
|
+
continue;
|
|
139
|
+
const chamada = pedidas.get(b.tool_use_id);
|
|
140
|
+
if (!chamada)
|
|
141
|
+
continue;
|
|
142
|
+
chamada.resultado = textoDoConteudo(b.content);
|
|
143
|
+
chamada.erro = b.is_error === true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (e.type === 'result' && typeof e.result === 'string')
|
|
147
|
+
respostaFinal = e.result;
|
|
148
|
+
}
|
|
149
|
+
return { ferramentasExpostas, chamadas, respostaFinal };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Trajetória do OpenClaw (`openclaw sessions export-trajectory`, `events.jsonl`): eventos
|
|
153
|
+
* `tool.call`/`tool.result` da origem `runtime`. As ferramentas expostas e a resposta final vêm
|
|
154
|
+
* do `openclaw agent --json` (`meta.systemPromptReport.tools.entries`, `payloads[].text`).
|
|
155
|
+
*/
|
|
156
|
+
function transcriptDoOpenclaw(eventsJsonl, agenteJson) {
|
|
157
|
+
const pedidas = new Map();
|
|
158
|
+
const chamadas = [];
|
|
159
|
+
for (const e of linhasJson(eventsJsonl)) {
|
|
160
|
+
if (e.source !== 'runtime')
|
|
161
|
+
continue;
|
|
162
|
+
const d = (e.data ?? {});
|
|
163
|
+
if (typeof d.toolCallId !== 'string' || typeof d.name !== 'string')
|
|
164
|
+
continue;
|
|
165
|
+
if (e.type === 'tool.call') {
|
|
166
|
+
const tipo = classificar('openclaw', d.name, d.args);
|
|
167
|
+
if (!tipo)
|
|
168
|
+
continue;
|
|
169
|
+
const chamada = { ferramenta: d.name, ...tipo, argumentos: d.args ?? null, resultado: null, erro: false };
|
|
170
|
+
pedidas.set(d.toolCallId, chamada);
|
|
171
|
+
chamadas.push(chamada);
|
|
172
|
+
}
|
|
173
|
+
else if (e.type === 'tool.result') {
|
|
174
|
+
const chamada = pedidas.get(d.toolCallId);
|
|
175
|
+
if (!chamada)
|
|
176
|
+
continue;
|
|
177
|
+
chamada.resultado = textoDoConteudo(d.result?.content);
|
|
178
|
+
chamada.erro = d.success !== true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const agente = (agenteJson ?? {});
|
|
182
|
+
const entradas = agente.meta?.systemPromptReport?.tools?.entries;
|
|
183
|
+
const ferramentasExpostas = Array.isArray(entradas) ? entradas.map(t => t?.name).filter((n) => typeof n === 'string') : null;
|
|
184
|
+
const textos = (agente.payloads ?? []).map(p => p?.text).filter((t) => typeof t === 'string');
|
|
185
|
+
return { ferramentasExpostas, chamadas, respostaFinal: textos.length ? textos.join('\n') : null };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Eventos do `codex exec --json` (B11): `item.started`/`item.completed` com `mcp_tool_call` (servidor,
|
|
189
|
+
* tool, argumentos, resultado, erro), `command_execution` (o shell do host) e `agent_message` (a
|
|
190
|
+
* resposta). O `codex exec` não lista as ferramentas expostas ao modelo: quem chama passa as do
|
|
191
|
+
* `tools/list` do mesmo servidor MCP que a sessão recebeu, já com o nome `mcp__<servidor>__<tool>`.
|
|
192
|
+
*/
|
|
193
|
+
function transcriptDoCodex(eventosJsonl, ferramentasExpostas) {
|
|
194
|
+
const porItem = new Map();
|
|
195
|
+
const chamadas = [];
|
|
196
|
+
const mensagens = [];
|
|
197
|
+
for (const e of linhasJson(eventosJsonl)) {
|
|
198
|
+
if (e.type !== 'item.started' && e.type !== 'item.completed')
|
|
199
|
+
continue;
|
|
200
|
+
const item = (e.item ?? {});
|
|
201
|
+
const id = typeof item.id === 'string' ? item.id : null;
|
|
202
|
+
if (item.type === 'agent_message') {
|
|
203
|
+
if (e.type === 'item.completed' && typeof item.text === 'string')
|
|
204
|
+
mensagens.push(item.text);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
let ferramenta, argumentos, resultado = null, erro = false;
|
|
208
|
+
if (item.type === 'mcp_tool_call' && typeof item.server === 'string' && typeof item.tool === 'string') {
|
|
209
|
+
ferramenta = `mcp__${item.server}__${item.tool}`;
|
|
210
|
+
argumentos = item.arguments ?? null;
|
|
211
|
+
const r = item.result;
|
|
212
|
+
resultado = typeof r === 'string' ? r : textoDoConteudo(r?.content);
|
|
213
|
+
const falha = item.error;
|
|
214
|
+
erro = !!falha || item.status === 'failed';
|
|
215
|
+
if (erro && resultado === null)
|
|
216
|
+
resultado = typeof falha === 'string' ? falha : typeof falha?.message === 'string' ? falha.message : 'falhou';
|
|
217
|
+
}
|
|
218
|
+
else if (item.type === 'command_execution' && typeof item.command === 'string') {
|
|
219
|
+
ferramenta = 'command_execution';
|
|
220
|
+
argumentos = { command: item.command };
|
|
221
|
+
resultado = typeof item.aggregated_output === 'string' ? item.aggregated_output : null;
|
|
222
|
+
erro = item.status === 'failed' || (typeof item.exit_code === 'number' && item.exit_code !== 0);
|
|
223
|
+
}
|
|
224
|
+
else
|
|
225
|
+
continue;
|
|
226
|
+
const tipo = classificar('codex', ferramenta, argumentos);
|
|
227
|
+
if (!tipo)
|
|
228
|
+
continue;
|
|
229
|
+
const anterior = id ? porItem.get(id) : undefined;
|
|
230
|
+
if (anterior) {
|
|
231
|
+
// `item.completed` do mesmo item fecha a chamada aberta no `item.started`.
|
|
232
|
+
if (e.type === 'item.completed')
|
|
233
|
+
Object.assign(anterior, { argumentos, resultado, erro });
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const chamada = { ferramenta, ...tipo, argumentos, resultado: e.type === 'item.completed' ? resultado : null,
|
|
237
|
+
erro: e.type === 'item.completed' ? erro : false };
|
|
238
|
+
if (id)
|
|
239
|
+
porItem.set(id, chamada);
|
|
240
|
+
chamadas.push(chamada);
|
|
241
|
+
}
|
|
242
|
+
return { ferramentasExpostas, chamadas, respostaFinal: mensagens.length ? mensagens.at(-1) : null };
|
|
243
|
+
}
|
|
244
|
+
/** O primeiro objeto `ork.maestro-snapshot/v1` do texto (o host pode juntar stderr ao stdout). */
|
|
245
|
+
function extrairSnapshot(texto) {
|
|
246
|
+
const inicio = texto.indexOf('{"schema":"ork.maestro-snapshot/v1"');
|
|
247
|
+
if (inicio < 0)
|
|
248
|
+
return null;
|
|
249
|
+
let profundidade = 0, emTexto = false, escape = false;
|
|
250
|
+
for (let i = inicio; i < texto.length; i++) {
|
|
251
|
+
const c = texto[i];
|
|
252
|
+
if (emTexto) {
|
|
253
|
+
if (escape)
|
|
254
|
+
escape = false;
|
|
255
|
+
else if (c === '\\')
|
|
256
|
+
escape = true;
|
|
257
|
+
else if (c === '"')
|
|
258
|
+
emTexto = false;
|
|
259
|
+
}
|
|
260
|
+
else if (c === '"')
|
|
261
|
+
emTexto = true;
|
|
262
|
+
else if (c === '{')
|
|
263
|
+
profundidade++;
|
|
264
|
+
else if (c === '}' && --profundidade === 0) {
|
|
265
|
+
try {
|
|
266
|
+
return JSON.parse(texto.slice(inicio, i + 1));
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
function expandirHome(raiz, home) {
|
|
276
|
+
return raiz === '~' ? home : raiz.startsWith('~/') ? path.join(home, raiz.slice(2)) : raiz;
|
|
277
|
+
}
|
|
278
|
+
const ROADMAP_VAZIO = /\broadmap\b:?((?:\s+[^\s.!?:;,]+){0,4}?)\s+(vazio|empty)\b/giu;
|
|
279
|
+
const NEGACAO = /(^|[^\p{L}])(n[ãa]o|nunca|jamais|not|never|isn't|doesn't|nem)([^\p{L}]|$)/iu;
|
|
280
|
+
/**
|
|
281
|
+
* A frase que conclui "roadmap vazio". A negação só conta quando governa a conclusão: dentro do
|
|
282
|
+
* trecho ("the roadmap is not empty") ou nas até seis palavras antes dele, sem atravessar
|
|
283
|
+
* pontuação ("zero threads não quer dizer roadmap vazio"). "O roadmap está vazio e não há
|
|
284
|
+
* threads" e "Não há itens: o roadmap está vazio" concluem.
|
|
285
|
+
*/
|
|
286
|
+
function concluiRoadmapVazio(texto) {
|
|
287
|
+
for (const m of texto.matchAll(ROADMAP_VAZIO)) {
|
|
288
|
+
const antes = texto.slice(0, m.index).split(/[.!?:;,\n]/).pop().trim().split(/\s+/).slice(-6).join(' ');
|
|
289
|
+
if (!NEGACAO.test(antes) && !NEGACAO.test(m[1]))
|
|
290
|
+
return `${antes} ${m[0]}`.trim();
|
|
291
|
+
}
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const canonica = (p) => { try {
|
|
295
|
+
return fs.realpathSync(p);
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
return path.resolve(p);
|
|
299
|
+
} };
|
|
300
|
+
/** Nome inteiro, não pedaço de palavra: a abreviação `pav` não casa com "pavimento". */
|
|
301
|
+
const nomeia = (texto, nome) => new RegExp(`(^|[^\\p{L}\\p{N}_-])${nome.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^\\p{L}\\p{N}_-]|$)`, 'iu').test(texto);
|
|
302
|
+
/**
|
|
303
|
+
* O texto de `ork network roadmap` (`textoDoPanoramaDaRede`): a primeira linha diz de onde foi
|
|
304
|
+
* lido, a segunda quais projetos foram consultados (`<nome> (clone em <raiz>)`) e o bloco
|
|
305
|
+
* "Não consultado:" o que ficou de fora.
|
|
306
|
+
*/
|
|
307
|
+
function lerPanoramaDaRede(texto) {
|
|
308
|
+
const linhas = texto.split('\n');
|
|
309
|
+
const i = linhas.findIndex(l => /^Panorama da rede lido de /.test(l));
|
|
310
|
+
if (i < 0 || !/^Consultado: /.test(linhas[i + 1] ?? '') || linhas[i + 2] !== 'Não consultado:')
|
|
311
|
+
return null;
|
|
312
|
+
const naoConsultado = [];
|
|
313
|
+
for (const l of linhas.slice(i + 3)) {
|
|
314
|
+
if (!l.startsWith('• '))
|
|
315
|
+
break;
|
|
316
|
+
naoConsultado.push(l.slice(2));
|
|
317
|
+
}
|
|
318
|
+
return { cabecalho: linhas[i], consultado: linhas[i + 1], naoConsultado };
|
|
319
|
+
}
|
|
320
|
+
function conferirProva(host, t, esperado) {
|
|
321
|
+
const conferencias = [];
|
|
322
|
+
const conferir = (id, ok, detalhe) => { conferencias.push({ id, ok, detalhe }); return ok; };
|
|
323
|
+
const nomes = exports.ENTRADAS[host].map(e => e.ferramenta);
|
|
324
|
+
const expostas = nomes.filter(n => t.ferramentasExpostas?.includes(n));
|
|
325
|
+
conferir('entrada.exposta', expostas.length > 0, t.ferramentasExpostas === null ? 'o transcript não lista as ferramentas expostas'
|
|
326
|
+
: expostas.length ? `${expostas.join(', ')} exposta(s) ao modelo`
|
|
327
|
+
: `${nomes.join(' e ')} ausente(s) entre ${t.ferramentasExpostas.length} ferramentas expostas`);
|
|
328
|
+
// A última chamada contratada com resultado é a que vale (uma nova tentativa depois de erro não
|
|
329
|
+
// reprova); qualquer `ork maestro` pelo shell reprova, mesmo ao lado da chamada contratada.
|
|
330
|
+
const contratadas = t.chamadas.filter(c => c.via === 'entrada');
|
|
331
|
+
const contratada = [...contratadas].reverse().find(c => c.resultado !== null && !c.erro) ?? contratadas.at(-1);
|
|
332
|
+
const desvio = t.chamadas.find(c => c.via === 'shell');
|
|
333
|
+
const comando = desvio && JSON.stringify(desvio.argumentos?.command);
|
|
334
|
+
conferir('entrada.chamada', !!contratada && !desvio, contratada && desvio ? `${contratada.ferramenta} chamada, mas também desvio: ${desvio.ferramenta} ${comando}`
|
|
335
|
+
: contratada ? `${contratada.ferramenta} chamada`
|
|
336
|
+
: desvio ? `desvio: ${desvio.ferramenta} ${comando} em vez de ${nomes.join(' ou ')}`
|
|
337
|
+
: `${nomes.join(' ou ')} não foi chamada`);
|
|
338
|
+
let snapshot = null;
|
|
339
|
+
let rede = null;
|
|
340
|
+
if (contratada && conferir('resultado.sem-erro', contratada.resultado !== null && !contratada.erro, contratada.resultado === null ? 'a chamada não teve resultado' : contratada.erro ? `erro: ${contratada.resultado.slice(0, 300)}` : 'resultado sem erro')) {
|
|
341
|
+
if (contratada.contrato === 'maestro') {
|
|
342
|
+
try {
|
|
343
|
+
snapshot = (0, maestro_contract_1.validateMaestroSnapshot)(extrairSnapshot(contratada.resultado));
|
|
344
|
+
conferir('resultado.contrato', true, `${snapshot.schema} validado`);
|
|
345
|
+
}
|
|
346
|
+
catch (e) {
|
|
347
|
+
conferir('resultado.contrato', false, `fora do contrato: ${e.message.slice(0, 300)}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
rede = lerPanoramaDaRede(contratada.resultado);
|
|
352
|
+
conferir('resultado.contrato', rede !== null, rede ? 'texto do ork.network-roadmap/v1: cabeçalho, Consultado e Não consultado'
|
|
353
|
+
: 'fora do contrato: sem o cabeçalho "Panorama da rede lido de", "Consultado:" e "Não consultado:"');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (snapshot) {
|
|
357
|
+
const p = snapshot.project;
|
|
358
|
+
const exibida = p.root === undefined || p.root.includes('[caminho privado]') ? null : canonica(expandirHome(p.root, esperado.home));
|
|
359
|
+
const mesmaCopia = p.fingerprint === esperado.projeto.fingerprint && (exibida === null || exibida === canonica(esperado.projeto.raiz));
|
|
360
|
+
conferir('resultado.projeto', p.name === esperado.projeto.nome && mesmaCopia, `leu ${p.name} (${p.origin}) em ${p.root ?? 'raiz não exibida'}, impressão ${p.fingerprint.slice(0, 12)}; ` +
|
|
361
|
+
`esperado ${esperado.projeto.nome}, impressão ${esperado.projeto.fingerprint.slice(0, 12)}`);
|
|
362
|
+
const lacunas = snapshot.notConsulted ?? [];
|
|
363
|
+
conferir('resultado.nao-consultado', lacunas.length > 0, lacunas.length ? `declara o que não leu: ${lacunas.length} item(ns)` : 'notConsulted ausente: zero threads pode virar "roadmap vazio"');
|
|
364
|
+
}
|
|
365
|
+
if (rede) {
|
|
366
|
+
// "Consultado: a (clone em X); b (clone em Y)": vale o projeto esperado na raiz esperada.
|
|
367
|
+
const lidos = [...rede.consultado.replace(/^Consultado: /, '').matchAll(/(?:^|; )(.+?) \(clone em ([^)]+)\)/g)];
|
|
368
|
+
const leu = lidos.some(([, nome, raiz]) => nome === esperado.projeto.nome &&
|
|
369
|
+
canonica(expandirHome(raiz, esperado.home)) === canonica(esperado.projeto.raiz));
|
|
370
|
+
conferir('resultado.projeto', leu, `${rede.consultado.slice(0, 300)}; esperado ${esperado.projeto.nome} (clone em ${esperado.projeto.raiz})`);
|
|
371
|
+
conferir('resultado.nao-consultado', rede.naoConsultado.length > 0, rede.naoConsultado.length ? `declara o que não leu: ${rede.naoConsultado.length} item(ns)` : 'sem o bloco do que não foi consultado');
|
|
372
|
+
}
|
|
373
|
+
const resposta = t.respostaFinal ?? '';
|
|
374
|
+
const citaProjeto = [esperado.projeto.nome, esperado.projeto.id].some(n => nomeia(resposta, n));
|
|
375
|
+
conferir('resposta.cita-projeto', citaProjeto, t.respostaFinal === null ? 'sem resposta final' : citaProjeto ? 'a resposta nomeia o projeto lido' : 'a resposta não nomeia o projeto lido');
|
|
376
|
+
const vazio = concluiRoadmapVazio(resposta);
|
|
377
|
+
conferir('resposta.sem-roadmap-vazio', vazio === null, vazio ? `a resposta conclui "roadmap vazio" a partir do panorama (incidente de 29/09): ${vazio.slice(0, 200)}` : 'sem concluir "roadmap vazio" a partir do panorama');
|
|
378
|
+
return {
|
|
379
|
+
ok: conferencias.every(c => c.ok),
|
|
380
|
+
conferencias,
|
|
381
|
+
snapshot: snapshot && {
|
|
382
|
+
schema: snapshot.schema, projeto: snapshot.project,
|
|
383
|
+
secoes: Object.fromEntries(Object.entries(snapshot.sections).map(([nome, s]) => [nome, s.state])),
|
|
384
|
+
notConsulted: snapshot.notConsulted ?? [],
|
|
385
|
+
},
|
|
386
|
+
rede,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Redação antes de qualquer gravação: o recibo vai ao repositório. Cobre tokens com prefixo
|
|
391
|
+
* conhecido, `Bearer`/`Basic`, variáveis de ambiente com nome de segredo e valores de chaves JSON
|
|
392
|
+
* com nome de segredo. Para objetos, use `redigirObjeto`, que aplica a regra a cada texto antes
|
|
393
|
+
* da serialização (JSON dentro de stdout escaparia depois dela).
|
|
394
|
+
*/
|
|
395
|
+
const CHAVE_DE_SEGREDO = /token|secret|password|passwd|api[_-]?key|apikey|credential|authorization|cookie/i;
|
|
396
|
+
function redigir(texto) {
|
|
397
|
+
return texto
|
|
398
|
+
.replace(/\b(sk-ant-[A-Za-z0-9_-]+|sk-or-[A-Za-z0-9_-]+|sk-[A-Za-z0-9_-]{16,}|[sr]k_live_[A-Za-z0-9]{10,}|AIza[0-9A-Za-z_-]{20,})/g, '[REDIGIDO]')
|
|
399
|
+
.replace(/\b(gh[pousr]_[A-Za-z0-9]{20,}|github_pat_[A-Za-z0-9_]{20,}|glpat-[A-Za-z0-9_-]{16,}|xox[abprs]-[A-Za-z0-9-]{10,})/g, '[REDIGIDO]')
|
|
400
|
+
.replace(/\b(Bearer|Basic)(\s+)[A-Za-z0-9._~+/-]{8,}=*/gi, '$1$2[REDIGIDO]')
|
|
401
|
+
// O valor para em aspas, barra invertida e espaço: aplicada a JSON, a regra não come o fecho.
|
|
402
|
+
.replace(/\b([A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)[A-Z0-9_]*\s*=\s*)(?!\d+\b)("[^"\\]*"|'[^'\\]*'|[^\s"'\\]+)/g, '$1[REDIGIDO]')
|
|
403
|
+
.replace(/("[^"]*(?:token|secret|password|passwd|api[_-]?key|apikey|credential|authorization|cookie)[^"]*"\s*:\s*)"(?:[^"\\]|\\.)*"/gi, '$1"[REDIGIDO]"');
|
|
404
|
+
}
|
|
405
|
+
function redigirObjeto(valor) {
|
|
406
|
+
if (typeof valor === 'string')
|
|
407
|
+
return redigir(valor);
|
|
408
|
+
if (Array.isArray(valor))
|
|
409
|
+
return valor.map(v => redigirObjeto(v));
|
|
410
|
+
if (valor && typeof valor === 'object') {
|
|
411
|
+
return Object.fromEntries(Object.entries(valor).map(([k, v]) => [k, typeof v === 'string' && CHAVE_DE_SEGREDO.test(k) ? '[REDIGIDO]' : redigirObjeto(v)]));
|
|
412
|
+
}
|
|
413
|
+
return valor;
|
|
414
|
+
}
|
package/dist/pulse-delivery.js
CHANGED
|
@@ -33,11 +33,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.adquirirLockMonitor = void 0;
|
|
36
|
+
exports.RETEM_PARADO_MS = exports.adquirirLockMonitor = void 0;
|
|
37
37
|
exports.assinaturaPulse = assinaturaPulse;
|
|
38
38
|
exports.assinaturaDoResumo = assinaturaDoResumo;
|
|
39
39
|
exports.mensagemPulse = mensagemPulse;
|
|
40
40
|
exports.varrerPulse = varrerPulse;
|
|
41
|
+
exports.varrerEDepoisPublicarNaRede = varrerEDepoisPublicarNaRede;
|
|
41
42
|
exports.enviarPayloadHost = enviarPayloadHost;
|
|
42
43
|
const manifest_1 = require("./manifest");
|
|
43
44
|
const write_activation_1 = require("./write-activation");
|
|
@@ -59,10 +60,14 @@ const hitl_contract_1 = require("./hitl-contract");
|
|
|
59
60
|
const monitor_lock_1 = require("./monitor-lock");
|
|
60
61
|
const fabrica_estado_1 = require("./fabrica-estado");
|
|
61
62
|
const maquina_1 = require("./maquina");
|
|
63
|
+
const rede_1 = require("./rede");
|
|
64
|
+
const rede_adesao_1 = require("./rede-adesao");
|
|
62
65
|
const pulse_cadencia_1 = require("./pulse-cadencia");
|
|
63
66
|
// O lock dos monitores mudou de modulo (I-41, GO-FIX 1); quem o importava daqui continua importando.
|
|
64
67
|
var monitor_lock_2 = require("./monitor-lock");
|
|
65
68
|
Object.defineProperty(exports, "adquirirLockMonitor", { enumerable: true, get: function () { return monitor_lock_2.adquirirLockMonitor; } });
|
|
69
|
+
/** RM-037 (fatia 4): por quanto tempo a parada ja informada continua sabida depois de sumir de uma batida. */
|
|
70
|
+
exports.RETEM_PARADO_MS = 6 * 60 * 60 * 1000;
|
|
66
71
|
/**
|
|
67
72
|
* I-41 (D9): a assinatura de deduplicacao NAO inclui `apresentacao`.
|
|
68
73
|
*
|
|
@@ -183,9 +188,24 @@ function varrerPulse(opcoes) {
|
|
|
183
188
|
const esperasFora = outras.flatMap(m => m.esperando.map(e => `maquina:${m.maquina}:${e.thread}:${e.fase}`));
|
|
184
189
|
for (const k of esperasFora)
|
|
185
190
|
presentes.add(k);
|
|
186
|
-
|
|
191
|
+
// RM-037 (fatia 4, D7): o trabalho parado no condutor e noticia uma vez por thread e caso, como a
|
|
192
|
+
// decisao informada: sai na janela da cadencia do dono e nunca abre pedido.
|
|
193
|
+
const parados = pulse.paradoNoCondutor ?? [];
|
|
194
|
+
const chaveDoParado = (p) => `parado:${p.thread}:${p.caso}`;
|
|
195
|
+
for (const p of parados)
|
|
196
|
+
presentes.add(chaveDoParado(p));
|
|
197
|
+
// A parada que some por uma batida (gh que falhou, um `ork verify` do condutor) e volta nao e noticia
|
|
198
|
+
// nova: a marca fica guardada por `RETEM_PARADO_MS` depois da ultima vez que a parada apareceu.
|
|
199
|
+
const guardada = (id, valor) => id.startsWith('parado:') &&
|
|
200
|
+
Date.parse(quando) - Number(valor.split('|')[1]) < exports.RETEM_PARADO_MS;
|
|
201
|
+
vistas = Object.fromEntries(Object.entries(vistas).filter(([id, valor]) => presentes.has(id) || guardada(id, valor)));
|
|
187
202
|
const esperaNovaFora = esperasFora.some(k => vistas[k] === undefined);
|
|
188
203
|
const decisoesNovas = decisoes.filter(d => vistas[chaveDaDecisao(d.id)] === undefined);
|
|
204
|
+
const paradosNovos = parados.filter(p => vistas[chaveDoParado(p)] === undefined);
|
|
205
|
+
// A marca guarda o instante em milissegundos: e dado de maquina, nao texto para o dono.
|
|
206
|
+
for (const p of parados)
|
|
207
|
+
if (vistas[chaveDoParado(p)] !== undefined)
|
|
208
|
+
vistas[chaveDoParado(p)] = `informada|${Date.parse(quando)}`;
|
|
189
209
|
// I-41 (GO-FIX 1): a thread que ja recebeu a pergunta e ainda nao respondeu nao e noticia. A
|
|
190
210
|
// mudanca no item dela (o pedido que o sim do dono abriu) e obra nossa, e avisar sobre ela seria
|
|
191
211
|
// mandar ao dono um resumo sobre a pergunta que ele acabou de receber.
|
|
@@ -205,7 +225,8 @@ function varrerPulse(opcoes) {
|
|
|
205
225
|
!config.argumentos.every(a => typeof a === 'string') || !config.argumentos.some(a => a.includes('{{mensagem}}'))) {
|
|
206
226
|
throw new Error('transporte requer executavel e argumentos com {{mensagem}}');
|
|
207
227
|
}
|
|
208
|
-
|
|
228
|
+
// A mensagem entra como texto: `$&` e `$'` nela nao sao padrao de substituicao (CHECK da RM-037, fatia 4).
|
|
229
|
+
const r = (0, node_child_process_1.spawnSync)(config.executavel, config.argumentos.map(a => a.replaceAll('{{mensagem}}', () => mensagem)), { cwd: raiz, encoding: 'utf8', input: mensagem, timeout: 30000, maxBuffer: 1024 * 1024 });
|
|
209
230
|
entregue = r.status === 0;
|
|
210
231
|
}
|
|
211
232
|
if (!entregue)
|
|
@@ -229,12 +250,15 @@ function varrerPulse(opcoes) {
|
|
|
229
250
|
// I-50: pergunta nova sai na hora; o resto (status, decisoes informadas) espera a janela da
|
|
230
251
|
// cadencia do dono, e a novidade que esperou continua nao vista ate sair.
|
|
231
252
|
const noPrazo = !opcoes.comCadencia || (0, pulse_cadencia_1.janelaAberta)(cadencia, (0, pulse_cadencia_1.lerUltimoResumo)(opcoes.raiz, dir), quando);
|
|
232
|
-
const
|
|
233
|
-
|
|
253
|
+
const informacaoNova = novas > 0 || decisoesNovas.length > 0 || paradosNovos.length > 0;
|
|
254
|
+
const adiada = !conjuntoNovo && !esperaNovaFora && informacaoNova && !noPrazo;
|
|
255
|
+
if (conjuntoNovo || esperaNovaFora || (noPrazo && informacaoNova)) {
|
|
234
256
|
const guardadas = anterior ? fila.candidatos.filter(c => anterior.candidatos.some(a => a.thread === c.thread)).length : 0;
|
|
235
257
|
const resumo = (0, hitl_resumo_1.resumirHitl)(itens, { quando, janelaMin, prontas: fila.candidatos.length, acumuladas: guardadas,
|
|
236
258
|
consertos: fila.consertos, atoDoItem: i => fila.atos.get(`${i.thread}|${i.fase}`),
|
|
237
|
-
decisoes: decisoesNovas, acimaDoLimiar: pulse.acimaDoLimiar ?? [], outrasMaquinas: outras
|
|
259
|
+
decisoes: decisoesNovas, acimaDoLimiar: pulse.acimaDoLimiar ?? [], outrasMaquinas: outras, paradosNoCondutor: parados,
|
|
260
|
+
// RM-057 (fatia 3): a linha so acompanha o resumo que ja sai; nao e novidade nem fura a cadencia.
|
|
261
|
+
...(pulse.hitlDeConducao ? { hitlDeConducao: pulse.hitlDeConducao } : {}) });
|
|
238
262
|
// Pedir licenca para mandar zero perguntas era o defeito: sem pergunta, nao ha codigo.
|
|
239
263
|
// I-50: cadencia curta nao encurta o prazo do dono para responder ao resumo (minimo de 60 min).
|
|
240
264
|
const consentimento = fila.candidatos.length ? (0, monitor_lock_1.comLockDaConversa)(dir, () => (0, pulse_consentimento_1.abrirConsentimento)(raiz, { quando,
|
|
@@ -252,6 +276,8 @@ function varrerPulse(opcoes) {
|
|
|
252
276
|
vistas[chaveDaDecisao(d.id)] = 'informada';
|
|
253
277
|
for (const k of esperasFora)
|
|
254
278
|
vistas[k] = 'informada';
|
|
279
|
+
for (const p of parados)
|
|
280
|
+
vistas[chaveDoParado(p)] = `informada|${Date.parse(quando)}`;
|
|
255
281
|
(0, pulse_cadencia_1.gravarUltimoResumo)(opcoes.raiz, quando, dir);
|
|
256
282
|
}
|
|
257
283
|
gravarCache(cache, vistas);
|
|
@@ -266,6 +292,22 @@ function varrerPulse(opcoes) {
|
|
|
266
292
|
trava.liberar();
|
|
267
293
|
}
|
|
268
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* RM-053: a entrega ao dono vem primeiro, e a rede depois, mesmo quando a varredura falha. M4 do
|
|
297
|
+
* CHECK 1: antes da entrega, uma forja lenta atrasava o HITL em minutos. S13 da revisao 2: sem o
|
|
298
|
+
* `finally`, uma excecao na varredura suprimia tambem a batida da rede.
|
|
299
|
+
*/
|
|
300
|
+
function varrerEDepoisPublicarNaRede(varrer, publicar) {
|
|
301
|
+
try {
|
|
302
|
+
return varrer();
|
|
303
|
+
}
|
|
304
|
+
finally {
|
|
305
|
+
try {
|
|
306
|
+
publicar();
|
|
307
|
+
}
|
|
308
|
+
catch { /* a rede registra a propria falha no rede.log */ }
|
|
309
|
+
}
|
|
310
|
+
}
|
|
269
311
|
if (require.main === module) {
|
|
270
312
|
try {
|
|
271
313
|
const raiz = process.argv[2] ?? process.cwd();
|
|
@@ -296,7 +338,18 @@ if (require.main === module) {
|
|
|
296
338
|
}
|
|
297
339
|
const outrasMaquinas = compartilhada
|
|
298
340
|
? () => (0, fabrica_estado_1.resumoDasOutrasMaquinas)((0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto, semRemoto: true }), (0, maquina_1.nomeDaMaquina)()) : undefined;
|
|
299
|
-
|
|
341
|
+
// RM-053 (D9): depois da entrega ao dono, a mesma batida publica o retrato desta maquina na rede da
|
|
342
|
+
// pessoa (so membro, uma tentativa a cada 14 min, retrato igual so de hora em hora).
|
|
343
|
+
const r = varrerEDepoisPublicarNaRede(() => varrerPulse({ raiz, escopo, comCadencia: true, outrasMaquinas }), () => {
|
|
344
|
+
try {
|
|
345
|
+
const rede = (0, rede_1.publicarRedeNaBatida)({ diretorio: carregado.raiz });
|
|
346
|
+
if (rede)
|
|
347
|
+
(0, rede_adesao_1.registrarNaRede)({ ...rede, origem: 'pulse' });
|
|
348
|
+
}
|
|
349
|
+
catch (e) {
|
|
350
|
+
(0, rede_adesao_1.registrarNaRede)({ acao: 'falhou', origem: 'pulse', erro: e.message });
|
|
351
|
+
}
|
|
352
|
+
});
|
|
300
353
|
console.log(JSON.stringify(r));
|
|
301
354
|
process.exitCode = r.code;
|
|
302
355
|
}
|