@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.
Files changed (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +87 -0
  3. package/adapters/README.md +22 -0
  4. package/adapters/claude-code/.claude-plugin/marketplace.json +15 -0
  5. package/adapters/claude-code/.claude-plugin/plugin.json +31 -0
  6. package/adapters/claude-code/README.md +102 -0
  7. package/adapters/claude-code/agents/ork-check.md +32 -0
  8. package/adapters/claude-code/agents/ork-go.md +32 -0
  9. package/adapters/claude-code/agents/ork-goal.md +33 -0
  10. package/adapters/claude-code/agents/ork-master.md +32 -0
  11. package/adapters/claude-code/agents/ork-plan.md +32 -0
  12. package/adapters/claude-code/agents/ork-ship.md +32 -0
  13. package/adapters/claude-code/commands/check.md +45 -0
  14. package/adapters/claude-code/commands/go.md +46 -0
  15. package/adapters/claude-code/commands/goal.md +54 -0
  16. package/adapters/claude-code/commands/master.md +42 -0
  17. package/adapters/claude-code/commands/ork.md +37 -0
  18. package/adapters/claude-code/commands/plan.md +47 -0
  19. package/adapters/claude-code/commands/ship.md +45 -0
  20. package/adapters/claude-code/hooks/hooks.json +17 -0
  21. package/adapters/claude-code/hooks/ork-guard.js +130 -0
  22. package/adapters/hermes/README.md +45 -0
  23. package/adapters/hermes/bin/ork-abrir-thread.sh +25 -0
  24. package/adapters/hermes/hermes.plugin.json +21 -0
  25. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +116 -0
  26. package/adapters/openclaw/README.md +63 -0
  27. package/adapters/openclaw/bin/ork-abrir-thread.sh +24 -0
  28. package/adapters/openclaw/openclaw.plugin.json +138 -0
  29. package/dist/adapters/claude-bg.js +308 -0
  30. package/dist/auditoria.js +848 -0
  31. package/dist/auditrun.js +976 -0
  32. package/dist/board.js +314 -0
  33. package/dist/canarios.js +271 -0
  34. package/dist/catalogo.js +124 -0
  35. package/dist/ciclos.js +156 -0
  36. package/dist/claims.js +226 -0
  37. package/dist/divida.js +374 -0
  38. package/dist/doctor.js +246 -0
  39. package/dist/evalrunner.js +458 -0
  40. package/dist/fix.js +450 -0
  41. package/dist/gates.js +92 -0
  42. package/dist/handoff.js +521 -0
  43. package/dist/hosts.js +331 -0
  44. package/dist/index.js +1910 -0
  45. package/dist/init.js +231 -0
  46. package/dist/leases.js +508 -0
  47. package/dist/ledger.js +138 -0
  48. package/dist/manifest.js +255 -0
  49. package/dist/master.js +453 -0
  50. package/dist/memoria.js +773 -0
  51. package/dist/modos.js +220 -0
  52. package/dist/orkmind.js +487 -0
  53. package/dist/orquestracao.js +559 -0
  54. package/dist/phase.js +572 -0
  55. package/dist/policies.js +176 -0
  56. package/dist/prompts.js +406 -0
  57. package/dist/ratelimit.js +179 -0
  58. package/dist/recall.js +252 -0
  59. package/dist/retry.js +917 -0
  60. package/dist/sandbox.js +94 -0
  61. package/dist/sessoes.js +104 -0
  62. package/dist/ship.js +551 -0
  63. package/dist/slug.js +100 -0
  64. package/dist/superficie.js +1347 -0
  65. package/dist/thread.js +333 -0
  66. package/dist/tokens.js +228 -0
  67. package/dist/types.js +20 -0
  68. package/dist/util.js +156 -0
  69. package/dist/verify.js +262 -0
  70. package/dist/worktree.js +576 -0
  71. package/dist/yaml.js +112 -0
  72. package/eval/README.md +85 -0
  73. package/eval/casos/check-quality.json +103 -0
  74. package/eval/casos/code-reviewer.json +102 -0
  75. package/eval/casos/decision-triage.json +103 -0
  76. package/eval/casos/go-implementation.json +103 -0
  77. package/eval/casos/goal-definition.json +103 -0
  78. package/eval/casos/master-metrics.json +103 -0
  79. package/eval/casos/narrative-guardian.json +163 -0
  80. package/eval/casos/orkastery-bootstrap.json +102 -0
  81. package/eval/casos/plan-specification.json +102 -0
  82. package/eval/casos/roadmap-keeper.json +103 -0
  83. package/eval/casos/scope-check-capability-map.json +83 -0
  84. package/eval/casos/security-auditor.json +102 -0
  85. package/eval/casos/ship-release.json +122 -0
  86. package/eval/casos/test-engineer.json +122 -0
  87. package/eval/casos/thread-state.json +82 -0
  88. package/eval/casos/thread-tracing.json +83 -0
  89. package/eval/casos/web-performance-auditor.json +102 -0
  90. package/eval/fixtures/b0-slug-e-modos/caso.json +56 -0
  91. package/eval/fixtures/b2-master-log/caso.json +91 -0
  92. package/eval/fixtures/fx-concurrency/caso.json +15 -0
  93. package/eval/fixtures/fx-hallucination/caso.json +12 -0
  94. package/eval/fixtures/fx-happy/caso.json +16 -0
  95. package/eval/fixtures/fx-schema-drift/caso.json +15 -0
  96. package/eval/fixtures/fx-stale-base/caso.json +12 -0
  97. package/eval/fixtures/fx-wiki-destroy/caso.json +16 -0
  98. package/eval/fixtures/superficie-de-rede/README.md +22 -0
  99. package/eval/fixtures/superficie-de-rede/api-express.js +30 -0
  100. package/eval/fixtures/superficie-de-rede/api_fastapi.py +17 -0
  101. package/eval/fixtures/superficie-de-rede/api_gin.go +18 -0
  102. package/package.json +56 -0
  103. package/references/README.md +25 -0
  104. package/references/code-review-axes.md +82 -0
  105. package/references/definition-of-done.md +74 -0
  106. package/references/performance-checklist.md +53 -0
  107. package/references/security-checklist.md +101 -0
  108. package/references/testing-patterns.md +51 -0
  109. package/skills/README.md +43 -0
  110. package/skills/core/orkastery-bootstrap/SKILL.md +89 -0
  111. package/skills/core/thread-state/SKILL.md +86 -0
  112. package/skills/governance/decision-triage/SKILL.md +65 -0
  113. package/skills/governance/narrative-guardian/SKILL.md +66 -0
  114. package/skills/governance/roadmap-keeper/SKILL.md +60 -0
  115. package/skills/governance/scope-check-capability-map/SKILL.md +61 -0
  116. package/skills/observability/thread-tracing/SKILL.md +63 -0
  117. package/skills/phases/check-quality/SKILL.md +87 -0
  118. package/skills/phases/go-implementation/SKILL.md +70 -0
  119. package/skills/phases/goal-definition/SKILL.md +69 -0
  120. package/skills/phases/master-metrics/SKILL.md +65 -0
  121. package/skills/phases/plan-specification/SKILL.md +67 -0
  122. package/skills/phases/ship-release/SKILL.md +68 -0
  123. package/skills/reviewers/code-reviewer/SKILL.md +61 -0
  124. package/skills/reviewers/security-auditor/SKILL.md +68 -0
  125. package/skills/reviewers/test-engineer/SKILL.md +66 -0
  126. package/skills/reviewers/web-performance-auditor/SKILL.md +63 -0
package/dist/board.js ADDED
@@ -0,0 +1,314 @@
1
+ "use strict";
2
+ /**
3
+ * `ork board --all` e `ork board plan`: a visao unica e o escalonador por maquina (B2).
4
+ *
5
+ * `board --all` responde "o que esta rolando nesta maquina agora", com todas as threads
6
+ * de todos os perfis encontrados: id, slug, modo, fase, status, pausas, worktree e leases.
7
+ *
8
+ * `board plan` responde a pergunta seguinte, que e a que evita incidente: "quem PODE
9
+ * avancar agora?". Ele respeita duas coisas ao mesmo tempo:
10
+ * - `concurrency.max_parallel_threads` do manifesto (quantas threads a maquina aguenta);
11
+ * - os leases e a fila por colisao (quem esta na regiao de quem).
12
+ *
13
+ * O `main-tree` continua sendo o UNICO gate de merge: o escalonador nao mergeia nada, ele
14
+ * apenas mostra a fila serializada que o `ork ship` ja obedece.
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.perfisDetectados = perfisDetectados;
51
+ exports.threadsDeTodosOsPerfis = threadsDeTodosOsPerfis;
52
+ exports.planejar = planejar;
53
+ exports.textoDoPlano = textoDoPlano;
54
+ exports.textoDoBoard = textoDoBoard;
55
+ const fs = __importStar(require("node:fs"));
56
+ const path = __importStar(require("node:path"));
57
+ const leases_1 = require("./leases");
58
+ const manifest_1 = require("./manifest");
59
+ const modos_1 = require("./modos");
60
+ const thread_1 = require("./thread");
61
+ const util_1 = require("./util");
62
+ /**
63
+ * Perfis detectados no projeto.
64
+ *
65
+ * O perfil padrao e o do manifesto (`board.default`), servido por `.orkastery/threads`.
66
+ * Perfis adicionais sao detectados em `.orkastery/perfis/<nome>/`, quando existirem: e
67
+ * assim que uma segunda configuracao de board entra no `--all` sem mudar o layout de disco.
68
+ */
69
+ function perfisDetectados(carregado) {
70
+ const perfis = [
71
+ { nome: carregado.manifesto.board.default || 'default', raiz: carregado.raiz },
72
+ ];
73
+ const dirPerfis = path.join((0, manifest_1.dirEstado)(carregado.raiz), 'perfis');
74
+ if (fs.existsSync(dirPerfis)) {
75
+ for (const e of fs.readdirSync(dirPerfis, { withFileTypes: true })) {
76
+ if (!e.isDirectory())
77
+ continue;
78
+ const raiz = path.join(dirPerfis, e.name);
79
+ if (fs.existsSync(path.join(raiz, '.orkastery', 'threads'))) {
80
+ perfis.push({ nome: e.name, raiz });
81
+ }
82
+ }
83
+ }
84
+ return perfis;
85
+ }
86
+ /** Todas as threads de todos os perfis, com os leases e a fila de cada uma. */
87
+ function threadsDeTodosOsPerfis(carregado, todos = true) {
88
+ const perfis = todos ? perfisDetectados(carregado) : perfisDetectados(carregado).slice(0, 1);
89
+ const saida = [];
90
+ for (const perfil of perfis) {
91
+ const fila = (0, leases_1.lerFila)(perfil.raiz);
92
+ for (const id of (0, thread_1.listarIds)(perfil.raiz)) {
93
+ const thread = (0, thread_1.lerThread)(perfil.raiz, id);
94
+ saida.push({
95
+ perfil: perfil.nome,
96
+ raiz: perfil.raiz,
97
+ thread,
98
+ leases: (0, leases_1.leasesDaThread)(perfil.raiz, id).map((l) => l.nome),
99
+ naFila: fila.filter((p) => p.thread === id),
100
+ });
101
+ }
102
+ }
103
+ return saida;
104
+ }
105
+ /**
106
+ * Escalonador por maquina: decide quem avanca agora e quem espera, com motivo tipado.
107
+ *
108
+ * A ordem e FIFO por criacao da thread. Quem ja segura lease conta como em andamento e
109
+ * ocupa vaga: e o unico jeito de o limite de paralelismo significar alguma coisa.
110
+ */
111
+ function planejar(carregado) {
112
+ const { raiz, manifesto } = carregado;
113
+ const max = Math.max(1, manifesto.concurrency.max_parallel_threads);
114
+ const fila = (0, leases_1.lerFila)(raiz);
115
+ const ativos = (0, leases_1.listarLeases)(raiz).filter((l) => !(0, leases_1.expirado)(l));
116
+ const threads = (0, thread_1.listarIds)(raiz)
117
+ .map((id) => (0, thread_1.lerThread)(raiz, id))
118
+ .sort((a, b) => a.criadaEm.localeCompare(b.criadaEm));
119
+ const vagas = [];
120
+ let ocupadas = 0;
121
+ // 1a passada: quem ja segura lease esta em andamento e ocupa vaga.
122
+ const emAndamento = new Set();
123
+ for (const t of threads) {
124
+ const meus = ativos.filter((l) => l.thread === t.id).map((l) => l.nome);
125
+ if (t.status === 'fechada' || meus.length === 0)
126
+ continue;
127
+ emAndamento.add(t.id);
128
+ ocupadas += 1;
129
+ vagas.push({
130
+ thread: t.id,
131
+ slug: t.slug,
132
+ modo: t.modo,
133
+ fase: t.faseAtual,
134
+ situacao: 'em-andamento',
135
+ motivo: null,
136
+ detalhe: `segura ${meus.join(', ')}`,
137
+ correcao: '',
138
+ leases: meus,
139
+ });
140
+ }
141
+ // 2a passada: as demais, em FIFO, ate o limite de paralelismo da maquina.
142
+ for (const t of threads) {
143
+ if (emAndamento.has(t.id))
144
+ continue;
145
+ if (t.status === 'fechada') {
146
+ vagas.push({
147
+ thread: t.id,
148
+ slug: t.slug,
149
+ modo: t.modo,
150
+ fase: t.faseAtual,
151
+ situacao: 'fechada',
152
+ motivo: null,
153
+ detalhe: t.score ? `score ${t.score.valor}/5 registrado` : 'fechada sem score registrado',
154
+ correcao: t.score ? '' : `ork master ${t.id} --score <0-5> --justificativa "<por que>"`,
155
+ leases: [],
156
+ });
157
+ continue;
158
+ }
159
+ if (t.status === 'pausada') {
160
+ vagas.push({
161
+ thread: t.id,
162
+ slug: t.slug,
163
+ modo: t.modo,
164
+ fase: t.faseAtual,
165
+ situacao: 'pausada',
166
+ motivo: 'human.pending',
167
+ detalhe: `esperando veredito humano na fase ${t.faseAtual}`,
168
+ correcao: `ork gate approve ${t.id} <sobre> --por <quem>`,
169
+ leases: [],
170
+ });
171
+ continue;
172
+ }
173
+ const esperas = fila.filter((p) => p.thread === t.id);
174
+ if (esperas.length > 0) {
175
+ const p = esperas[0];
176
+ vagas.push({
177
+ thread: t.id,
178
+ slug: t.slug,
179
+ modo: t.modo,
180
+ fase: t.faseAtual,
181
+ situacao: 'espera',
182
+ motivo: 'lease.busy',
183
+ detalhe: `na fila de ${p.nome}, atras da thread ${p.bloqueadaPor} (colide com ${p.colidiuCom})`,
184
+ correcao: `espere a thread ${p.bloqueadaPor} liberar, ou reduza a regiao pedida`,
185
+ leases: [],
186
+ });
187
+ continue;
188
+ }
189
+ if (ocupadas >= max) {
190
+ vagas.push({
191
+ thread: t.id,
192
+ slug: t.slug,
193
+ modo: t.modo,
194
+ fase: t.faseAtual,
195
+ situacao: 'espera',
196
+ motivo: 'concurrency.limite',
197
+ detalhe: `a maquina ja tem ${ocupadas} thread(s) em andamento, o limite e ${max}`,
198
+ correcao: 'espere uma thread liberar, ou suba concurrency.max_parallel_threads no orkastery.yaml',
199
+ leases: [],
200
+ });
201
+ continue;
202
+ }
203
+ ocupadas += 1;
204
+ vagas.push({
205
+ thread: t.id,
206
+ slug: t.slug,
207
+ modo: t.modo,
208
+ fase: t.faseAtual,
209
+ situacao: 'pode-avancar',
210
+ motivo: null,
211
+ detalhe: `vaga ${ocupadas}/${max}, sem colisao de lease`,
212
+ correcao: '',
213
+ leases: [],
214
+ });
215
+ }
216
+ return {
217
+ maxParalelas: max,
218
+ emAndamento: emAndamento.size,
219
+ vagas,
220
+ filaDeMerge: (0, leases_1.esperandoPor)(raiz, leases_1.LEASE_MAIN_TREE),
221
+ filaDeRegiao: fila.filter((p) => p.tipo !== 'main-tree'),
222
+ decididoEm: (0, util_1.agora)(),
223
+ };
224
+ }
225
+ function linhaDeFila(p, i) {
226
+ return ` ${i + 1}. ${p.thread} quer ${p.nome} (colide com ${p.colidiuCom}, thread ${p.bloqueadaPor}) desde ${p.desdeEm}`;
227
+ }
228
+ /** Texto de `ork board plan`. */
229
+ function textoDoPlano(plano) {
230
+ const linhas = [];
231
+ linhas.push('Escalonador por maquina');
232
+ linhas.push(` limite de paralelismo: ${plano.maxParalelas} (concurrency.max_parallel_threads) | ` +
233
+ `em andamento agora: ${plano.emAndamento}`);
234
+ linhas.push('');
235
+ if (plano.vagas.length === 0) {
236
+ linhas.push(' Nenhuma thread no projeto.');
237
+ }
238
+ else {
239
+ linhas.push((0, util_1.tabela)(['THREAD', 'SLUG', 'MODO', 'FASE', 'SITUACAO', 'MOTIVO', 'DETALHE'], plano.vagas.map((v) => [
240
+ v.thread,
241
+ v.slug,
242
+ (0, modos_1.tagDoModo)(v.modo),
243
+ v.fase,
244
+ v.situacao,
245
+ v.motivo ?? '-',
246
+ v.detalhe,
247
+ ])));
248
+ const comCorrecao = plano.vagas.filter((v) => v.correcao !== '');
249
+ if (comCorrecao.length > 0) {
250
+ linhas.push('');
251
+ linhas.push(' Correcoes acionaveis:');
252
+ for (const v of comCorrecao)
253
+ linhas.push(` ${v.thread}: ${v.correcao}`);
254
+ }
255
+ }
256
+ linhas.push('');
257
+ linhas.push(`Merge queue (lease ${leases_1.LEASE_MAIN_TREE}, o unico gate de merge)`);
258
+ if (plano.filaDeMerge.length === 0) {
259
+ linhas.push(' vazia: nenhuma thread esperando para mergear');
260
+ }
261
+ else {
262
+ plano.filaDeMerge.forEach((p, i) => linhas.push(linhaDeFila(p, i)));
263
+ }
264
+ linhas.push('');
265
+ linhas.push('Fila por colisao de regiao');
266
+ if (plano.filaDeRegiao.length === 0) {
267
+ linhas.push(' vazia: nenhuma colisao de path, board ou porta');
268
+ }
269
+ else {
270
+ plano.filaDeRegiao.forEach((p, i) => linhas.push(linhaDeFila(p, i)));
271
+ }
272
+ return linhas.join('\n');
273
+ }
274
+ /** Texto de `ork board [--all]`: a visao unica das threads. */
275
+ function textoDoBoard(carregado, todos) {
276
+ const itens = threadsDeTodosOsPerfis(carregado, todos);
277
+ const perfis = todos ? perfisDetectados(carregado) : perfisDetectados(carregado).slice(0, 1);
278
+ const linhas = [];
279
+ linhas.push(`Board do Orkastery, projeto ${carregado.manifesto.project.name} ` +
280
+ `(${itens.length} thread(s) em ${perfis.length} perfil(is): ${perfis.map((p) => p.nome).join(', ')})`);
281
+ linhas.push('');
282
+ if (itens.length === 0) {
283
+ linhas.push(' Nenhuma thread ainda. Crie uma com: ork thread new "<nome>" --modo default');
284
+ return linhas.join('\n');
285
+ }
286
+ linhas.push((0, util_1.tabela)(['PERFIL', 'ID', 'SLUG', 'MODO', 'FASE', 'STATUS', 'PAUSAS', 'SCORE', 'WORKTREE', 'LEASES'], itens.map((i) => [
287
+ i.perfil,
288
+ i.thread.id,
289
+ i.thread.slug,
290
+ (0, modos_1.tagDoModo)(i.thread.modo),
291
+ i.thread.faseAtual,
292
+ i.thread.status,
293
+ String((0, thread_1.pausasDaThread)(i.thread)),
294
+ i.thread.score ? `${i.thread.score.valor}/5` : '-',
295
+ i.thread.worktree ? path.basename(i.thread.worktree) : '-',
296
+ i.leases.length > 0 ? i.leases.join(' ') : i.naFila.length > 0 ? `fila:${i.naFila[0].nome}` : '-',
297
+ ])));
298
+ const comVariante = itens.filter((i) => i.thread.variante);
299
+ if (comVariante.length > 0) {
300
+ linhas.push('');
301
+ linhas.push(' Variantes de ciclo em uso:');
302
+ for (const i of comVariante)
303
+ linhas.push(` ${i.thread.id}: --ciclo ${i.thread.variante}`);
304
+ }
305
+ linhas.push('');
306
+ linhas.push(textoDoPlano(planejar(carregado)));
307
+ const semScore = itens.filter((i) => !i.thread.score && i.thread.faseAtual === 'MASTER');
308
+ if (semScore.length > 0) {
309
+ linhas.push('');
310
+ linhas.push(`Fila de batch scoring: ${semScore.length} thread(s) esperando score humano`);
311
+ linhas.push(' veja em: ork master --batch');
312
+ }
313
+ return linhas.join('\n');
314
+ }
@@ -0,0 +1,271 @@
1
+ "use strict";
2
+ /**
3
+ * Os 6 canarios de `ork eval` (bloco B4).
4
+ *
5
+ * Canario nao e teste unitario: e um comportamento inteiro do produto, exercitado ponta a
6
+ * ponta contra git de verdade, que precisa continuar acontecendo depois de qualquer mudanca.
7
+ * Cada um nasce de um jeito conhecido de o trabalho de um agente parecer certo e nao ser:
8
+ *
9
+ * fx-happy o ciclo que funciona, para o eval nao provar so o que quebra
10
+ * fx-hallucination arquivo citado que nao existe: a alegacao reprova na reexecucao
11
+ * fx-stale-base a base andou embaixo da thread e o `ork` percebe antes do merge
12
+ * fx-wiki-destroy comando destrutivo em massa barrado pelo guard e pela policy
13
+ * fx-schema-drift o contrato congelado do MASTER log recusa mutacao
14
+ * fx-concurrency duas threads na mesma regiao: a segunda entra na fila, nao escreve
15
+ *
16
+ * A DIVISAO DE TRABALHO E DELIBERADA: o executor aqui e codigo tipado, e o que se espera dele
17
+ * e dado versionado em `eval/fixtures/<id>/caso.json`. Assim a expectativa e revisavel por
18
+ * quem nao le TypeScript, e mudar o comportamento esperado e um diff que aparece na revisao.
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ exports.gitDisponivel = exports.CANARIOS = void 0;
55
+ exports.canarioPorId = canarioPorId;
56
+ const node_child_process_1 = require("node:child_process");
57
+ const fs = __importStar(require("node:fs"));
58
+ const path = __importStar(require("node:path"));
59
+ const claims_1 = require("./claims");
60
+ const leases_1 = require("./leases");
61
+ const master_1 = require("./master");
62
+ const policies_1 = require("./policies");
63
+ const phase_1 = require("./phase");
64
+ const sandbox_1 = require("./sandbox");
65
+ Object.defineProperty(exports, "gitDisponivel", { enumerable: true, get: function () { return sandbox_1.gitDisponivel; } });
66
+ const thread_1 = require("./thread");
67
+ const verify_1 = require("./verify");
68
+ const worktree_1 = require("./worktree");
69
+ function comSandbox(nome, fn) {
70
+ const s = (0, sandbox_1.sandboxGit)(nome);
71
+ try {
72
+ return fn(s);
73
+ }
74
+ finally {
75
+ s.limpar();
76
+ }
77
+ }
78
+ /** fx-happy: o ciclo que funciona, do `thread new` ao `verify` verde. */
79
+ const fxHappy = {
80
+ id: 'fx-happy',
81
+ sobre: 'thread aberta, fase montada com prompt gravado e claim verificada no HEAD real',
82
+ precisaDeGit: true,
83
+ rodar: () => comSandbox('happy', (s) => {
84
+ const { thread } = (0, thread_1.novaThread)(s.carregado, { nome: 'checkout', modo: 'ork' });
85
+ const corrida = (0, phase_1.rodarFase)(s.carregado, thread.id, {
86
+ fase: 'GOAL',
87
+ prompt: 'Mapear o objetivo do checkout',
88
+ dryRun: true,
89
+ });
90
+ (0, claims_1.adicionarClaim)(s.dir, thread.id, {
91
+ arquivo: 'README.md',
92
+ alegacao: 'o README do projeto existe e esta versionado',
93
+ verificar: ['test -f README.md'],
94
+ fase: 'GOAL',
95
+ });
96
+ const v = (0, verify_1.verificar)(s.carregado, thread.id, { soClaims: true });
97
+ return {
98
+ slug: thread.slug,
99
+ modo: thread.modo,
100
+ pausas: thread.blocos.filter((b) => b.pausa).length,
101
+ promptGravado: fs.existsSync(corrida.promptPath),
102
+ promptSha256Hex: /^[0-9a-f]{64}$/.test(corrida.promptSha256),
103
+ despachoBloqueado: corrida.bloqueado,
104
+ verifyOk: v.ok,
105
+ motivos: v.motivos,
106
+ };
107
+ }),
108
+ };
109
+ /** fx-hallucination: a citacao sem lastro reprova na reexecucao, com motivo tipado. */
110
+ const fxHallucination = {
111
+ id: 'fx-hallucination',
112
+ sobre: 'arquivo e teste citados pelo agente que nao existem no repositorio',
113
+ precisaDeGit: true,
114
+ rodar: () => comSandbox('hallucination', (s) => {
115
+ const { thread } = (0, thread_1.novaThread)(s.carregado, { nome: 'alucinada', modo: 'auto' });
116
+ (0, claims_1.adicionarClaim)(s.dir, thread.id, {
117
+ arquivo: 'src/pagamentos.ts',
118
+ alegacao: 'implementei src/pagamentos.ts e o teste de pagamento passa',
119
+ verificar: ['test -f src/pagamentos.ts'],
120
+ fase: 'GO',
121
+ });
122
+ (0, claims_1.adicionarClaim)(s.dir, thread.id, {
123
+ arquivo: 'README.md',
124
+ alegacao: 'nao existe nenhum TODO em lugar nenhum do repositorio',
125
+ fase: 'GO',
126
+ });
127
+ const v = (0, verify_1.verificar)(s.carregado, thread.id, { soClaims: true });
128
+ return {
129
+ // O modo mais autonomo do espectro nao afrouxa a verificacao: `#Auto` reprova igual.
130
+ modo: thread.modo,
131
+ verifyOk: v.ok,
132
+ motivos: [...new Set(v.motivos)].sort(),
133
+ claimsReprovadas: v.claims.filter((c) => !c.verificado).length,
134
+ };
135
+ }),
136
+ };
137
+ /** fx-stale-base: a base andou embaixo da thread e o `ork` percebe antes do merge. */
138
+ const fxStaleBase = {
139
+ id: 'fx-stale-base',
140
+ sobre: 'a branch base avancou depois de a thread carimbar a sua base',
141
+ precisaDeGit: true,
142
+ rodar: () => comSandbox('stalebase', (s) => {
143
+ const { thread } = (0, thread_1.novaThread)(s.carregado, {
144
+ nome: 'baseandou',
145
+ modo: 'classic',
146
+ criarWorktree: true,
147
+ });
148
+ (0, worktree_1.garantirWorktree)(s.carregado, thread.id);
149
+ const antes = (0, worktree_1.auditarWorktree)(s.carregado, thread.id);
150
+ (0, sandbox_1.commitar)(s.dir, 'MUDOU.md', '# a base andou\n', 'commit na base depois da thread');
151
+ const depois = (0, worktree_1.auditarWorktree)(s.carregado, thread.id);
152
+ const checkBase = depois.checks.find((c) => c.nome === 'base');
153
+ return {
154
+ auditavaAntes: antes.ok,
155
+ auditaDepois: depois.ok,
156
+ checkDaBase: checkBase ? checkBase.nivel : 'ausente',
157
+ correcao: checkBase?.correcao ?? '',
158
+ };
159
+ }),
160
+ };
161
+ /** fx-wiki-destroy: comando destrutivo em massa barrado no host e na entrega. */
162
+ const fxWikiDestroy = {
163
+ id: 'fx-wiki-destroy',
164
+ sobre: 'agente tenta apagar trabalho alheio em massa, no host e na entrega',
165
+ precisaDeGit: false,
166
+ rodar: (ctx) => {
167
+ const guard = path.join(ctx.catalogo, 'adapters', 'claude-code', 'hooks', 'ork-guard.js');
168
+ const decidir = (comando) => {
169
+ const entrada = JSON.stringify({ tool_name: 'Bash', tool_input: { command: comando } });
170
+ try {
171
+ const saida = (0, node_child_process_1.execFileSync)(process.execPath, [guard], {
172
+ input: entrada,
173
+ encoding: 'utf8',
174
+ // stderr capturado: o guard fala com o host, nao com a saida do `ork eval`.
175
+ stdio: ['pipe', 'pipe', 'pipe'],
176
+ });
177
+ return { decisao: JSON.parse(saida).hookSpecificOutput.permissionDecision, codigo: 0 };
178
+ }
179
+ catch (e) {
180
+ const erro = e;
181
+ const saida = JSON.parse(erro.stdout ?? '{}');
182
+ return {
183
+ decisao: saida.hookSpecificOutput?.permissionDecision ?? 'sem-decisao',
184
+ codigo: erro.status ?? -1,
185
+ };
186
+ }
187
+ };
188
+ // A outra metade do canario: a policy bloqueante do nucleo, que reprova entregar em cima
189
+ // da propria base. Guard do host e policy do nucleo sao defesas independentes de proposito.
190
+ const manifesto = {
191
+ runtime: { provider_policy: 'subscription-only' },
192
+ policies: { push_direto_na_base: 'block' },
193
+ };
194
+ const violacoes = (0, policies_1.avaliarPolicies)(manifesto, {
195
+ gate: 'ship',
196
+ de: 'main',
197
+ para: 'main',
198
+ baseBranch: 'main',
199
+ });
200
+ return {
201
+ gitAddEmMassa: decidir('git add -A').decisao,
202
+ codigoDoGitAdd: decidir('git add -A').codigo,
203
+ removeRecursivo: decidir('rm -rf $ALVO/').decisao,
204
+ resetDestrutivo: decidir('git reset --hard origin/main').decisao,
205
+ forcePush: decidir('git push --force origin main').decisao,
206
+ comandoDoOrkPassa: decidir('ork ship ork-x --para main').decisao,
207
+ addNomeadoPassa: decidir('git add -- src/pagamentos.ts').decisao,
208
+ policyDoShipBloqueia: (0, policies_1.bloqueantes)(violacoes).length,
209
+ };
210
+ },
211
+ };
212
+ /** fx-schema-drift: o contrato congelado do MASTER log recusa mutacao. */
213
+ const fxSchemaDrift = {
214
+ id: 'fx-schema-drift',
215
+ sobre: 'MASTER log com contrato, escala ou catalogo de classes alterados',
216
+ precisaDeGit: false,
217
+ rodar: (ctx) => {
218
+ const caminho = path.join(ctx.catalogo, 'eval', 'fixtures', 'b2-master-log', 'caso.json');
219
+ const fixture = JSON.parse(fs.readFileSync(caminho, 'utf8'));
220
+ const erroDe = (mudanca) => (0, master_1.validarMasterLog)({ ...fixture.valido, ...mudanca }).length;
221
+ return {
222
+ validoPassa: (0, master_1.validarMasterLog)(fixture.valido).length === 0,
223
+ contratoTrocado: erroDe({ contrato: 'ork.master-log/v2' }) > 0,
224
+ scoreForaDaEscala: erroDe({ score: 7 }) > 0,
225
+ classeInventada: erroDe({ classesDeFalha: ['quase-deu-certo'] }) > 0,
226
+ faseForaDoCiclo: erroDe({ fases: ['GOAL', 'F7'] }) > 0,
227
+ justificativaVazia: erroDe({ justificativa: '' }) > 0,
228
+ evidenciaAusente: erroDe({ evidencia: { eventos: 0 } }) > 0,
229
+ };
230
+ },
231
+ };
232
+ /** fx-concurrency: duas threads na mesma regiao, a segunda entra na fila. */
233
+ const fxConcurrency = {
234
+ id: 'fx-concurrency',
235
+ sobre: 'duas threads pedindo regiao que se cruza, com fila FIFO em vez de escrita por cima',
236
+ precisaDeGit: true,
237
+ rodar: () => comSandbox('concurrency', (s) => {
238
+ const a = (0, thread_1.novaThread)(s.carregado, { nome: 'primeira', modo: 'classic' }).thread;
239
+ const b = (0, thread_1.novaThread)(s.carregado, { nome: 'segunda', modo: 'maestro' }).thread;
240
+ const pedidoA = (0, leases_1.adquirirRegiao)(s.dir, 'path:core/src/**', {
241
+ thread: a.id,
242
+ motivo: 'GO da primeira',
243
+ });
244
+ const pedidoB = (0, leases_1.adquirirRegiao)(s.dir, 'path:core/src/board.ts', {
245
+ thread: b.id,
246
+ motivo: 'GO da segunda',
247
+ });
248
+ return {
249
+ primeiraAdquiriu: pedidoA.ok,
250
+ segundaAdquiriu: pedidoB.ok,
251
+ segundaNaFila: pedidoB.esperando,
252
+ posicaoDaSegunda: pedidoB.posicaoNaFila,
253
+ motivoDaSegunda: pedidoB.motivo,
254
+ colidiuComAThread: pedidoB.colidiuCom ? pedidoB.colidiuCom.thread : null,
255
+ threadDaPrimeira: a.id,
256
+ };
257
+ }),
258
+ };
259
+ /** Os canarios registrados, na ordem em que o `ork eval` os roda. */
260
+ exports.CANARIOS = [
261
+ fxHappy,
262
+ fxHallucination,
263
+ fxStaleBase,
264
+ fxWikiDestroy,
265
+ fxSchemaDrift,
266
+ fxConcurrency,
267
+ ];
268
+ /** Um canario por id, ou null quando a fixture aponta para um canario que nao existe. */
269
+ function canarioPorId(id) {
270
+ return exports.CANARIOS.find((c) => c.id === id) ?? null;
271
+ }