@orkastery/cli 0.2.0 → 0.3.0
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/LICENSE +1 -1
- package/README.md +86 -65
- package/adapters/README.md +30 -15
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
- package/adapters/claude-code/README.md +110 -8
- package/adapters/claude-code/commands/onboarding.md +21 -0
- package/adapters/claude-code/commands/ork.md +99 -27
- package/adapters/claude-code/hooks/hooks.json +6 -1
- package/adapters/claude-code/hooks/ork-sensor.js +66 -0
- package/adapters/codex/skills/ork/SKILL.md +57 -0
- package/adapters/hermes/README.md +163 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
- package/adapters/hermes/bin/ork-brain.sh +4 -0
- package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
- package/adapters/hermes/bin/ork-maestro.sh +6 -0
- package/adapters/hermes/bin/ork-master-enviar.py +84 -0
- package/adapters/hermes/bin/ork-objective-message.sh +17 -0
- package/adapters/hermes/bin/ork-objective-status.sh +12 -0
- package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +26 -4
- package/adapters/hermes/hitl-ingress/__init__.py +356 -0
- package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
- package/adapters/openclaw/README.md +135 -26
- package/adapters/openclaw/bin/ork-brain.sh +4 -0
- package/adapters/openclaw/construir.sh +19 -0
- package/adapters/openclaw/dist/hitl-ingress.js +199 -0
- package/adapters/openclaw/dist/index.js +437 -0
- package/adapters/openclaw/openclaw.plugin.json +39 -134
- package/adapters/openclaw/package.json +26 -0
- package/adapters/openclaw/src/hitl-ingress.ts +180 -0
- package/adapters/openclaw/src/index.ts +458 -0
- package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
- package/adapters/openclaw/tsconfig.json +15 -0
- package/assets/docs/markdownlint-cli2.jsonc +22 -0
- package/assets/docs/padroes/documentacao-de-produto.md +133 -0
- package/assets/docs/padroes/roadmap-de-produto.md +98 -0
- package/assets/docs/produto/README.md +14 -0
- package/assets/docs/produto/_modelo-feature.md +59 -0
- package/assets/docs/roadmap/README.md +14 -0
- package/assets/docs/roadmap/_modelo-item.md +73 -0
- package/assets/orkmind-native-schema.json +32 -0
- package/assets/orkmind_bridge.py +357 -0
- package/assets/orkmind_fixture.py +67 -0
- package/assets/orkmind_prospective.py +138 -0
- package/assets/reference-tariffs-i07.json +23 -0
- package/dist/adapters/claude-bg.js +488 -39
- package/dist/adapters/codex-controller-sensor.js +449 -0
- package/dist/adapters/codex-controller-worker.js +361 -0
- package/dist/adapters/codex-controller.js +252 -0
- package/dist/adapters/codex-events.js +205 -0
- package/dist/adapters/codex-question.js +26 -0
- package/dist/adapters/codex-runner.js +133 -0
- package/dist/adapters/codex.js +394 -0
- package/dist/agents-md.js +84 -0
- package/dist/auditoria.js +11 -8
- package/dist/auditrun.js +5 -4
- package/dist/board.js +173 -22
- package/dist/branch-de-estado.js +136 -0
- package/dist/canarios-hitl.js +177 -0
- package/dist/canarios-i43.js +543 -0
- package/dist/canarios-pulse.js +147 -0
- package/dist/canarios-sensores.js +129 -0
- package/dist/canarios.js +111 -2
- package/dist/catalogo.js +9 -0
- package/dist/ci.js +216 -0
- package/dist/ciclos.js +2 -1
- package/dist/claim-lint.js +64 -0
- package/dist/claims.js +60 -0
- package/dist/company-brain-capture.js +195 -0
- package/dist/company-brain-cli.js +123 -0
- package/dist/company-brain-client.js +61 -0
- package/dist/company-brain-contract.js +166 -0
- package/dist/company-brain-journal.js +192 -0
- package/dist/company-brain-mcp.js +33 -0
- package/dist/company-brain-migration.js +60 -0
- package/dist/company-brain-source.js +177 -0
- package/dist/company-brain-worker.js +18 -0
- package/dist/conducao-texto.js +61 -0
- package/dist/conducao.js +876 -0
- package/dist/contrato-publico.js +39 -0
- package/dist/creation-operation-store.js +251 -0
- package/dist/creation-operation.js +148 -0
- package/dist/decisao-autonoma.js +183 -0
- package/dist/delegation.js +79 -0
- package/dist/demo.js +120 -0
- package/dist/docs.js +828 -0
- package/dist/doctor.js +183 -24
- package/dist/entrega-pr.js +117 -0
- package/dist/escopo-escrita.js +71 -0
- package/dist/estado-thread.js +222 -0
- package/dist/evalrunner.js +12 -0
- package/dist/fabrica-estado.js +329 -0
- package/dist/fabrica-publicar.js +76 -0
- package/dist/fix.js +21 -0
- package/dist/gates.js +55 -9
- package/dist/handoff.js +39 -23
- package/dist/hitl-canais.js +333 -0
- package/dist/hitl-classificacao.js +131 -0
- package/dist/hitl-contract.js +465 -0
- package/dist/hitl-estado.js +136 -0
- package/dist/hitl-gates.js +554 -0
- package/dist/hitl-ingress-receipt.js +382 -0
- package/dist/hitl-local-atestado.js +57 -0
- package/dist/hitl-local-receipt.js +328 -0
- package/dist/hitl-local.js +143 -0
- package/dist/hitl-lock.js +139 -0
- package/dist/hitl-lote.js +223 -0
- package/dist/hitl-native-offer.js +97 -0
- package/dist/hitl-native.js +65 -0
- package/dist/hitl-presentation.js +209 -0
- package/dist/hitl-public-receipt.js +176 -0
- package/dist/hitl-resumo.js +209 -0
- package/dist/hitl-sessions.js +475 -0
- package/dist/hitl.js +711 -0
- package/dist/horario.js +269 -0
- package/dist/hosts.js +198 -22
- package/dist/index.js +1736 -93
- package/dist/indice.js +99 -0
- package/dist/init.js +28 -3
- package/dist/integracoes-locais.js +17 -0
- package/dist/leases.js +65 -21
- package/dist/ledger-stats.js +272 -0
- package/dist/ledger.js +107 -2
- package/dist/licoes.js +215 -0
- package/dist/liveness.js +218 -0
- package/dist/maestro-actions.js +51 -0
- package/dist/maestro-authority.js +152 -0
- package/dist/maestro-cli.js +97 -0
- package/dist/maestro-contract.js +55 -0
- package/dist/maestro-discovery.js +132 -0
- package/dist/maestro-runtime.js +268 -0
- package/dist/maestro-snapshot.js +86 -0
- package/dist/maestro-sources.js +224 -0
- package/dist/manifest.js +165 -6
- package/dist/maquina.js +102 -0
- package/dist/master-audit.js +101 -0
- package/dist/master-batch.js +43 -0
- package/dist/master-digest.js +149 -0
- package/dist/master-migracao.js +155 -0
- package/dist/master.js +361 -77
- package/dist/mcp-artifacts.js +234 -0
- package/dist/mcp-git.js +433 -0
- package/dist/mcp-install.js +310 -0
- package/dist/mcp-maestro.js +25 -0
- package/dist/mcp-server.js +469 -0
- package/dist/mcp-ship.js +436 -0
- package/dist/mcp-verify.js +173 -0
- package/dist/memoria-humana.js +207 -0
- package/dist/memoria.js +314 -78
- package/dist/memory-migration.js +279 -0
- package/dist/memory-prospective.js +148 -0
- package/dist/modos-migracao.js +191 -0
- package/dist/modos.js +151 -15
- package/dist/monitor-lock.js +110 -0
- package/dist/objective.js +449 -0
- package/dist/ocupacao.js +267 -0
- package/dist/onboarding.js +303 -0
- package/dist/orkmind.js +389 -90
- package/dist/orquestracao.js +96 -69
- package/dist/phase.js +596 -150
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/portfolio-context.js +61 -0
- package/dist/portfolio.js +180 -0
- package/dist/preflight.js +207 -0
- package/dist/process-audit.js +112 -0
- package/dist/project-state.js +93 -0
- package/dist/prompts.js +25 -5
- package/dist/prova-minima.js +112 -0
- package/dist/pulse-cadencia.js +163 -0
- package/dist/pulse-consentimento.js +260 -0
- package/dist/pulse-delivery.js +323 -0
- package/dist/pulse-resposta.js +542 -0
- package/dist/pulse.js +262 -0
- package/dist/ratelimit.js +35 -2
- package/dist/recall.js +80 -3
- package/dist/redacao-saida.js +45 -0
- package/dist/redacao-url.js +66 -0
- package/dist/retry.js +637 -115
- package/dist/roadmap-reservas.js +243 -0
- package/dist/runtime-ambiente.js +38 -0
- package/dist/runtime-context.js +215 -0
- package/dist/runtime-profiles.js +869 -0
- package/dist/runtimes.js +103 -0
- package/dist/sandbox.js +9 -0
- package/dist/session-events.js +203 -0
- package/dist/session-watcher-claude.js +637 -0
- package/dist/session-watcher.js +683 -0
- package/dist/sessoes-adopt.js +154 -0
- package/dist/sessoes-inventario.js +159 -0
- package/dist/sessoes.js +16 -35
- package/dist/setup.js +691 -0
- package/dist/ship.js +150 -15
- package/dist/slug.js +1 -1
- package/dist/thread-close.js +115 -0
- package/dist/thread.js +142 -28
- package/dist/tokens.js +1 -1
- package/dist/util.js +4 -2
- package/dist/verify-sandbox.js +265 -0
- package/dist/verify.js +270 -25
- package/dist/versao.js +60 -0
- package/dist/worktree.js +31 -2
- package/dist/write-activation.js +291 -0
- package/dist/yaml.js +2 -0
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +35 -1
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +2 -2
- package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
- package/eval/fixtures/b2-master-log/caso.json +1 -1
- package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
- package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
- package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
- package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
- package/eval/fixtures/fx-codex-dry/caso.json +18 -0
- package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
- package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
- package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
- package/eval/fixtures/fx-happy/caso.json +6 -4
- package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
- package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
- package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
- package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
- package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
- package/eval/fixtures/fx-omnicanal/caso.json +17 -0
- package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
- package/monitor/company-brain.cjs +17 -0
- package/monitor/pulse-scope.cjs +45 -0
- package/monitor/pulse.cron +18 -0
- package/monitor/varredura-pulse.sh +27 -0
- package/package.json +25 -4
- package/schemas/claims.schema.json +25 -0
- package/schemas/company-brain.schema.json +1158 -0
- package/schemas/creation-operation.schema.json +365 -0
- package/schemas/maestro-snapshot.schema.json +2716 -0
- package/skills/core/onboarding/SKILL.md +50 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
- package/skills/core/thread-state/SKILL.md +3 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/board.js
CHANGED
|
@@ -49,16 +49,27 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
49
49
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
50
|
exports.perfisDetectados = perfisDetectados;
|
|
51
51
|
exports.threadsDeTodosOsPerfis = threadsDeTodosOsPerfis;
|
|
52
|
+
exports.estadosDeSessao = estadosDeSessao;
|
|
52
53
|
exports.planejar = planejar;
|
|
54
|
+
exports.devolverVagas = devolverVagas;
|
|
55
|
+
exports.textoDoReap = textoDoReap;
|
|
53
56
|
exports.textoDoPlano = textoDoPlano;
|
|
54
57
|
exports.textoDoBoard = textoDoBoard;
|
|
55
58
|
const fs = __importStar(require("node:fs"));
|
|
56
59
|
const path = __importStar(require("node:path"));
|
|
60
|
+
const adapter = __importStar(require("./adapters/claude-bg"));
|
|
61
|
+
const hitl_1 = require("./hitl");
|
|
57
62
|
const leases_1 = require("./leases");
|
|
63
|
+
const ledger_1 = require("./ledger");
|
|
58
64
|
const manifest_1 = require("./manifest");
|
|
59
65
|
const modos_1 = require("./modos");
|
|
66
|
+
const ocupacao_1 = require("./ocupacao");
|
|
60
67
|
const thread_1 = require("./thread");
|
|
61
68
|
const util_1 = require("./util");
|
|
69
|
+
const sessoes_adopt_1 = require("./sessoes-adopt");
|
|
70
|
+
const horario_1 = require("./horario");
|
|
71
|
+
const conducao_1 = require("./conducao");
|
|
72
|
+
const conducao_texto_1 = require("./conducao-texto");
|
|
62
73
|
/**
|
|
63
74
|
* Perfis detectados no projeto.
|
|
64
75
|
*
|
|
@@ -95,34 +106,60 @@ function threadsDeTodosOsPerfis(carregado, todos = true) {
|
|
|
95
106
|
perfil: perfil.nome,
|
|
96
107
|
raiz: perfil.raiz,
|
|
97
108
|
thread,
|
|
98
|
-
|
|
109
|
+
// I-36: a conducao (`exec:`) tem secao propria; o escalonador segue contando so os leases de escrita.
|
|
110
|
+
leases: (0, leases_1.leasesDaThread)(perfil.raiz, id).filter((l) => (0, leases_1.tipoDoLease)(l.nome) !== 'exec').map((l) => l.nome),
|
|
99
111
|
naFila: fila.filter((p) => p.thread === id),
|
|
100
112
|
});
|
|
101
113
|
}
|
|
102
114
|
}
|
|
103
115
|
return saida;
|
|
104
116
|
}
|
|
117
|
+
/** Estados de sessao do runtime, ou null quando ele nao pode ser consultado. */
|
|
118
|
+
function estadosDeSessao() {
|
|
119
|
+
if (!adapter.disponivel())
|
|
120
|
+
return null;
|
|
121
|
+
return new Map(adapter
|
|
122
|
+
.listarSessoes()
|
|
123
|
+
.filter((s) => !!s.sessionId)
|
|
124
|
+
.map((s) => [s.sessionId, (0, hitl_1.estadoBruto)(s)]));
|
|
125
|
+
}
|
|
105
126
|
/**
|
|
106
127
|
* Escalonador por maquina: decide quem avanca agora e quem espera, com motivo tipado.
|
|
107
128
|
*
|
|
108
|
-
* A
|
|
109
|
-
* ocupa vaga
|
|
129
|
+
* A vaga e OCUPACAO REAL, nao existencia de thread aberta (correcao do incidente de
|
|
130
|
+
* 06/09/2026): ocupa vaga quem tem procura ativa (`avaliarOcupacao`) ou quem segura
|
|
131
|
+
* lease sem estar travada. Pausa humana aberta, impedimento nao-transitorio e stale
|
|
132
|
+
* devolvem a vaga com motivo tipado, e a fila anda em FIFO por criacao da thread.
|
|
110
133
|
*/
|
|
111
|
-
function planejar(carregado) {
|
|
134
|
+
function planejar(carregado, opcoes = {}) {
|
|
112
135
|
const { raiz, manifesto } = carregado;
|
|
113
136
|
const max = Math.max(1, manifesto.concurrency.max_parallel_threads);
|
|
137
|
+
const staleMin = manifesto.concurrency.stale_after_min;
|
|
138
|
+
const quando = opcoes.agora ?? (0, util_1.agora)();
|
|
139
|
+
const estados = opcoes.estados === undefined ? estadosDeSessao() : opcoes.estados;
|
|
114
140
|
const fila = (0, leases_1.lerFila)(raiz);
|
|
115
|
-
|
|
141
|
+
// I-36: a conducao (`exec:`) nao entra na conta de vagas: a ocupacao da sessao ja sai do ledger
|
|
142
|
+
// e do runtime (`avaliarOcupacao`), e conta-la de novo mudaria o escalonador.
|
|
143
|
+
const ativos = (0, leases_1.listarLeases)(raiz).filter((l) => !(0, leases_1.expirado)(l) && (0, leases_1.tipoDoLease)(l.nome) !== 'exec');
|
|
116
144
|
const threads = (0, thread_1.listarIds)(raiz)
|
|
117
145
|
.map((id) => (0, thread_1.lerThread)(raiz, id))
|
|
118
146
|
.sort((a, b) => a.criadaEm.localeCompare(b.criadaEm));
|
|
147
|
+
const ocupacoes = new Map(threads.map((t) => [
|
|
148
|
+
t.id,
|
|
149
|
+
(0, ocupacao_1.avaliarOcupacao)(t, (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, t.id)), { agora: quando, estados, staleMin }),
|
|
150
|
+
]));
|
|
119
151
|
const vagas = [];
|
|
120
152
|
let ocupadas = 0;
|
|
121
|
-
// 1a passada: quem
|
|
153
|
+
// 1a passada: quem tem procura ativa esta em andamento e ocupa vaga. Segurar lease
|
|
154
|
+
// sem estar travada tambem ocupa: o lease e trabalho em curso na regiao protegida.
|
|
122
155
|
const emAndamento = new Set();
|
|
123
156
|
for (const t of threads) {
|
|
157
|
+
if (t.status === 'fechada' || (0, sessoes_adopt_1.ehRegistroDeAdocao)(t))
|
|
158
|
+
continue;
|
|
159
|
+
const oc = ocupacoes.get(t.id);
|
|
124
160
|
const meus = ativos.filter((l) => l.thread === t.id).map((l) => l.nome);
|
|
125
|
-
|
|
161
|
+
const ocupa = oc.ocupaVaga || (meus.length > 0 && oc.classe === 'ociosa');
|
|
162
|
+
if (!ocupa)
|
|
126
163
|
continue;
|
|
127
164
|
emAndamento.add(t.id);
|
|
128
165
|
ocupadas += 1;
|
|
@@ -133,15 +170,17 @@ function planejar(carregado) {
|
|
|
133
170
|
fase: t.faseAtual,
|
|
134
171
|
situacao: 'em-andamento',
|
|
135
172
|
motivo: null,
|
|
136
|
-
detalhe: `segura ${meus.join(', ')}
|
|
173
|
+
detalhe: meus.length > 0 ? `segura ${meus.join(', ')}; ${oc.detalhe}` : oc.detalhe,
|
|
137
174
|
correcao: '',
|
|
138
175
|
leases: meus,
|
|
139
176
|
});
|
|
140
177
|
}
|
|
141
|
-
// 2a passada: as demais, em FIFO
|
|
178
|
+
// 2a passada: as demais, em FIFO. Thread travada (pausa humana, impedimento, stale)
|
|
179
|
+
// NAO ocupa vaga: e exatamente a thread orfa que sufocava as demandas legitimas.
|
|
142
180
|
for (const t of threads) {
|
|
143
181
|
if (emAndamento.has(t.id))
|
|
144
182
|
continue;
|
|
183
|
+
const meus = ativos.filter((l) => l.thread === t.id).map((l) => l.nome);
|
|
145
184
|
if (t.status === 'fechada') {
|
|
146
185
|
vagas.push({
|
|
147
186
|
thread: t.id,
|
|
@@ -156,7 +195,15 @@ function planejar(carregado) {
|
|
|
156
195
|
});
|
|
157
196
|
continue;
|
|
158
197
|
}
|
|
159
|
-
|
|
198
|
+
const oc = ocupacoes.get(t.id);
|
|
199
|
+
if ((0, sessoes_adopt_1.ehRegistroDeAdocao)(t)) {
|
|
200
|
+
vagas.push({ thread: t.id, slug: t.slug, modo: t.modo, fase: t.faseAtual,
|
|
201
|
+
situacao: oc.classe === 'pausa-humana' ? 'pausada' : 'espera',
|
|
202
|
+
motivo: oc.motivo, detalhe: 'registro de adoção: identidade preservada, sem trabalho a despachar',
|
|
203
|
+
correcao: oc.classe === 'pausa-humana' ? 'ork sessions hitl' : '', leases: meus });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (oc.classe === 'pausa-humana') {
|
|
160
207
|
vagas.push({
|
|
161
208
|
thread: t.id,
|
|
162
209
|
slug: t.slug,
|
|
@@ -164,9 +211,38 @@ function planejar(carregado) {
|
|
|
164
211
|
fase: t.faseAtual,
|
|
165
212
|
situacao: 'pausada',
|
|
166
213
|
motivo: 'human.pending',
|
|
167
|
-
detalhe:
|
|
214
|
+
detalhe: oc.detalhe,
|
|
168
215
|
correcao: `ork gate approve ${t.id} <sobre> --por <quem>`,
|
|
169
|
-
leases:
|
|
216
|
+
leases: meus,
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (oc.classe === 'impedida') {
|
|
221
|
+
vagas.push({
|
|
222
|
+
thread: t.id,
|
|
223
|
+
slug: t.slug,
|
|
224
|
+
modo: t.modo,
|
|
225
|
+
fase: t.faseAtual,
|
|
226
|
+
situacao: 'espera',
|
|
227
|
+
motivo: oc.motivo,
|
|
228
|
+
detalhe: oc.detalhe,
|
|
229
|
+
correcao: `ork retry plan ${t.id} --motivo ${String(oc.motivo)}, ou feche com ork master ${t.id}`,
|
|
230
|
+
leases: meus,
|
|
231
|
+
});
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (oc.classe === 'stale') {
|
|
235
|
+
vagas.push({
|
|
236
|
+
thread: t.id,
|
|
237
|
+
slug: t.slug,
|
|
238
|
+
modo: t.modo,
|
|
239
|
+
fase: t.faseAtual,
|
|
240
|
+
situacao: 'espera',
|
|
241
|
+
motivo: 'vaga.stale',
|
|
242
|
+
detalhe: oc.detalhe,
|
|
243
|
+
correcao: `redespache com ork phase run ${t.id} --fase ${t.faseAtual}, ` +
|
|
244
|
+
`ou feche com ork master ${t.id}`,
|
|
245
|
+
leases: meus,
|
|
170
246
|
});
|
|
171
247
|
continue;
|
|
172
248
|
}
|
|
@@ -219,18 +295,85 @@ function planejar(carregado) {
|
|
|
219
295
|
vagas,
|
|
220
296
|
filaDeMerge: (0, leases_1.esperandoPor)(raiz, leases_1.LEASE_MAIN_TREE),
|
|
221
297
|
filaDeRegiao: fila.filter((p) => p.tipo !== 'main-tree'),
|
|
222
|
-
decididoEm:
|
|
298
|
+
decididoEm: quando,
|
|
223
299
|
};
|
|
224
300
|
}
|
|
225
|
-
|
|
226
|
-
|
|
301
|
+
/**
|
|
302
|
+
* `ork board reap`: grava no ledger de cada thread SEM procura ativa o evento
|
|
303
|
+
* `slot_released`, com quem decidiu, evidencia e razao.
|
|
304
|
+
*
|
|
305
|
+
* A vaga em si e derivada (o `planejar` ja a devolve sozinho a cada decisao); o reap
|
|
306
|
+
* existe para a devolucao virar EVENTO VERIFICAVEL no ledger da thread devolvida.
|
|
307
|
+
* Ele e idempotente: enquanto um `slot_released` estiver aberto (sem evento posterior
|
|
308
|
+
* que destrave a thread), rodar de novo nao grava linha nova.
|
|
309
|
+
*/
|
|
310
|
+
function devolverVagas(carregado, opcoes = {}) {
|
|
311
|
+
const { raiz, manifesto } = carregado;
|
|
312
|
+
const staleMin = manifesto.concurrency.stale_after_min;
|
|
313
|
+
const quando = opcoes.agora ?? (0, util_1.agora)();
|
|
314
|
+
const estados = opcoes.estados === undefined ? estadosDeSessao() : opcoes.estados;
|
|
315
|
+
const quem = opcoes.por ?? 'escalonador (ork board reap)';
|
|
316
|
+
const devolvidas = [];
|
|
317
|
+
for (const id of (0, thread_1.listarIds)(raiz)) {
|
|
318
|
+
const t = (0, thread_1.lerThread)(raiz, id);
|
|
319
|
+
if (t.status === 'fechada' || (0, sessoes_adopt_1.ehRegistroDeAdocao)(t))
|
|
320
|
+
continue;
|
|
321
|
+
const dir = (0, thread_1.dirThread)(raiz, id);
|
|
322
|
+
const eventos = (0, ledger_1.lerLedger)(dir);
|
|
323
|
+
const oc = (0, ocupacao_1.avaliarOcupacao)(t, eventos, { agora: quando, estados, staleMin });
|
|
324
|
+
if (oc.classe !== 'pausa-humana' && oc.classe !== 'impedida' && oc.classe !== 'stale') {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const jaRegistrada = eventos.some((e, i) => e.tipo === ledger_1.TIPOS_DE_EVENTO.vagaLiberada &&
|
|
328
|
+
!eventos
|
|
329
|
+
.slice(i + 1)
|
|
330
|
+
.some((p) => ocupacao_1.EVENTOS_QUE_DESTRAVAM.includes(p.tipo) || (0, ocupacao_1.ehAprovacaoHumana)(p)));
|
|
331
|
+
if (!jaRegistrada) {
|
|
332
|
+
(0, ledger_1.registrar)(dir, id, ledger_1.TIPOS_DE_EVENTO.vagaLiberada, {
|
|
333
|
+
fase: t.faseAtual,
|
|
334
|
+
motivo: oc.motivo,
|
|
335
|
+
quem,
|
|
336
|
+
detalhe: oc.detalhe,
|
|
337
|
+
evidencia: oc.evidencia,
|
|
338
|
+
razao: 'thread sem procura ativa nao ocupa vaga de concurrency.max_parallel_threads: ' +
|
|
339
|
+
'a vaga volta para as threads prontas para rodar',
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
devolvidas.push({
|
|
343
|
+
thread: id,
|
|
344
|
+
classe: oc.classe,
|
|
345
|
+
motivo: oc.motivo,
|
|
346
|
+
detalhe: oc.detalhe,
|
|
347
|
+
evidencia: oc.evidencia,
|
|
348
|
+
registrada: !jaRegistrada,
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
return devolvidas;
|
|
352
|
+
}
|
|
353
|
+
/** Texto de `ork board reap`. */
|
|
354
|
+
function textoDoReap(devolvidas) {
|
|
355
|
+
if (devolvidas.length === 0) {
|
|
356
|
+
return 'Nenhuma vaga a devolver: toda thread aberta tem procura ativa ou esta pronta para rodar.';
|
|
357
|
+
}
|
|
358
|
+
// I-35: o ledger guarda o ISO; o texto ao dono sai no fuso dele, rotulado uma vez.
|
|
359
|
+
const linhas = [`Vagas devolvidas por falta de procura ativa: ${devolvidas.length}. ${(0, horario_1.legendaDoFuso)()}`, ''];
|
|
360
|
+
for (const d of devolvidas) {
|
|
361
|
+
const marca = d.registrada ? 'slot_released gravado no ledger' : 'ja registrado antes (idempotente)';
|
|
362
|
+
linhas.push(` ${d.thread.padEnd(20)} [${d.motivo}] ${marca}`);
|
|
363
|
+
linhas.push(` detalhe : ${(0, horario_1.localizarTexto)(d.detalhe)}`);
|
|
364
|
+
linhas.push(` evidencia: ${(0, horario_1.localizarTexto)(d.evidencia)}`);
|
|
365
|
+
}
|
|
366
|
+
return linhas.join('\n');
|
|
367
|
+
}
|
|
368
|
+
function linhaDeFila(p, i, agora) {
|
|
369
|
+
return ` ${i + 1}. ${p.thread} quer ${p.nome} (colide com ${p.colidiuCom}, thread ${p.bloqueadaPor}) desde ${(0, horario_1.formatarDesde)(p.desdeEm, { agora })}`;
|
|
227
370
|
}
|
|
228
371
|
/** Texto de `ork board plan`. */
|
|
229
372
|
function textoDoPlano(plano) {
|
|
230
373
|
const linhas = [];
|
|
231
|
-
linhas.push(
|
|
374
|
+
linhas.push(`Escalonador por maquina. ${(0, horario_1.legendaDoFuso)(undefined, plano.decididoEm)}`);
|
|
232
375
|
linhas.push(` limite de paralelismo: ${plano.maxParalelas} (concurrency.max_parallel_threads) | ` +
|
|
233
|
-
`em andamento agora: ${plano.emAndamento}`);
|
|
376
|
+
`em andamento agora (procura ativa): ${plano.emAndamento}`);
|
|
234
377
|
linhas.push('');
|
|
235
378
|
if (plano.vagas.length === 0) {
|
|
236
379
|
linhas.push(' Nenhuma thread no projeto.');
|
|
@@ -243,14 +386,14 @@ function textoDoPlano(plano) {
|
|
|
243
386
|
v.fase,
|
|
244
387
|
v.situacao,
|
|
245
388
|
v.motivo ?? '-',
|
|
246
|
-
v.detalhe,
|
|
389
|
+
(0, horario_1.localizarTexto)(v.detalhe, { agora: plano.decididoEm }),
|
|
247
390
|
])));
|
|
248
391
|
const comCorrecao = plano.vagas.filter((v) => v.correcao !== '');
|
|
249
392
|
if (comCorrecao.length > 0) {
|
|
250
393
|
linhas.push('');
|
|
251
394
|
linhas.push(' Correcoes acionaveis:');
|
|
252
395
|
for (const v of comCorrecao)
|
|
253
|
-
linhas.push(` ${v.thread}: ${v.correcao}`);
|
|
396
|
+
linhas.push(` ${v.thread}: ${(0, horario_1.localizarTexto)(v.correcao, { agora: plano.decididoEm })}`);
|
|
254
397
|
}
|
|
255
398
|
}
|
|
256
399
|
linhas.push('');
|
|
@@ -259,7 +402,7 @@ function textoDoPlano(plano) {
|
|
|
259
402
|
linhas.push(' vazia: nenhuma thread esperando para mergear');
|
|
260
403
|
}
|
|
261
404
|
else {
|
|
262
|
-
plano.filaDeMerge.forEach((p, i) => linhas.push(linhaDeFila(p, i)));
|
|
405
|
+
plano.filaDeMerge.forEach((p, i) => linhas.push(linhaDeFila(p, i, plano.decididoEm)));
|
|
263
406
|
}
|
|
264
407
|
linhas.push('');
|
|
265
408
|
linhas.push('Fila por colisao de regiao');
|
|
@@ -267,7 +410,7 @@ function textoDoPlano(plano) {
|
|
|
267
410
|
linhas.push(' vazia: nenhuma colisao de path, board ou porta');
|
|
268
411
|
}
|
|
269
412
|
else {
|
|
270
|
-
plano.filaDeRegiao.forEach((p, i) => linhas.push(linhaDeFila(p, i)));
|
|
413
|
+
plano.filaDeRegiao.forEach((p, i) => linhas.push(linhaDeFila(p, i, plano.decididoEm)));
|
|
271
414
|
}
|
|
272
415
|
return linhas.join('\n');
|
|
273
416
|
}
|
|
@@ -295,6 +438,14 @@ function textoDoBoard(carregado, todos) {
|
|
|
295
438
|
i.thread.worktree ? path.basename(i.thread.worktree) : '-',
|
|
296
439
|
i.leases.length > 0 ? i.leases.join(' ') : i.naFila.length > 0 ? `fila:${i.naFila[0].nome}` : '-',
|
|
297
440
|
])));
|
|
441
|
+
// I-36 (T17): quem conduz cada thread agora, pela leitura unica do nucleo.
|
|
442
|
+
const conduzidas = itens.map((i) => ({ id: i.thread.id, c: (0, conducao_1.conducaoDaThread)(i.raiz, i.thread.id) })).filter((x) => x.c);
|
|
443
|
+
if (conduzidas.length > 0) {
|
|
444
|
+
linhas.push('');
|
|
445
|
+
linhas.push('Conducao agora');
|
|
446
|
+
for (const x of conduzidas)
|
|
447
|
+
linhas.push(` ${x.id}: ${(0, conducao_texto_1.linhaDeConducao)(x.c)}`);
|
|
448
|
+
}
|
|
298
449
|
const comVariante = itens.filter((i) => i.thread.variante);
|
|
299
450
|
if (comVariante.length > 0) {
|
|
300
451
|
linhas.push('');
|
|
@@ -308,7 +459,7 @@ function textoDoBoard(carregado, todos) {
|
|
|
308
459
|
if (semScore.length > 0) {
|
|
309
460
|
linhas.push('');
|
|
310
461
|
linhas.push(`Fila de batch scoring: ${semScore.length} thread(s) esperando score humano`);
|
|
311
|
-
linhas.push(' veja em: ork master
|
|
462
|
+
linhas.push(' veja em: ork master (com o indice derivado do ledger)');
|
|
312
463
|
}
|
|
313
464
|
return linhas.join('\n');
|
|
314
465
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
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.refRemota = void 0;
|
|
37
|
+
exports.git = git;
|
|
38
|
+
exports.exigirGit = exigirGit;
|
|
39
|
+
exports.pontaLocal = pontaLocal;
|
|
40
|
+
exports.buscarBranch = buscarBranch;
|
|
41
|
+
exports.jsonsDaPonta = jsonsDaPonta;
|
|
42
|
+
exports.gravarNaBranch = gravarNaBranch;
|
|
43
|
+
/**
|
|
44
|
+
* I-51 (RM-047): uma branch de estado compartilhada entre maquinas, fora da `main` e sem PR.
|
|
45
|
+
*
|
|
46
|
+
* Nasceu nas reservas do roadmap (I-47) e agora serve tambem ao estado da fabrica. Nada aqui toca
|
|
47
|
+
* a arvore de trabalho nem o indice do repositorio: blobs, arvore e commit sao montados com um
|
|
48
|
+
* indice temporario, e a branch local nunca e criada.
|
|
49
|
+
*
|
|
50
|
+
* A atomicidade vem do proprio git: a versao nova e um commit em cima da ponta lida, e o push
|
|
51
|
+
* nunca e forcado. Push recusado volta `false`, e quem chamou rele a ponta e aplica a propria
|
|
52
|
+
* regra de novo sobre o estado novo.
|
|
53
|
+
*
|
|
54
|
+
* `prefixo` da nome aos erros de quem usa (`roadmap.git`, `fabrica.sem-remoto`...).
|
|
55
|
+
*/
|
|
56
|
+
const node_child_process_1 = require("node:child_process");
|
|
57
|
+
const fs = __importStar(require("node:fs"));
|
|
58
|
+
const os = __importStar(require("node:os"));
|
|
59
|
+
const path = __importStar(require("node:path"));
|
|
60
|
+
function git(raiz, args, extra = {}) {
|
|
61
|
+
const r = (0, node_child_process_1.spawnSync)('git', args, { cwd: raiz, encoding: 'utf8', input: extra.input, timeout: extra.timeoutMs ?? 60000,
|
|
62
|
+
env: { ...process.env, ...extra.env } });
|
|
63
|
+
return { ok: r.status === 0, stdout: (r.stdout ?? '').toString(), stderr: (r.stderr ?? '').toString() };
|
|
64
|
+
}
|
|
65
|
+
function exigirGit(raiz, args, prefixo, extra = {}) {
|
|
66
|
+
const r = git(raiz, args, extra);
|
|
67
|
+
if (!r.ok)
|
|
68
|
+
throw new Error(`${prefixo}.git: git ${args[0]} falhou: ${r.stderr.trim().split('\n').pop() ?? ''}`);
|
|
69
|
+
return r.stdout;
|
|
70
|
+
}
|
|
71
|
+
const refRemota = (remoto, branch) => `refs/remotes/${remoto}/${branch}`;
|
|
72
|
+
exports.refRemota = refRemota;
|
|
73
|
+
/** A ultima copia lida da branch nesta maquina, sem rede. `null` quando nunca foi lida. */
|
|
74
|
+
function pontaLocal(raiz, remoto, branch) {
|
|
75
|
+
const local = git(raiz, ['rev-parse', '--verify', '--quiet', (0, exports.refRemota)(remoto, branch)]);
|
|
76
|
+
return local.ok ? local.stdout.trim() : null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Traz a ponta da branch. `ponta: null` quando ela ainda nao existe no remoto; sem rede, a ultima
|
|
80
|
+
* copia local com `atualizado: false`.
|
|
81
|
+
*/
|
|
82
|
+
function buscarBranch(raiz, remoto, branch, prefixo, timeoutMs) {
|
|
83
|
+
const r = git(raiz, ['fetch', '--quiet', '--no-tags', remoto, `+refs/heads/${branch}:${(0, exports.refRemota)(remoto, branch)}`], { timeoutMs });
|
|
84
|
+
if (r.ok)
|
|
85
|
+
return { ponta: exigirGit(raiz, ['rev-parse', '--verify', (0, exports.refRemota)(remoto, branch)], prefixo).trim(), atualizado: true };
|
|
86
|
+
if (/couldn't find remote ref|could not find remote ref/i.test(r.stderr)) {
|
|
87
|
+
// A branch ainda nao nasceu: a primeira gravacao a cria. Copia local antiga nao vale mais.
|
|
88
|
+
git(raiz, ['update-ref', '-d', (0, exports.refRemota)(remoto, branch)]);
|
|
89
|
+
return { ponta: null, atualizado: true };
|
|
90
|
+
}
|
|
91
|
+
return { ponta: pontaLocal(raiz, remoto, branch), atualizado: false };
|
|
92
|
+
}
|
|
93
|
+
/** Os `.json` de um diretorio da ponta, ja lidos. Filtro por caminho: diretorio vazio some da arvore. */
|
|
94
|
+
function jsonsDaPonta(raiz, ponta, dir, prefixo) {
|
|
95
|
+
if (!ponta)
|
|
96
|
+
return [];
|
|
97
|
+
const caminhos = exigirGit(raiz, ['ls-tree', '-r', '--name-only', ponta, '--', `${dir}/`], prefixo)
|
|
98
|
+
.split('\n').filter((n) => n.endsWith('.json'));
|
|
99
|
+
return caminhos.map((c) => JSON.parse(exigirGit(raiz, ['show', `${ponta}:${c}`], prefixo)));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Grava uma versao nova da branch em cima de `ponta`, sem tocar arvore de trabalho nem indice:
|
|
103
|
+
* indice temporario, blobs, `write-tree` e `commit-tree`. Push sem forca; recusa volta `false`.
|
|
104
|
+
*/
|
|
105
|
+
function gravarNaBranch(raiz, remoto, branch, ponta, mudancas, mensagem, prefixo) {
|
|
106
|
+
const indice = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'ork-branch-estado-')), 'index');
|
|
107
|
+
const env = { GIT_INDEX_FILE: indice };
|
|
108
|
+
try {
|
|
109
|
+
if (ponta)
|
|
110
|
+
exigirGit(raiz, ['read-tree', ponta], prefixo, { env });
|
|
111
|
+
else
|
|
112
|
+
exigirGit(raiz, ['read-tree', '--empty'], prefixo, { env });
|
|
113
|
+
for (const m of mudancas) {
|
|
114
|
+
if (m.conteudo === null) {
|
|
115
|
+
exigirGit(raiz, ['update-index', '--force-remove', m.caminho], prefixo, { env });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const blob = exigirGit(raiz, ['hash-object', '-w', '--stdin'], prefixo, { input: m.conteudo }).trim();
|
|
119
|
+
exigirGit(raiz, ['update-index', '--add', '--cacheinfo', `100644,${blob},${m.caminho}`], prefixo, { env });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const arvore = exigirGit(raiz, ['write-tree'], prefixo, { env }).trim();
|
|
123
|
+
const commit = exigirGit(raiz, ['commit-tree', arvore, ...(ponta ? ['-p', ponta] : []), '-m', mensagem], prefixo).trim();
|
|
124
|
+
const push = git(raiz, ['push', '--quiet', remoto, `${commit}:refs/heads/${branch}`]);
|
|
125
|
+
if (push.ok) {
|
|
126
|
+
git(raiz, ['update-ref', (0, exports.refRemota)(remoto, branch), commit]);
|
|
127
|
+
return commit;
|
|
128
|
+
}
|
|
129
|
+
if (/rejected|non-fast-forward|fetch first|stale info|failed to push/i.test(push.stderr))
|
|
130
|
+
return false;
|
|
131
|
+
throw new Error(`${prefixo}.sem-remoto: o push para ${remoto} falhou: ${push.stderr.trim().split('\n').pop() ?? ''}`);
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
fs.rmSync(path.dirname(indice), { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CANARIOS_HITL = void 0;
|
|
4
|
+
const sandbox_1 = require("./sandbox");
|
|
5
|
+
const thread_1 = require("./thread");
|
|
6
|
+
const ledger_1 = require("./ledger");
|
|
7
|
+
const gates_1 = require("./gates");
|
|
8
|
+
const hitl_gates_1 = require("./hitl-gates");
|
|
9
|
+
const pulse_1 = require("./pulse");
|
|
10
|
+
const hitl_gates_2 = require("./hitl-gates");
|
|
11
|
+
const hitl_gates_3 = require("./hitl-gates");
|
|
12
|
+
const hitl_local_atestado_1 = require("./hitl-local-atestado");
|
|
13
|
+
const hitl_canais_1 = require("./hitl-canais");
|
|
14
|
+
exports.CANARIOS_HITL = [
|
|
15
|
+
{ id: 'fx-blanket-approve', sobre: 'SIMULADO: aprovação cega e envelope sem autenticação são recusados', precisaDeGit: true, rodar: () => {
|
|
16
|
+
const s = (0, sandbox_1.sandboxGit)('blanket-approve');
|
|
17
|
+
try {
|
|
18
|
+
let recusas = 0, humanos = 0;
|
|
19
|
+
for (const modo of ['classic']) {
|
|
20
|
+
const t = (0, thread_1.novaThread)(s.carregado, { nome: modo, modo }).thread;
|
|
21
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(s.dir, t.id), t.id, 'phase_result', { fase: 'GOAL' });
|
|
22
|
+
const p = (0, hitl_gates_1.abrirPedidoGate)(s.dir, t.id);
|
|
23
|
+
try {
|
|
24
|
+
(0, gates_1.aprovarGateHumano)(s.dir, t.id, 'push', 'modelo');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
recusas++;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
(0, hitl_gates_1.responderGate)(s.dir, t.id, p.id, { origem: 'telegram', por: 'telegram:42', mensagem: 'telegram:-7:1',
|
|
31
|
+
recebidoEm: new Date().toISOString(), resposta: '1', prova: '0'.repeat(64) });
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
recusas++;
|
|
35
|
+
}
|
|
36
|
+
humanos += (0, ledger_1.lerLedger)((0, thread_1.dirThread)(s.dir, t.id)).filter(e => e.tipo === 'human_gate').length;
|
|
37
|
+
}
|
|
38
|
+
return { simulado: true, recusas, humanos };
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
s.limpar();
|
|
42
|
+
}
|
|
43
|
+
} },
|
|
44
|
+
{ id: 'fx-auto-quiet', sobre: 'SIMULADO: Auto/Maestro silenciosos fora de pausas; policy bloqueia', precisaDeGit: true, rodar: () => {
|
|
45
|
+
const s = (0, sandbox_1.sandboxGit)('auto-quiet');
|
|
46
|
+
try {
|
|
47
|
+
let pedidosRecusados = 0;
|
|
48
|
+
for (const modo of ['auto', 'maestro']) {
|
|
49
|
+
const t = (0, thread_1.novaThread)(s.carregado, { nome: modo, modo }).thread;
|
|
50
|
+
// Registro histórico incorreto não se sobrepõe ao contrato do modo corrente.
|
|
51
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(s.dir, t.id), t.id, 'human_gate', { fase: 'GOAL', estado: 'prevista ao fim do bloco' });
|
|
52
|
+
try {
|
|
53
|
+
(0, hitl_gates_1.abrirPedidoGate)(s.dir, t.id);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
pedidosRecusados++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const consulta = { ok: true, sessoes: [], detalhe: 'runtime SIMULADO' };
|
|
60
|
+
const antes = (0, pulse_1.montarPulse)(s.carregado, { consulta }).resumo.humanos;
|
|
61
|
+
const t = (0, thread_1.novaThread)(s.carregado, { nome: 'policy', modo: 'auto' }).thread;
|
|
62
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(s.dir, t.id), t.id, 'gate_blocked', { fase: 'GOAL', motivo: 'policy.violation' });
|
|
63
|
+
const depois = (0, pulse_1.montarPulse)(s.carregado, { consulta });
|
|
64
|
+
return { simulado: true, pedidosRecusados, humanosSemEscalacao: antes,
|
|
65
|
+
policyPreservada: depois.precisaDeHumanoAgora.some(i => i.thread === t.id && i.motivo === 'policy.violation') };
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
s.limpar();
|
|
69
|
+
}
|
|
70
|
+
} },
|
|
71
|
+
// O transporte de cada canal tem teste proprio; aqui o alvo e o RECIBO: os quatro
|
|
72
|
+
// precisam responder e ficar distinguiveis depois, que e o que D12 exige.
|
|
73
|
+
{ id: 'fx-omnicanal', sobre: 'SIMULADO: os quatro canais respondem e ficam distinguiveis no recibo', precisaDeGit: true, rodar: () => {
|
|
74
|
+
const s = (0, sandbox_1.sandboxGit)('omnicanal');
|
|
75
|
+
// FX1: cada canal de telegram tem a SUA chave; o canario nunca compartilha segredo.
|
|
76
|
+
const nomes = ['ORK_HITL_INGRESS_KEY_HERMES', 'ORK_HITL_INGRESS_KEY_OPENCLAW',
|
|
77
|
+
'ORK_HITL_OPENCLAW_ACCOUNT', 'ORK_HITL_TELEGRAM_USERS', 'ORK_HITL_TELEGRAM_CHATS',
|
|
78
|
+
'ORK_HITL_ROOT', 'ORK_HITL_TELEGRAM_BOT_ID'];
|
|
79
|
+
const antigos = nomes.map(n => process.env[n]);
|
|
80
|
+
const chaves = { hermes: 'chave-SIMULADA-do-canario-hermes-00000000',
|
|
81
|
+
openclaw: 'chave-SIMULADA-do-canario-openclaw-000000' };
|
|
82
|
+
// FX5: so o OpenClaw tem conta homologada, e ela entra no corpo assinado.
|
|
83
|
+
const conta = 'conta-SIMULADA-do-canario-openclaw';
|
|
84
|
+
[chaves.hermes, chaves.openclaw, conta, '42', '-7', '/tmp/ork-hitl-canario', '999']
|
|
85
|
+
.forEach((v, i) => { process.env[nomes[i]] = v; });
|
|
86
|
+
try {
|
|
87
|
+
const registro = (0, hitl_canais_1.conferirRegistro)();
|
|
88
|
+
// Um gate por canal: a mensagem do Telegram nao se repete entre pedidos.
|
|
89
|
+
const gate = (nome) => {
|
|
90
|
+
const t = (0, thread_1.novaThread)(s.carregado, { nome, modo: 'classic' }).thread;
|
|
91
|
+
(0, ledger_1.registrar)((0, thread_1.dirThread)(s.dir, t.id), t.id, 'phase_result', { fase: 'GOAL' });
|
|
92
|
+
return { t, pedido: (0, hitl_gates_1.abrirPedidoGate)(s.dir, t.id) };
|
|
93
|
+
};
|
|
94
|
+
const recibos = {};
|
|
95
|
+
for (const canal of ['hermes', 'openclaw']) {
|
|
96
|
+
const { t, pedido } = gate(canal);
|
|
97
|
+
const base = { resposta: '1', origem: 'telegram', canal, por: 'telegram:42',
|
|
98
|
+
mensagem: `telegram:-7:${canal}`, recebidoEm: new Date().toISOString(),
|
|
99
|
+
...(canal === 'openclaw' ? { conta } : {}) };
|
|
100
|
+
(0, hitl_gates_1.responderGate)(s.dir, t.id, pedido.id, { ...base, prova: (0, hitl_gates_1.assinaturaDaResposta)(t.id, pedido.id, base, chaves[canal]) });
|
|
101
|
+
recibos[canal] = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(s.dir, t.id)).find(e => e.tipo === 'human_gate');
|
|
102
|
+
}
|
|
103
|
+
for (const canal of ['claude-code', 'codex']) {
|
|
104
|
+
const { t, pedido } = gate(canal);
|
|
105
|
+
// Atestado da conexao, como o servidor MCP emite depois de uma elicitation viva.
|
|
106
|
+
const token = Object.freeze({});
|
|
107
|
+
(0, hitl_local_atestado_1.registrarAtestadoLocal)(token, { raiz: s.dir, thread: t.id, pedidoId: pedido.id,
|
|
108
|
+
contexto: (0, hitl_gates_3.contextoHitl)(s.dir, t.id), pedidoSha256: (0, hitl_local_atestado_1.hashPedidoLocal)(pedido), host: canal,
|
|
109
|
+
connectionId: `conn-${canal}`, requestId: `req-${canal}`, opcao: '1',
|
|
110
|
+
recebidoEm: new Date().toISOString(), alvo: 'gate' });
|
|
111
|
+
(0, hitl_gates_2.responderGateLocal)(s.dir, t.id, pedido.id, token);
|
|
112
|
+
recibos[canal] = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(s.dir, t.id)).find(e => e.tipo === 'human_gate');
|
|
113
|
+
}
|
|
114
|
+
// Os quatro responderam, e o recibo de cada um nomeia o seu canal.
|
|
115
|
+
const canais = (0, hitl_canais_1.canaisHomologados)().map(c => c.canal);
|
|
116
|
+
const aprovados = canais.filter(c => recibos[c]?.estado === 'aprovado');
|
|
117
|
+
const lidos = canais.map(c => (0, hitl_canais_1.canalDaResposta)((recibos[c] ?? {})).canal);
|
|
118
|
+
// Recusas: aprovacao cega, ingresso nao homologado e canal de outro transporte.
|
|
119
|
+
let recusas = 0;
|
|
120
|
+
const { t: tr, pedido: pr } = gate('recusas');
|
|
121
|
+
try {
|
|
122
|
+
(0, gates_1.aprovarGateHumano)(s.dir, tr.id, 'push', 'modelo');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
recusas++;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
(0, hitl_canais_1.recusarIngressoNaoHomologado)('transcrito-de-tool');
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
recusas++;
|
|
132
|
+
}
|
|
133
|
+
const trocado = { resposta: '1', origem: 'telegram', canal: 'codex',
|
|
134
|
+
por: 'telegram:42', mensagem: 'telegram:-7:trocado', recebidoEm: new Date().toISOString() };
|
|
135
|
+
try {
|
|
136
|
+
(0, hitl_gates_1.responderGate)(s.dir, tr.id, pr.id, { ...trocado, prova: (0, hitl_gates_1.assinaturaDaResposta)(tr.id, pr.id, trocado, chaves.hermes) });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
recusas++;
|
|
140
|
+
}
|
|
141
|
+
// FX1: chave de um canal nao autentica envelope do outro, mesmo com tudo mais correto.
|
|
142
|
+
const cruzado = { resposta: '1', origem: 'telegram', canal: 'openclaw', conta,
|
|
143
|
+
por: 'telegram:42', mensagem: 'telegram:-7:cruzado', recebidoEm: new Date().toISOString() };
|
|
144
|
+
try {
|
|
145
|
+
(0, hitl_gates_1.responderGate)(s.dir, tr.id, pr.id, { ...cruzado, prova: (0, hitl_gates_1.assinaturaDaResposta)(tr.id, pr.id, cruzado, chaves.hermes) });
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
recusas++;
|
|
149
|
+
}
|
|
150
|
+
// FX5: conta fora da allowlist do canal, com assinatura correta, tambem e recusada.
|
|
151
|
+
const outraConta = { ...cruzado, conta: 'conta-nao-autorizada', mensagem: 'telegram:-7:conta' };
|
|
152
|
+
try {
|
|
153
|
+
(0, hitl_gates_1.responderGate)(s.dir, tr.id, pr.id, { ...outraConta, prova: (0, hitl_gates_1.assinaturaDaResposta)(tr.id, pr.id, outraConta, chaves.openclaw) });
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
recusas++;
|
|
157
|
+
}
|
|
158
|
+
const semIngresso = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(s.dir, tr.id)).filter(e => e.tipo === 'human_gate').length;
|
|
159
|
+
// Oferta ao humano: com credencial e conexoes, os quatro ficam disponiveis.
|
|
160
|
+
const oferta = (0, hitl_canais_1.ofertaDeCanais)({ env: process.env,
|
|
161
|
+
conexoesMcp: ['claude-code', 'codex'] });
|
|
162
|
+
return { simulado: true, canaisRegistrados: registro.canais, transportes: registro.transportes,
|
|
163
|
+
chavesIndependentes: registro.chaves,
|
|
164
|
+
aprovados: aprovados.length, canaisDistinguiveis: new Set(lidos).size,
|
|
165
|
+
canalPorInferencia: lidos.filter(c => c === null).length,
|
|
166
|
+
recusas, humanosSemIngresso: semIngresso,
|
|
167
|
+
ofertaDisponivel: oferta.filter(o => o.estado === 'disponivel').length };
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
nomes.forEach((n, i) => { if (antigos[i] === undefined)
|
|
171
|
+
delete process.env[n];
|
|
172
|
+
else
|
|
173
|
+
process.env[n] = antigos[i]; });
|
|
174
|
+
s.limpar();
|
|
175
|
+
}
|
|
176
|
+
} },
|
|
177
|
+
];
|