@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/phase.js
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `ork phase run|list`: despacho de fase pelo runtime adapter e leitura do ledger.
|
|
4
|
+
*
|
|
5
|
+
* O prompt e montado pelo `ork` (nomenclatura das fases + modo de conducao + contexto da
|
|
6
|
+
* thread + pedido do builder), gravado com hash sha256 no diretorio da thread e so entao
|
|
7
|
+
* despachado. Depois do despacho o `ork` RE-VERIFICA no runtime que a sessao existe:
|
|
8
|
+
* self-report de despacho nao vale como evidencia.
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.REGRAS_DE_EVIDENCIA = exports.CONTRATO_DAS_FASES = void 0;
|
|
45
|
+
exports.valoresDoPrompt = valoresDoPrompt;
|
|
46
|
+
exports.montarPrompt = montarPrompt;
|
|
47
|
+
exports.montarPromptComMemoria = montarPromptComMemoria;
|
|
48
|
+
exports.hashDoPrompt = hashDoPrompt;
|
|
49
|
+
exports.slugDaSessao = slugDaSessao;
|
|
50
|
+
exports.resolverDespacho = resolverDespacho;
|
|
51
|
+
exports.dadosDoDespacho = dadosDoDespacho;
|
|
52
|
+
exports.concluirDespacho = concluirDespacho;
|
|
53
|
+
exports.rodarFase = rodarFase;
|
|
54
|
+
exports.tabelaDoLedger = tabelaDoLedger;
|
|
55
|
+
exports.descreverSlug = descreverSlug;
|
|
56
|
+
const node_crypto_1 = require("node:crypto");
|
|
57
|
+
const path = __importStar(require("node:path"));
|
|
58
|
+
const adapter = __importStar(require("./adapters/claude-bg"));
|
|
59
|
+
const modos_1 = require("./modos");
|
|
60
|
+
const gates_1 = require("./gates");
|
|
61
|
+
const policies_1 = require("./policies");
|
|
62
|
+
const ratelimit_1 = require("./ratelimit");
|
|
63
|
+
const memoria_1 = require("./memoria");
|
|
64
|
+
const prompts_1 = require("./prompts");
|
|
65
|
+
const slug_1 = require("./slug");
|
|
66
|
+
const thread_1 = require("./thread");
|
|
67
|
+
const types_1 = require("./types");
|
|
68
|
+
const util_1 = require("./util");
|
|
69
|
+
const ledger_1 = require("./ledger");
|
|
70
|
+
/** O que cada fase canonica entrega. Vai no cabecalho do prompt de toda sessao. */
|
|
71
|
+
exports.CONTRATO_DAS_FASES = {
|
|
72
|
+
GOAL: 'GOAL (F1): objetivo verificavel, impact map, criterios de sucesso e claims com comando de verificacao. Nao implementa.',
|
|
73
|
+
PLAN: 'PLAN (F2): plano com tarefas, touch_paths, decisoes D1..Dn com domicilio unico e verify executavel por tarefa. Nao implementa.',
|
|
74
|
+
GO: 'GO (F3): implementacao slice por slice, um commit atomico por tarefa, dentro da worktree da thread.',
|
|
75
|
+
CHECK: 'CHECK (F4): verificacao contra a baseline (regressao versus divida pre-existente), review de codigo, testes, seguranca e performance.',
|
|
76
|
+
SHIP: 'SHIP (F5): merge serializado, push provado por comando, roadmap atualizado e plano de rollback.',
|
|
77
|
+
MASTER: 'MASTER (F6): MASTER log com postmortem tipado, licoes e o score humano de 0 a 5. Uma entrega sem MASTER log nao aconteceu.',
|
|
78
|
+
};
|
|
79
|
+
/** As regras de evidencia que valem em toda fase, em todo modo. */
|
|
80
|
+
exports.REGRAS_DE_EVIDENCIA = [
|
|
81
|
+
'Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.',
|
|
82
|
+
'Trabalhe apenas no diretorio de trabalho indicado acima.',
|
|
83
|
+
'Passos irreversiveis (push, merge, delecao) so acontecem quando o modo autoriza.',
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* Os valores que o template de fase recebe.
|
|
87
|
+
*
|
|
88
|
+
* Tudo que o prompt diz sai daqui, e nada e calculado dentro do template: template e dado,
|
|
89
|
+
* decisao e codigo. E o que permite um projeto reescrever o texto do prompt em
|
|
90
|
+
* `prompts/fase-padrao.md` sem poder mudar o que o `ork` considera verdade.
|
|
91
|
+
*/
|
|
92
|
+
function valoresDoPrompt(thread, fase, pedido, memoriaInjetada = '') {
|
|
93
|
+
const def = (0, modos_1.definicaoDoModo)(thread.modo);
|
|
94
|
+
const bloco = (0, thread_1.blocoDaThread)(thread, fase);
|
|
95
|
+
const pausa = (0, thread_1.pausaNaThread)(thread, fase);
|
|
96
|
+
return {
|
|
97
|
+
fase,
|
|
98
|
+
thread: thread.id,
|
|
99
|
+
bloco: bloco.fases.join('-'),
|
|
100
|
+
nome: thread.nome,
|
|
101
|
+
ciclo_canonico: types_1.FASES.map((f) => `${bloco.fases.includes(f) ? '>' : ' '} ${exports.CONTRATO_DAS_FASES[f]}`).join('\n'),
|
|
102
|
+
tag: def.tag,
|
|
103
|
+
blocos: thread.blocos.map((b) => b.fases.join('-')).join(' / '),
|
|
104
|
+
pausas: String(thread.blocos.filter((b) => b.pausa).length),
|
|
105
|
+
linha_variante: thread.variante ? `Variante de ciclo: ${thread.variante}` : '',
|
|
106
|
+
regra_de_pausa: pausa
|
|
107
|
+
? `Ao fim deste bloco HA PAUSA humana sobre: ${bloco.pausaSobre}. Pare, apresente a evidencia e espere o veredito.`
|
|
108
|
+
: 'Ao fim deste bloco NAO ha pausa humana: siga com decisao autonoma e registre no ledger quem decidiu, com que evidencia e por que.',
|
|
109
|
+
invariantes: modos_1.INVARIANTES.map((i) => `- ${i}`).join('\n'),
|
|
110
|
+
slug: thread.slug,
|
|
111
|
+
projeto_nome: thread.projeto.name,
|
|
112
|
+
projeto_abbrev: thread.projeto.abbrev,
|
|
113
|
+
base_branch: thread.base.branch,
|
|
114
|
+
base_commit: thread.base.commit,
|
|
115
|
+
diretorio: thread.worktree ?? '(raiz do projeto)',
|
|
116
|
+
pedido: pedido.trim(),
|
|
117
|
+
// Bloco B6: o bloco de memoria injetada deterministicamente. Vazio em toda thread sem
|
|
118
|
+
// decisao fechada e sem OrkMind, e ai a linha da variavel some do prompt: o texto fica
|
|
119
|
+
// byte a byte igual ao que o B4 ja despachava.
|
|
120
|
+
memoria_injetada: memoriaInjetada,
|
|
121
|
+
regras_de_evidencia: exports.REGRAS_DE_EVIDENCIA.map((r) => `- ${r}`).join('\n'),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Monta o prompt da fase renderizando o template versionado (bloco B4).
|
|
126
|
+
*
|
|
127
|
+
* Sem `raiz`, ou sem `prompts/` no projeto, vale o template embutido do `ork`. Com um
|
|
128
|
+
* `prompts/fase-padrao.md` (ou `prompts/fase-goal.md` e companhia) versionado no repositorio,
|
|
129
|
+
* vale o do projeto, e `ork prompt lint` e quem garante que ele nao perdeu o contrato.
|
|
130
|
+
*/
|
|
131
|
+
function montarPrompt(thread, fase, pedido, raiz, memoriaInjetada = '') {
|
|
132
|
+
return (0, prompts_1.renderizar)((0, prompts_1.templateDaFase)(fase, raiz), valoresDoPrompt(thread, fase, pedido, memoriaInjetada));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Monta o prompt da fase JA com a memoria injetada (bloco B6).
|
|
136
|
+
*
|
|
137
|
+
* Separado de `montarPrompt` de proposito: quem so quer renderizar um template (o
|
|
138
|
+
* `ork prompt render --exemplo`, o lint) nao precisa abrir memoria nenhuma, e quem
|
|
139
|
+
* despacha uma fase de verdade precisa. Em regime `files` a injecao continua acontecendo,
|
|
140
|
+
* com as decisoes fechadas lidas do `thread.json`: a garantia nao depende do OrkMind.
|
|
141
|
+
*/
|
|
142
|
+
function montarPromptComMemoria(carregado, thread, fase, pedido, memoria) {
|
|
143
|
+
const injecao = (0, memoria_1.injecaoDaFase)(carregado, memoria, thread, fase);
|
|
144
|
+
return {
|
|
145
|
+
prompt: montarPrompt(thread, fase, pedido, carregado.raiz, injecao.texto),
|
|
146
|
+
injecao,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** sha256 do prompt, o mesmo hash gravado no `thread.json` e no ledger. */
|
|
150
|
+
function hashDoPrompt(prompt) {
|
|
151
|
+
return (0, node_crypto_1.createHash)('sha256').update(prompt, 'utf8').digest('hex');
|
|
152
|
+
}
|
|
153
|
+
/** Slug da sessao que conduz esta fase, rotacionando quando o slug ja foi usado na thread. */
|
|
154
|
+
function slugDaSessao(thread, fase) {
|
|
155
|
+
const bloco = (0, thread_1.blocoDaThread)(thread, fase);
|
|
156
|
+
const base = (0, slug_1.montarSlug)(thread.projeto.abbrev, thread.assunto, bloco.slugFases);
|
|
157
|
+
const usados = thread.sessoes.map((s) => s.slug);
|
|
158
|
+
if (!usados.includes(base))
|
|
159
|
+
return base;
|
|
160
|
+
return (0, slug_1.proximaRotacao)(base, usados);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Modelo e esforco EFETIVAMENTE usados num despacho, resolvidos numa funcao so.
|
|
164
|
+
*
|
|
165
|
+
* Regra do esforco: quem informa SO o modelo esta pedindo o despacho mais capaz que
|
|
166
|
+
* existe, entao o esforco assume `high` em vez de herdar o do manifesto. Quem informa o
|
|
167
|
+
* esforco manda, e sem nenhum dos dois vale o manifesto. Resolver isso aqui, e nao no
|
|
168
|
+
* ponto de chamada, e o que permite gravar o par no ledger como FATO: o mesmo valor que
|
|
169
|
+
* foi para o runtime adapter e o que fica carimbado no evento.
|
|
170
|
+
*/
|
|
171
|
+
function resolverDespacho(manifesto, opcoes) {
|
|
172
|
+
const model = opcoes.model ?? manifesto.runtime.model;
|
|
173
|
+
const effort = opcoes.effort ?? (opcoes.model !== undefined ? 'high' : manifesto.runtime.effort);
|
|
174
|
+
return { model, effort };
|
|
175
|
+
}
|
|
176
|
+
/** O comando com o prompt mascarado pelo hash: o ledger nao guarda o texto inteiro. */
|
|
177
|
+
function comandoMascarado(comando, sha) {
|
|
178
|
+
return comando.map((c, i) => (i === 2 ? `<prompt:${sha.slice(0, 8)}>` : c));
|
|
179
|
+
}
|
|
180
|
+
/** Os campos que todo evento de despacho carrega, no caminho normal e na retomada. */
|
|
181
|
+
function dadosDoDespacho(ctx, comando) {
|
|
182
|
+
return {
|
|
183
|
+
fase: ctx.fase,
|
|
184
|
+
slug: ctx.slug,
|
|
185
|
+
modo: ctx.thread.modo,
|
|
186
|
+
bloco: (0, thread_1.blocoDaThread)(ctx.thread, ctx.fase).fases.join('-'),
|
|
187
|
+
pausaAoFim: (0, thread_1.pausaNaThread)(ctx.thread, ctx.fase),
|
|
188
|
+
runtime: ctx.runtime,
|
|
189
|
+
// Fato verificavel: o modelo e o esforco reais do despacho ficam no proprio evento,
|
|
190
|
+
// e nao no relato do agente. `ork phase list` le daqui.
|
|
191
|
+
model: ctx.model,
|
|
192
|
+
effort: ctx.effort,
|
|
193
|
+
cwd: ctx.cwd,
|
|
194
|
+
promptPath: path.relative(ctx.raiz, ctx.promptPath),
|
|
195
|
+
promptSha256: ctx.promptSha256,
|
|
196
|
+
origem: ctx.origem,
|
|
197
|
+
comando: comandoMascarado(comando, ctx.promptSha256),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Fecha um despacho BEM SUCEDIDO: ledger, decisao autonoma ou pausa prevista, e a
|
|
202
|
+
* sessao gravada no `thread.json`. Usada pelo `ork phase run` e pela retomada do B3.
|
|
203
|
+
*/
|
|
204
|
+
function concluirDespacho(ctx, sessionId, verificada, comando) {
|
|
205
|
+
const dir = (0, thread_1.dirThread)(ctx.raiz, ctx.thread.id);
|
|
206
|
+
const comum = dadosDoDespacho(ctx, comando);
|
|
207
|
+
const bloco = (0, thread_1.blocoDaThread)(ctx.thread, ctx.fase);
|
|
208
|
+
const pausaAoFim = (0, thread_1.pausaNaThread)(ctx.thread, ctx.fase);
|
|
209
|
+
(0, ledger_1.registrar)(dir, ctx.thread.id, ledger_1.TIPOS_DE_EVENTO.faseDespachada, { ...comum, sessionId });
|
|
210
|
+
(0, ledger_1.registrar)(dir, ctx.thread.id, ledger_1.TIPOS_DE_EVENTO.despachoVerificado, {
|
|
211
|
+
fase: ctx.fase,
|
|
212
|
+
slug: ctx.slug,
|
|
213
|
+
sessionId,
|
|
214
|
+
fonte: 'claude agents --json',
|
|
215
|
+
encontrada: verificada,
|
|
216
|
+
});
|
|
217
|
+
if (!pausaAoFim) {
|
|
218
|
+
(0, ledger_1.registrar)(dir, ctx.thread.id, ledger_1.TIPOS_DE_EVENTO.decisaoAutonoma, {
|
|
219
|
+
fase: ctx.fase,
|
|
220
|
+
slug: ctx.slug,
|
|
221
|
+
sessionId,
|
|
222
|
+
decisao: `bloco ${bloco.fases.join('-')} segue sem pausa humana`,
|
|
223
|
+
autorizadoPor: `#TAG ${(0, modos_1.definicaoDoModo)(ctx.thread.modo).tag} no pedido do builder`,
|
|
224
|
+
evidencia: `prompt sha256 ${ctx.promptSha256}`,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
(0, ledger_1.registrar)(dir, ctx.thread.id, ledger_1.TIPOS_DE_EVENTO.pausaHumana, {
|
|
229
|
+
fase: ctx.fase,
|
|
230
|
+
slug: ctx.slug,
|
|
231
|
+
sessionId,
|
|
232
|
+
previstaSobre: bloco.pausaSobre,
|
|
233
|
+
estado: 'prevista ao fim do bloco',
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const sessao = {
|
|
237
|
+
slug: ctx.slug,
|
|
238
|
+
fase: ctx.fase,
|
|
239
|
+
bloco: bloco.fases.join('-'),
|
|
240
|
+
sessionId,
|
|
241
|
+
runtime: ctx.runtime,
|
|
242
|
+
despachadaEm: (0, util_1.agora)(),
|
|
243
|
+
promptPath: path.relative(ctx.raiz, ctx.promptPath),
|
|
244
|
+
promptSha256: ctx.promptSha256,
|
|
245
|
+
verificada,
|
|
246
|
+
};
|
|
247
|
+
ctx.thread.sessoes.push(sessao);
|
|
248
|
+
ctx.thread.faseAtual = ctx.fase;
|
|
249
|
+
(0, thread_1.gravarThread)(ctx.raiz, ctx.thread);
|
|
250
|
+
return sessao;
|
|
251
|
+
}
|
|
252
|
+
/** Despacha a fase pelo runtime adapter e registra tudo no ledger da thread. */
|
|
253
|
+
function rodarFase(carregado, threadId, opcoes) {
|
|
254
|
+
const { raiz, manifesto } = carregado;
|
|
255
|
+
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
256
|
+
const fase = opcoes.fase;
|
|
257
|
+
const dir = (0, thread_1.dirThread)(raiz, thread.id);
|
|
258
|
+
const slug = slugDaSessao(thread, fase);
|
|
259
|
+
// Resolve UMA vez o par modelo/esforco: o mesmo objeto vai ao runtime adapter, ao
|
|
260
|
+
// ledger e a resposta do CLI. Resolver duas vezes e o caminho curto para o ledger
|
|
261
|
+
// dizer um modelo e o `claude --bg` receber outro.
|
|
262
|
+
const { model, effort } = resolverDespacho(manifesto, opcoes);
|
|
263
|
+
// Bloco B6: a memoria entra ANTES do hash. O prompt que o ledger carimba e o mesmo que
|
|
264
|
+
// o agente recebe, memoria injetada inclusa.
|
|
265
|
+
const memoria = opcoes.memoria ?? (0, memoria_1.abrirMemoria)(carregado);
|
|
266
|
+
const { prompt, injecao } = montarPromptComMemoria(carregado, thread, fase, opcoes.prompt, memoria);
|
|
267
|
+
const sha = hashDoPrompt(prompt);
|
|
268
|
+
const promptPath = path.join(dir, 'prompts', `${slug}-${fase.toLowerCase()}-${sha.slice(0, 8)}.md`);
|
|
269
|
+
// Gate tipado do bloco B1: as policies do manifesto valem ANTES do despacho, em
|
|
270
|
+
// qualquer modo. Prompt reprovado nem chega a ser gravado em disco: gravar um prompt
|
|
271
|
+
// com credencial e criar um segundo vazamento no proprio repositorio.
|
|
272
|
+
const violacoes = (0, policies_1.avaliarPolicies)(manifesto, { gate: 'phase.dispatch', prompt });
|
|
273
|
+
const bloqueiam = (0, policies_1.bloqueantes)(violacoes);
|
|
274
|
+
if (bloqueiam.length > 0) {
|
|
275
|
+
const detalhe = bloqueiam.map((v) => `${v.policy}: ${v.detalhe}`).join('; ');
|
|
276
|
+
// Bloco B3: violacao de CUSTO sai tipada como tal. E o que permite a politica de
|
|
277
|
+
// retry recusar reexecucao automatica dela sem reabrir o nome da policy aqui.
|
|
278
|
+
const motivoDoLote = (0, policies_1.motivoDominante)(bloqueiam);
|
|
279
|
+
(0, gates_1.registrarGateBloqueado)(dir, thread.id, {
|
|
280
|
+
gate: 'phase.dispatch',
|
|
281
|
+
motivo: motivoDoLote,
|
|
282
|
+
modo: thread.modo,
|
|
283
|
+
detalhe,
|
|
284
|
+
correcao: bloqueiam.map((v) => v.correcao).join('; '),
|
|
285
|
+
fase,
|
|
286
|
+
slug,
|
|
287
|
+
evidencia: `prompt sha256 ${sha} (nao gravado em disco)`,
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
thread,
|
|
291
|
+
slug,
|
|
292
|
+
promptPath,
|
|
293
|
+
promptSha256: sha,
|
|
294
|
+
comando: [],
|
|
295
|
+
sessionId: null,
|
|
296
|
+
verificada: false,
|
|
297
|
+
pausaAoFim: (0, thread_1.pausaNaThread)(thread, fase),
|
|
298
|
+
dryRun: opcoes.dryRun === true,
|
|
299
|
+
model,
|
|
300
|
+
effort,
|
|
301
|
+
bloqueado: true,
|
|
302
|
+
motivo: motivoDoLote,
|
|
303
|
+
violacoes,
|
|
304
|
+
erro: detalhe,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
(0, util_1.gravar)(promptPath, prompt);
|
|
308
|
+
// A injecao e evidencia: o ledger diz quantos itens entraram, de que colecao e de onde,
|
|
309
|
+
// para que "o prompt tinha a decisao D2" seja verificavel depois sem reler o prompt.
|
|
310
|
+
if (injecao.itens.length > 0) {
|
|
311
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.memoriaInjetada, {
|
|
312
|
+
fase,
|
|
313
|
+
slug,
|
|
314
|
+
regime: injecao.regime,
|
|
315
|
+
decisoes: injecao.decisoes,
|
|
316
|
+
licoes: injecao.licoes,
|
|
317
|
+
regras: injecao.regras,
|
|
318
|
+
itens: injecao.itens.map((i) => `${i.id}:${i.colecao}:${i.location}`),
|
|
319
|
+
promptSha256: sha,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
if (memoria.estado.motivo && memoria.estado.pedido === 'orkmind') {
|
|
323
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.memoriaDegradada, {
|
|
324
|
+
fase,
|
|
325
|
+
slug,
|
|
326
|
+
pedido: memoria.estado.pedido,
|
|
327
|
+
efetivo: memoria.estado.efetivo,
|
|
328
|
+
motivo: memoria.estado.motivo,
|
|
329
|
+
detalhe: memoria.estado.detalhe,
|
|
330
|
+
correcao: memoria.estado.correcao,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
const cwd = thread.worktree ?? raiz;
|
|
334
|
+
const pausaAoFim = (0, thread_1.pausaNaThread)(thread, fase);
|
|
335
|
+
const resultado = adapter.despachar({
|
|
336
|
+
prompt,
|
|
337
|
+
nome: slug,
|
|
338
|
+
cwd,
|
|
339
|
+
model,
|
|
340
|
+
effort,
|
|
341
|
+
dryRun: opcoes.dryRun,
|
|
342
|
+
});
|
|
343
|
+
const ctx = {
|
|
344
|
+
raiz,
|
|
345
|
+
thread,
|
|
346
|
+
fase,
|
|
347
|
+
slug,
|
|
348
|
+
promptPath,
|
|
349
|
+
promptSha256: sha,
|
|
350
|
+
runtime: manifesto.runtime.adapter,
|
|
351
|
+
cwd,
|
|
352
|
+
model,
|
|
353
|
+
effort,
|
|
354
|
+
origem: 'phase.run',
|
|
355
|
+
};
|
|
356
|
+
const comum = dadosDoDespacho(ctx, resultado.comando);
|
|
357
|
+
if (opcoes.dryRun) {
|
|
358
|
+
return {
|
|
359
|
+
thread,
|
|
360
|
+
slug,
|
|
361
|
+
promptPath,
|
|
362
|
+
promptSha256: sha,
|
|
363
|
+
comando: resultado.comando,
|
|
364
|
+
sessionId: null,
|
|
365
|
+
verificada: false,
|
|
366
|
+
pausaAoFim,
|
|
367
|
+
dryRun: true,
|
|
368
|
+
// O ensaio NAO toca no ledger (a garantia do B0 continua de pe), mas devolve o
|
|
369
|
+
// par resolvido: e assim que o `--dry-run` mostra o modelo que seria despachado.
|
|
370
|
+
model,
|
|
371
|
+
effort,
|
|
372
|
+
bloqueado: false,
|
|
373
|
+
motivo: null,
|
|
374
|
+
violacoes,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
if (!resultado.ok || !resultado.sessionId) {
|
|
378
|
+
const erro = resultado.erro ?? 'sem sessionId na saida do runtime';
|
|
379
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.despachoFalhou, {
|
|
380
|
+
...comum,
|
|
381
|
+
erro,
|
|
382
|
+
stderr: resultado.stderr.slice(0, 500),
|
|
383
|
+
});
|
|
384
|
+
// Bloco B3: rate limit nao e falha seca. A fase morreu com HORA de volta, entao ela
|
|
385
|
+
// vira pedido na fila duravel em vez de virar tarefa da memoria de alguem. O prompt
|
|
386
|
+
// ja esta gravado em disco com o sha256 acima, e e ele que sera redespachado.
|
|
387
|
+
const sinal = resultado.rateLimit ?? null;
|
|
388
|
+
if (sinal) {
|
|
389
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.rateLimitDetectado, {
|
|
390
|
+
fase,
|
|
391
|
+
slug,
|
|
392
|
+
fonte: sinal.fonte,
|
|
393
|
+
resetEm: sinal.resetEm,
|
|
394
|
+
trecho: sinal.trecho,
|
|
395
|
+
evidencia: 'stderr real do runtime adapter, nao relato do agente',
|
|
396
|
+
});
|
|
397
|
+
const pedido = (0, ratelimit_1.enfileirar)(carregado, {
|
|
398
|
+
thread: thread.id,
|
|
399
|
+
fase,
|
|
400
|
+
slug,
|
|
401
|
+
promptPath,
|
|
402
|
+
promptSha256: sha,
|
|
403
|
+
cwd,
|
|
404
|
+
model,
|
|
405
|
+
effort,
|
|
406
|
+
sinal,
|
|
407
|
+
detalhe: erro,
|
|
408
|
+
});
|
|
409
|
+
(0, ledger_1.registrar)(dir, thread.id, ledger_1.TIPOS_DE_EVENTO.rateLimitEnfileirado, {
|
|
410
|
+
fase,
|
|
411
|
+
slug,
|
|
412
|
+
pedido: pedido.id,
|
|
413
|
+
liberaEm: pedido.liberaEm,
|
|
414
|
+
janelaEstimada: pedido.janelaEstimada,
|
|
415
|
+
fonte: sinal.fonte,
|
|
416
|
+
promptSha256: sha,
|
|
417
|
+
correcao: `ork retry resume (ou aguarde ate ${pedido.liberaEm})`,
|
|
418
|
+
});
|
|
419
|
+
return {
|
|
420
|
+
thread,
|
|
421
|
+
slug,
|
|
422
|
+
promptPath,
|
|
423
|
+
promptSha256: sha,
|
|
424
|
+
comando: resultado.comando,
|
|
425
|
+
sessionId: null,
|
|
426
|
+
verificada: false,
|
|
427
|
+
pausaAoFim,
|
|
428
|
+
dryRun: false,
|
|
429
|
+
model,
|
|
430
|
+
effort,
|
|
431
|
+
bloqueado: false,
|
|
432
|
+
motivo: 'runtime.rate-limited',
|
|
433
|
+
violacoes,
|
|
434
|
+
naFila: pedido,
|
|
435
|
+
erro,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
return {
|
|
439
|
+
thread,
|
|
440
|
+
slug,
|
|
441
|
+
promptPath,
|
|
442
|
+
promptSha256: sha,
|
|
443
|
+
comando: resultado.comando,
|
|
444
|
+
sessionId: null,
|
|
445
|
+
verificada: false,
|
|
446
|
+
pausaAoFim,
|
|
447
|
+
dryRun: false,
|
|
448
|
+
model,
|
|
449
|
+
effort,
|
|
450
|
+
bloqueado: false,
|
|
451
|
+
motivo: 'runtime.unavailable',
|
|
452
|
+
violacoes,
|
|
453
|
+
naFila: null,
|
|
454
|
+
erro,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
concluirDespacho(ctx, resultado.sessionId, resultado.verificada, resultado.comando);
|
|
458
|
+
return {
|
|
459
|
+
thread,
|
|
460
|
+
slug,
|
|
461
|
+
promptPath,
|
|
462
|
+
promptSha256: sha,
|
|
463
|
+
comando: resultado.comando,
|
|
464
|
+
sessionId: resultado.sessionId,
|
|
465
|
+
verificada: resultado.verificada,
|
|
466
|
+
pausaAoFim,
|
|
467
|
+
dryRun: false,
|
|
468
|
+
model,
|
|
469
|
+
effort,
|
|
470
|
+
bloqueado: false,
|
|
471
|
+
motivo: null,
|
|
472
|
+
violacoes,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
/** Tabela de `ork phase list`: o historico do ledger da thread. */
|
|
476
|
+
function tabelaDoLedger(raiz, threadId) {
|
|
477
|
+
// Thread inexistente e erro, nao ledger vazio: o CLI precisa reprovar o id errado.
|
|
478
|
+
(0, thread_1.lerThread)(raiz, threadId);
|
|
479
|
+
const eventos = (0, ledger_1.lerLedger)((0, thread_1.dirThread)(raiz, threadId));
|
|
480
|
+
if (eventos.length === 0) {
|
|
481
|
+
return `Ledger vazio para a thread ${threadId}.`;
|
|
482
|
+
}
|
|
483
|
+
const linhas = eventos.map((e) => {
|
|
484
|
+
const detalhe = [];
|
|
485
|
+
if (e.fase)
|
|
486
|
+
detalhe.push(String(e.fase));
|
|
487
|
+
if (e.slug)
|
|
488
|
+
detalhe.push(String(e.slug));
|
|
489
|
+
if (e.sessionId)
|
|
490
|
+
detalhe.push(`sessao ${String(e.sessionId).slice(0, 8)}`);
|
|
491
|
+
if (e.decisao)
|
|
492
|
+
detalhe.push(String(e.decisao));
|
|
493
|
+
if (e.previstaSobre)
|
|
494
|
+
detalhe.push(`pausa sobre ${String(e.previstaSobre)}`);
|
|
495
|
+
if (e.encontrada !== undefined)
|
|
496
|
+
detalhe.push(`no runtime: ${e.encontrada ? 'sim' : 'nao'}`);
|
|
497
|
+
// Fato verificavel do despacho: o par modelo/esforco real, lido do proprio evento.
|
|
498
|
+
if (e.model)
|
|
499
|
+
detalhe.push(`modelo ${String(e.model)}/${String(e.effort ?? '-')}`);
|
|
500
|
+
// Eventos do bloco B1: motivo tipado, veredito e as provas do ship.
|
|
501
|
+
if (e.motivo)
|
|
502
|
+
detalhe.push(`motivo ${String(e.motivo)}`);
|
|
503
|
+
if (e.claim)
|
|
504
|
+
detalhe.push(`claim ${String(e.claim)}`);
|
|
505
|
+
if (e.veredito)
|
|
506
|
+
detalhe.push(`veredito: ${String(e.veredito)}`);
|
|
507
|
+
if (e.fonte && e.ocupacao !== undefined) {
|
|
508
|
+
detalhe.push(`ocupacao ${e.ocupacao === null ? 'nao medivel' : String(e.ocupacao)} (${String(e.fonte)})`);
|
|
509
|
+
}
|
|
510
|
+
if (e.slugSugerido)
|
|
511
|
+
detalhe.push(`proximo slug ${String(e.slugSugerido)}`);
|
|
512
|
+
if (e.lease)
|
|
513
|
+
detalhe.push(`lease ${String(e.lease)}`);
|
|
514
|
+
// Eventos do bloco B3: acao de retry, playbook da retomada e rodada de GO-FIX.
|
|
515
|
+
if (e.acao)
|
|
516
|
+
detalhe.push(`acao ${String(e.acao)}`);
|
|
517
|
+
if (e.playbook)
|
|
518
|
+
detalhe.push(`playbook ${String(e.playbook)}`);
|
|
519
|
+
if (e.pedido)
|
|
520
|
+
detalhe.push(`pedido ${String(e.pedido)}`);
|
|
521
|
+
if (e.rodada !== undefined)
|
|
522
|
+
detalhe.push(`rodada ${String(e.rodada)}`);
|
|
523
|
+
if (e.cobertura)
|
|
524
|
+
detalhe.push(`cobertura ${String(e.cobertura)}`);
|
|
525
|
+
if (e.liberaEm)
|
|
526
|
+
detalhe.push(`libera em ${String(e.liberaEm)}`);
|
|
527
|
+
if (e.tentativa !== undefined && e.limite !== undefined) {
|
|
528
|
+
detalhe.push(`tentativa ${String(e.tentativa)}/${String(e.limite)}`);
|
|
529
|
+
}
|
|
530
|
+
if (e.mergeSha)
|
|
531
|
+
detalhe.push(`merge ${String(e.mergeSha).slice(0, 8)}`);
|
|
532
|
+
if (e.shaRemoto)
|
|
533
|
+
detalhe.push(`remoto ${String(e.shaRemoto).slice(0, 8)}`);
|
|
534
|
+
if (e.pushVerificado !== undefined)
|
|
535
|
+
detalhe.push(`push provado: ${e.pushVerificado ? 'sim' : 'nao'}`);
|
|
536
|
+
if (e.autorizadoPor)
|
|
537
|
+
detalhe.push(`autorizado por ${String(e.autorizadoPor)}`);
|
|
538
|
+
if (e.sobre)
|
|
539
|
+
detalhe.push(`sobre ${String(e.sobre)}`);
|
|
540
|
+
if (e.estado)
|
|
541
|
+
detalhe.push(String(e.estado));
|
|
542
|
+
if (typeof e.de === 'string' && typeof e.para === 'string') {
|
|
543
|
+
detalhe.push(`${e.de} -> ${e.para}`);
|
|
544
|
+
}
|
|
545
|
+
if (e.dryRun === true)
|
|
546
|
+
detalhe.push('ensaio (--dry-run)');
|
|
547
|
+
if (e.tipo === ledger_1.TIPOS_DE_EVENTO.worktreeCriada && e.dir) {
|
|
548
|
+
detalhe.push(`${String(e.branch)} em ${String(e.dir)}`);
|
|
549
|
+
}
|
|
550
|
+
if (e.inline !== undefined) {
|
|
551
|
+
detalhe.push(`triagem ${String(e.inline)} inline / ${String(e.pointers)} ponteiros / ${String(e.summaries)} resumos`);
|
|
552
|
+
}
|
|
553
|
+
if (e.location)
|
|
554
|
+
detalhe.push(`ponteiro ${String(e.location)}`);
|
|
555
|
+
if (e.erro)
|
|
556
|
+
detalhe.push(`erro: ${String(e.erro)}`);
|
|
557
|
+
if (e.detalhe && !e.decisao)
|
|
558
|
+
detalhe.push(String(e.detalhe).slice(0, 90));
|
|
559
|
+
if (e.modo && !e.fase)
|
|
560
|
+
detalhe.push(`modo ${String(e.modo)}`);
|
|
561
|
+
return [e.ts.replace('T', ' ').slice(0, 19), e.tipo, detalhe.join(' | ')];
|
|
562
|
+
});
|
|
563
|
+
return (0, util_1.tabela)(['QUANDO', 'EVENTO', 'DETALHE'], linhas);
|
|
564
|
+
}
|
|
565
|
+
/** Slug legivel por humano de uma sessao (usado nas mensagens do CLI). */
|
|
566
|
+
function descreverSlug(slug) {
|
|
567
|
+
const p = (0, slug_1.parseSlug)(slug);
|
|
568
|
+
if (!p)
|
|
569
|
+
return slug;
|
|
570
|
+
const rot = p.rotacao ? `, rotacao ${p.rotacao}` : '';
|
|
571
|
+
return `produto "${p.produto}", assunto "${p.assunto}", fases "${p.fases}"${rot}`;
|
|
572
|
+
}
|