@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/setup.js
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Feature #setup: customizacao de runtime/modelo/esforco POR BLOCO de cada modo de conducao.
|
|
4
|
+
*
|
|
5
|
+
* A tag #setup no pedido ao orquestrador abre UMA entrevista padronizada com o owner
|
|
6
|
+
* (mesma mecanica HITL do fluxo de demanda): a lista topificada dos modos VIVOS com seus
|
|
7
|
+
* blocos, perguntada na ordem do espectro VIVO (ver `ORDEM_DOS_MODOS`). A
|
|
8
|
+
* entrevista termina quando todos os modos foram cobertos OU quando o owner diz que
|
|
9
|
+
* concluiu (o restante fica no default). Quem CONDUZ a entrevista e o orquestrador
|
|
10
|
+
* (Camada 1); quem GUARDA e APLICA a resposta e o nucleo, por este modulo.
|
|
11
|
+
*
|
|
12
|
+
* Persistencia fora do orkastery.yaml de proposito: a matriz por bloco cresce com os modos, e
|
|
13
|
+
* o manifesto tem limite duro de 16 KB e vocacao de configuracao minima. Arquivo AUSENTE
|
|
14
|
+
* significa default puro: um recem-instalado roda TUDO em claude-bg/opus/high sem setup.
|
|
15
|
+
*
|
|
16
|
+
* I-52 (RM-047, fatia 3): dois lugares, e so um vale de cada vez.
|
|
17
|
+
* `orkastery.setup.json` na raiz do checkout, VERSIONADO: vale para todas as maquinas e
|
|
18
|
+
* muda por PR, como codigo. Quando existe, e ele que vale.
|
|
19
|
+
* `.orkastery/setup.json` na raiz de ESTADO (a mesma de todas as worktrees da maquina):
|
|
20
|
+
* o setup local, para quem ainda nao versionou. Antes da I-52 ele era lido a partir do
|
|
21
|
+
* checkout, e o despacho feito de dentro de uma worktree caia no default sem aviso.
|
|
22
|
+
* `ork setup versionar` leva o setup local para o arquivo versionado.
|
|
23
|
+
*/
|
|
24
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
27
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
28
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
29
|
+
}
|
|
30
|
+
Object.defineProperty(o, k2, desc);
|
|
31
|
+
}) : (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
o[k2] = m[k];
|
|
34
|
+
}));
|
|
35
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
36
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
37
|
+
}) : function(o, v) {
|
|
38
|
+
o["default"] = v;
|
|
39
|
+
});
|
|
40
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
41
|
+
var ownKeys = function(o) {
|
|
42
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
43
|
+
var ar = [];
|
|
44
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
45
|
+
return ar;
|
|
46
|
+
};
|
|
47
|
+
return ownKeys(o);
|
|
48
|
+
};
|
|
49
|
+
return function (mod) {
|
|
50
|
+
if (mod && mod.__esModule) return mod;
|
|
51
|
+
var result = {};
|
|
52
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
53
|
+
__setModuleDefault(result, mod);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
})();
|
|
57
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
58
|
+
exports.BLOCO_PADRAO = exports.EVENTO_SETUP_CONFIGURADO = exports.NOME_SETUP_VERSIONADO = exports.NOME_SETUP = exports.CONTRATO_DO_SETUP = void 0;
|
|
59
|
+
exports.validarFallback = validarFallback;
|
|
60
|
+
exports.normalizarFallback = normalizarFallback;
|
|
61
|
+
exports.alvosDaOrdemDeFallback = alvosDaOrdemDeFallback;
|
|
62
|
+
exports.fallbackDoBloco = fallbackDoBloco;
|
|
63
|
+
exports.validarLimitesDeBloco = validarLimitesDeBloco;
|
|
64
|
+
exports.blocoPadraoDoModo = blocoPadraoDoModo;
|
|
65
|
+
exports.caminhoSetupVersionado = caminhoSetupVersionado;
|
|
66
|
+
exports.caminhoSetupLocal = caminhoSetupLocal;
|
|
67
|
+
exports.origemDoSetup = origemDoSetup;
|
|
68
|
+
exports.caminhoSetup = caminhoSetup;
|
|
69
|
+
exports.setupPadrao = setupPadrao;
|
|
70
|
+
exports.lerSetup = lerSetup;
|
|
71
|
+
exports.gravarSetup = gravarSetup;
|
|
72
|
+
exports.versionarSetup = versionarSetup;
|
|
73
|
+
exports.configDoBloco = configDoBloco;
|
|
74
|
+
exports.limitesDoBloco = limitesDoBloco;
|
|
75
|
+
exports.iniciarPrazoDoBloco = iniciarPrazoDoBloco;
|
|
76
|
+
exports.consumirPrazoDoBloco = consumirPrazoDoBloco;
|
|
77
|
+
exports.herdarPrazoDoBloco = herdarPrazoDoBloco;
|
|
78
|
+
exports.ehPadrao = ehPadrao;
|
|
79
|
+
exports.editarBloco = editarBloco;
|
|
80
|
+
exports.resetarSetup = resetarSetup;
|
|
81
|
+
exports.registrarSetupNoLedger = registrarSetupNoLedger;
|
|
82
|
+
exports.linhaDaOrigemDoSetup = linhaDaOrigemDoSetup;
|
|
83
|
+
exports.textoDoSetup = textoDoSetup;
|
|
84
|
+
exports.textoDaEntrevista = textoDaEntrevista;
|
|
85
|
+
const fs = __importStar(require("node:fs"));
|
|
86
|
+
const path = __importStar(require("node:path"));
|
|
87
|
+
const estado_thread_1 = require("./estado-thread");
|
|
88
|
+
const ledger_1 = require("./ledger");
|
|
89
|
+
const manifest_1 = require("./manifest");
|
|
90
|
+
const modos_1 = require("./modos");
|
|
91
|
+
const runtimes_1 = require("./runtimes");
|
|
92
|
+
const util_1 = require("./util");
|
|
93
|
+
exports.CONTRATO_DO_SETUP = 'ork.setup/v1';
|
|
94
|
+
exports.NOME_SETUP = 'setup.json';
|
|
95
|
+
/** I-52: o setup versionado, ao lado do `orkastery.yaml`. */
|
|
96
|
+
exports.NOME_SETUP_VERSIONADO = 'orkastery.setup.json';
|
|
97
|
+
/** Limite de representacao Date, nao teto de trabalho ou de temporizador nativo. */
|
|
98
|
+
const MAX_INSTANTE_MS = 8_640_000_000_000_000;
|
|
99
|
+
const CAMPOS_LIMITES = ['duracaoMs', 'maxChildren', 'maxDepth', 'maxRetries'];
|
|
100
|
+
function objeto(valor, campo) {
|
|
101
|
+
if (!valor || typeof valor !== 'object' || Array.isArray(valor)) {
|
|
102
|
+
throw new Error(`${campo} deve ser objeto`);
|
|
103
|
+
}
|
|
104
|
+
return valor;
|
|
105
|
+
}
|
|
106
|
+
function camposExatos(valor, campos, campo) {
|
|
107
|
+
if (Object.keys(valor).length !== campos.length ||
|
|
108
|
+
campos.some(c => !Object.hasOwn(valor, c))) {
|
|
109
|
+
throw new Error(`${campo} deve conter somente ${campos.join(', ')}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const ENTRADA_DE_FALLBACK = /^([a-z][a-z0-9-]*):([^\s:]+)(?::([a-z]+))?$/;
|
|
113
|
+
/** Validacao estrita da entrada do operador: recusa em vez de descartar em silencio. */
|
|
114
|
+
function validarFallback(lista, principal) {
|
|
115
|
+
const vistos = new Set([principal]);
|
|
116
|
+
return lista.map((item) => {
|
|
117
|
+
const m = ENTRADA_DE_FALLBACK.exec(item.trim());
|
|
118
|
+
if (!m)
|
|
119
|
+
throw new Error(`fallback invalido: "${item}" (use runtime:modelo[:esforco], por exemplo codex:gpt-5.5)`);
|
|
120
|
+
if (!(0, runtimes_1.runtimeConhecido)(m[1]))
|
|
121
|
+
throw new Error(`fallback com runtime desconhecido: "${m[1]}" (homologados: ${runtimes_1.ORDEM_DOS_RUNTIMES.join(', ')})`);
|
|
122
|
+
if (vistos.has(m[1]))
|
|
123
|
+
throw new Error(`fallback repete o runtime ${m[1]} (o runtime do bloco e cada fallback aparecem uma vez)`);
|
|
124
|
+
vistos.add(m[1]);
|
|
125
|
+
return item.trim();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** Leitura normalizadora: entrada malformada, desconhecida ou repetida e descartada. */
|
|
129
|
+
function normalizarFallback(valor, principal) {
|
|
130
|
+
if (!Array.isArray(valor))
|
|
131
|
+
return [];
|
|
132
|
+
const vistos = new Set([principal]);
|
|
133
|
+
const saida = [];
|
|
134
|
+
for (const item of valor) {
|
|
135
|
+
const m = typeof item === 'string' ? ENTRADA_DE_FALLBACK.exec(item) : null;
|
|
136
|
+
if (!m || !(0, runtimes_1.runtimeConhecido)(m[1]) || vistos.has(m[1]))
|
|
137
|
+
continue;
|
|
138
|
+
vistos.add(m[1]);
|
|
139
|
+
saida.push(item);
|
|
140
|
+
}
|
|
141
|
+
return saida;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* D6 (A13): o UNICO parser da ordem de fallback. A leitura normalizadora (`normalizarFallback`)
|
|
145
|
+
* decide o que vale, com as mesmas regras da edicao; aqui cada entrada valida so e decomposta em
|
|
146
|
+
* runtime, modelo e esforco. A rotacao do retry le a ordem por esta funcao.
|
|
147
|
+
*/
|
|
148
|
+
function alvosDaOrdemDeFallback(valor, principal) {
|
|
149
|
+
return normalizarFallback(valor, principal).map((item) => {
|
|
150
|
+
const m = ENTRADA_DE_FALLBACK.exec(item);
|
|
151
|
+
return { runtime: m[1], model: m[2], ...(m[3] ? { effort: m[3] } : {}) };
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/** A ordem de fallback do bloco que conduz a fase (vazia quando nao configurada). */
|
|
155
|
+
function fallbackDoBloco(setup, modo, fase) {
|
|
156
|
+
const cfg = configDoBloco(setup, modo, fase);
|
|
157
|
+
return cfg?.fallback ?? [];
|
|
158
|
+
}
|
|
159
|
+
/** Recusa valores invalidos antes de JSON.stringify converter NaN/Infinity em null. */
|
|
160
|
+
function validarLimitesDeBloco(valor) {
|
|
161
|
+
const limites = objeto(valor, 'limites');
|
|
162
|
+
camposExatos(limites, CAMPOS_LIMITES, 'limites');
|
|
163
|
+
for (const campo of CAMPOS_LIMITES) {
|
|
164
|
+
const n = limites[campo];
|
|
165
|
+
if (typeof n !== 'number' || !Number.isSafeInteger(n) || n < (campo === 'duracaoMs' ? 1 : 0) ||
|
|
166
|
+
(campo === 'duracaoMs' && n > MAX_INSTANTE_MS)) {
|
|
167
|
+
throw new Error(`limites.${campo} deve ser inteiro ${campo === 'duracaoMs' ? 'positivo' : 'nao negativo'}, finito e representavel`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
duracaoMs: limites.duracaoMs, maxChildren: limites.maxChildren,
|
|
172
|
+
maxDepth: limites.maxDepth, maxRetries: limites.maxRetries,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function validarConfigComLimites(config) {
|
|
176
|
+
if (!Object.hasOwn(config, 'limites'))
|
|
177
|
+
return;
|
|
178
|
+
validarLimitesDeBloco(config.limites);
|
|
179
|
+
if (typeof config.runtime !== 'string' || !(0, runtimes_1.runtimeConhecido)(config.runtime) ||
|
|
180
|
+
typeof config.model !== 'string' || config.model.trim() === '' ||
|
|
181
|
+
typeof config.effort !== 'string' || config.effort.trim() === '') {
|
|
182
|
+
throw new Error('bloco com limites exige runtime conhecido, model e effort explicitos validos');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Valida tambem entradas que a normalizacao antiga descartaria. */
|
|
186
|
+
function validarEstruturaSetup(valor) {
|
|
187
|
+
const setup = objeto(valor, 'setup');
|
|
188
|
+
if (setup.contrato !== undefined && setup.contrato !== exports.CONTRATO_DO_SETUP) {
|
|
189
|
+
throw new Error('contrato de setup incompativel');
|
|
190
|
+
}
|
|
191
|
+
if (setup.modos === undefined)
|
|
192
|
+
return;
|
|
193
|
+
for (const [modo, valorModo] of Object.entries(objeto(setup.modos, 'setup.modos'))) {
|
|
194
|
+
const configModo = objeto(valorModo, `setup.modos.${modo}`);
|
|
195
|
+
if (configModo.blocos === undefined)
|
|
196
|
+
continue;
|
|
197
|
+
if (!Array.isArray(configModo.blocos))
|
|
198
|
+
throw new Error(`blocos de ${modo} devem ser array`);
|
|
199
|
+
for (const [i, valorBloco] of configModo.blocos.entries()) {
|
|
200
|
+
const config = objeto(valorBloco, `bloco ${modo}/${i + 1}`);
|
|
201
|
+
validarConfigComLimites(config);
|
|
202
|
+
if (Object.hasOwn(config, 'limites') && (setup.contrato !== exports.CONTRATO_DO_SETUP ||
|
|
203
|
+
!modos_1.ORDEM_DOS_MODOS.includes(modo) || i >= modos_1.MODOS[modo].blocos.length)) {
|
|
204
|
+
throw new Error('limites exigem contrato e bloco de modo conhecidos');
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/** Evento do ledger que carimba toda customizacao do #setup. */
|
|
210
|
+
exports.EVENTO_SETUP_CONFIGURADO = 'setup_configured';
|
|
211
|
+
/** O default pos-instalacao de todo bloco, menos o dos modos com default proprio (`blocoPadraoDoModo`). */
|
|
212
|
+
exports.BLOCO_PADRAO = {
|
|
213
|
+
runtime: runtimes_1.RUNTIME_PADRAO,
|
|
214
|
+
model: 'opus',
|
|
215
|
+
effort: 'high',
|
|
216
|
+
};
|
|
217
|
+
/**
|
|
218
|
+
* I-42: o default de um bloco depende do modo. O `#Fast` e o pedido pequeno: Sonnet com esforco
|
|
219
|
+
* alto no Claude e, sem conta Claude, o Terra com esforco alto no Codex. Os outros modos seguem
|
|
220
|
+
* no BLOCO_PADRAO.
|
|
221
|
+
*/
|
|
222
|
+
const PADRAO_POR_MODO = {
|
|
223
|
+
fast: { runtime: runtimes_1.RUNTIME_PADRAO, model: 'sonnet', effort: 'high', fallback: ['codex:gpt-5.6-terra:high'] },
|
|
224
|
+
};
|
|
225
|
+
function blocoPadraoDoModo(modo) {
|
|
226
|
+
const proprio = PADRAO_POR_MODO[modo];
|
|
227
|
+
return proprio ? { ...proprio, ...(proprio.fallback ? { fallback: [...proprio.fallback] } : {}) } : { ...exports.BLOCO_PADRAO };
|
|
228
|
+
}
|
|
229
|
+
/** I-52: o setup versionado deste checkout (existindo ou nao). */
|
|
230
|
+
function caminhoSetupVersionado(raiz) {
|
|
231
|
+
return path.join(raiz, exports.NOME_SETUP_VERSIONADO);
|
|
232
|
+
}
|
|
233
|
+
/** I-52: o setup local desta maquina, na raiz de estado (a mesma de todas as worktrees). */
|
|
234
|
+
function caminhoSetupLocal(raiz) {
|
|
235
|
+
return path.join((0, manifest_1.dirEstado)((0, estado_thread_1.raizDoEstado)(raiz)), exports.NOME_SETUP);
|
|
236
|
+
}
|
|
237
|
+
/** De onde vem o setup que vale agora. */
|
|
238
|
+
function origemDoSetup(raiz) {
|
|
239
|
+
if (fs.existsSync(caminhoSetupVersionado(raiz)))
|
|
240
|
+
return 'versionado';
|
|
241
|
+
return fs.existsSync(caminhoSetupLocal(raiz)) ? 'local' : 'padrao';
|
|
242
|
+
}
|
|
243
|
+
/** O arquivo que vale (e que a edicao grava): o versionado quando existe, senao o local. */
|
|
244
|
+
function caminhoSetup(raiz) {
|
|
245
|
+
return origemDoSetup(raiz) === 'versionado' ? caminhoSetupVersionado(raiz) : caminhoSetupLocal(raiz);
|
|
246
|
+
}
|
|
247
|
+
/** O setup default: a matriz dos modos vivos, cada bloco no default do seu modo. */
|
|
248
|
+
function setupPadrao() {
|
|
249
|
+
const modos = {};
|
|
250
|
+
for (const modo of modos_1.ORDEM_DOS_MODOS) {
|
|
251
|
+
modos[modo] = {
|
|
252
|
+
blocos: modos_1.MODOS[modo].blocos.map(() => blocoPadraoDoModo(modo)),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
return { contrato: exports.CONTRATO_DO_SETUP, atualizadoEm: (0, util_1.agora)(), modos };
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Le o setup do projeto, sempre COMPLETO.
|
|
259
|
+
*
|
|
260
|
+
* O arquivo em disco pode estar ausente (default puro), vir de versao antiga com um modo
|
|
261
|
+
* faltando, ou trazer blocos a mais de uma matriz que mudou. A leitura normaliza contra a
|
|
262
|
+
* matriz ATUAL dos modos: todo modo presente, um config por bloco, e campo vazio cai no
|
|
263
|
+
* default do mesmo runtime; modelo ausente em outro runtime permanece pendente.
|
|
264
|
+
* JSON, estrutura e limites configurados invalidos sao recusados antes do despacho.
|
|
265
|
+
*/
|
|
266
|
+
function lerSetup(raiz) {
|
|
267
|
+
const caminho = caminhoSetup(raiz);
|
|
268
|
+
const padrao = setupPadrao();
|
|
269
|
+
if (!fs.existsSync(caminho))
|
|
270
|
+
return padrao;
|
|
271
|
+
let bruto;
|
|
272
|
+
try {
|
|
273
|
+
bruto = (0, util_1.lerJson)(caminho);
|
|
274
|
+
}
|
|
275
|
+
catch (e) {
|
|
276
|
+
throw new Error(`setup invalido (${caminho}): ${e.message}`);
|
|
277
|
+
}
|
|
278
|
+
validarEstruturaSetup(bruto);
|
|
279
|
+
const modosBrutos = (bruto.modos ?? {});
|
|
280
|
+
for (const modo of modos_1.ORDEM_DOS_MODOS) {
|
|
281
|
+
const doArquivo = modosBrutos[modo]?.blocos ?? [];
|
|
282
|
+
const doModo = blocoPadraoDoModo(modo);
|
|
283
|
+
padrao.modos[modo] = {
|
|
284
|
+
blocos: modos_1.MODOS[modo].blocos.map((_, i) => {
|
|
285
|
+
// I-42: bloco ausente no arquivo (setup gravado antes do modo existir) nasce no
|
|
286
|
+
// default DO MODO, com o fallback dele; os blocos presentes seguem como estavam.
|
|
287
|
+
if (doArquivo[i] === undefined)
|
|
288
|
+
return blocoPadraoDoModo(modo);
|
|
289
|
+
const b = doArquivo[i];
|
|
290
|
+
const runtime = typeof b.runtime === 'string' && (0, runtimes_1.runtimeConhecido)(b.runtime)
|
|
291
|
+
? b.runtime
|
|
292
|
+
: doModo.runtime;
|
|
293
|
+
return {
|
|
294
|
+
runtime,
|
|
295
|
+
model: typeof b.model === 'string' && b.model.trim() !== '' ? b.model
|
|
296
|
+
: runtime === doModo.runtime ? doModo.model : '',
|
|
297
|
+
effort: typeof b.effort === 'string' && b.effort !== '' ? b.effort : doModo.effort,
|
|
298
|
+
...('limites' in b ? { limites: validarLimitesDeBloco(b.limites) } : {}),
|
|
299
|
+
...(() => {
|
|
300
|
+
const fallback = normalizarFallback(b.fallback, runtime);
|
|
301
|
+
return fallback.length ? { fallback } : {};
|
|
302
|
+
})(),
|
|
303
|
+
};
|
|
304
|
+
}),
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
if (typeof bruto.atualizadoEm === 'string')
|
|
308
|
+
padrao.atualizadoEm = bruto.atualizadoEm;
|
|
309
|
+
return padrao;
|
|
310
|
+
}
|
|
311
|
+
/** Grava o setup onde ele vale (o versionado, quando existe). */
|
|
312
|
+
function gravarSetup(raiz, setup) {
|
|
313
|
+
validarEstruturaSetup(setup);
|
|
314
|
+
const caminho = caminhoSetup(raiz);
|
|
315
|
+
setup.atualizadoEm = (0, util_1.agora)();
|
|
316
|
+
(0, util_1.gravarJson)(caminho, setup);
|
|
317
|
+
return caminho;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* I-52: `ork setup versionar` leva o setup que vale agora para `orkastery.setup.json`, na raiz do
|
|
321
|
+
* checkout. O arquivo entra no repositorio por PR, e dali em diante e ele que vale em todas as
|
|
322
|
+
* maquinas; o local fica onde esta, ignorado enquanto o versionado existir.
|
|
323
|
+
*/
|
|
324
|
+
function versionarSetup(raiz, por = 'owner') {
|
|
325
|
+
const caminho = caminhoSetupVersionado(raiz);
|
|
326
|
+
if (fs.existsSync(caminho))
|
|
327
|
+
throw new Error(`setup.versionado: ${exports.NOME_SETUP_VERSIONADO} ja existe neste checkout; edite com ork setup <modo> --bloco N`);
|
|
328
|
+
const origem = origemDoSetup(raiz);
|
|
329
|
+
const setup = lerSetup(raiz);
|
|
330
|
+
validarEstruturaSetup(setup);
|
|
331
|
+
setup.atualizadoEm = (0, util_1.agora)();
|
|
332
|
+
(0, util_1.gravarJson)(caminho, setup);
|
|
333
|
+
registrarSetupNoLedger(raiz, { acao: 'versionar', de: origem, para: exports.NOME_SETUP_VERSIONADO, por });
|
|
334
|
+
return { caminho, setup };
|
|
335
|
+
}
|
|
336
|
+
/** A config que abre a sessao do bloco que conduz a fase informada no modo informado. */
|
|
337
|
+
// Leitor: thread em modo aposentado continua tendo bloco, runtime e limites.
|
|
338
|
+
function configDoBloco(setup, modo, fase) {
|
|
339
|
+
const def = modos_1.MODOS[modo];
|
|
340
|
+
if (!def)
|
|
341
|
+
return null;
|
|
342
|
+
const indice = def.blocos.findIndex((b) => b.fases.includes(fase));
|
|
343
|
+
if (indice < 0)
|
|
344
|
+
return null;
|
|
345
|
+
const config = setup.modos[modo]?.blocos[indice] ?? { ...exports.BLOCO_PADRAO };
|
|
346
|
+
validarConfigComLimites(objeto(config, 'config do bloco'));
|
|
347
|
+
return config;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Resolve o perfil I09 sem despachar. Opt-in exige matriz completa nos modos permitidos.
|
|
351
|
+
* T11 devera consumir este contrato antes do spawn e persistir a identidade reservada.
|
|
352
|
+
*/
|
|
353
|
+
function limitesDoBloco(manifesto, setup, modo, fase) {
|
|
354
|
+
validarEstruturaSetup(setup);
|
|
355
|
+
if (!(0, manifest_1.validarOptInPlaybook)(manifesto.playbook))
|
|
356
|
+
return null;
|
|
357
|
+
const permitidos = manifesto.conduction.allowed_modes;
|
|
358
|
+
if (!Array.isArray(permitidos) || permitidos.length === 0 ||
|
|
359
|
+
permitidos.some(m => !modos_1.ORDEM_DOS_MODOS.includes(m)) ||
|
|
360
|
+
!permitidos.includes(modo)) {
|
|
361
|
+
throw new Error('playbook ativo exige modo permitido valido');
|
|
362
|
+
}
|
|
363
|
+
for (const permitido of permitidos) {
|
|
364
|
+
const blocos = setup.modos?.[permitido]?.blocos;
|
|
365
|
+
if (!blocos || blocos.length !== modos_1.MODOS[permitido].blocos.length) {
|
|
366
|
+
throw new Error(`playbook ativo exige todos os blocos de ${permitido}`);
|
|
367
|
+
}
|
|
368
|
+
for (const config of blocos) {
|
|
369
|
+
validarConfigComLimites(objeto(config, 'config do bloco'));
|
|
370
|
+
validarLimitesDeBloco(config.limites);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const config = configDoBloco(setup, modo, fase);
|
|
374
|
+
if (!config)
|
|
375
|
+
throw new Error(`fase ${fase} fora do modo ${modo}`);
|
|
376
|
+
return validarLimitesDeBloco(config.limites);
|
|
377
|
+
}
|
|
378
|
+
function instante(valor, campo) {
|
|
379
|
+
if (typeof valor !== 'number' || !Number.isSafeInteger(valor) || valor < 0 || valor > MAX_INSTANTE_MS) {
|
|
380
|
+
throw new Error(`${campo} deve ser instante inteiro nao negativo e representavel`);
|
|
381
|
+
}
|
|
382
|
+
return valor;
|
|
383
|
+
}
|
|
384
|
+
function somarPrazo(inicio, duracao) {
|
|
385
|
+
return instante(inicio + duracao, 'deadline (overflow)');
|
|
386
|
+
}
|
|
387
|
+
function validarIdentidade(valor) {
|
|
388
|
+
const id = objeto(valor, 'identidade');
|
|
389
|
+
camposExatos(id, ['threadId', 'execucaoId', 'modo', 'bloco'], 'identidade');
|
|
390
|
+
for (const campo of ['threadId', 'execucaoId']) {
|
|
391
|
+
if (typeof id[campo] !== 'string' || id[campo].trim() === '') {
|
|
392
|
+
throw new Error(`identidade.${campo} deve ser texto nao vazio`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (!modos_1.ORDEM_DOS_MODOS.includes(id.modo) ||
|
|
396
|
+
typeof id.bloco !== 'number' || !Number.isSafeInteger(id.bloco) ||
|
|
397
|
+
id.bloco < 1 || id.bloco > modos_1.MODOS[id.modo].blocos.length) {
|
|
398
|
+
throw new Error('identidade de modo/bloco invalida');
|
|
399
|
+
}
|
|
400
|
+
return { threadId: id.threadId, execucaoId: id.execucaoId, modo: id.modo, bloco: id.bloco };
|
|
401
|
+
}
|
|
402
|
+
function semAmpliacao(limites, origem) {
|
|
403
|
+
for (const campo of CAMPOS_LIMITES) {
|
|
404
|
+
if (limites[campo] > origem[campo])
|
|
405
|
+
throw new Error(`heranca nao pode ampliar limites.${campo}`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Primeiro trabalho ativo de uma identidade NOVA reservada pelo controlador.
|
|
410
|
+
* Nao usar para filhos/retries/retomadas. Nao cria timer, processo ou registro em disco.
|
|
411
|
+
*/
|
|
412
|
+
function iniciarPrazoDoBloco(manifesto, setup, identidade, fase, agoraMs) {
|
|
413
|
+
const limites = limitesDoBloco(manifesto, setup, identidade.modo, fase);
|
|
414
|
+
if (limites === null)
|
|
415
|
+
return null;
|
|
416
|
+
const id = validarIdentidade(identidade);
|
|
417
|
+
if (!modos_1.MODOS[id.modo].blocos[id.bloco - 1].fases.includes(fase)) {
|
|
418
|
+
throw new Error('identidade do bloco diverge da fase selecionada');
|
|
419
|
+
}
|
|
420
|
+
const inicio = instante(agoraMs, 'iniciadaEmMs');
|
|
421
|
+
const deadline = somarPrazo(inicio, limites.duracaoMs);
|
|
422
|
+
return {
|
|
423
|
+
versao: 1, identidade: id, iniciadaEmMs: inicio, deadlineOriginalMs: deadline,
|
|
424
|
+
limitesOriginais: { ...limites }, deadlineMs: deadline, limites: { ...limites }, observadoEmMs: inicio,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
function validarPrazo(valor, esperada) {
|
|
428
|
+
const p = objeto(valor, 'prazo');
|
|
429
|
+
camposExatos(p, ['versao', 'identidade', 'iniciadaEmMs', 'deadlineOriginalMs',
|
|
430
|
+
'limitesOriginais', 'deadlineMs', 'limites', 'observadoEmMs'], 'prazo');
|
|
431
|
+
if (p.versao !== 1)
|
|
432
|
+
throw new Error('versao de prazo incompativel');
|
|
433
|
+
const identidade = validarIdentidade(p.identidade);
|
|
434
|
+
const idEsperada = validarIdentidade(esperada);
|
|
435
|
+
if (Object.keys(identidade).some(c => identidade[c] !== idEsperada[c])) {
|
|
436
|
+
throw new Error('identidade da execucao divergente');
|
|
437
|
+
}
|
|
438
|
+
const limitesOriginais = validarLimitesDeBloco(p.limitesOriginais);
|
|
439
|
+
const limites = validarLimitesDeBloco(p.limites);
|
|
440
|
+
semAmpliacao(limites, limitesOriginais);
|
|
441
|
+
const iniciadaEmMs = instante(p.iniciadaEmMs, 'iniciadaEmMs');
|
|
442
|
+
const observadoEmMs = instante(p.observadoEmMs, 'observadoEmMs');
|
|
443
|
+
const deadlineOriginalMs = instante(p.deadlineOriginalMs, 'deadlineOriginalMs');
|
|
444
|
+
const deadlineMs = instante(p.deadlineMs, 'deadlineMs');
|
|
445
|
+
if (deadlineOriginalMs !== somarPrazo(iniciadaEmMs, limitesOriginais.duracaoMs) ||
|
|
446
|
+
deadlineMs !== somarPrazo(iniciadaEmMs, limites.duracaoMs) || observadoEmMs < iniciadaEmMs) {
|
|
447
|
+
throw new Error('origem/deadline do prazo inconsistente');
|
|
448
|
+
}
|
|
449
|
+
return { versao: 1, identidade, iniciadaEmMs, deadlineOriginalMs, limitesOriginais, deadlineMs, limites, observadoEmMs };
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Consome a janela absoluta, sem a renovar. Espera sem processo nao e timeout de runtime;
|
|
453
|
+
* nao prorroga a deadline e nao permite reentrada em trabalho depois de expirada.
|
|
454
|
+
* Relogio e contagem de processos devem vir do controlador, nao da resposta do modelo.
|
|
455
|
+
*/
|
|
456
|
+
function consumirPrazoDoBloco(snapshot, identidadeEsperada, agoraMs, atividade = { tipo: 'trabalho' }) {
|
|
457
|
+
const prazo = validarPrazo(snapshot, identidadeEsperada);
|
|
458
|
+
const agoraValidado = instante(agoraMs, 'agoraMs');
|
|
459
|
+
if (agoraValidado < prazo.observadoEmMs)
|
|
460
|
+
throw new Error('relogio regressivo no prazo');
|
|
461
|
+
const a = objeto(atividade, 'atividade');
|
|
462
|
+
if (a.tipo === 'trabalho') {
|
|
463
|
+
camposExatos(a, ['tipo'], 'atividade');
|
|
464
|
+
}
|
|
465
|
+
else if (a.tipo === 'espera_lease' || a.tipo === 'espera_score') {
|
|
466
|
+
camposExatos(a, ['tipo', 'processosAtivos'], 'atividade');
|
|
467
|
+
if (a.processosAtivos !== 0)
|
|
468
|
+
throw new Error('espera exige ausencia comprovada de processos ativos');
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
throw new Error('atividade de prazo desconhecida');
|
|
472
|
+
}
|
|
473
|
+
prazo.observadoEmMs = agoraValidado;
|
|
474
|
+
const restanteMs = Math.max(0, prazo.deadlineMs - agoraValidado);
|
|
475
|
+
return {
|
|
476
|
+
prazo, restanteMs,
|
|
477
|
+
estado: a.tipo !== 'trabalho' ? 'espera_sem_processo' : restanteMs > 0 ? 'ativo' : 'expirado',
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
/** Heranca para filho, retry ou proxima fase do MESMO bloco. Nao admite processos. */
|
|
481
|
+
function herdarPrazoDoBloco(origem, identidadeEsperada, agoraMs, limitesSolicitados) {
|
|
482
|
+
const consumo = consumirPrazoDoBloco(origem, identidadeEsperada, agoraMs);
|
|
483
|
+
if (consumo.estado !== 'ativo')
|
|
484
|
+
throw new Error('prazo expirado: heranca recusada');
|
|
485
|
+
const prazo = consumo.prazo;
|
|
486
|
+
const limites = validarLimitesDeBloco(limitesSolicitados === undefined ? prazo.limites : limitesSolicitados);
|
|
487
|
+
semAmpliacao(limites, prazo.limites);
|
|
488
|
+
const deadlineMs = somarPrazo(prazo.iniciadaEmMs, limites.duracaoMs);
|
|
489
|
+
if (deadlineMs <= agoraMs)
|
|
490
|
+
throw new Error('prazo reduzido ja expirado');
|
|
491
|
+
return { ...prazo, limites, deadlineMs };
|
|
492
|
+
}
|
|
493
|
+
/** A config do bloco e o default pos-instalacao? */
|
|
494
|
+
function ehPadrao(cfg, modo) {
|
|
495
|
+
// I-42: com o modo, o default e o DO MODO (o `#Fast` nasce em Sonnet com fallback).
|
|
496
|
+
const padrao = modo ? blocoPadraoDoModo(modo) : { ...exports.BLOCO_PADRAO };
|
|
497
|
+
const fallback = cfg.fallback ?? [];
|
|
498
|
+
const esperado = padrao.fallback ?? [];
|
|
499
|
+
return (cfg.runtime === padrao.runtime &&
|
|
500
|
+
cfg.model === padrao.model &&
|
|
501
|
+
cfg.effort === padrao.effort &&
|
|
502
|
+
cfg.limites === undefined &&
|
|
503
|
+
fallback.length === esperado.length &&
|
|
504
|
+
fallback.every((f, i) => f === esperado[i]));
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Edita a config de UM bloco de UM modo e carimba `setup_configured` no ledger do projeto.
|
|
508
|
+
*
|
|
509
|
+
* O indice do bloco e 1-based porque e assim que a entrevista e o CLI falam com o owner
|
|
510
|
+
* ("bloco 1 GOAL-PLAN"). Runtime desconhecido reprova aqui, antes de ir ao disco: um
|
|
511
|
+
* arquivo de setup com runtime inexistente viraria erro tipado so na hora do despacho.
|
|
512
|
+
*/
|
|
513
|
+
function editarBloco(raiz, modo, bloco, edicao, por = 'owner') {
|
|
514
|
+
const def = (0, modos_1.definicaoDoModo)(modo);
|
|
515
|
+
const setup = lerSetup(raiz);
|
|
516
|
+
const base = {
|
|
517
|
+
ok: false,
|
|
518
|
+
setup,
|
|
519
|
+
caminho: caminhoSetup(raiz),
|
|
520
|
+
modo,
|
|
521
|
+
bloco,
|
|
522
|
+
de: null,
|
|
523
|
+
para: null,
|
|
524
|
+
};
|
|
525
|
+
if (!Number.isInteger(bloco) || bloco < 1 || bloco > def.blocos.length) {
|
|
526
|
+
return {
|
|
527
|
+
...base,
|
|
528
|
+
erro: `bloco ${bloco} nao existe no modo ${def.tag}: ele tem ${def.blocos.length} bloco(s)`,
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
if (edicao.runtime !== undefined && !(0, runtimes_1.runtimeConhecido)(edicao.runtime)) {
|
|
532
|
+
return {
|
|
533
|
+
...base,
|
|
534
|
+
erro: `runtime desconhecido: "${edicao.runtime}" (homologados: ${runtimes_1.ORDEM_DOS_RUNTIMES.join(', ')})`,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
const atual = setup.modos[modo].blocos[bloco - 1];
|
|
538
|
+
if (edicao.runtime !== undefined && edicao.runtime !== atual.runtime && !edicao.model?.trim())
|
|
539
|
+
return { ...base, erro: 'setup.model.required: para mudar o runtime do bloco, informe --runtime e --model juntos; nenhuma configuracao foi gravada.' };
|
|
540
|
+
if (!(edicao.model ?? atual.model).trim())
|
|
541
|
+
return { ...base, erro: 'setup.model.required: modelo pendente neste bloco; informe --model antes de salvar.' };
|
|
542
|
+
const de = { ...atual };
|
|
543
|
+
const runtimeNovo = edicao.runtime ?? atual.runtime;
|
|
544
|
+
let fallback;
|
|
545
|
+
try {
|
|
546
|
+
// A ordem pedida e validada estrita; a herdada so perde o runtime que virou o do bloco.
|
|
547
|
+
fallback = edicao.fallback !== undefined ? validarFallback(edicao.fallback, runtimeNovo)
|
|
548
|
+
: normalizarFallback(atual.fallback, runtimeNovo);
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
return { ...base, erro: e.message };
|
|
552
|
+
}
|
|
553
|
+
const para = {
|
|
554
|
+
runtime: runtimeNovo,
|
|
555
|
+
model: edicao.model ?? atual.model,
|
|
556
|
+
effort: edicao.effort ?? atual.effort,
|
|
557
|
+
...(atual.limites === undefined ? {} : { limites: { ...atual.limites } }),
|
|
558
|
+
...(Object.hasOwn(edicao, 'limites') ? { limites: edicao.limites } : {}),
|
|
559
|
+
...(fallback.length ? { fallback } : {}),
|
|
560
|
+
};
|
|
561
|
+
try {
|
|
562
|
+
validarConfigComLimites(objeto(para, 'config do bloco'));
|
|
563
|
+
if (para.limites)
|
|
564
|
+
para.limites = validarLimitesDeBloco(para.limites);
|
|
565
|
+
}
|
|
566
|
+
catch (e) {
|
|
567
|
+
return { ...base, erro: e.message };
|
|
568
|
+
}
|
|
569
|
+
setup.modos[modo].blocos[bloco - 1] = para;
|
|
570
|
+
const caminho = gravarSetup(raiz, setup);
|
|
571
|
+
registrarSetupNoLedger(raiz, {
|
|
572
|
+
acao: 'editar',
|
|
573
|
+
modo,
|
|
574
|
+
bloco,
|
|
575
|
+
fases: def.blocos[bloco - 1].fases.join('-'),
|
|
576
|
+
de,
|
|
577
|
+
para,
|
|
578
|
+
por,
|
|
579
|
+
});
|
|
580
|
+
return { ...base, ok: true, setup, caminho, de, para };
|
|
581
|
+
}
|
|
582
|
+
/** Reseta UM modo (ou todos, sem `modo`) para o default claude-bg/opus/high. */
|
|
583
|
+
function resetarSetup(raiz, modo, por = 'owner') {
|
|
584
|
+
const setup = lerSetup(raiz);
|
|
585
|
+
const padrao = setupPadrao();
|
|
586
|
+
if (modo) {
|
|
587
|
+
(0, modos_1.definicaoDoModo)(modo);
|
|
588
|
+
setup.modos[modo] = padrao.modos[modo];
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
setup.modos = padrao.modos;
|
|
592
|
+
}
|
|
593
|
+
gravarSetup(raiz, setup);
|
|
594
|
+
registrarSetupNoLedger(raiz, {
|
|
595
|
+
acao: 'resetar',
|
|
596
|
+
modo: modo ?? 'todos',
|
|
597
|
+
para: modo ? blocoPadraoDoModo(modo) : exports.BLOCO_PADRAO,
|
|
598
|
+
por,
|
|
599
|
+
});
|
|
600
|
+
return setup;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Carimba a customizacao no ledger DO PROJETO (`.orkastery/ledger.jsonl`).
|
|
604
|
+
*
|
|
605
|
+
* O setup nao pertence a uma thread: ele governa despachos futuros de todas. O evento
|
|
606
|
+
* reusa o registrador do ledger com o id fixo `projeto`, no mesmo formato append-only.
|
|
607
|
+
*/
|
|
608
|
+
function registrarSetupNoLedger(raiz, dados) {
|
|
609
|
+
// I-52: o ledger do projeto e o da raiz de estado, de qualquer worktree.
|
|
610
|
+
(0, ledger_1.registrar)((0, manifest_1.dirEstado)((0, estado_thread_1.raizDoEstado)(raiz)), 'projeto', exports.EVENTO_SETUP_CONFIGURADO, dados);
|
|
611
|
+
}
|
|
612
|
+
/** I-52: a linha que diz ao dono de onde vem o setup que vale. */
|
|
613
|
+
function linhaDaOrigemDoSetup(raiz) {
|
|
614
|
+
const origem = origemDoSetup(raiz);
|
|
615
|
+
if (origem === 'versionado') {
|
|
616
|
+
return `Setup versionado em ${exports.NOME_SETUP_VERSIONADO}: vale para todas as maquinas e muda por PR.` +
|
|
617
|
+
(fs.existsSync(caminhoSetupLocal(raiz)) ? ' O .orkastery/setup.json local desta maquina fica ignorado.' : '');
|
|
618
|
+
}
|
|
619
|
+
if (origem === 'local')
|
|
620
|
+
return 'Setup local desta maquina (.orkastery/setup.json). Para valer em todas: ork setup versionar.';
|
|
621
|
+
return 'Nenhum setup gravado: vale o default. Para valer em todas as maquinas: ork setup versionar.';
|
|
622
|
+
}
|
|
623
|
+
/** Tabela de um modo: cada bloco com sua config e a marca do que saiu do default. */
|
|
624
|
+
function textoDoSetup(raiz, modo) {
|
|
625
|
+
const def = (0, modos_1.definicaoDoModo)(modo);
|
|
626
|
+
const setup = lerSetup(raiz);
|
|
627
|
+
const linhas = def.blocos.map((b, i) => {
|
|
628
|
+
const cfg = setup.modos[modo].blocos[i];
|
|
629
|
+
return [
|
|
630
|
+
String(i + 1),
|
|
631
|
+
b.fases.join('-'),
|
|
632
|
+
cfg.runtime,
|
|
633
|
+
cfg.model || '(modelo pendente)',
|
|
634
|
+
cfg.effort,
|
|
635
|
+
cfg.fallback?.join(', ') || '-',
|
|
636
|
+
ehPadrao(cfg, modo) ? 'default' : 'customizado',
|
|
637
|
+
];
|
|
638
|
+
});
|
|
639
|
+
const saida = [];
|
|
640
|
+
saida.push(`Setup do modo ${def.tag} (${def.blocos.length} bloco(s), ${def.pausas} pausa(s))`);
|
|
641
|
+
saida.push('');
|
|
642
|
+
saida.push((0, util_1.tabela)(['BLOCO', 'FASES', 'RUNTIME', 'MODEL', 'EFFORT', 'FALLBACK', 'ORIGEM'], linhas));
|
|
643
|
+
saida.push('');
|
|
644
|
+
saida.push(`Editar: ork setup ${modo} --bloco N --runtime R --model M --effort E`);
|
|
645
|
+
saida.push(`Fallback: ork setup ${modo} --bloco N --fallback runtime:modelo[:esforco],... (--fallback "" remove)`);
|
|
646
|
+
const padrao = blocoPadraoDoModo(modo);
|
|
647
|
+
saida.push(`Resetar: ork setup ${modo} --reset (volta para ${padrao.runtime}/${padrao.model}/${padrao.effort})`);
|
|
648
|
+
saida.push(`Runtimes homologados: ${runtimes_1.ORDEM_DOS_RUNTIMES.join(', ')}`);
|
|
649
|
+
saida.push('');
|
|
650
|
+
saida.push(linhaDaOrigemDoSetup(raiz));
|
|
651
|
+
return saida.join('\n');
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* A pauta da entrevista do #setup: a lista topificada dos modos vivos com seus blocos.
|
|
655
|
+
*
|
|
656
|
+
* E este texto que o orquestrador entrega ao owner quando a tag #setup chega no pedido.
|
|
657
|
+
* A ordem das perguntas e a do espectro vivo (o mais HITL primeiro), a entrevista pode parar quando
|
|
658
|
+
* o owner disser que concluiu, e todo bloco nao respondido fica no default.
|
|
659
|
+
*/
|
|
660
|
+
function textoDaEntrevista(raiz) {
|
|
661
|
+
const setup = lerSetup(raiz);
|
|
662
|
+
const saida = [];
|
|
663
|
+
saida.push('Entrevista #setup: runtime + modelo + esforco por bloco de cada modo');
|
|
664
|
+
saida.push('');
|
|
665
|
+
saida.push(`Ordem das perguntas: ${modos_1.ORDEM_DOS_MODOS.map((m) => modos_1.MODOS[m].tag).join(' -> ')}.`);
|
|
666
|
+
saida.push('A entrevista termina quando todos os modos forem cobertos OU quando o owner');
|
|
667
|
+
saida.push('disser que concluiu: o que nao for respondido fica no default.');
|
|
668
|
+
const proprios = modos_1.ORDEM_DOS_MODOS.filter((m) => !ehPadrao(blocoPadraoDoModo(m)));
|
|
669
|
+
saida.push(`Default pos-instalacao: ${exports.BLOCO_PADRAO.runtime}/${exports.BLOCO_PADRAO.model}/${exports.BLOCO_PADRAO.effort} em todos os blocos` +
|
|
670
|
+
(proprios.length ? `, menos ${proprios.map((m) => {
|
|
671
|
+
const b = blocoPadraoDoModo(m);
|
|
672
|
+
return `${modos_1.MODOS[m].tag} (${b.runtime}/${b.model}/${b.effort}${b.fallback?.length ? `, fallback ${b.fallback.join(', ')}` : ''})`;
|
|
673
|
+
}).join(', ')}.` : '.'));
|
|
674
|
+
saida.push('');
|
|
675
|
+
for (const modo of modos_1.ORDEM_DOS_MODOS) {
|
|
676
|
+
const def = modos_1.MODOS[modo];
|
|
677
|
+
saida.push(`${def.tag}`);
|
|
678
|
+
def.blocos.forEach((b, i) => {
|
|
679
|
+
const cfg = setup.modos[modo].blocos[i];
|
|
680
|
+
const marca = ehPadrao(cfg, modo) ? '' : ' <- customizado';
|
|
681
|
+
saida.push(` bloco ${i + 1}: ${b.fases.join('-')} [${cfg.runtime}/${cfg.model || '(modelo pendente)'}/${cfg.effort}]${marca}`);
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
saida.push('');
|
|
685
|
+
saida.push('Ver um modo: ork setup <modo>');
|
|
686
|
+
saida.push('Editar bloco: ork setup <modo> --bloco N --runtime R --model M --effort E');
|
|
687
|
+
saida.push('Resetar tudo: ork setup --reset');
|
|
688
|
+
saida.push('');
|
|
689
|
+
saida.push(linhaDaOrigemDoSetup(raiz));
|
|
690
|
+
return saida.join('\n');
|
|
691
|
+
}
|