@orkastery/cli 0.2.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 +21 -0
- package/README.md +87 -0
- package/adapters/README.md +22 -0
- package/adapters/claude-code/.claude-plugin/marketplace.json +15 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +31 -0
- package/adapters/claude-code/README.md +102 -0
- package/adapters/claude-code/agents/ork-check.md +32 -0
- package/adapters/claude-code/agents/ork-go.md +32 -0
- package/adapters/claude-code/agents/ork-goal.md +33 -0
- package/adapters/claude-code/agents/ork-master.md +32 -0
- package/adapters/claude-code/agents/ork-plan.md +32 -0
- package/adapters/claude-code/agents/ork-ship.md +32 -0
- package/adapters/claude-code/commands/check.md +45 -0
- package/adapters/claude-code/commands/go.md +46 -0
- package/adapters/claude-code/commands/goal.md +54 -0
- package/adapters/claude-code/commands/master.md +42 -0
- package/adapters/claude-code/commands/ork.md +37 -0
- package/adapters/claude-code/commands/plan.md +47 -0
- package/adapters/claude-code/commands/ship.md +45 -0
- package/adapters/claude-code/hooks/hooks.json +17 -0
- package/adapters/claude-code/hooks/ork-guard.js +130 -0
- package/adapters/hermes/README.md +45 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +25 -0
- package/adapters/hermes/hermes.plugin.json +21 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +116 -0
- package/adapters/openclaw/README.md +63 -0
- package/adapters/openclaw/bin/ork-abrir-thread.sh +24 -0
- package/adapters/openclaw/openclaw.plugin.json +138 -0
- package/dist/adapters/claude-bg.js +308 -0
- package/dist/auditoria.js +848 -0
- package/dist/auditrun.js +976 -0
- package/dist/board.js +314 -0
- package/dist/canarios.js +271 -0
- package/dist/catalogo.js +124 -0
- package/dist/ciclos.js +156 -0
- package/dist/claims.js +226 -0
- package/dist/divida.js +374 -0
- package/dist/doctor.js +246 -0
- package/dist/evalrunner.js +458 -0
- package/dist/fix.js +450 -0
- package/dist/gates.js +92 -0
- package/dist/handoff.js +521 -0
- package/dist/hosts.js +331 -0
- package/dist/index.js +1910 -0
- package/dist/init.js +231 -0
- package/dist/leases.js +508 -0
- package/dist/ledger.js +138 -0
- package/dist/manifest.js +255 -0
- package/dist/master.js +453 -0
- package/dist/memoria.js +773 -0
- package/dist/modos.js +220 -0
- package/dist/orkmind.js +487 -0
- package/dist/orquestracao.js +559 -0
- package/dist/phase.js +572 -0
- package/dist/policies.js +176 -0
- package/dist/prompts.js +406 -0
- package/dist/ratelimit.js +179 -0
- package/dist/recall.js +252 -0
- package/dist/retry.js +917 -0
- package/dist/sandbox.js +94 -0
- package/dist/sessoes.js +104 -0
- package/dist/ship.js +551 -0
- package/dist/slug.js +100 -0
- package/dist/superficie.js +1347 -0
- package/dist/thread.js +333 -0
- package/dist/tokens.js +228 -0
- package/dist/types.js +20 -0
- package/dist/util.js +156 -0
- package/dist/verify.js +262 -0
- package/dist/worktree.js +576 -0
- package/dist/yaml.js +112 -0
- package/eval/README.md +85 -0
- package/eval/casos/check-quality.json +103 -0
- package/eval/casos/code-reviewer.json +102 -0
- package/eval/casos/decision-triage.json +103 -0
- package/eval/casos/go-implementation.json +103 -0
- package/eval/casos/goal-definition.json +103 -0
- package/eval/casos/master-metrics.json +103 -0
- package/eval/casos/narrative-guardian.json +163 -0
- package/eval/casos/orkastery-bootstrap.json +102 -0
- package/eval/casos/plan-specification.json +102 -0
- package/eval/casos/roadmap-keeper.json +103 -0
- package/eval/casos/scope-check-capability-map.json +83 -0
- package/eval/casos/security-auditor.json +102 -0
- package/eval/casos/ship-release.json +122 -0
- package/eval/casos/test-engineer.json +122 -0
- package/eval/casos/thread-state.json +82 -0
- package/eval/casos/thread-tracing.json +83 -0
- package/eval/casos/web-performance-auditor.json +102 -0
- package/eval/fixtures/b0-slug-e-modos/caso.json +56 -0
- package/eval/fixtures/b2-master-log/caso.json +91 -0
- package/eval/fixtures/fx-concurrency/caso.json +15 -0
- package/eval/fixtures/fx-hallucination/caso.json +12 -0
- package/eval/fixtures/fx-happy/caso.json +16 -0
- package/eval/fixtures/fx-schema-drift/caso.json +15 -0
- package/eval/fixtures/fx-stale-base/caso.json +12 -0
- package/eval/fixtures/fx-wiki-destroy/caso.json +16 -0
- package/eval/fixtures/superficie-de-rede/README.md +22 -0
- package/eval/fixtures/superficie-de-rede/api-express.js +30 -0
- package/eval/fixtures/superficie-de-rede/api_fastapi.py +17 -0
- package/eval/fixtures/superficie-de-rede/api_gin.go +18 -0
- package/package.json +56 -0
- package/references/README.md +25 -0
- package/references/code-review-axes.md +82 -0
- package/references/definition-of-done.md +74 -0
- package/references/performance-checklist.md +53 -0
- package/references/security-checklist.md +101 -0
- package/references/testing-patterns.md +51 -0
- package/skills/README.md +43 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +89 -0
- package/skills/core/thread-state/SKILL.md +86 -0
- package/skills/governance/decision-triage/SKILL.md +65 -0
- package/skills/governance/narrative-guardian/SKILL.md +66 -0
- package/skills/governance/roadmap-keeper/SKILL.md +60 -0
- package/skills/governance/scope-check-capability-map/SKILL.md +61 -0
- package/skills/observability/thread-tracing/SKILL.md +63 -0
- package/skills/phases/check-quality/SKILL.md +87 -0
- package/skills/phases/go-implementation/SKILL.md +70 -0
- package/skills/phases/goal-definition/SKILL.md +69 -0
- package/skills/phases/master-metrics/SKILL.md +65 -0
- package/skills/phases/plan-specification/SKILL.md +67 -0
- package/skills/phases/ship-release/SKILL.md +68 -0
- package/skills/reviewers/code-reviewer/SKILL.md +61 -0
- package/skills/reviewers/security-auditor/SKILL.md +68 -0
- package/skills/reviewers/test-engineer/SKILL.md +66 -0
- package/skills/reviewers/web-performance-auditor/SKILL.md +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1910 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* `ork`: nucleo CLI deterministico do Orkastery (bloco B0).
|
|
5
|
+
*
|
|
6
|
+
* Sem LLM embutido: o `ork` monta prompt, despacha pelo runtime adapter, verifica no
|
|
7
|
+
* mundo real e registra no ledger. Quem escreve codigo e a orquestra (Camada 3);
|
|
8
|
+
* quem decide e o humano; o meio e conduzido por software.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.parseArgs = parseArgs;
|
|
12
|
+
exports.main = main;
|
|
13
|
+
const auditoria_1 = require("./auditoria");
|
|
14
|
+
const auditrun_1 = require("./auditrun");
|
|
15
|
+
const superficie_1 = require("./superficie");
|
|
16
|
+
const board_1 = require("./board");
|
|
17
|
+
const orquestracao_1 = require("./orquestracao");
|
|
18
|
+
const divida_1 = require("./divida");
|
|
19
|
+
const ciclos_1 = require("./ciclos");
|
|
20
|
+
const claims_1 = require("./claims");
|
|
21
|
+
const catalogo_1 = require("./catalogo");
|
|
22
|
+
const doctor_1 = require("./doctor");
|
|
23
|
+
const evalrunner_1 = require("./evalrunner");
|
|
24
|
+
const gates_1 = require("./gates");
|
|
25
|
+
const handoff_1 = require("./handoff");
|
|
26
|
+
const hosts_1 = require("./hosts");
|
|
27
|
+
const init_1 = require("./init");
|
|
28
|
+
const leases_1 = require("./leases");
|
|
29
|
+
const master_1 = require("./master");
|
|
30
|
+
const manifest_1 = require("./manifest");
|
|
31
|
+
const memoria_1 = require("./memoria");
|
|
32
|
+
const recall_1 = require("./recall");
|
|
33
|
+
const fix_1 = require("./fix");
|
|
34
|
+
const ratelimit_1 = require("./ratelimit");
|
|
35
|
+
const retry_1 = require("./retry");
|
|
36
|
+
const modos_1 = require("./modos");
|
|
37
|
+
const phase_1 = require("./phase");
|
|
38
|
+
const prompts_1 = require("./prompts");
|
|
39
|
+
const sessoes_1 = require("./sessoes");
|
|
40
|
+
const util_1 = require("./util");
|
|
41
|
+
const ship_1 = require("./ship");
|
|
42
|
+
const thread_1 = require("./thread");
|
|
43
|
+
const tokens_1 = require("./tokens");
|
|
44
|
+
const types_1 = require("./types");
|
|
45
|
+
const verify_1 = require("./verify");
|
|
46
|
+
const worktree_1 = require("./worktree");
|
|
47
|
+
/** A versao publicada em `@orkastery/cli`. Anda junto com o `version` do package.json. */
|
|
48
|
+
const VERSAO = '0.2.0';
|
|
49
|
+
/** Parse simples de argumentos: `--chave valor`, `--chave=valor` e flags booleanas. */
|
|
50
|
+
function parseArgs(argv) {
|
|
51
|
+
const posicionais = [];
|
|
52
|
+
const opcoes = {};
|
|
53
|
+
for (let i = 0; i < argv.length; i++) {
|
|
54
|
+
const a = argv[i];
|
|
55
|
+
if (a.startsWith('--')) {
|
|
56
|
+
const igual = a.indexOf('=');
|
|
57
|
+
if (igual > 0) {
|
|
58
|
+
opcoes[a.slice(2, igual)] = a.slice(igual + 1);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const proximo = argv[i + 1];
|
|
62
|
+
if (proximo !== undefined && !proximo.startsWith('--')) {
|
|
63
|
+
opcoes[a.slice(2)] = proximo;
|
|
64
|
+
i++;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
opcoes[a.slice(2)] = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
posicionais.push(a);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { posicionais, opcoes };
|
|
76
|
+
}
|
|
77
|
+
function texto(v) {
|
|
78
|
+
return typeof v === 'string' ? v : undefined;
|
|
79
|
+
}
|
|
80
|
+
const AJUDA = `ork ${VERSAO}, nucleo de orquestracao do Orkastery
|
|
81
|
+
|
|
82
|
+
Uso: ork <comando> [argumentos]
|
|
83
|
+
|
|
84
|
+
doctor O que vale nesta maquina agora (sai != 0 se bloqueado)
|
|
85
|
+
init [--force] [--name N] [--abbrev A] Gera o orkastery.yaml do repositorio
|
|
86
|
+
modos Tabela dos 5 modos de conducao por #TAG
|
|
87
|
+
|
|
88
|
+
thread new <nome> --modo <MODO> Cria a thread, o slug de 3 partes e o ledger
|
|
89
|
+
[--slug S] [--assunto A] [--worktree auto|DIR] [--dry-run]
|
|
90
|
+
thread list Threads do projeto
|
|
91
|
+
thread status <thread-id> Estado da thread, cruzado com o runtime
|
|
92
|
+
|
|
93
|
+
phase run <thread-id> <FASE> --prompt "<texto>"
|
|
94
|
+
[--model M] [--effort E] [--dry-run] Despacha a fase como background agent
|
|
95
|
+
(so --model assume --effort high; o par
|
|
96
|
+
efetivo vai ao ledger como fato verificavel)
|
|
97
|
+
phase list <thread-id> Historico do ledger da thread
|
|
98
|
+
(mostra o modelo/esforco reais de cada fase)
|
|
99
|
+
|
|
100
|
+
sessions [--all] Sessoes vivas do runtime, cruzadas com as threads
|
|
101
|
+
sessions logs <sessao> [--linhas N] Logs de uma sessao
|
|
102
|
+
sessions stop <sessao> Para uma sessao
|
|
103
|
+
sessions attach <sessao> Imprime o comando de attach (precisa de TTY)
|
|
104
|
+
|
|
105
|
+
claims add <thread-id> <arquivo> --claim "<alegacao>" [--verificar "<comando>"] [--fase F]
|
|
106
|
+
Registra alegacao verificavel da thread
|
|
107
|
+
claims list <thread-id> Claims da thread e o estado de cada uma
|
|
108
|
+
claims verificar <thread-id> <claim-id> --comando "<comando>"
|
|
109
|
+
Anexa o comando que comprova uma claim ja feita
|
|
110
|
+
claims retirar <thread-id> <claim-id> --motivo "<motivo>"
|
|
111
|
+
Retira a alegacao (o historico fica no claims.jsonl)
|
|
112
|
+
verify <thread-id> [--baseline] Reexecuta claims e verify do manifesto no HEAD real
|
|
113
|
+
[--so-claims] --baseline grava o estado do mundo antes do GO
|
|
114
|
+
|
|
115
|
+
gate next <thread-id> [--proximo FASE] Gate de tokens: mesma sessao ou nova sessao
|
|
116
|
+
[--ocupacao 0..1] [--fonte F] [--transcript ARQ] [--janela N] [--refazer]
|
|
117
|
+
gate approve <thread-id> <sobre> --por Q Registra autorizacao humana no ledger
|
|
118
|
+
|
|
119
|
+
retry policy [--motivo M] [--json] Politica de retry por motivo tipado de gate
|
|
120
|
+
retry plan <thread-id> [--motivo M] O que o ork faria pelo ultimo gate reprovado
|
|
121
|
+
[--fase F] [--json] (calcula, nao executa, nao gasta tentativa)
|
|
122
|
+
retry run <thread-id> [--reverify] Executa a acao tipada do ultimo gate reprovado
|
|
123
|
+
[--por Q] [--dry-run] (--por autoriza quando o bloco do modo pausa)
|
|
124
|
+
retry list [--json] Fila DURAVEL de rate limit do projeto
|
|
125
|
+
retry resume [--id R1] [--agora ISO] Retoma a fase morta por rate limit na janela seguinte
|
|
126
|
+
[--ocupacao 0..1] [--forcar] [--dry-run] (playbooks: mesma-sessao, nova-sessao, escalada)
|
|
127
|
+
retry cancel <id> --motivo M Tira um pedido da fila, com motivo registrado
|
|
128
|
+
retry parse --stderr "<texto>" Le o horario de reset do stderr do adapter
|
|
129
|
+
|
|
130
|
+
fix open <thread-id> [--so-claims] GO-FIX: deriva a spec exata do CHECK reprovado
|
|
131
|
+
[--reverify] [--json] (uma correcao por motivo tipado, tipo A ou B)
|
|
132
|
+
fix list <thread-id> [--rodada N] Correcoes da rodada e o veredito de cada uma
|
|
133
|
+
fix reverify <thread-id> [--rodada N] CHECK-REVERIFY com veredito POR correcao
|
|
134
|
+
[--parcial] [--json] (--parcial e RECUSADO se houver tipo B)
|
|
135
|
+
|
|
136
|
+
handoff export <thread-id> Handoff triado CRITICO/IMPORTANTE/RESUMIVEL
|
|
137
|
+
[--proxima-fase FASE] [--slug S]
|
|
138
|
+
handoff recall <thread-id> <ponteiro> Resolve um ponteiro path#ancora de volta ao conteudo
|
|
139
|
+
|
|
140
|
+
recall <thread-id> --fase FASE Recuperacao TARDIA: resolve so os ponteiros do
|
|
141
|
+
[--id ptr-N] [--todos] [--forcar] momento (retrieve_when), nunca a janela inteira
|
|
142
|
+
[--sem-conteudo] [--json] (orkmind por tag, files por path#ancora)
|
|
143
|
+
|
|
144
|
+
memory status [--json] Regime efetivo (files|orkmind), tenant e degradacao
|
|
145
|
+
memory sync [<thread-id>] [--json] Publica decisoes, policies, handoff, licao e roadmap
|
|
146
|
+
memory search --tags '<json>' [--colecao C] Busca deterministica por tag (mandatory sempre volta)
|
|
147
|
+
[--limite N] [--json]
|
|
148
|
+
|
|
149
|
+
ship <thread-id> --para <branch> Merge --no-ff serializado por lease e push PROVADO
|
|
150
|
+
[--de <branch>] [--remoto origin] [--autorizar-push <quem>] [--sem-push] [--dry-run]
|
|
151
|
+
|
|
152
|
+
board [--all] Visao unica das threads (todos os perfis com --all)
|
|
153
|
+
board plan Escalonador: quem avanca agora, quem espera e por que
|
|
154
|
+
|
|
155
|
+
orquestracao status [--all] [--json] Monitor PROATIVO de pausas e impedimentos: quem esta
|
|
156
|
+
[--atencao N] [--so-paradas] parado, esperando o que, ha quanto tempo e o que
|
|
157
|
+
[--sem-runtime] [--exigir-limpo] destrava (alias curto: ork monitor)
|
|
158
|
+
|
|
159
|
+
worktree ensure <thread-id> Garante a worktree da thread (base resolvida pelo ork)
|
|
160
|
+
worktree sync <thread-id> [--dry-run] Rebasa a branch da thread quando a base avancou
|
|
161
|
+
worktree audit <thread-id> Confere a worktree no proprio git (sai != 0 se divergir)
|
|
162
|
+
worktree release <thread-id> [--forcar] Remove a worktree e limpa o registro
|
|
163
|
+
|
|
164
|
+
lease list Leases, familias e as filas (merge e colisao de regiao)
|
|
165
|
+
lease acquire <nome> --thread T --motivo M Toma um lease tipado (entra na fila se colidir)
|
|
166
|
+
lease release <nome> [--thread T] [--forcar]
|
|
167
|
+
|
|
168
|
+
master <thread-id> --score 0-5 --justificativa "<texto>"
|
|
169
|
+
[--classe C[,C]] [--resumo R] [--por Q] [--refazer]
|
|
170
|
+
Fecha a thread: POSTMORTEM + MASTER log + score
|
|
171
|
+
master --batch [--todas] Fila de review em bloco (threads entregues sem score)
|
|
172
|
+
master classes As classes de falha fixas do POSTMORTEM
|
|
173
|
+
|
|
174
|
+
ciclos Variantes de ciclo de "ork thread new --ciclo"
|
|
175
|
+
modos --do-pedido "<texto>" [--json] Le a #TAG do pedido do builder (usado pelos adaptadores)
|
|
176
|
+
|
|
177
|
+
prompt list Templates de prompt (embutidos e os do projeto)
|
|
178
|
+
prompt lint [--template ID] Reprova template quebrado antes de ele virar despacho
|
|
179
|
+
prompt render <thread-id> --fase F Mostra o prompt exato, com o sha256 que vai ao ledger
|
|
180
|
+
[--pedido "<texto>"] [--template ID]
|
|
181
|
+
prompt render --exemplo --fase F --modo M Renderiza sem thread nenhuma, para revisar o texto
|
|
182
|
+
|
|
183
|
+
adapter list Adaptadores de host (Camada 1) e o destino de cada um
|
|
184
|
+
adapter show <host> Os 3 pitfalls de instalacao do host
|
|
185
|
+
adapter install <host> [--dir D] Instala o adaptador (hermes|openclaw|claude-code)
|
|
186
|
+
[--dry-run] [--force]
|
|
187
|
+
|
|
188
|
+
eval [--skill S] [--canario C] Canarios de comportamento + corpus das skills finas
|
|
189
|
+
[--so-canarios] [--so-skills] [--json] (sai != 0 em qualquer falha)
|
|
190
|
+
|
|
191
|
+
audit packs [--estagio E] [--pack P] Os 7 packs, o estagio que os ativa e a postura
|
|
192
|
+
audit run <pack> [--profile P] Monta o prompt do pack e despacha pelo runtime adapter
|
|
193
|
+
[--since Nd] [--tudo] [--effort E] [--model M] [--agora "<quem>"] [--forcar] [--dry-run]
|
|
194
|
+
audit list Rodadas de auditoria do projeto
|
|
195
|
+
audit show <rodada> [--ledger] Contexto, achados e propostas de uma rodada
|
|
196
|
+
audit prompt <pack> [--since Nd] O prompt exato do pack, com o sha256 que vai ao ledger
|
|
197
|
+
audit lint Reprova template de auditoria quebrado (auditors/)
|
|
198
|
+
audit ingest <rodada> --arquivo J Registra em lote os achados que o auditor escreveu
|
|
199
|
+
audit finding add <rodada> --regra R Registra um achado com evidencia, claim e proposta
|
|
200
|
+
--titulo T --arquivo caminho:linha --impacto I --fix F --estimativa E
|
|
201
|
+
[--severidade critico|maior|menor] [--irreversivel "<passo>"] [--verificar "<comando>"]
|
|
202
|
+
audit verify <rodada> Reexecuta as claims dos achados (auditor sem self-report)
|
|
203
|
+
audit report <rodada> [--publicar] Relatorio com o bloco OBRIGATORIO de propostas
|
|
204
|
+
audit divida [--pack P] [--todos] Board de divida: propostas abertas e recorrencia
|
|
205
|
+
audit surface [<dir>] [--regra SPn] Varredura DETERMINISTICA da superficie de ataque de rede
|
|
206
|
+
[--limite N] [--json] (SP8..SP12; sai != 0 quando ha achado)
|
|
207
|
+
audit surface --registrar <rodada> Grava os achados da varredura no board da rodada
|
|
208
|
+
audit finding estado <id> <estado> Carimba o achado (aberto|adiado|resolvido|descartado)
|
|
209
|
+
|
|
210
|
+
thread new <nome> --from-finding <ID> Abre a thread a partir de um achado de auditoria
|
|
211
|
+
[--modo M] [--worktree auto] [--dry-run] (evidencia, claim e proposta viajam junto)
|
|
212
|
+
|
|
213
|
+
Regimes de memoria: files (fallback honesto) e orkmind (bloco B6, base propria por tenant
|
|
214
|
+
declarada em memory.database_url_env pelo NOME da variavel de ambiente, sem fallback).
|
|
215
|
+
Colecoes gravadas no OrkMind: decision, handoff, rule, learning, roadmap (source=agent,
|
|
216
|
+
nunca mandatory: regra critica so nasce de humano autenticado).
|
|
217
|
+
|
|
218
|
+
Retry tipado (bloco B3): reexecutar, corrigir-dirigido, sincronizar-worktree,
|
|
219
|
+
escalar-esforco, esperar-janela, escalar-humano, sem-retry. Violacao de custo
|
|
220
|
+
(cost.violation) NUNCA recebe retry automatico. O limite de escalacao do manifesto
|
|
221
|
+
(retry.max_tentativas) pausa QUALQUER modo, inclusive #Auto.
|
|
222
|
+
|
|
223
|
+
Monitor de orquestracao (ork orquestracao status / ork monitor): duas naturezas de parada.
|
|
224
|
+
pausa-humana e a parada PREVISTA pelo modo (o bloco fechou e espera veredito, com o
|
|
225
|
+
pausaSobre do bloco dizendo o que o humano decide); impedimento e a nao prevista
|
|
226
|
+
(lease.busy, runtime.rate-limited, concurrency.limite e os demais gates tipados). Tudo e
|
|
227
|
+
DERIVADO de thread.json, ledger.jsonl e das filas em disco: o monitor le, nunca grava.
|
|
228
|
+
--exigir-limpo sai != 0 enquanto houver thread parada, para virar watchdog do orquestrador.
|
|
229
|
+
|
|
230
|
+
Fases: GOAL PLAN GO CHECK SHIP MASTER. Modos: #Look #Default #Ork #Maestro #Auto.
|
|
231
|
+
Familias de lease: main-tree, worktree-write:<thread>, path:<glob>, board:<card>, service:<porta>.
|
|
232
|
+
Ciclos: greenfield, merge-branch, goal-plan, gap, feature-xl-faseada.
|
|
233
|
+
Fontes de medida do gate de tokens: runtime_reported, estimated, informada, unavailable.
|
|
234
|
+
Hosts de Camada 1: claude-code, hermes, openclaw. Canarios: fx-happy, fx-hallucination,
|
|
235
|
+
fx-stale-base, fx-wiki-destroy, fx-schema-drift, fx-concurrency.
|
|
236
|
+
Packs de auditoria: clean-code, reuse, architecture, data-model, ux, security-privacy, process.
|
|
237
|
+
Superficie de ataque de rede (SP8..SP12, varredura deterministica): rota sem auth, endpoint de
|
|
238
|
+
administracao exposto, rota sem rate limit, CORS permissivo, rota sem esquema de payload.
|
|
239
|
+
Estagios do produto: nascente, crescendo, maduro (hardening gradual, visao secao 5.2).
|
|
240
|
+
`;
|
|
241
|
+
function comandoThread(args) {
|
|
242
|
+
const sub = args.posicionais[1];
|
|
243
|
+
if (sub === 'new') {
|
|
244
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
245
|
+
// `--from-finding <id>`: o achado de auditoria vira thread sem retrabalho (bloco B5).
|
|
246
|
+
// O nome posicional passa a ser opcional, porque o titulo do achado ja serve de nome.
|
|
247
|
+
const doAchado = texto(args.opcoes['from-finding']) ?? texto(args.opcoes['do-achado']);
|
|
248
|
+
if (doAchado) {
|
|
249
|
+
const brutoModoAchado = texto(args.opcoes.modo) ?? texto(args.opcoes.mode);
|
|
250
|
+
const modoAchado = brutoModoAchado ? (0, modos_1.parseModo)(brutoModoAchado) : undefined;
|
|
251
|
+
if (brutoModoAchado && !modoAchado) {
|
|
252
|
+
console.error(`modo invalido: "${brutoModoAchado}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
|
|
253
|
+
return 2;
|
|
254
|
+
}
|
|
255
|
+
const brutoWorktreeAchado = args.opcoes.worktree;
|
|
256
|
+
const criarWorktreeAchado = brutoWorktreeAchado === true || brutoWorktreeAchado === 'auto';
|
|
257
|
+
const r = (0, auditrun_1.abrirThreadDoAchado)(carregado, doAchado, {
|
|
258
|
+
nome: args.posicionais[2],
|
|
259
|
+
modo: modoAchado ?? undefined,
|
|
260
|
+
slug: texto(args.opcoes.slug),
|
|
261
|
+
assunto: texto(args.opcoes.assunto),
|
|
262
|
+
criarWorktree: criarWorktreeAchado,
|
|
263
|
+
worktree: criarWorktreeAchado ? null : (texto(brutoWorktreeAchado) ?? null),
|
|
264
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
265
|
+
});
|
|
266
|
+
if (!r.ok) {
|
|
267
|
+
console.error(`Thread a partir do achado ${r.achado.id} RECUSADA.`);
|
|
268
|
+
console.error(` ${auditoria_1.DESCRICAO_DO_MOTIVO_DE_AUDITORIA[r.motivo ?? 'claims.failed']}`);
|
|
269
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
270
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
271
|
+
console.error(` correcao: ${r.correcao}`);
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
const gravadaDoAchado = args.opcoes['dry-run'] !== true;
|
|
275
|
+
console.log(gravadaDoAchado
|
|
276
|
+
? `Thread criada a partir do achado ${r.achado.id}.`
|
|
277
|
+
: 'Simulacao (--dry-run), nada foi gravado.');
|
|
278
|
+
console.log((0, divida_1.textoDoAchado)(r.achado));
|
|
279
|
+
console.log('');
|
|
280
|
+
if (r.thread) {
|
|
281
|
+
console.log((0, thread_1.resumoDaThread)(r.thread));
|
|
282
|
+
console.log('');
|
|
283
|
+
console.log(` slug em 3 partes: ${(0, phase_1.descreverSlug)(r.thread.slug)}`);
|
|
284
|
+
}
|
|
285
|
+
if (r.motivo === 'claims.unverifiable') {
|
|
286
|
+
console.log('');
|
|
287
|
+
console.log(` ${r.detalhe}`);
|
|
288
|
+
}
|
|
289
|
+
// Bloco B6: a origem da thread vai para a colecao `roadmap` (achado -> proposta ->
|
|
290
|
+
// thread -> entrega e rastreavel sem abrir o board).
|
|
291
|
+
if (r.thread && gravadaDoAchado) {
|
|
292
|
+
relatarPublicacao((0, memoria_1.publicar)(carregado, r.thread.id, {
|
|
293
|
+
tipo: 'achado',
|
|
294
|
+
referencia: r.achado.id,
|
|
295
|
+
detalhe: `Achado ${r.achado.id} (${r.achado.pack}/${r.achado.regra}): ${r.achado.titulo}. ` +
|
|
296
|
+
`Fix proposto: ${r.achado.proposta.fix}`,
|
|
297
|
+
}));
|
|
298
|
+
}
|
|
299
|
+
if (gravadaDoAchado && r.thread) {
|
|
300
|
+
console.log(` origem do GOAL: .orkastery/threads/${r.thread.id}/achado.json`);
|
|
301
|
+
console.log('');
|
|
302
|
+
console.log('Pedido de GOAL ja montado a partir do achado:');
|
|
303
|
+
console.log('');
|
|
304
|
+
console.log(r.pedido);
|
|
305
|
+
console.log('');
|
|
306
|
+
console.log('Proximo passo:');
|
|
307
|
+
console.log(` ork phase run ${r.thread.id} GOAL --prompt "$(cat .orkastery/threads/${r.thread.id}/pedido-goal.md)"`);
|
|
308
|
+
}
|
|
309
|
+
return 0;
|
|
310
|
+
}
|
|
311
|
+
const nome = args.posicionais[2];
|
|
312
|
+
if (!nome) {
|
|
313
|
+
console.error('uso: ork thread new <nome> --modo <MODO>');
|
|
314
|
+
return 2;
|
|
315
|
+
}
|
|
316
|
+
const brutoModo = texto(args.opcoes.modo) ?? texto(args.opcoes.mode);
|
|
317
|
+
const modo = brutoModo
|
|
318
|
+
? (0, modos_1.parseModo)(brutoModo)
|
|
319
|
+
: carregado.manifesto.conduction.default_mode;
|
|
320
|
+
if (!modo) {
|
|
321
|
+
console.error(`modo invalido: "${brutoModo}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
|
|
322
|
+
return 2;
|
|
323
|
+
}
|
|
324
|
+
const dryRun = args.opcoes['dry-run'] === true;
|
|
325
|
+
const brutoWorktree = args.opcoes.worktree;
|
|
326
|
+
// `--worktree auto` (ou `--worktree` sozinho) cria a worktree isolada da thread;
|
|
327
|
+
// um caminho reusa um diretorio que ja existe.
|
|
328
|
+
const criarWorktree = brutoWorktree === true || brutoWorktree === 'auto';
|
|
329
|
+
const brutoCiclo = texto(args.opcoes.ciclo) ?? texto(args.opcoes.variante);
|
|
330
|
+
const variante = brutoCiclo ? (0, ciclos_1.parseVariante)(brutoCiclo) : null;
|
|
331
|
+
if (brutoCiclo && !variante) {
|
|
332
|
+
console.error(`variante de ciclo invalida: "${brutoCiclo}". Use uma de: ${Object.keys(ciclos_1.VARIANTES).join(', ')}`);
|
|
333
|
+
return 2;
|
|
334
|
+
}
|
|
335
|
+
const brutoFatias = texto(args.opcoes.fatias);
|
|
336
|
+
const { thread, gravada } = (0, thread_1.novaThread)(carregado, {
|
|
337
|
+
nome,
|
|
338
|
+
modo,
|
|
339
|
+
slug: texto(args.opcoes.slug),
|
|
340
|
+
assunto: texto(args.opcoes.assunto),
|
|
341
|
+
worktree: criarWorktree ? null : (texto(brutoWorktree) ?? null),
|
|
342
|
+
criarWorktree,
|
|
343
|
+
dryRun,
|
|
344
|
+
variante,
|
|
345
|
+
branch: texto(args.opcoes.branch),
|
|
346
|
+
fatias: brutoFatias !== undefined ? Number(brutoFatias) : undefined,
|
|
347
|
+
});
|
|
348
|
+
console.log(gravada ? 'Thread criada.' : 'Simulacao (--dry-run), nada foi gravado.');
|
|
349
|
+
console.log((0, thread_1.resumoDaThread)(thread));
|
|
350
|
+
console.log('');
|
|
351
|
+
console.log(` slug em 3 partes: ${(0, phase_1.descreverSlug)(thread.slug)}`);
|
|
352
|
+
if (gravada) {
|
|
353
|
+
console.log(` estado: .orkastery/threads/${thread.id}/thread.json`);
|
|
354
|
+
// Bloco B6: a origem da thread e as policies do projeto vao para a memoria
|
|
355
|
+
// semantica quando ela esta ligada. Em regime files nada muda nesta saida.
|
|
356
|
+
relatarPublicacao((0, memoria_1.publicar)(carregado, thread.id));
|
|
357
|
+
console.log('');
|
|
358
|
+
console.log(`Proximo passo: ork phase run ${thread.id} ${thread.faseAtual} --prompt "<pedido>"`);
|
|
359
|
+
}
|
|
360
|
+
return 0;
|
|
361
|
+
}
|
|
362
|
+
if (sub === 'list' || sub === undefined) {
|
|
363
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
364
|
+
console.log((0, thread_1.tabelaDeThreads)(carregado.raiz));
|
|
365
|
+
return 0;
|
|
366
|
+
}
|
|
367
|
+
if (sub === 'status') {
|
|
368
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
369
|
+
const id = args.posicionais[2];
|
|
370
|
+
if (!id) {
|
|
371
|
+
console.error('uso: ork thread status <thread-id>');
|
|
372
|
+
return 2;
|
|
373
|
+
}
|
|
374
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
375
|
+
console.log(`Thread ${thread.id}`);
|
|
376
|
+
console.log((0, thread_1.resumoDaThread)(thread));
|
|
377
|
+
console.log('');
|
|
378
|
+
if (thread.sessoes.length === 0) {
|
|
379
|
+
console.log(' nenhuma sessao despachada ainda');
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
console.log(' sessoes despachadas (estado real conferido em `ork sessions`)');
|
|
383
|
+
for (const s of thread.sessoes) {
|
|
384
|
+
console.log(` ${s.slug.padEnd(24)} ${s.fase.padEnd(6)} ${s.sessionId.slice(0, 8)} ` +
|
|
385
|
+
`verificada no runtime: ${s.verificada ? 'sim' : 'nao'}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
console.log('');
|
|
389
|
+
console.log(` pausas humanas do modo: ${(0, modos_1.pausasDoModo)(thread.modo)}`);
|
|
390
|
+
return 0;
|
|
391
|
+
}
|
|
392
|
+
console.error(`subcomando desconhecido: thread ${sub}`);
|
|
393
|
+
return 2;
|
|
394
|
+
}
|
|
395
|
+
function comandoPhase(args) {
|
|
396
|
+
const sub = args.posicionais[1];
|
|
397
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
398
|
+
if (sub === 'run') {
|
|
399
|
+
const id = args.posicionais[2];
|
|
400
|
+
const faseBruta = args.posicionais[3];
|
|
401
|
+
const prompt = texto(args.opcoes.prompt);
|
|
402
|
+
if (!id || !faseBruta || !prompt) {
|
|
403
|
+
console.error('uso: ork phase run <thread-id> <FASE> --prompt "<texto>"');
|
|
404
|
+
return 2;
|
|
405
|
+
}
|
|
406
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
407
|
+
const fase = (0, thread_1.exigirFase)(thread, faseBruta);
|
|
408
|
+
const r = (0, phase_1.rodarFase)(carregado, id, {
|
|
409
|
+
fase,
|
|
410
|
+
prompt,
|
|
411
|
+
model: texto(args.opcoes.model),
|
|
412
|
+
effort: texto(args.opcoes.effort),
|
|
413
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
414
|
+
});
|
|
415
|
+
if (r.dryRun) {
|
|
416
|
+
console.log('Simulacao (--dry-run), nada foi despachado.');
|
|
417
|
+
console.log(` slug da sessao : ${r.slug}`);
|
|
418
|
+
console.log(` prompt : ${r.promptPath}`);
|
|
419
|
+
console.log(` sha256 : ${r.promptSha256}`);
|
|
420
|
+
console.log(` pausa ao fim : ${r.pausaAoFim ? 'sim' : 'nao'}`);
|
|
421
|
+
console.log(` modelo/esforco : ${r.model}/${r.effort}`);
|
|
422
|
+
console.log(` comando : claude --bg "<prompt>" --name ${r.slug} ...`);
|
|
423
|
+
return 0;
|
|
424
|
+
}
|
|
425
|
+
if (r.bloqueado) {
|
|
426
|
+
console.error(`Despacho BLOQUEADO pelo gate tipado: ${r.motivo}`);
|
|
427
|
+
for (const v of r.violacoes) {
|
|
428
|
+
console.error(` [${v.severidade}] policy ${v.policy}: ${v.detalhe}`);
|
|
429
|
+
console.error(` correcao: ${v.correcao}`);
|
|
430
|
+
}
|
|
431
|
+
console.error(` o prompt nao foi gravado em disco; evento gate_blocked no ledger de ${id}`);
|
|
432
|
+
return 1;
|
|
433
|
+
}
|
|
434
|
+
if (!r.sessionId) {
|
|
435
|
+
console.error(`Despacho falhou: ${r.erro}`);
|
|
436
|
+
console.error(` evento registrado no ledger de ${id}`);
|
|
437
|
+
return 1;
|
|
438
|
+
}
|
|
439
|
+
console.log(`Fase ${fase} despachada como background agent.`);
|
|
440
|
+
console.log(` sessionId : ${r.sessionId}`);
|
|
441
|
+
console.log(` slug da sessao : ${r.slug} (${(0, phase_1.descreverSlug)(r.slug)})`);
|
|
442
|
+
console.log(` prompt : ${r.promptPath}`);
|
|
443
|
+
console.log(` sha256 : ${r.promptSha256}`);
|
|
444
|
+
console.log(` modelo/esforco : ${r.model}/${r.effort} (gravado no ledger, veja \`ork phase list\`)`);
|
|
445
|
+
console.log(` verificada no runtime: ${r.verificada ? 'sim' : 'NAO (confira `ork sessions`)'}`);
|
|
446
|
+
console.log(` pausa ao fim do bloco: ${r.pausaAoFim ? 'sim' : 'nao (decisao autonoma no ledger)'}`);
|
|
447
|
+
console.log('');
|
|
448
|
+
console.log(`Acompanhe: claude attach ${r.sessionId} | ork phase list ${id}`);
|
|
449
|
+
return r.verificada ? 0 : 1;
|
|
450
|
+
}
|
|
451
|
+
if (sub === 'list') {
|
|
452
|
+
const id = args.posicionais[2];
|
|
453
|
+
if (!id) {
|
|
454
|
+
console.error('uso: ork phase list <thread-id>');
|
|
455
|
+
return 2;
|
|
456
|
+
}
|
|
457
|
+
console.log((0, phase_1.tabelaDoLedger)(carregado.raiz, id));
|
|
458
|
+
return 0;
|
|
459
|
+
}
|
|
460
|
+
console.error(`subcomando desconhecido: phase ${sub}`);
|
|
461
|
+
return 2;
|
|
462
|
+
}
|
|
463
|
+
function comandoSessions(args) {
|
|
464
|
+
const sub = args.posicionais[1];
|
|
465
|
+
const carregado = (0, manifest_1.carregarManifesto)();
|
|
466
|
+
const raiz = carregado?.raiz ?? process.cwd();
|
|
467
|
+
if (sub === undefined || sub === 'list') {
|
|
468
|
+
console.log((0, sessoes_1.tabelaDeSessoes)(raiz, args.opcoes.all === true));
|
|
469
|
+
return 0;
|
|
470
|
+
}
|
|
471
|
+
const chave = args.posicionais[2];
|
|
472
|
+
if (!chave) {
|
|
473
|
+
console.error(`uso: ork sessions ${sub} <sessao>`);
|
|
474
|
+
return 2;
|
|
475
|
+
}
|
|
476
|
+
if (sub === 'logs') {
|
|
477
|
+
const n = Number(texto(args.opcoes.linhas) ?? '60');
|
|
478
|
+
const r = (0, sessoes_1.logsDaSessao)(chave, Number.isFinite(n) ? n : 60);
|
|
479
|
+
console.log(r.texto);
|
|
480
|
+
return r.codigo;
|
|
481
|
+
}
|
|
482
|
+
if (sub === 'stop') {
|
|
483
|
+
const r = (0, sessoes_1.pararSessao)(chave);
|
|
484
|
+
console.log(r.texto);
|
|
485
|
+
return r.codigo;
|
|
486
|
+
}
|
|
487
|
+
if (sub === 'attach') {
|
|
488
|
+
const r = (0, sessoes_1.comandoDeAttach)(chave);
|
|
489
|
+
console.log(r.texto);
|
|
490
|
+
return r.codigo;
|
|
491
|
+
}
|
|
492
|
+
console.error(`subcomando desconhecido: sessions ${sub}`);
|
|
493
|
+
return 2;
|
|
494
|
+
}
|
|
495
|
+
function comandoClaims(args) {
|
|
496
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
497
|
+
const sub = args.posicionais[1];
|
|
498
|
+
if (sub === 'add') {
|
|
499
|
+
const id = args.posicionais[2];
|
|
500
|
+
const arquivo = args.posicionais[3];
|
|
501
|
+
const alegacao = texto(args.opcoes.claim) ?? texto(args.opcoes.alegacao);
|
|
502
|
+
if (!id || !arquivo || !alegacao) {
|
|
503
|
+
console.error('uso: ork claims add <thread-id> <arquivo> --claim "<alegacao>" [--verificar "<comando>"]');
|
|
504
|
+
return 2;
|
|
505
|
+
}
|
|
506
|
+
const comando = texto(args.opcoes.verificar) ?? texto(args.opcoes.verify);
|
|
507
|
+
const faseBruta = texto(args.opcoes.fase);
|
|
508
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
509
|
+
const claim = (0, claims_1.adicionarClaim)(carregado.raiz, id, {
|
|
510
|
+
arquivo,
|
|
511
|
+
alegacao,
|
|
512
|
+
verificar: comando ? [comando] : [],
|
|
513
|
+
fase: faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined,
|
|
514
|
+
});
|
|
515
|
+
console.log(`Claim ${claim.id} registrada na thread ${id}.`);
|
|
516
|
+
console.log(` arquivo ${claim.arquivo}`);
|
|
517
|
+
console.log(` alegacao ${claim.alegacao}`);
|
|
518
|
+
console.log(` negativa ${claim.negativa ? 'sim (exige comando de verificacao)' : 'nao'}`);
|
|
519
|
+
console.log(` verificar ${claim.verificar.join(' && ') || '(nenhum comando declarado)'}`);
|
|
520
|
+
console.log(` estado ${claim.estado}`);
|
|
521
|
+
if (claim.negativa && claim.verificar.length === 0) {
|
|
522
|
+
console.log('');
|
|
523
|
+
console.log('AVISO: alegacao negativa sem comando de verificacao reprova em `ork verify`.');
|
|
524
|
+
}
|
|
525
|
+
return 0;
|
|
526
|
+
}
|
|
527
|
+
if (sub === 'verificar') {
|
|
528
|
+
const id = args.posicionais[2];
|
|
529
|
+
const claimId = args.posicionais[3];
|
|
530
|
+
const comando = texto(args.opcoes.comando) ?? texto(args.opcoes.verificar);
|
|
531
|
+
if (!id || !claimId || !comando) {
|
|
532
|
+
console.error('uso: ork claims verificar <thread-id> <claim-id> --comando "<comando>"');
|
|
533
|
+
return 2;
|
|
534
|
+
}
|
|
535
|
+
const claim = (0, claims_1.anexarComando)(carregado.raiz, id, claimId, comando);
|
|
536
|
+
console.log(`Claim ${claim.id} agora tem comando de verificacao.`);
|
|
537
|
+
console.log(` verificar ${claim.verificar.join(' && ')}`);
|
|
538
|
+
console.log(` estado ${claim.estado}`);
|
|
539
|
+
console.log('');
|
|
540
|
+
console.log(`Prove agora: ork verify ${id}`);
|
|
541
|
+
return 0;
|
|
542
|
+
}
|
|
543
|
+
if (sub === 'retirar') {
|
|
544
|
+
const id = args.posicionais[2];
|
|
545
|
+
const claimId = args.posicionais[3];
|
|
546
|
+
const motivo = texto(args.opcoes.motivo);
|
|
547
|
+
if (!id || !claimId || !motivo) {
|
|
548
|
+
console.error('uso: ork claims retirar <thread-id> <claim-id> --motivo "<motivo>"');
|
|
549
|
+
return 2;
|
|
550
|
+
}
|
|
551
|
+
const claim = (0, claims_1.retirarClaim)(carregado.raiz, id, claimId, motivo);
|
|
552
|
+
console.log(`Claim ${claim.id} retirada da thread ${id}.`);
|
|
553
|
+
console.log(` alegacao ${claim.alegacao}`);
|
|
554
|
+
console.log(` motivo ${motivo}`);
|
|
555
|
+
console.log(' o historico da alegacao continua no claims.jsonl e no ledger.');
|
|
556
|
+
return 0;
|
|
557
|
+
}
|
|
558
|
+
if (sub === 'list' || sub === undefined) {
|
|
559
|
+
const id = args.posicionais[2];
|
|
560
|
+
if (!id) {
|
|
561
|
+
console.error('uso: ork claims list <thread-id>');
|
|
562
|
+
return 2;
|
|
563
|
+
}
|
|
564
|
+
console.log((0, claims_1.tabelaDeClaims)(carregado.raiz, id));
|
|
565
|
+
return 0;
|
|
566
|
+
}
|
|
567
|
+
console.error(`subcomando desconhecido: claims ${sub}`);
|
|
568
|
+
return 2;
|
|
569
|
+
}
|
|
570
|
+
function comandoVerify(args) {
|
|
571
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
572
|
+
const id = args.posicionais[1];
|
|
573
|
+
if (!id) {
|
|
574
|
+
console.error('uso: ork verify <thread-id> [--baseline] [--so-claims]');
|
|
575
|
+
return 2;
|
|
576
|
+
}
|
|
577
|
+
if (args.opcoes.baseline === true) {
|
|
578
|
+
const b = (0, verify_1.gravarBaseline)(carregado, id);
|
|
579
|
+
console.log(`Baseline gravada para a thread ${id}.`);
|
|
580
|
+
console.log(` commit ${b.commit}`);
|
|
581
|
+
for (const c of b.comandos) {
|
|
582
|
+
console.log(` ${c.nome.padEnd(10)} ${c.ok ? 'passava' : `ja falhava (codigo ${c.code})`} ${c.comando}`);
|
|
583
|
+
}
|
|
584
|
+
if (b.comandos.length === 0) {
|
|
585
|
+
console.log(' (nenhum comando em verify: no manifesto; sem baseline nao ha como separar regressao)');
|
|
586
|
+
}
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
const r = (0, verify_1.verificar)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
|
|
590
|
+
console.log((0, verify_1.textoDoVerify)(r));
|
|
591
|
+
return r.ok ? 0 : 1;
|
|
592
|
+
}
|
|
593
|
+
function comandoGate(args) {
|
|
594
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
595
|
+
const sub = args.posicionais[1];
|
|
596
|
+
if (sub === 'next') {
|
|
597
|
+
const id = args.posicionais[2];
|
|
598
|
+
if (!id) {
|
|
599
|
+
console.error('uso: ork gate next <thread-id> [--proximo FASE] [--ocupacao 0..1]');
|
|
600
|
+
return 2;
|
|
601
|
+
}
|
|
602
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
603
|
+
const proximoBruto = texto(args.opcoes.proximo) ?? texto(args.opcoes['proxima-fase']);
|
|
604
|
+
const ocupacaoBruta = texto(args.opcoes.ocupacao);
|
|
605
|
+
const janelaBruta = texto(args.opcoes.janela);
|
|
606
|
+
const v = (0, tokens_1.gateDeTokens)(carregado, id, {
|
|
607
|
+
proximo: proximoBruto ? (0, thread_1.exigirFase)(thread, proximoBruto) : undefined,
|
|
608
|
+
ocupacao: ocupacaoBruta !== undefined ? Number(ocupacaoBruta) : undefined,
|
|
609
|
+
fonte: texto(args.opcoes.fonte),
|
|
610
|
+
transcript: texto(args.opcoes.transcript),
|
|
611
|
+
janela: janelaBruta !== undefined ? Number(janelaBruta) : undefined,
|
|
612
|
+
refazer: args.opcoes.refazer === true,
|
|
613
|
+
sessao: texto(args.opcoes.sessao),
|
|
614
|
+
});
|
|
615
|
+
console.log((0, tokens_1.textoDoGateDeTokens)(v));
|
|
616
|
+
return 0;
|
|
617
|
+
}
|
|
618
|
+
if (sub === 'approve') {
|
|
619
|
+
const id = args.posicionais[2];
|
|
620
|
+
const sobre = args.posicionais[3];
|
|
621
|
+
const por = texto(args.opcoes.por) ?? texto(args.opcoes.quem);
|
|
622
|
+
if (!id || !sobre || !por) {
|
|
623
|
+
console.error('uso: ork gate approve <thread-id> <sobre> --por <quem>');
|
|
624
|
+
return 2;
|
|
625
|
+
}
|
|
626
|
+
(0, thread_1.lerThread)(carregado.raiz, id);
|
|
627
|
+
const e = (0, gates_1.aprovarGateHumano)(carregado.raiz, id, sobre, por, texto(args.opcoes.obs));
|
|
628
|
+
console.log(`Autorizacao humana registrada no ledger da thread ${id}.`);
|
|
629
|
+
console.log(` sobre ${sobre}`);
|
|
630
|
+
console.log(` autorizado por ${por}`);
|
|
631
|
+
console.log(` quando ${e.ts}`);
|
|
632
|
+
return 0;
|
|
633
|
+
}
|
|
634
|
+
console.error(`subcomando desconhecido: gate ${sub}`);
|
|
635
|
+
return 2;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* `ork retry`: a politica de retry tipada e a fila duravel de rate limit (bloco B3).
|
|
639
|
+
*
|
|
640
|
+
* O comando existe separado do `ork gate` porque ele nao decide VERDADE: ele decide o
|
|
641
|
+
* que fazer com uma verdade que o gate ja estabeleceu. `plan` calcula sem executar, e
|
|
642
|
+
* por isso nao gasta tentativa nem toca no repositorio.
|
|
643
|
+
*/
|
|
644
|
+
function comandoRetry(args) {
|
|
645
|
+
const sub = args.posicionais[1];
|
|
646
|
+
if (sub === 'policy') {
|
|
647
|
+
const alvo = texto(args.opcoes.motivo);
|
|
648
|
+
if (alvo) {
|
|
649
|
+
const politica = retry_1.POLITICA_DE_RETRY[alvo];
|
|
650
|
+
if (!politica) {
|
|
651
|
+
console.error(`motivo tipado desconhecido: ${alvo}`);
|
|
652
|
+
console.error(` conhecidos: ${Object.keys(retry_1.POLITICA_DE_RETRY).join(', ')}`);
|
|
653
|
+
return 2;
|
|
654
|
+
}
|
|
655
|
+
if (args.opcoes.json === true) {
|
|
656
|
+
console.log(JSON.stringify(politica, null, 2));
|
|
657
|
+
return 0;
|
|
658
|
+
}
|
|
659
|
+
console.log(`motivo tipado: ${politica.motivo}`);
|
|
660
|
+
console.log(` significado ${auditoria_1.DESCRICAO_DO_MOTIVO_DE_AUDITORIA[politica.motivo]}`);
|
|
661
|
+
console.log(` acao ${politica.acao}`);
|
|
662
|
+
console.log(` automatica ${politica.automatica ? 'sim' : 'nao'}`);
|
|
663
|
+
console.log(` por que ${politica.porque}`);
|
|
664
|
+
console.log(` correcao ${politica.correcao}`);
|
|
665
|
+
return 0;
|
|
666
|
+
}
|
|
667
|
+
if (args.opcoes.json === true) {
|
|
668
|
+
console.log(JSON.stringify(Object.values(retry_1.POLITICA_DE_RETRY), null, 2));
|
|
669
|
+
return 0;
|
|
670
|
+
}
|
|
671
|
+
console.log('Politica de retry por motivo tipado de gate (bloco B3)');
|
|
672
|
+
console.log('');
|
|
673
|
+
console.log((0, retry_1.tabelaDaPolitica)());
|
|
674
|
+
console.log('');
|
|
675
|
+
console.log('A politica e a MESMA em todos os modos: o modo afrouxa a pausa, nunca a');
|
|
676
|
+
console.log('verificacao. cost.violation nunca recebe retry automatico, e o limite de');
|
|
677
|
+
console.log('escalacao (retry.max_tentativas) pausa qualquer modo, inclusive #Auto.');
|
|
678
|
+
return 0;
|
|
679
|
+
}
|
|
680
|
+
if (sub === 'parse') {
|
|
681
|
+
const bruto = texto(args.opcoes.stderr) ?? args.posicionais.slice(2).join(' ');
|
|
682
|
+
if (!bruto) {
|
|
683
|
+
console.error('uso: ork retry parse --stderr "<texto do stderr do adapter>"');
|
|
684
|
+
return 2;
|
|
685
|
+
}
|
|
686
|
+
const sinal = (0, ratelimit_1.parseRateLimit)(bruto);
|
|
687
|
+
if (args.opcoes.json === true) {
|
|
688
|
+
console.log(JSON.stringify(sinal, null, 2));
|
|
689
|
+
return sinal ? 0 : 1;
|
|
690
|
+
}
|
|
691
|
+
if (!sinal) {
|
|
692
|
+
console.log('Nenhum sinal de rate limit reconhecido neste texto.');
|
|
693
|
+
return 1;
|
|
694
|
+
}
|
|
695
|
+
console.log('Sinal de rate limit reconhecido no stderr do runtime:');
|
|
696
|
+
console.log(` fonte da hora ${sinal.fonte}`);
|
|
697
|
+
console.log(` reset em ${sinal.resetEm ?? '(o runtime nao disse a hora)'}`);
|
|
698
|
+
console.log(` trecho ${sinal.trecho}`);
|
|
699
|
+
if (sinal.resetEm === null) {
|
|
700
|
+
console.log('');
|
|
701
|
+
console.log(' Sem hora no texto, a fila usa retry.janela_padrao_min do manifesto e marca');
|
|
702
|
+
console.log(' o pedido como janela ESTIMADA. O `ork` nao inventa horario de reset.');
|
|
703
|
+
}
|
|
704
|
+
return 0;
|
|
705
|
+
}
|
|
706
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
707
|
+
if (sub === 'plan' || sub === 'run') {
|
|
708
|
+
const id = args.posicionais[2];
|
|
709
|
+
if (!id) {
|
|
710
|
+
console.error(`uso: ork retry ${sub} <thread-id> [--motivo M] [--fase F]`);
|
|
711
|
+
return 2;
|
|
712
|
+
}
|
|
713
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
714
|
+
const faseBruta = texto(args.opcoes.fase);
|
|
715
|
+
const opcoes = {
|
|
716
|
+
motivo: texto(args.opcoes.motivo),
|
|
717
|
+
fase: faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined,
|
|
718
|
+
autorizadoPor: texto(args.opcoes.por) ?? texto(args.opcoes.quem),
|
|
719
|
+
};
|
|
720
|
+
if (sub === 'plan') {
|
|
721
|
+
const plano = (0, retry_1.planejarRetry)(carregado, id, opcoes);
|
|
722
|
+
if (args.opcoes.json === true) {
|
|
723
|
+
console.log(JSON.stringify(plano, null, 2));
|
|
724
|
+
return 0;
|
|
725
|
+
}
|
|
726
|
+
console.log((0, retry_1.textoDoPlano)(plano));
|
|
727
|
+
return 0;
|
|
728
|
+
}
|
|
729
|
+
const r = (0, retry_1.executarRetry)(carregado, id, {
|
|
730
|
+
...opcoes,
|
|
731
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
732
|
+
reverify: args.opcoes.reverify === true,
|
|
733
|
+
});
|
|
734
|
+
if (args.opcoes.json === true) {
|
|
735
|
+
console.log(JSON.stringify(r, null, 2));
|
|
736
|
+
}
|
|
737
|
+
else {
|
|
738
|
+
console.log((0, retry_1.textoDoRetry)(r));
|
|
739
|
+
}
|
|
740
|
+
// Codigo de saida != 0 quando nada pode ser feito sozinho: e o sinal para o
|
|
741
|
+
// orquestrador parar e chamar o humano, em vez de seguir achando que retomou.
|
|
742
|
+
return r.executada ? 0 : 1;
|
|
743
|
+
}
|
|
744
|
+
if (sub === 'list') {
|
|
745
|
+
if (args.opcoes.json === true) {
|
|
746
|
+
console.log(JSON.stringify((0, ratelimit_1.lerFilaDeRetomada)(carregado.raiz), null, 2));
|
|
747
|
+
return 0;
|
|
748
|
+
}
|
|
749
|
+
console.log((0, ratelimit_1.tabelaDaFila)(carregado.raiz));
|
|
750
|
+
const espera = (0, ratelimit_1.lerFilaDeRetomada)(carregado.raiz).filter((p) => p.estado === 'aguardando');
|
|
751
|
+
if (espera.length > 0) {
|
|
752
|
+
console.log('');
|
|
753
|
+
console.log(`Proxima janela: ${espera[0].liberaEm} (${(0, ratelimit_1.faltaPara)(espera[0])}).`);
|
|
754
|
+
console.log('Retome com: ork retry resume');
|
|
755
|
+
}
|
|
756
|
+
return 0;
|
|
757
|
+
}
|
|
758
|
+
if (sub === 'resume') {
|
|
759
|
+
const ocupacaoBruta = texto(args.opcoes.ocupacao);
|
|
760
|
+
const opcoes = {
|
|
761
|
+
quando: texto(args.opcoes.agora),
|
|
762
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
763
|
+
forcar: args.opcoes.forcar === true,
|
|
764
|
+
ocupacao: ocupacaoBruta !== undefined ? Number(ocupacaoBruta) : undefined,
|
|
765
|
+
fonte: texto(args.opcoes.fonte),
|
|
766
|
+
};
|
|
767
|
+
const idPedido = texto(args.opcoes.id);
|
|
768
|
+
const rs = idPedido
|
|
769
|
+
? [(0, retry_1.retomarPorId)(carregado, idPedido, opcoes)]
|
|
770
|
+
: (0, retry_1.retomarFila)(carregado, opcoes);
|
|
771
|
+
if (args.opcoes.json === true) {
|
|
772
|
+
console.log(JSON.stringify(rs, null, 2));
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
console.log((0, retry_1.textoDaRetomada)(rs));
|
|
776
|
+
}
|
|
777
|
+
// Escalada nao e sucesso: ela e o pedido de socorro que pausa qualquer modo.
|
|
778
|
+
return rs.some((r) => r.playbook === 'escalada') ? 1 : 0;
|
|
779
|
+
}
|
|
780
|
+
if (sub === 'cancel') {
|
|
781
|
+
const idPedido = args.posicionais[2];
|
|
782
|
+
const motivo = texto(args.opcoes.motivo);
|
|
783
|
+
if (!idPedido || !motivo) {
|
|
784
|
+
console.error('uso: ork retry cancel <id> --motivo "<motivo>"');
|
|
785
|
+
return 2;
|
|
786
|
+
}
|
|
787
|
+
const p = (0, retry_1.cancelarPedido)(carregado, idPedido, motivo);
|
|
788
|
+
console.log(`Pedido ${p.id} cancelado na fila de rate limit.`);
|
|
789
|
+
console.log(` thread ${p.thread}`);
|
|
790
|
+
console.log(` fase ${p.fase}`);
|
|
791
|
+
console.log(` motivo ${motivo}`);
|
|
792
|
+
return 0;
|
|
793
|
+
}
|
|
794
|
+
console.error(`subcomando desconhecido: retry ${sub ?? ''}`);
|
|
795
|
+
return 2;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* `ork fix`: o sub-loop GO-FIX / CHECK-REVERIFY (bloco B3).
|
|
799
|
+
*
|
|
800
|
+
* `open` deriva a spec do resultado REAL do `ork verify`; `reverify` da veredito POR
|
|
801
|
+
* correcao. O `--parcial` e recusado quando a rodada tem correcao tipo B, porque
|
|
802
|
+
* parcial depois de tipo B nao e CHECK (DoD 10).
|
|
803
|
+
*/
|
|
804
|
+
function comandoFix(args) {
|
|
805
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
806
|
+
const sub = args.posicionais[1];
|
|
807
|
+
const id = args.posicionais[2];
|
|
808
|
+
if (sub === 'open') {
|
|
809
|
+
if (!id) {
|
|
810
|
+
console.error('uso: ork fix open <thread-id> [--so-claims] [--reverify]');
|
|
811
|
+
return 2;
|
|
812
|
+
}
|
|
813
|
+
const rodada = (0, fix_1.abrirRodada)(carregado, id, { soClaims: args.opcoes['so-claims'] === true });
|
|
814
|
+
const reverify = args.opcoes.reverify === true && rodada.correcoes.length > 0
|
|
815
|
+
? (0, fix_1.reverificar)(carregado, id, { rodada: rodada.rodada })
|
|
816
|
+
: null;
|
|
817
|
+
if (args.opcoes.json === true) {
|
|
818
|
+
console.log(JSON.stringify({ rodada, reverify }, null, 2));
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
console.log((0, fix_1.textoDaRodada)(rodada));
|
|
822
|
+
if (reverify) {
|
|
823
|
+
console.log('');
|
|
824
|
+
console.log((0, fix_1.textoDoReverify)(reverify));
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (rodada.correcoes.length === 0)
|
|
828
|
+
return 0;
|
|
829
|
+
return reverify && reverify.veredito === 'PASSOU' ? 0 : 1;
|
|
830
|
+
}
|
|
831
|
+
if (sub === 'list') {
|
|
832
|
+
if (!id) {
|
|
833
|
+
console.error('uso: ork fix list <thread-id> [--rodada N]');
|
|
834
|
+
return 2;
|
|
835
|
+
}
|
|
836
|
+
(0, thread_1.lerThread)(carregado.raiz, id);
|
|
837
|
+
const rodadaBruta = texto(args.opcoes.rodada);
|
|
838
|
+
const rodada = rodadaBruta ? Number(rodadaBruta) : (0, fix_1.ultimaRodada)(carregado.raiz, id);
|
|
839
|
+
if (rodada === 0) {
|
|
840
|
+
console.log(`A thread ${id} nao tem rodada de GO-FIX. Abra com: ork fix open ${id}`);
|
|
841
|
+
return 0;
|
|
842
|
+
}
|
|
843
|
+
const correcoes = (0, fix_1.correcoesDaRodada)(carregado.raiz, id, rodada);
|
|
844
|
+
if (args.opcoes.json === true) {
|
|
845
|
+
console.log(JSON.stringify(correcoes, null, 2));
|
|
846
|
+
return 0;
|
|
847
|
+
}
|
|
848
|
+
console.log(`Correcoes da rodada ${rodada} da thread ${id}`);
|
|
849
|
+
console.log('');
|
|
850
|
+
console.log((0, util_1.tabela)(['ID', 'TIPO', 'MOTIVO', 'ALVO', 'ESTADO', 'JULGADO POR'], correcoes.map((c) => [
|
|
851
|
+
c.id,
|
|
852
|
+
c.tipo,
|
|
853
|
+
c.origem,
|
|
854
|
+
c.alvo,
|
|
855
|
+
c.estado,
|
|
856
|
+
c.verificar.join(' && ') || '(verify completo)',
|
|
857
|
+
])));
|
|
858
|
+
return 0;
|
|
859
|
+
}
|
|
860
|
+
if (sub === 'reverify') {
|
|
861
|
+
if (!id) {
|
|
862
|
+
console.error('uso: ork fix reverify <thread-id> [--rodada N] [--parcial]');
|
|
863
|
+
return 2;
|
|
864
|
+
}
|
|
865
|
+
const rodadaBruta = texto(args.opcoes.rodada);
|
|
866
|
+
const r = (0, fix_1.reverificar)(carregado, id, {
|
|
867
|
+
rodada: rodadaBruta ? Number(rodadaBruta) : undefined,
|
|
868
|
+
parcial: args.opcoes.parcial === true,
|
|
869
|
+
});
|
|
870
|
+
if (args.opcoes.json === true) {
|
|
871
|
+
console.log(JSON.stringify(r, null, 2));
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
console.log((0, fix_1.textoDoReverify)(r));
|
|
875
|
+
}
|
|
876
|
+
return r.veredito === 'PASSOU' ? 0 : 1;
|
|
877
|
+
}
|
|
878
|
+
console.error(`subcomando desconhecido: fix ${sub ?? ''}`);
|
|
879
|
+
return 2;
|
|
880
|
+
}
|
|
881
|
+
function comandoHandoff(args) {
|
|
882
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
883
|
+
const sub = args.posicionais[1];
|
|
884
|
+
const id = args.posicionais[2];
|
|
885
|
+
if (sub === 'export') {
|
|
886
|
+
if (!id) {
|
|
887
|
+
console.error('uso: ork handoff export <thread-id> [--proxima-fase FASE]');
|
|
888
|
+
return 2;
|
|
889
|
+
}
|
|
890
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
891
|
+
const faseBruta = texto(args.opcoes['proxima-fase']) ?? texto(args.opcoes.fase);
|
|
892
|
+
const r = (0, handoff_1.exportarHandoff)(carregado, id, {
|
|
893
|
+
proximaFase: faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined,
|
|
894
|
+
slugDestino: texto(args.opcoes.slug),
|
|
895
|
+
});
|
|
896
|
+
console.log((0, handoff_1.textoDoHandoff)(r.handoff, r.caminho));
|
|
897
|
+
console.log('');
|
|
898
|
+
console.log(`Historico: ${r.caminhoHistorico}`);
|
|
899
|
+
return 0;
|
|
900
|
+
}
|
|
901
|
+
if (sub === 'recall') {
|
|
902
|
+
const ponteiro = args.posicionais[3];
|
|
903
|
+
if (!id || !ponteiro) {
|
|
904
|
+
console.error('uso: ork handoff recall <thread-id> <path#ancora>');
|
|
905
|
+
return 2;
|
|
906
|
+
}
|
|
907
|
+
const r = (0, handoff_1.recall)(carregado, id, ponteiro);
|
|
908
|
+
console.log(`Ponteiro resolvido: ${r.location}`);
|
|
909
|
+
console.log(` metodo ${r.metodo}`);
|
|
910
|
+
console.log(` sha256 ${r.sha256}`);
|
|
911
|
+
console.log(` linhas ${r.intervalo ? `${r.intervalo.inicio}-${r.intervalo.fim}` : '(nao aplicavel)'}`);
|
|
912
|
+
console.log('');
|
|
913
|
+
console.log(r.conteudo);
|
|
914
|
+
return 0;
|
|
915
|
+
}
|
|
916
|
+
console.error(`subcomando desconhecido: handoff ${sub}`);
|
|
917
|
+
return 2;
|
|
918
|
+
}
|
|
919
|
+
function comandoShip(args) {
|
|
920
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
921
|
+
const id = args.posicionais[1];
|
|
922
|
+
const para = texto(args.opcoes.para) ?? texto(args.opcoes.to);
|
|
923
|
+
if (!id || !para) {
|
|
924
|
+
console.error('uso: ork ship <thread-id> --para <branch> [--de <branch>] [--dry-run]');
|
|
925
|
+
return 2;
|
|
926
|
+
}
|
|
927
|
+
const autorizar = args.opcoes['autorizar-push'];
|
|
928
|
+
const r = (0, ship_1.ship)(carregado, id, {
|
|
929
|
+
para,
|
|
930
|
+
de: texto(args.opcoes.de),
|
|
931
|
+
remoto: texto(args.opcoes.remoto),
|
|
932
|
+
mensagem: texto(args.opcoes.mensagem),
|
|
933
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
934
|
+
autorizarPush: typeof autorizar === 'string' ? autorizar : undefined,
|
|
935
|
+
semPush: args.opcoes['sem-push'] === true,
|
|
936
|
+
});
|
|
937
|
+
console.log((0, ship_1.textoDoShip)(r));
|
|
938
|
+
return r.ok ? 0 : 1;
|
|
939
|
+
}
|
|
940
|
+
function comandoLease(args) {
|
|
941
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
942
|
+
const sub = args.posicionais[1];
|
|
943
|
+
if (sub === undefined || sub === 'list') {
|
|
944
|
+
console.log((0, leases_1.tabelaDeLeases)(carregado.raiz));
|
|
945
|
+
return 0;
|
|
946
|
+
}
|
|
947
|
+
if (sub === 'acquire' || sub === 'take') {
|
|
948
|
+
const nome = args.posicionais[2];
|
|
949
|
+
const thread = texto(args.opcoes.thread);
|
|
950
|
+
const motivo = texto(args.opcoes.motivo) ?? 'sem motivo declarado';
|
|
951
|
+
if (!nome || !thread) {
|
|
952
|
+
console.error('uso: ork lease acquire <nome> --thread <thread-id> [--motivo "<motivo>"]');
|
|
953
|
+
return 2;
|
|
954
|
+
}
|
|
955
|
+
(0, thread_1.lerThread)(carregado.raiz, thread);
|
|
956
|
+
const r = (0, leases_1.adquirirRegiao)(carregado.raiz, nome, { thread, motivo });
|
|
957
|
+
if (r.ok) {
|
|
958
|
+
console.log(`Lease ${r.nome} [${r.tipo}] adquirido pela thread ${thread}.`);
|
|
959
|
+
console.log(` expira em ${r.lease?.expiraEm}`);
|
|
960
|
+
if (r.tomadoDeVencido)
|
|
961
|
+
console.log(' (o lease anterior estava VENCIDO e foi tomado)');
|
|
962
|
+
return 0;
|
|
963
|
+
}
|
|
964
|
+
console.error(`Lease ${r.nome} NAO adquirido.`);
|
|
965
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
966
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
967
|
+
console.error(` posicao na fila: ${r.posicaoNaFila}`);
|
|
968
|
+
console.error(` correcao: ${r.correcao}`);
|
|
969
|
+
return 1;
|
|
970
|
+
}
|
|
971
|
+
if (sub === 'release') {
|
|
972
|
+
const nome = args.posicionais[2];
|
|
973
|
+
if (!nome) {
|
|
974
|
+
console.error('uso: ork lease release <nome> [--thread <thread-id>] [--forcar]');
|
|
975
|
+
return 2;
|
|
976
|
+
}
|
|
977
|
+
const r = (0, leases_1.liberar)(carregado.raiz, nome, texto(args.opcoes.thread) ?? '', args.opcoes.forcar === true);
|
|
978
|
+
console.log(r.detalhe);
|
|
979
|
+
return r.ok ? 0 : 1;
|
|
980
|
+
}
|
|
981
|
+
console.error(`subcomando desconhecido: lease ${sub}`);
|
|
982
|
+
return 2;
|
|
983
|
+
}
|
|
984
|
+
function comandoBoard(args) {
|
|
985
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
986
|
+
const sub = args.posicionais[1];
|
|
987
|
+
if (sub === 'plan' || sub === 'plano') {
|
|
988
|
+
console.log((0, board_1.textoDoPlano)((0, board_1.planejar)(carregado)));
|
|
989
|
+
return 0;
|
|
990
|
+
}
|
|
991
|
+
if (sub !== undefined && sub !== 'list') {
|
|
992
|
+
console.error(`subcomando desconhecido: board ${sub}`);
|
|
993
|
+
return 2;
|
|
994
|
+
}
|
|
995
|
+
console.log((0, board_1.textoDoBoard)(carregado, args.opcoes.all === true || args.opcoes.todos === true));
|
|
996
|
+
return 0;
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* `ork orquestracao status` (alias `ork monitor`): pausas e impedimentos de uma chamada.
|
|
1000
|
+
*
|
|
1001
|
+
* Existe para o orquestrador ser PROATIVO: ele roda isto em laco, ve quem esta parado
|
|
1002
|
+
* esperando veredito humano e avisa o humano com alternativas, em vez de descobrir a
|
|
1003
|
+
* pausa so quando o humano pergunta. O `ork` entrega o estado; quem notifica e a
|
|
1004
|
+
* Camada 1, que consome o `--json`.
|
|
1005
|
+
*/
|
|
1006
|
+
function comandoOrquestracao(args) {
|
|
1007
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1008
|
+
const sub = args.posicionais[1];
|
|
1009
|
+
if (sub !== undefined && sub !== 'status') {
|
|
1010
|
+
console.error(`subcomando desconhecido: orquestracao ${sub}`);
|
|
1011
|
+
console.error('uso: ork orquestracao status [--all] [--json] [--atencao N] [--so-paradas]');
|
|
1012
|
+
return 2;
|
|
1013
|
+
}
|
|
1014
|
+
const bruto = texto(args.opcoes.atencao);
|
|
1015
|
+
const atencaoMin = bruto === undefined ? undefined : Number(bruto);
|
|
1016
|
+
if (atencaoMin !== undefined && (!Number.isFinite(atencaoMin) || atencaoMin < 0)) {
|
|
1017
|
+
console.error(`--atencao espera minutos (inteiro >= 0), recebeu "${bruto}"`);
|
|
1018
|
+
return 2;
|
|
1019
|
+
}
|
|
1020
|
+
const monitor = (0, orquestracao_1.montarMonitor)(carregado, {
|
|
1021
|
+
todos: args.opcoes.all === true || args.opcoes.todos === true,
|
|
1022
|
+
atencaoMin,
|
|
1023
|
+
soParadas: args.opcoes['so-paradas'] === true,
|
|
1024
|
+
semRuntime: args.opcoes['sem-runtime'] === true,
|
|
1025
|
+
});
|
|
1026
|
+
console.log(args.opcoes.json === true ? JSON.stringify(monitor, null, 2) : (0, orquestracao_1.textoDoMonitor)(monitor));
|
|
1027
|
+
// `--exigir-limpo` transforma o monitor em watchdog: sai != 0 enquanto houver thread
|
|
1028
|
+
// parada. E o que deixa o orquestrador (ou um cron) tratar "tem gente esperando" como
|
|
1029
|
+
// falha acionavel, sem precisar interpretar texto.
|
|
1030
|
+
if (args.opcoes['exigir-limpo'] === true) {
|
|
1031
|
+
return monitor.resumo.aguardandoHumano + monitor.resumo.comImpedimento > 0 ? 1 : 0;
|
|
1032
|
+
}
|
|
1033
|
+
return 0;
|
|
1034
|
+
}
|
|
1035
|
+
function comandoWorktree(args) {
|
|
1036
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1037
|
+
const sub = args.posicionais[1];
|
|
1038
|
+
const id = args.posicionais[2];
|
|
1039
|
+
if (!sub || !id) {
|
|
1040
|
+
console.error('uso: ork worktree <ensure|sync|audit|release> <thread-id>');
|
|
1041
|
+
return 2;
|
|
1042
|
+
}
|
|
1043
|
+
if (sub === 'ensure') {
|
|
1044
|
+
const r = (0, worktree_1.garantirWorktree)(carregado, id);
|
|
1045
|
+
if (!r.ok) {
|
|
1046
|
+
console.error(`Worktree da thread ${id} NAO garantida.`);
|
|
1047
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
1048
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
1049
|
+
console.error(` correcao: ${r.correcao}`);
|
|
1050
|
+
return 1;
|
|
1051
|
+
}
|
|
1052
|
+
console.log(r.criada ? `Worktree criada para a thread ${id}.` : `Worktree ja existia para a thread ${id}.`);
|
|
1053
|
+
console.log(` dir ${r.dir}`);
|
|
1054
|
+
console.log(` branch ${r.branch}`);
|
|
1055
|
+
console.log(` base ${r.base} (resolvida pelo ork, nao pelo executor)`);
|
|
1056
|
+
console.log(` ${r.detalhe}`);
|
|
1057
|
+
return 0;
|
|
1058
|
+
}
|
|
1059
|
+
if (sub === 'sync') {
|
|
1060
|
+
const r = (0, worktree_1.sincronizarWorktree)(carregado, id, { dryRun: args.opcoes['dry-run'] === true });
|
|
1061
|
+
if (!r.ok) {
|
|
1062
|
+
console.error(`Sync da worktree da thread ${id} BLOQUEADO.`);
|
|
1063
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
1064
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
1065
|
+
console.error(` correcao: ${r.correcao}`);
|
|
1066
|
+
return 1;
|
|
1067
|
+
}
|
|
1068
|
+
console.log(r.dryRun ? `Sync (--dry-run) da thread ${id}: nada foi executado.` : `Sync da thread ${id}.`);
|
|
1069
|
+
console.log(` base ${r.base} @ ${r.shaBase.slice(0, 8)}`);
|
|
1070
|
+
console.log(` branch ${r.branch} @ ${r.shaAntes.slice(0, 8)} -> ${r.shaDepois.slice(0, 8)}`);
|
|
1071
|
+
console.log(` rebase ${r.rebaseFeito ? 'feito' : r.jaAtualizada ? 'desnecessario' : 'seria feito'}`);
|
|
1072
|
+
console.log(` ${r.detalhe}`);
|
|
1073
|
+
if (r.passos.length > 0) {
|
|
1074
|
+
console.log('');
|
|
1075
|
+
console.log(' Comandos reais, na ordem:');
|
|
1076
|
+
for (const passo of r.passos)
|
|
1077
|
+
console.log(` ${passo}`);
|
|
1078
|
+
}
|
|
1079
|
+
return 0;
|
|
1080
|
+
}
|
|
1081
|
+
if (sub === 'audit') {
|
|
1082
|
+
const r = (0, worktree_1.auditarWorktree)(carregado, id);
|
|
1083
|
+
console.log((0, worktree_1.textoDoAudit)(id, r));
|
|
1084
|
+
return r.ok ? 0 : 1;
|
|
1085
|
+
}
|
|
1086
|
+
if (sub === 'release') {
|
|
1087
|
+
const r = (0, worktree_1.liberarWorktree)(carregado, id, { forcar: args.opcoes.forcar === true });
|
|
1088
|
+
if (!r.ok) {
|
|
1089
|
+
console.error(`Release da worktree da thread ${id} BLOQUEADO.`);
|
|
1090
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
1091
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
1092
|
+
console.error(` correcao: ${r.correcao}`);
|
|
1093
|
+
return 1;
|
|
1094
|
+
}
|
|
1095
|
+
console.log(`Worktree da thread ${id} liberada.`);
|
|
1096
|
+
console.log(` dir ${r.dir}`);
|
|
1097
|
+
console.log(` removida ${r.removida ? 'sim' : 'nao (o diretorio ja nao existia)'}`);
|
|
1098
|
+
console.log(` leases ${r.leasesLiberados.join(', ') || '(nenhum lease de escrita para soltar)'}`);
|
|
1099
|
+
console.log(` ${r.detalhe}`);
|
|
1100
|
+
return 0;
|
|
1101
|
+
}
|
|
1102
|
+
console.error(`subcomando desconhecido: worktree ${sub}`);
|
|
1103
|
+
return 2;
|
|
1104
|
+
}
|
|
1105
|
+
function comandoMaster(args) {
|
|
1106
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1107
|
+
const primeiro = args.posicionais[1];
|
|
1108
|
+
if (primeiro === 'classes') {
|
|
1109
|
+
console.log((0, master_1.tabelaDeClasses)());
|
|
1110
|
+
return 0;
|
|
1111
|
+
}
|
|
1112
|
+
if (args.opcoes.batch === true || primeiro === 'batch' || primeiro === undefined) {
|
|
1113
|
+
console.log((0, master_1.tabelaDeBatch)(carregado.raiz, args.opcoes.todas === true));
|
|
1114
|
+
return 0;
|
|
1115
|
+
}
|
|
1116
|
+
const id = primeiro;
|
|
1117
|
+
const brutoScore = texto(args.opcoes.score);
|
|
1118
|
+
const justificativa = texto(args.opcoes.justificativa) ?? texto(args.opcoes.porque);
|
|
1119
|
+
if (brutoScore === undefined) {
|
|
1120
|
+
console.error('uso: ork master <thread-id> --score 0-5 --justificativa "<texto>"');
|
|
1121
|
+
console.error(' o score do MASTER e humano, de 0 a 5, e a justificativa e obrigatoria.');
|
|
1122
|
+
return 2;
|
|
1123
|
+
}
|
|
1124
|
+
if (!justificativa) {
|
|
1125
|
+
console.error(`Score RECUSADO para a thread ${id}: falta --justificativa "<texto>".`);
|
|
1126
|
+
console.error(' Score sem justificativa nao vira aprendizado; o `ork` nao o registra.');
|
|
1127
|
+
console.error(` ork master ${id} --score ${brutoScore} --justificativa "<por que este score>"`);
|
|
1128
|
+
return 2;
|
|
1129
|
+
}
|
|
1130
|
+
const brutasClasses = texto(args.opcoes.classe) ?? texto(args.opcoes.classes);
|
|
1131
|
+
const classes = [];
|
|
1132
|
+
for (const bruta of (brutasClasses ?? '').split(',').map((c) => c.trim()).filter(Boolean)) {
|
|
1133
|
+
const classe = (0, master_1.parseClasse)(bruta);
|
|
1134
|
+
if (!classe) {
|
|
1135
|
+
console.error(`classe de falha invalida: "${bruta}".`);
|
|
1136
|
+
console.error(` classes fixas: ${master_1.ORDEM_DAS_CLASSES.join(', ')}`);
|
|
1137
|
+
return 2;
|
|
1138
|
+
}
|
|
1139
|
+
classes.push(classe);
|
|
1140
|
+
}
|
|
1141
|
+
const r = (0, master_1.registrarMaster)(carregado.raiz, id, {
|
|
1142
|
+
score: Number(brutoScore),
|
|
1143
|
+
justificativa,
|
|
1144
|
+
classes,
|
|
1145
|
+
resumo: texto(args.opcoes.resumo),
|
|
1146
|
+
por: texto(args.opcoes.por) ?? texto(args.opcoes.quem),
|
|
1147
|
+
refazer: args.opcoes.refazer === true,
|
|
1148
|
+
});
|
|
1149
|
+
console.log((0, master_1.textoDoMaster)(r));
|
|
1150
|
+
// Bloco B6: fechada a thread, a licao (POSTMORTEM + score) vai para a colecao
|
|
1151
|
+
// `learning`, e e o que uma thread NOVA do mesmo produto recebe no GOAL.
|
|
1152
|
+
relatarPublicacao((0, memoria_1.publicar)(carregado, id));
|
|
1153
|
+
console.log('');
|
|
1154
|
+
console.log(`Proximo passo: ork board --all | fila de score: ork master --batch`);
|
|
1155
|
+
return 0;
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* `ork prompt list|lint|render`: os prompts do `ork` como templates versionados (bloco B4).
|
|
1159
|
+
*
|
|
1160
|
+
* O `lint` reprova template quebrado ANTES de ele virar despacho; o `render` mostra o prompt
|
|
1161
|
+
* exato com o mesmo sha256 que iria para o ledger, para o builder revisar texto sem gastar
|
|
1162
|
+
* uma sessao do runtime para descobrir o que foi pedido.
|
|
1163
|
+
*/
|
|
1164
|
+
function comandoPrompt(args) {
|
|
1165
|
+
const sub = args.posicionais[1] ?? 'list';
|
|
1166
|
+
const carregado = (0, manifest_1.carregarManifesto)();
|
|
1167
|
+
const raiz = carregado?.raiz;
|
|
1168
|
+
if (sub === 'list') {
|
|
1169
|
+
console.log((0, prompts_1.tabelaDeTemplates)((0, prompts_1.carregarTemplates)(raiz)));
|
|
1170
|
+
return 0;
|
|
1171
|
+
}
|
|
1172
|
+
if (sub === 'lint') {
|
|
1173
|
+
const id = texto(args.opcoes.template);
|
|
1174
|
+
const templates = id ? [(0, prompts_1.exigirTemplate)(id, raiz)] : (0, prompts_1.carregarTemplates)(raiz);
|
|
1175
|
+
const problemas = templates.flatMap((t) => (0, prompts_1.lintTemplate)(t));
|
|
1176
|
+
console.log(`Lint dos templates de prompt${raiz ? ` (projeto ${raiz})` : ' (somente embutidos)'}`);
|
|
1177
|
+
console.log('');
|
|
1178
|
+
console.log((0, prompts_1.textoDoLint)(problemas, templates.length));
|
|
1179
|
+
return problemas.some((p) => p.gravidade === 'erro') ? 2 : 0;
|
|
1180
|
+
}
|
|
1181
|
+
if (sub === 'render') {
|
|
1182
|
+
const fase = exigirFaseCanonica(texto(args.opcoes.fase) ?? args.posicionais[3]);
|
|
1183
|
+
const pedido = texto(args.opcoes.pedido) ?? '<pedido do builder>';
|
|
1184
|
+
const idTemplate = texto(args.opcoes.template);
|
|
1185
|
+
// Modo exemplo: renderiza sem thread nenhuma, para revisar o texto de um modo antes de
|
|
1186
|
+
// abrir trabalho. Nada e gravado, e o `ork` diz em voz alta que a thread e ficticia.
|
|
1187
|
+
if (args.opcoes.exemplo === true || args.opcoes.modo !== undefined || args.opcoes.mode !== undefined) {
|
|
1188
|
+
const bruto = texto(args.opcoes.modo) ?? texto(args.opcoes.mode) ?? 'classic';
|
|
1189
|
+
const modo = (0, modos_1.parseModo)(bruto);
|
|
1190
|
+
if (!modo) {
|
|
1191
|
+
console.error(`modo invalido: "${bruto}". Use um de: ${Object.values(modos_1.MODOS).map((m) => m.tag).join(', ')}`);
|
|
1192
|
+
return 2;
|
|
1193
|
+
}
|
|
1194
|
+
const exemplo = (0, prompts_1.threadDeExemplo)(modo, fase, carregado?.manifesto.project);
|
|
1195
|
+
const template = idTemplate ? (0, prompts_1.exigirTemplate)(idTemplate, raiz) : (0, prompts_1.templateDaFase)(fase, raiz);
|
|
1196
|
+
const prompt = (0, prompts_1.renderizar)(template, (0, phase_1.valoresDoPrompt)(exemplo, fase, pedido));
|
|
1197
|
+
console.log(`# template ${template.id} v${template.versao} (origem: ${template.origem})`);
|
|
1198
|
+
console.log(`# thread de EXEMPLO (nada foi gravado), modo ${modos_1.MODOS[modo].tag}, sha256 ${(0, phase_1.hashDoPrompt)(prompt)}`);
|
|
1199
|
+
console.log('');
|
|
1200
|
+
console.log(prompt);
|
|
1201
|
+
return 0;
|
|
1202
|
+
}
|
|
1203
|
+
const obrigatorio = (0, manifest_1.exigirManifesto)();
|
|
1204
|
+
const threadId = args.posicionais[2];
|
|
1205
|
+
if (!threadId) {
|
|
1206
|
+
console.error('uso: ork prompt render <thread-id> <FASE> --pedido "<texto>"');
|
|
1207
|
+
console.error(' ork prompt render --exemplo --fase GOAL --modo auto --pedido "<texto>"');
|
|
1208
|
+
return 2;
|
|
1209
|
+
}
|
|
1210
|
+
const thread = (0, thread_1.lerThread)(obrigatorio.raiz, threadId);
|
|
1211
|
+
const template = idTemplate ? (0, prompts_1.exigirTemplate)(idTemplate, obrigatorio.raiz) : (0, prompts_1.templateDaFase)(fase, obrigatorio.raiz);
|
|
1212
|
+
const prompt = idTemplate
|
|
1213
|
+
? (0, prompts_1.renderizar)(template, (0, phase_1.valoresDoPrompt)(thread, fase, pedido))
|
|
1214
|
+
: (0, phase_1.montarPrompt)(thread, fase, pedido, obrigatorio.raiz);
|
|
1215
|
+
console.log(`# template ${template.id} v${template.versao} (origem: ${template.origem})`);
|
|
1216
|
+
console.log(`# thread ${thread.id}, fase ${fase}, sha256 ${(0, phase_1.hashDoPrompt)(prompt)}`);
|
|
1217
|
+
console.log('');
|
|
1218
|
+
console.log(prompt);
|
|
1219
|
+
return 0;
|
|
1220
|
+
}
|
|
1221
|
+
console.error(`subcomando desconhecido: prompt ${sub}`);
|
|
1222
|
+
return 2;
|
|
1223
|
+
}
|
|
1224
|
+
/** Fase canonica a partir do texto do usuario, com erro tipado quando nao existe. */
|
|
1225
|
+
function exigirFaseCanonica(bruto) {
|
|
1226
|
+
const alvo = (bruto ?? '').toUpperCase();
|
|
1227
|
+
if (!types_1.FASES.includes(alvo)) {
|
|
1228
|
+
throw new Error(`fase "${bruto ?? ''}" fora do ciclo canonico (${types_1.FASES.join(' ')})`);
|
|
1229
|
+
}
|
|
1230
|
+
return alvo;
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* `ork adapter list|show|install <host>`: instalacao dos adaptadores de Camada 1 (bloco B4).
|
|
1234
|
+
*/
|
|
1235
|
+
function comandoAdapter(args) {
|
|
1236
|
+
const sub = args.posicionais[1] ?? 'list';
|
|
1237
|
+
if (sub === 'list') {
|
|
1238
|
+
console.log((0, hosts_1.tabelaDeHosts)());
|
|
1239
|
+
return 0;
|
|
1240
|
+
}
|
|
1241
|
+
if (sub === 'show') {
|
|
1242
|
+
const host = (0, hosts_1.parseHost)(args.posicionais[2]);
|
|
1243
|
+
if (!host) {
|
|
1244
|
+
console.error(`host desconhecido: "${args.posicionais[2] ?? ''}". Use: ${hosts_1.ORDEM_DOS_HOSTS.join(' | ')}`);
|
|
1245
|
+
return 2;
|
|
1246
|
+
}
|
|
1247
|
+
const def = hosts_1.HOSTS[host];
|
|
1248
|
+
console.log(`Adaptador ${host}`);
|
|
1249
|
+
console.log(` ${def.descricao}`);
|
|
1250
|
+
console.log(` destino padrao: <projeto>/${def.destinoPadrao}${def.subdir ? '/' + def.subdir : ''}`);
|
|
1251
|
+
console.log('');
|
|
1252
|
+
console.log((0, hosts_1.textoDosPitfalls)(host));
|
|
1253
|
+
return 0;
|
|
1254
|
+
}
|
|
1255
|
+
if (sub === 'install') {
|
|
1256
|
+
const host = (0, hosts_1.parseHost)(args.posicionais[2]);
|
|
1257
|
+
if (!host) {
|
|
1258
|
+
console.error(`host desconhecido: "${args.posicionais[2] ?? ''}". Use: ${hosts_1.ORDEM_DOS_HOSTS.join(' | ')}`);
|
|
1259
|
+
return 2;
|
|
1260
|
+
}
|
|
1261
|
+
const carregado = (0, manifest_1.carregarManifesto)();
|
|
1262
|
+
const r = (0, hosts_1.instalarAdaptador)(host, {
|
|
1263
|
+
projeto: carregado?.raiz ?? process.cwd(),
|
|
1264
|
+
dir: texto(args.opcoes.dir),
|
|
1265
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
1266
|
+
force: args.opcoes.force === true || args.opcoes.forcar === true,
|
|
1267
|
+
orkBin: texto(args.opcoes.ork),
|
|
1268
|
+
versao: VERSAO,
|
|
1269
|
+
});
|
|
1270
|
+
console.log((0, hosts_1.textoDaInstalacao)(r));
|
|
1271
|
+
return r.ok ? 0 : 2;
|
|
1272
|
+
}
|
|
1273
|
+
console.error(`subcomando desconhecido: adapter ${sub}`);
|
|
1274
|
+
return 2;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* `ork eval`: canarios de comportamento e o corpus das skills finas (bloco B4).
|
|
1278
|
+
*
|
|
1279
|
+
* Skill sem eval nao entra, e comportamento sem canario tambem nao. O comando sai diferente
|
|
1280
|
+
* de zero em qualquer falha, para o CI do kit poder barrar merge sem eval.
|
|
1281
|
+
*/
|
|
1282
|
+
function comandoEval(args) {
|
|
1283
|
+
const catalogo = (0, catalogo_1.exigirCatalogo)((0, manifest_1.carregarManifesto)()?.raiz ?? process.cwd());
|
|
1284
|
+
const lista = (v) => {
|
|
1285
|
+
const t = texto(v);
|
|
1286
|
+
return t ? t.split(',').map((x) => x.trim()).filter(Boolean) : undefined;
|
|
1287
|
+
};
|
|
1288
|
+
const r = (0, evalrunner_1.rodarEval)({
|
|
1289
|
+
catalogo,
|
|
1290
|
+
skills: lista(args.opcoes.skill),
|
|
1291
|
+
canarios: lista(args.opcoes.canario) ?? lista(args.opcoes.fixture),
|
|
1292
|
+
soCanarios: args.opcoes['so-canarios'] === true,
|
|
1293
|
+
soSkills: args.opcoes['so-skills'] === true,
|
|
1294
|
+
});
|
|
1295
|
+
if (args.opcoes.json === true) {
|
|
1296
|
+
console.log(JSON.stringify(r, null, 2));
|
|
1297
|
+
}
|
|
1298
|
+
else {
|
|
1299
|
+
console.log((0, evalrunner_1.textoDoEval)(r));
|
|
1300
|
+
}
|
|
1301
|
+
return r.ok ? 0 : 1;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* `ork audit ...`: os auditores periodicos (bloco B5).
|
|
1305
|
+
*
|
|
1306
|
+
* O comando existe para ser chamado por CRON e por orquestrador sem sessao interativa:
|
|
1307
|
+
* e por isso que ele mora no CLI deterministico e nao numa skill. Todo subcomando sai
|
|
1308
|
+
* diferente de zero quando reprova, para o agendador do host perceber sem ler texto.
|
|
1309
|
+
*/
|
|
1310
|
+
function comandoAudit(args) {
|
|
1311
|
+
const sub = args.posicionais[1] ?? 'packs';
|
|
1312
|
+
// `audit packs` e `audit lint` funcionam sem manifesto: sao catalogo, nao estado.
|
|
1313
|
+
if (sub === 'packs' || sub === 'pack') {
|
|
1314
|
+
const carregado = (0, manifest_1.carregarManifesto)();
|
|
1315
|
+
const bruto = texto(args.opcoes.estagio) ?? texto(args.opcoes.stage);
|
|
1316
|
+
const estagio = bruto ? (0, auditoria_1.parseEstagio)(bruto) : carregado?.manifesto.project.stage;
|
|
1317
|
+
if (bruto && !estagio) {
|
|
1318
|
+
console.error(`estagio invalido: "${bruto}". Use: nascente | crescendo | maduro`);
|
|
1319
|
+
return 2;
|
|
1320
|
+
}
|
|
1321
|
+
const pack = texto(args.opcoes.pack) ?? args.posicionais[2];
|
|
1322
|
+
if (pack) {
|
|
1323
|
+
const alvo = (0, auditoria_1.parsePack)(pack);
|
|
1324
|
+
if (!alvo) {
|
|
1325
|
+
console.error(`pack desconhecido: "${pack}". Use um de: ${auditoria_1.ORDEM_DOS_PACKS.join(', ')}`);
|
|
1326
|
+
return 2;
|
|
1327
|
+
}
|
|
1328
|
+
console.log((0, auditoria_1.textoDoPack)(alvo, estagio ?? undefined));
|
|
1329
|
+
return 0;
|
|
1330
|
+
}
|
|
1331
|
+
console.log(`Packs de auditoria periodica${estagio ? ` (estagio declarado do projeto: ${estagio})` : ''}`);
|
|
1332
|
+
console.log('');
|
|
1333
|
+
console.log((0, auditoria_1.tabelaDePacks)(estagio ?? undefined));
|
|
1334
|
+
if (estagio) {
|
|
1335
|
+
console.log('');
|
|
1336
|
+
console.log(`Ativos aqui e agora: ${(0, auditoria_1.packsAtivos)(estagio).join(', ')}`);
|
|
1337
|
+
console.log(`Postura: ${(0, auditoria_1.posturaDoPack)(estagio)}`);
|
|
1338
|
+
}
|
|
1339
|
+
return 0;
|
|
1340
|
+
}
|
|
1341
|
+
if (sub === 'lint') {
|
|
1342
|
+
const raiz = (0, manifest_1.carregarManifesto)()?.raiz;
|
|
1343
|
+
const templates = (0, auditoria_1.carregarTemplatesDeAuditoria)(raiz);
|
|
1344
|
+
const problemas = templates.flatMap((t) => (0, auditoria_1.lintTemplateDeAuditoria)(t));
|
|
1345
|
+
console.log(`Lint dos templates de auditoria${raiz ? ` (projeto ${raiz})` : ' (somente embutidos)'}`);
|
|
1346
|
+
console.log('');
|
|
1347
|
+
for (const p of problemas) {
|
|
1348
|
+
console.log(` [${p.gravidade}] ${p.template} :: ${p.regra}`);
|
|
1349
|
+
console.log(` ${p.detalhe}`);
|
|
1350
|
+
}
|
|
1351
|
+
if (problemas.length === 0)
|
|
1352
|
+
console.log(` nenhum problema em ${templates.length} template(s)`);
|
|
1353
|
+
console.log('');
|
|
1354
|
+
console.log(`templates: ${templates.length} | erros: ${problemas.filter((p) => p.gravidade === 'erro').length} | ` +
|
|
1355
|
+
`avisos: ${problemas.filter((p) => p.gravidade === 'aviso').length}`);
|
|
1356
|
+
return problemas.some((p) => p.gravidade === 'erro') ? 2 : 0;
|
|
1357
|
+
}
|
|
1358
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1359
|
+
if (sub === 'run') {
|
|
1360
|
+
const pack = (0, auditoria_1.parsePack)(args.posicionais[2]);
|
|
1361
|
+
if (!pack) {
|
|
1362
|
+
console.error('uso: ork audit run <pack> [--profile P] [--since Nd]');
|
|
1363
|
+
console.error(` packs: ${auditoria_1.ORDEM_DOS_PACKS.join(', ')}`);
|
|
1364
|
+
return 2;
|
|
1365
|
+
}
|
|
1366
|
+
const autorizar = args.opcoes.agora;
|
|
1367
|
+
const r = (0, auditrun_1.rodarAuditoria)(carregado, pack, {
|
|
1368
|
+
perfil: texto(args.opcoes.profile) ?? texto(args.opcoes.perfil),
|
|
1369
|
+
since: texto(args.opcoes.since),
|
|
1370
|
+
tudo: args.opcoes.tudo === true,
|
|
1371
|
+
effort: texto(args.opcoes.effort),
|
|
1372
|
+
model: texto(args.opcoes.model),
|
|
1373
|
+
dryRun: args.opcoes['dry-run'] === true,
|
|
1374
|
+
agora: typeof autorizar === 'string' ? autorizar : undefined,
|
|
1375
|
+
forcar: args.opcoes.forcar === true || args.opcoes.force === true,
|
|
1376
|
+
});
|
|
1377
|
+
if (r.status === 'bloqueada') {
|
|
1378
|
+
console.error(`Rodada de auditoria ${r.id} BLOQUEADA.`);
|
|
1379
|
+
console.error(` ${auditoria_1.DESCRICAO_DO_MOTIVO_DE_AUDITORIA[r.motivo ?? 'runtime.unavailable']}`);
|
|
1380
|
+
console.error(` motivo tipado: ${r.motivo}`);
|
|
1381
|
+
console.error(` detalhe: ${r.detalhe}`);
|
|
1382
|
+
console.error(` estado da rodada: .orkastery/audits/${r.id}/run.json`);
|
|
1383
|
+
return 1;
|
|
1384
|
+
}
|
|
1385
|
+
if (r.status === 'ensaio') {
|
|
1386
|
+
console.log(`Simulacao (--dry-run) da rodada ${r.id}: nada foi despachado.`);
|
|
1387
|
+
console.log(` pack ${r.pack} (postura ${r.postura} no estagio ${r.estagio})`);
|
|
1388
|
+
console.log(` escopo ${r.escopo.detalhe}`);
|
|
1389
|
+
console.log(` graphify ${r.escopo.graphify}`);
|
|
1390
|
+
console.log(` custo effort ${r.custo.effort}, ${r.custo.janela.detalhe}`);
|
|
1391
|
+
console.log(` prompt ${r.promptPath} (sha256 ${r.promptSha256})`);
|
|
1392
|
+
console.log(` comando claude --bg "<prompt>" --name ${r.slug} --model ${r.custo.model} --effort ${r.custo.effort}`);
|
|
1393
|
+
if (r.superficie) {
|
|
1394
|
+
console.log(` superficie ${r.superficie.detalhe}`);
|
|
1395
|
+
console.log(` nada registrado no board (--dry-run). Para gravar: ork audit surface --registrar ${r.id}`);
|
|
1396
|
+
}
|
|
1397
|
+
return 0;
|
|
1398
|
+
}
|
|
1399
|
+
console.log(`Rodada de auditoria ${r.id} despachada pelo runtime adapter ${r.runtime}.`);
|
|
1400
|
+
console.log(` pack ${r.pack} (${auditoria_1.PACKS[r.pack].titulo})`);
|
|
1401
|
+
console.log(` produto ${r.produto} (perfil ${r.perfil}), estagio ${r.estagio}, postura ${r.postura}`);
|
|
1402
|
+
console.log(` escopo ${r.escopo.detalhe}`);
|
|
1403
|
+
console.log(` graphify ${r.escopo.graphify}`);
|
|
1404
|
+
console.log(` custo effort ${r.custo.effort}, model ${r.custo.model}`);
|
|
1405
|
+
console.log(` janela ${r.custo.janela.detalhe}`);
|
|
1406
|
+
console.log(` sessionId ${r.sessionId}`);
|
|
1407
|
+
console.log(` prompt ${r.promptPath} (sha256 ${r.promptSha256})`);
|
|
1408
|
+
console.log(` verificada no runtime: ${r.verificada ? 'sim' : 'NAO (confira `ork sessions`)'}`);
|
|
1409
|
+
if (r.superficie) {
|
|
1410
|
+
console.log(` superficie ${r.superficie.detalhe}`);
|
|
1411
|
+
console.log(` ${r.superficie.registrados} achado(s) de superficie ja no board de divida` +
|
|
1412
|
+
(r.superficie.aConfirmar > 0
|
|
1413
|
+
? `, ${r.superficie.aConfirmar} com confianca baixa (pedem confirmacao humana)`
|
|
1414
|
+
: ''));
|
|
1415
|
+
}
|
|
1416
|
+
console.log('');
|
|
1417
|
+
console.log('A rodada termina em PROPOSTA para o roadmap, nunca em correcao aplicada.');
|
|
1418
|
+
console.log(`Depois dos achados: ork audit verify ${r.id} && ork audit report ${r.id}`);
|
|
1419
|
+
return r.verificada ? 0 : 1;
|
|
1420
|
+
}
|
|
1421
|
+
if (sub === 'list') {
|
|
1422
|
+
console.log((0, auditrun_1.tabelaDeRodadas)(carregado.raiz));
|
|
1423
|
+
console.log('');
|
|
1424
|
+
console.log(`Board de divida: ${(0, auditrun_1.resumoDoBoard)(carregado.raiz)}`);
|
|
1425
|
+
return 0;
|
|
1426
|
+
}
|
|
1427
|
+
if (sub === 'show') {
|
|
1428
|
+
const id = args.posicionais[2];
|
|
1429
|
+
if (!id) {
|
|
1430
|
+
console.error('uso: ork audit show <rodada> [--ledger]');
|
|
1431
|
+
return 2;
|
|
1432
|
+
}
|
|
1433
|
+
if (args.opcoes.ledger === true) {
|
|
1434
|
+
console.log((0, auditrun_1.tabelaDoLedgerDaRodada)(carregado.raiz, id));
|
|
1435
|
+
return 0;
|
|
1436
|
+
}
|
|
1437
|
+
console.log((0, auditrun_1.textoDaRodada)(carregado.raiz, id));
|
|
1438
|
+
return 0;
|
|
1439
|
+
}
|
|
1440
|
+
if (sub === 'prompt') {
|
|
1441
|
+
const pack = (0, auditoria_1.parsePack)(args.posicionais[2]);
|
|
1442
|
+
if (!pack) {
|
|
1443
|
+
console.error('uso: ork audit prompt <pack> [--since Nd]');
|
|
1444
|
+
console.error(` packs: ${auditoria_1.ORDEM_DOS_PACKS.join(', ')}`);
|
|
1445
|
+
return 2;
|
|
1446
|
+
}
|
|
1447
|
+
const { raiz, manifesto } = carregado;
|
|
1448
|
+
const estagio = manifesto.project.stage;
|
|
1449
|
+
const escopo = (0, auditoria_1.escopoDaRodada)(raiz, manifesto, {
|
|
1450
|
+
since: texto(args.opcoes.since),
|
|
1451
|
+
tudo: args.opcoes.tudo === true,
|
|
1452
|
+
pack,
|
|
1453
|
+
});
|
|
1454
|
+
const template = (0, auditoria_1.templateDoPack)(pack, raiz);
|
|
1455
|
+
const prompt = (0, auditoria_1.montarPromptDeAuditoria)({
|
|
1456
|
+
pack,
|
|
1457
|
+
produto: manifesto.project.name,
|
|
1458
|
+
perfil: texto(args.opcoes.profile) ?? manifesto.board.default,
|
|
1459
|
+
estagio,
|
|
1460
|
+
postura: (0, auditoria_1.posturaDoPack)(estagio),
|
|
1461
|
+
rodada: '<rodada ainda nao criada>',
|
|
1462
|
+
dirDaRodada: '.orkastery/audits/<rodada>',
|
|
1463
|
+
escopo,
|
|
1464
|
+
janela: (0, auditoria_1.janelaDeCusto)(manifesto),
|
|
1465
|
+
effort: texto(args.opcoes.effort) ?? manifesto.audit.effort,
|
|
1466
|
+
}, raiz);
|
|
1467
|
+
console.log(`# template ${template.id} v${template.versao} (origem: ${template.origem})`);
|
|
1468
|
+
console.log(`# pack ${pack}, estagio ${estagio}, sha256 ${(0, phase_1.hashDoPrompt)(prompt)}`);
|
|
1469
|
+
console.log('');
|
|
1470
|
+
console.log(prompt);
|
|
1471
|
+
return 0;
|
|
1472
|
+
}
|
|
1473
|
+
if (sub === 'ingest') {
|
|
1474
|
+
const id = args.posicionais[2];
|
|
1475
|
+
const arquivo = texto(args.opcoes.arquivo) ?? texto(args.opcoes.file);
|
|
1476
|
+
if (!id || !arquivo) {
|
|
1477
|
+
console.error('uso: ork audit ingest <rodada> --arquivo <achados.json>');
|
|
1478
|
+
return 2;
|
|
1479
|
+
}
|
|
1480
|
+
const r = (0, auditrun_1.ingerirAchados)(carregado, id, arquivo);
|
|
1481
|
+
console.log(`Ingestao da rodada ${r.rodada}: ${r.registrados.length} achado(s) no board de divida.`);
|
|
1482
|
+
// Bloco B6: cada proposta enderecada ao roadmap tambem vai para a colecao `roadmap`.
|
|
1483
|
+
if (r.registrados.length > 0) {
|
|
1484
|
+
const naMemoria = (0, memoria_1.publicarPropostas)(carregado, r.registrados);
|
|
1485
|
+
if (naMemoria.regime === 'orkmind') {
|
|
1486
|
+
console.log(`Memoria (orkmind): propostas na colecao roadmap, ${naMemoria.detalhe}.`);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
for (const a of r.registrados) {
|
|
1490
|
+
console.log((0, divida_1.textoDoAchado)(a));
|
|
1491
|
+
}
|
|
1492
|
+
if (r.duplicados.length > 0) {
|
|
1493
|
+
console.log('');
|
|
1494
|
+
console.log('Ja registrados nesta rodada, ignorados (a ingestao e idempotente): ' +
|
|
1495
|
+
r.duplicados.map((a) => a.id).join(', '));
|
|
1496
|
+
}
|
|
1497
|
+
if (r.recusados.length > 0) {
|
|
1498
|
+
console.log('');
|
|
1499
|
+
console.error(`RECUSADOS (${r.recusados.length}):`);
|
|
1500
|
+
for (const rec of r.recusados) {
|
|
1501
|
+
console.error(` achado #${rec.indice + 1}: ${rec.erro}`);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
console.log('');
|
|
1505
|
+
console.log(`Prove os achados antes de qualquer thread: ork audit verify ${r.rodada}`);
|
|
1506
|
+
return r.recusados.length > 0 ? 1 : 0;
|
|
1507
|
+
}
|
|
1508
|
+
if (sub === 'finding' || sub === 'achado') {
|
|
1509
|
+
const acao = args.posicionais[2];
|
|
1510
|
+
if (acao === 'add') {
|
|
1511
|
+
const id = args.posicionais[3];
|
|
1512
|
+
if (!id) {
|
|
1513
|
+
console.error('uso: ork audit finding add <rodada> --regra R --titulo T --arquivo caminho:linha --impacto I --fix F --estimativa E');
|
|
1514
|
+
return 2;
|
|
1515
|
+
}
|
|
1516
|
+
const verificar = texto(args.opcoes.verificar) ?? texto(args.opcoes.verify);
|
|
1517
|
+
const achado = (0, auditrun_1.registrarAchadoDaRodada)(carregado, id, {
|
|
1518
|
+
regra: texto(args.opcoes.regra),
|
|
1519
|
+
severidade: texto(args.opcoes.severidade) ?? texto(args.opcoes.severity),
|
|
1520
|
+
titulo: texto(args.opcoes.titulo),
|
|
1521
|
+
arquivo: texto(args.opcoes.arquivo),
|
|
1522
|
+
descricao: texto(args.opcoes.descricao),
|
|
1523
|
+
alegacao: texto(args.opcoes.alegacao) ?? texto(args.opcoes.claim),
|
|
1524
|
+
verificar: verificar ? [verificar] : [],
|
|
1525
|
+
impacto: texto(args.opcoes.impacto),
|
|
1526
|
+
fix: texto(args.opcoes.fix),
|
|
1527
|
+
irreversivel: texto(args.opcoes.irreversivel) ?? 'nenhum',
|
|
1528
|
+
estimativa: texto(args.opcoes.estimativa),
|
|
1529
|
+
});
|
|
1530
|
+
console.log(`Achado ${achado.id} registrado no board de divida da rodada ${id}.`);
|
|
1531
|
+
console.log((0, divida_1.textoDoAchado)(achado));
|
|
1532
|
+
const naMemoria = (0, memoria_1.publicarPropostas)(carregado, [achado]);
|
|
1533
|
+
if (naMemoria.regime === 'orkmind') {
|
|
1534
|
+
console.log(`Memoria (orkmind): proposta na colecao roadmap, ${naMemoria.detalhe}.`);
|
|
1535
|
+
}
|
|
1536
|
+
return 0;
|
|
1537
|
+
}
|
|
1538
|
+
if (acao === 'estado') {
|
|
1539
|
+
const id = args.posicionais[3];
|
|
1540
|
+
const estado = (0, divida_1.parseEstadoDeAchado)(args.posicionais[4]);
|
|
1541
|
+
if (!id || !estado) {
|
|
1542
|
+
console.error('uso: ork audit finding estado <achado-id> <aberto|adiado|resolvido|descartado>');
|
|
1543
|
+
return 2;
|
|
1544
|
+
}
|
|
1545
|
+
if (estado === 'virou-thread') {
|
|
1546
|
+
console.error('o estado `virou-thread` e carimbado pelo proprio `ork thread new --from-finding`.');
|
|
1547
|
+
return 2;
|
|
1548
|
+
}
|
|
1549
|
+
const achado = (0, divida_1.exigirAchado)(carregado.raiz, id);
|
|
1550
|
+
const atualizado = (0, divida_1.carimbarAchado)(carregado.raiz, achado, { estado });
|
|
1551
|
+
console.log(`Achado ${atualizado.id} agora esta ${atualizado.estado}.`);
|
|
1552
|
+
console.log((0, divida_1.textoDoAchado)(atualizado));
|
|
1553
|
+
return 0;
|
|
1554
|
+
}
|
|
1555
|
+
console.error(`subcomando desconhecido: audit finding ${acao ?? ''}`);
|
|
1556
|
+
return 2;
|
|
1557
|
+
}
|
|
1558
|
+
if (sub === 'verify') {
|
|
1559
|
+
const id = args.posicionais[2];
|
|
1560
|
+
if (!id) {
|
|
1561
|
+
console.error('uso: ork audit verify <rodada>');
|
|
1562
|
+
return 2;
|
|
1563
|
+
}
|
|
1564
|
+
const v = (0, auditrun_1.verificarRodada)(carregado, id);
|
|
1565
|
+
console.log(`Claims dos achados da rodada ${v.rodada}, reexecutadas no HEAD real.`);
|
|
1566
|
+
console.log(` HEAD real ${v.commit}`);
|
|
1567
|
+
console.log(` diretorio ${v.cwd}`);
|
|
1568
|
+
console.log('');
|
|
1569
|
+
if (v.resultados.length === 0) {
|
|
1570
|
+
console.log(' (nenhum achado aberto nesta rodada)');
|
|
1571
|
+
}
|
|
1572
|
+
for (const r of v.resultados) {
|
|
1573
|
+
console.log(` ${r.claim.id} verificado: ${r.verificado ? 'sim' : 'NAO'} ${r.claim.alegacao}`);
|
|
1574
|
+
console.log(` arquivo: ${r.claim.arquivo}`);
|
|
1575
|
+
console.log(` ${r.claim.verificar.length > 0 ? `comando(s): ${r.claim.verificar.join(' && ')}` : 'sem comando de verificacao'}`);
|
|
1576
|
+
if (!r.verificado)
|
|
1577
|
+
console.log(` motivo tipado: ${r.motivo} (${r.detalhe})`);
|
|
1578
|
+
}
|
|
1579
|
+
console.log('');
|
|
1580
|
+
console.log(v.ok
|
|
1581
|
+
? 'Veredito: ACHADOS SUSTENTADOS (o auditor provou o que alegou).'
|
|
1582
|
+
: `Veredito: REPROVADO. Motivos tipados: ${v.motivos.join(', ')}`);
|
|
1583
|
+
if (v.motivos.includes('claims.unverifiable')) {
|
|
1584
|
+
console.log(' aviso: achado sem comando de verificacao avisa e nao bloqueia (regra do gate do B1).');
|
|
1585
|
+
}
|
|
1586
|
+
return v.ok ? 0 : 1;
|
|
1587
|
+
}
|
|
1588
|
+
if (sub === 'report' || sub === 'relatorio') {
|
|
1589
|
+
const id = args.posicionais[2];
|
|
1590
|
+
if (!id) {
|
|
1591
|
+
console.error('uso: ork audit report <rodada> [--publicar]');
|
|
1592
|
+
return 2;
|
|
1593
|
+
}
|
|
1594
|
+
const r = (0, auditrun_1.relatorioDaRodada)(carregado, id, { publicar: args.opcoes.publicar === true });
|
|
1595
|
+
console.log(r.texto);
|
|
1596
|
+
console.log(`(relatorio gravado em ${r.caminho})`);
|
|
1597
|
+
if (r.publicado)
|
|
1598
|
+
console.log(`(publicado em ${r.publicado})`);
|
|
1599
|
+
return 0;
|
|
1600
|
+
}
|
|
1601
|
+
if (sub === 'divida' || sub === 'board') {
|
|
1602
|
+
const bruto = texto(args.opcoes.pack);
|
|
1603
|
+
const pack = bruto ? (0, auditoria_1.parsePack)(bruto) : undefined;
|
|
1604
|
+
if (bruto && !pack) {
|
|
1605
|
+
console.error(`pack desconhecido: "${bruto}". Use um de: ${auditoria_1.ORDEM_DOS_PACKS.join(', ')}`);
|
|
1606
|
+
return 2;
|
|
1607
|
+
}
|
|
1608
|
+
console.log((0, divida_1.tabelaDaDivida)(carregado.raiz, {
|
|
1609
|
+
pack: pack ?? undefined,
|
|
1610
|
+
todos: args.opcoes.todos === true || args.opcoes.all === true,
|
|
1611
|
+
}));
|
|
1612
|
+
return 0;
|
|
1613
|
+
}
|
|
1614
|
+
// `audit surface`: a varredura deterministica da superficie de ataque de rede (SP8..SP12).
|
|
1615
|
+
// Ela roda sozinha dentro de `audit run security-privacy`; aqui ela e exposta para o
|
|
1616
|
+
// operador olhar a superficie sem despachar rodada nenhuma, e para registrar no board os
|
|
1617
|
+
// achados de uma rodada que rodou em `--dry-run`.
|
|
1618
|
+
if (sub === 'surface' || sub === 'superficie') {
|
|
1619
|
+
const bruta = texto(args.opcoes.regra);
|
|
1620
|
+
if (bruta && !superficie_1.REGRAS_DE_SUPERFICIE.includes(bruta.toUpperCase())) {
|
|
1621
|
+
console.error(`regra desconhecida: "${bruta}". Use uma de: ${superficie_1.REGRAS_DE_SUPERFICIE.join(', ')}`);
|
|
1622
|
+
return 2;
|
|
1623
|
+
}
|
|
1624
|
+
const regra = bruta ? bruta.toUpperCase() : undefined;
|
|
1625
|
+
const limiteBruto = texto(args.opcoes.limite);
|
|
1626
|
+
const limite = limiteBruto ? Number(limiteBruto) : undefined;
|
|
1627
|
+
if (limite !== undefined && (!Number.isFinite(limite) || limite < 1)) {
|
|
1628
|
+
console.error(`--limite invalido: "${limiteBruto}". Use um inteiro >= 1.`);
|
|
1629
|
+
return 2;
|
|
1630
|
+
}
|
|
1631
|
+
const rodadaAlvo = texto(args.opcoes.registrar);
|
|
1632
|
+
if (rodadaAlvo) {
|
|
1633
|
+
const r = (0, auditrun_1.varrerSuperficieDaRodada)(carregado, rodadaAlvo, { registrar: true, limitePorRegra: limite });
|
|
1634
|
+
console.log((0, superficie_1.textoDaVarredura)(r.resultado));
|
|
1635
|
+
console.log('');
|
|
1636
|
+
console.log(`Rodada ${r.rodada}: ${r.registrados.length} achado(s) registrado(s) no board de divida.`);
|
|
1637
|
+
for (const a of r.registrados)
|
|
1638
|
+
console.log(` ${a.id} ${a.regra} ${a.arquivo}:${a.linha} ${a.titulo}`);
|
|
1639
|
+
if (r.duplicados.length > 0) {
|
|
1640
|
+
console.log(` ja registrados nesta rodada: ${r.duplicados.map((a) => a.id).join(', ')}`);
|
|
1641
|
+
}
|
|
1642
|
+
for (const rec of r.recusados) {
|
|
1643
|
+
console.error(` RECUSADO ${rec.achado.regra} ${rec.achado.arquivo}:${rec.achado.linha}: ${rec.erro}`);
|
|
1644
|
+
}
|
|
1645
|
+
console.log('');
|
|
1646
|
+
console.log(`Prove os achados antes de qualquer thread: ork audit verify ${r.rodada}`);
|
|
1647
|
+
if (r.recusados.length > 0)
|
|
1648
|
+
return 1;
|
|
1649
|
+
return r.registrados.length > 0 ? 1 : 0;
|
|
1650
|
+
}
|
|
1651
|
+
const resultado = (0, superficie_1.varrerSuperficie)(carregado.raiz, {
|
|
1652
|
+
dir: args.posicionais[2],
|
|
1653
|
+
regra,
|
|
1654
|
+
limitePorRegra: limite,
|
|
1655
|
+
});
|
|
1656
|
+
if (args.opcoes.json === true) {
|
|
1657
|
+
console.log(JSON.stringify(resultado, null, 2));
|
|
1658
|
+
}
|
|
1659
|
+
else {
|
|
1660
|
+
console.log((0, superficie_1.textoDaVarredura)(resultado));
|
|
1661
|
+
}
|
|
1662
|
+
// Codigo != 0 com achado: o agendador do host percebe a superficie aberta sem ler texto.
|
|
1663
|
+
return resultado.achados.length > 0 ? 1 : 0;
|
|
1664
|
+
}
|
|
1665
|
+
console.error(`subcomando desconhecido: audit ${sub}`);
|
|
1666
|
+
return 2;
|
|
1667
|
+
}
|
|
1668
|
+
/** Roteia o comando. Devolve o codigo de saida do processo. */
|
|
1669
|
+
/**
|
|
1670
|
+
* Imprime o resultado de uma publicacao na memoria semantica (bloco B6).
|
|
1671
|
+
*
|
|
1672
|
+
* Em regime `files` ele nao imprime nada: o comando que chamou continua com a mesma saida
|
|
1673
|
+
* que sempre teve. E o que garante que ligar o B6 nao muda o que o builder ja conhece.
|
|
1674
|
+
*/
|
|
1675
|
+
function relatarPublicacao(r) {
|
|
1676
|
+
if (r.regime !== 'orkmind')
|
|
1677
|
+
return;
|
|
1678
|
+
const gravados = [
|
|
1679
|
+
`${r.decisoes.gravadas.filter((g) => g.ok).length} decision`,
|
|
1680
|
+
`${r.policies.gravadas.filter((g) => g.ok).length} rule`,
|
|
1681
|
+
r.handoff?.ok ? '1 handoff' : '',
|
|
1682
|
+
r.learning?.ok ? '1 learning' : '',
|
|
1683
|
+
r.roadmap?.ok ? '1 roadmap' : '',
|
|
1684
|
+
].filter((t) => t !== '');
|
|
1685
|
+
console.log('');
|
|
1686
|
+
console.log(`Memoria (orkmind, tenant ${r.estado.tenant}): ${gravados.join(', ') || 'nada a gravar'}.`);
|
|
1687
|
+
if (r.falhas > 0)
|
|
1688
|
+
console.log(` ${r.falhas} gravacao(oes) nao concluida(s); veja ork memory status.`);
|
|
1689
|
+
}
|
|
1690
|
+
/** `ork recall`: recuperacao tardia dos ponteiros do handoff, no momento indicado. */
|
|
1691
|
+
function comandoRecall(args) {
|
|
1692
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1693
|
+
const id = args.posicionais[1];
|
|
1694
|
+
if (!id) {
|
|
1695
|
+
console.error('uso: ork recall <thread-id> [--fase FASE] [--id ptr-N] [--todos] [--forcar]');
|
|
1696
|
+
return 2;
|
|
1697
|
+
}
|
|
1698
|
+
const thread = (0, thread_1.lerThread)(carregado.raiz, id);
|
|
1699
|
+
const faseBruta = texto(args.opcoes.fase) ?? texto(args.opcoes.momento);
|
|
1700
|
+
const momento = faseBruta ? (0, thread_1.exigirFase)(thread, faseBruta) : undefined;
|
|
1701
|
+
const memoria = (0, memoria_1.abrirMemoria)(carregado);
|
|
1702
|
+
const r = (0, recall_1.recallDaThread)(carregado, memoria, id, {
|
|
1703
|
+
momento,
|
|
1704
|
+
id: texto(args.opcoes.id),
|
|
1705
|
+
todos: args.opcoes.todos === true,
|
|
1706
|
+
forcar: args.opcoes.forcar === true,
|
|
1707
|
+
});
|
|
1708
|
+
if (args.opcoes.json === true) {
|
|
1709
|
+
console.log(JSON.stringify(r, null, 2));
|
|
1710
|
+
}
|
|
1711
|
+
else {
|
|
1712
|
+
console.log((0, recall_1.textoDoRecall)(r, args.opcoes['sem-conteudo'] !== true));
|
|
1713
|
+
}
|
|
1714
|
+
// Ponteiro que deveria resolver e nao resolveu e falha, nao relatorio.
|
|
1715
|
+
return r.falhas.length > 0 ? 1 : 0;
|
|
1716
|
+
}
|
|
1717
|
+
/** `ork memory`: o regime, a publicacao e a busca deterministica por tag. */
|
|
1718
|
+
function comandoMemory(args) {
|
|
1719
|
+
const carregado = (0, manifest_1.exigirManifesto)();
|
|
1720
|
+
const sub = args.posicionais[1] ?? 'status';
|
|
1721
|
+
const memoria = (0, memoria_1.abrirMemoria)(carregado);
|
|
1722
|
+
if (sub === 'status') {
|
|
1723
|
+
if (args.opcoes.json === true) {
|
|
1724
|
+
console.log(JSON.stringify(memoria.estado, null, 2));
|
|
1725
|
+
return 0;
|
|
1726
|
+
}
|
|
1727
|
+
console.log((0, memoria_1.textoDoEstado)(memoria.estado));
|
|
1728
|
+
return 0;
|
|
1729
|
+
}
|
|
1730
|
+
if (sub === 'sync') {
|
|
1731
|
+
const threadId = args.posicionais[2];
|
|
1732
|
+
// Thread inexistente reprova aqui, e nao no meio da gravacao.
|
|
1733
|
+
if (threadId)
|
|
1734
|
+
(0, thread_1.lerThread)(carregado.raiz, threadId);
|
|
1735
|
+
const r = (0, memoria_1.sincronizarMemoria)(carregado, memoria, threadId ?? null);
|
|
1736
|
+
if (args.opcoes.json === true) {
|
|
1737
|
+
console.log(JSON.stringify(r, null, 2));
|
|
1738
|
+
}
|
|
1739
|
+
else {
|
|
1740
|
+
console.log((0, memoria_1.textoDoSync)(r));
|
|
1741
|
+
}
|
|
1742
|
+
return 0;
|
|
1743
|
+
}
|
|
1744
|
+
if (sub === 'search') {
|
|
1745
|
+
const tagsBrutas = texto(args.opcoes.tags);
|
|
1746
|
+
if (!tagsBrutas) {
|
|
1747
|
+
console.error('uso: ork memory search --tags \'{"project":["orkastery"],"skill":["orkastery-decision"]}\'');
|
|
1748
|
+
return 2;
|
|
1749
|
+
}
|
|
1750
|
+
let tags;
|
|
1751
|
+
try {
|
|
1752
|
+
tags = JSON.parse(tagsBrutas);
|
|
1753
|
+
}
|
|
1754
|
+
catch (e) {
|
|
1755
|
+
console.error(`--tags nao e JSON valido: ${e.message}`);
|
|
1756
|
+
return 2;
|
|
1757
|
+
}
|
|
1758
|
+
const colecao = texto(args.opcoes.colecao) ?? texto(args.opcoes.collection);
|
|
1759
|
+
const limiteBruto = texto(args.opcoes.limite);
|
|
1760
|
+
const entradas = memoria.buscar({
|
|
1761
|
+
collection: colecao,
|
|
1762
|
+
tags,
|
|
1763
|
+
limite: limiteBruto ? Number(limiteBruto) : undefined,
|
|
1764
|
+
});
|
|
1765
|
+
if (args.opcoes.json === true) {
|
|
1766
|
+
console.log(JSON.stringify(entradas, null, 2));
|
|
1767
|
+
return 0;
|
|
1768
|
+
}
|
|
1769
|
+
console.log(`Busca deterministica por tag (regime ${memoria.regime})`);
|
|
1770
|
+
console.log('');
|
|
1771
|
+
if (memoria.regime === 'files') {
|
|
1772
|
+
console.log(` ${memoria.estado.detalhe}`);
|
|
1773
|
+
console.log(` correcao: ${memoria.estado.correcao}`);
|
|
1774
|
+
return 0;
|
|
1775
|
+
}
|
|
1776
|
+
for (const e of entradas) {
|
|
1777
|
+
console.log(` [${e.collection}] ${e.id} ${e.priority}${e.mandatory ? ' [MANDATORY]' : ''}`);
|
|
1778
|
+
console.log(` ${e.content.split('\n')[0].slice(0, 100)}`);
|
|
1779
|
+
}
|
|
1780
|
+
console.log('');
|
|
1781
|
+
console.log(` ${entradas.length} entrada(s)`);
|
|
1782
|
+
return 0;
|
|
1783
|
+
}
|
|
1784
|
+
console.error(`subcomando desconhecido: memory ${sub}`);
|
|
1785
|
+
return 2;
|
|
1786
|
+
}
|
|
1787
|
+
function main(argv) {
|
|
1788
|
+
const args = parseArgs(argv);
|
|
1789
|
+
const comando = args.posicionais[0];
|
|
1790
|
+
if (!comando || args.opcoes.help === true || comando === 'help') {
|
|
1791
|
+
console.log(AJUDA);
|
|
1792
|
+
return 0;
|
|
1793
|
+
}
|
|
1794
|
+
if (args.opcoes.version === true || comando === 'version') {
|
|
1795
|
+
console.log(VERSAO);
|
|
1796
|
+
return 0;
|
|
1797
|
+
}
|
|
1798
|
+
switch (comando) {
|
|
1799
|
+
case 'doctor': {
|
|
1800
|
+
const r = (0, doctor_1.doctor)();
|
|
1801
|
+
console.log(r.texto);
|
|
1802
|
+
return r.codigo;
|
|
1803
|
+
}
|
|
1804
|
+
case 'init': {
|
|
1805
|
+
const r = (0, init_1.init)(process.cwd(), {
|
|
1806
|
+
force: args.opcoes.force === true,
|
|
1807
|
+
nome: texto(args.opcoes.name) ?? texto(args.opcoes.nome),
|
|
1808
|
+
abbrev: texto(args.opcoes.abbrev),
|
|
1809
|
+
});
|
|
1810
|
+
if (!r.criado) {
|
|
1811
|
+
console.log(`Manifesto ja existe: ${r.caminho}`);
|
|
1812
|
+
console.log('Nada foi sobrescrito. Use --force para regerar.');
|
|
1813
|
+
return 0;
|
|
1814
|
+
}
|
|
1815
|
+
console.log(`Manifesto criado: ${r.caminho}`);
|
|
1816
|
+
console.log(` projeto ${r.deteccao.nome} (abbrev "${r.deteccao.abbrev}")`);
|
|
1817
|
+
console.log(` branch base ${r.deteccao.baseBranch}`);
|
|
1818
|
+
console.log(` gerenciador ${r.deteccao.gerenciador}`);
|
|
1819
|
+
console.log(` verify ${Object.entries(r.deteccao.verify).map(([k, v]) => `${k}="${v}"`).join(', ') || '(nenhum script detectado)'}`);
|
|
1820
|
+
console.log('');
|
|
1821
|
+
console.log('Proximo passo: ork doctor');
|
|
1822
|
+
return 0;
|
|
1823
|
+
}
|
|
1824
|
+
case 'modos': {
|
|
1825
|
+
// `--do-pedido` existe para os adaptadores de host: eles extraem a #TAG do texto do
|
|
1826
|
+
// builder SEM reimplementar o parse, e repassam `--mode` ao `ork`. A validacao contra
|
|
1827
|
+
// `conduction.allowed_modes` continua sendo do nucleo, no `ork thread new`.
|
|
1828
|
+
const pedido = texto(args.opcoes['do-pedido']);
|
|
1829
|
+
if (pedido !== undefined) {
|
|
1830
|
+
const carregado = (0, manifest_1.carregarManifesto)();
|
|
1831
|
+
const extraido = (0, modos_1.extrairTagDoPedido)(pedido);
|
|
1832
|
+
const modo = extraido ?? carregado?.manifesto.conduction.default_mode ?? 'classic';
|
|
1833
|
+
if (args.opcoes.json === true) {
|
|
1834
|
+
console.log(JSON.stringify({
|
|
1835
|
+
modo,
|
|
1836
|
+
tag: modos_1.MODOS[modo].tag,
|
|
1837
|
+
daTag: extraido !== null,
|
|
1838
|
+
origem: extraido !== null ? 'tag no pedido' : 'conduction.default_mode',
|
|
1839
|
+
pausas: (0, modos_1.pausasDoModo)(modo),
|
|
1840
|
+
}));
|
|
1841
|
+
}
|
|
1842
|
+
else {
|
|
1843
|
+
console.log(modo);
|
|
1844
|
+
}
|
|
1845
|
+
return 0;
|
|
1846
|
+
}
|
|
1847
|
+
console.log((0, modos_1.tabelaDeModos)());
|
|
1848
|
+
return 0;
|
|
1849
|
+
}
|
|
1850
|
+
case 'thread':
|
|
1851
|
+
return comandoThread(args);
|
|
1852
|
+
case 'phase':
|
|
1853
|
+
return comandoPhase(args);
|
|
1854
|
+
case 'sessions':
|
|
1855
|
+
return comandoSessions(args);
|
|
1856
|
+
case 'claims':
|
|
1857
|
+
return comandoClaims(args);
|
|
1858
|
+
case 'verify':
|
|
1859
|
+
return comandoVerify(args);
|
|
1860
|
+
case 'gate':
|
|
1861
|
+
return comandoGate(args);
|
|
1862
|
+
case 'retry':
|
|
1863
|
+
return comandoRetry(args);
|
|
1864
|
+
case 'fix':
|
|
1865
|
+
return comandoFix(args);
|
|
1866
|
+
case 'handoff':
|
|
1867
|
+
return comandoHandoff(args);
|
|
1868
|
+
case 'recall':
|
|
1869
|
+
return comandoRecall(args);
|
|
1870
|
+
case 'memory':
|
|
1871
|
+
return comandoMemory(args);
|
|
1872
|
+
case 'ship':
|
|
1873
|
+
return comandoShip(args);
|
|
1874
|
+
case 'lease':
|
|
1875
|
+
return comandoLease(args);
|
|
1876
|
+
case 'board':
|
|
1877
|
+
return comandoBoard(args);
|
|
1878
|
+
case 'orquestracao':
|
|
1879
|
+
case 'monitor':
|
|
1880
|
+
return comandoOrquestracao(args);
|
|
1881
|
+
case 'worktree':
|
|
1882
|
+
return comandoWorktree(args);
|
|
1883
|
+
case 'master':
|
|
1884
|
+
return comandoMaster(args);
|
|
1885
|
+
case 'eval':
|
|
1886
|
+
return comandoEval(args);
|
|
1887
|
+
case 'audit':
|
|
1888
|
+
return comandoAudit(args);
|
|
1889
|
+
case 'adapter':
|
|
1890
|
+
return comandoAdapter(args);
|
|
1891
|
+
case 'prompt':
|
|
1892
|
+
return comandoPrompt(args);
|
|
1893
|
+
case 'ciclos':
|
|
1894
|
+
console.log((0, ciclos_1.tabelaDeVariantes)());
|
|
1895
|
+
return 0;
|
|
1896
|
+
default:
|
|
1897
|
+
console.error(`comando desconhecido: ${comando}`);
|
|
1898
|
+
console.log(AJUDA);
|
|
1899
|
+
return 2;
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
if (require.main === module) {
|
|
1903
|
+
try {
|
|
1904
|
+
process.exitCode = main(process.argv.slice(2));
|
|
1905
|
+
}
|
|
1906
|
+
catch (e) {
|
|
1907
|
+
console.error(`erro: ${e.message}`);
|
|
1908
|
+
process.exitCode = 1;
|
|
1909
|
+
}
|
|
1910
|
+
}
|