@orkastery/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -65
  3. package/adapters/README.md +30 -15
  4. package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
  5. package/adapters/claude-code/README.md +110 -8
  6. package/adapters/claude-code/commands/onboarding.md +21 -0
  7. package/adapters/claude-code/commands/ork.md +99 -27
  8. package/adapters/claude-code/hooks/hooks.json +6 -1
  9. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  10. package/adapters/codex/skills/ork/SKILL.md +57 -0
  11. package/adapters/hermes/README.md +163 -0
  12. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  13. package/adapters/hermes/bin/ork-brain.sh +4 -0
  14. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  15. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  16. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  17. package/adapters/hermes/bin/ork-objective-message.sh +17 -0
  18. package/adapters/hermes/bin/ork-objective-status.sh +12 -0
  19. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  20. package/adapters/hermes/hermes.plugin.json +26 -4
  21. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  22. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  23. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  24. package/adapters/openclaw/README.md +135 -26
  25. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  26. package/adapters/openclaw/construir.sh +19 -0
  27. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  28. package/adapters/openclaw/dist/index.js +437 -0
  29. package/adapters/openclaw/openclaw.plugin.json +39 -134
  30. package/adapters/openclaw/package.json +26 -0
  31. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  32. package/adapters/openclaw/src/index.ts +458 -0
  33. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  34. package/adapters/openclaw/tsconfig.json +15 -0
  35. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  36. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  37. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  38. package/assets/docs/produto/README.md +14 -0
  39. package/assets/docs/produto/_modelo-feature.md +59 -0
  40. package/assets/docs/roadmap/README.md +14 -0
  41. package/assets/docs/roadmap/_modelo-item.md +73 -0
  42. package/assets/orkmind-native-schema.json +32 -0
  43. package/assets/orkmind_bridge.py +357 -0
  44. package/assets/orkmind_fixture.py +67 -0
  45. package/assets/orkmind_prospective.py +138 -0
  46. package/assets/reference-tariffs-i07.json +23 -0
  47. package/dist/adapters/claude-bg.js +488 -39
  48. package/dist/adapters/codex-controller-sensor.js +449 -0
  49. package/dist/adapters/codex-controller-worker.js +361 -0
  50. package/dist/adapters/codex-controller.js +252 -0
  51. package/dist/adapters/codex-events.js +205 -0
  52. package/dist/adapters/codex-question.js +26 -0
  53. package/dist/adapters/codex-runner.js +133 -0
  54. package/dist/adapters/codex.js +394 -0
  55. package/dist/agents-md.js +84 -0
  56. package/dist/auditoria.js +11 -8
  57. package/dist/auditrun.js +5 -4
  58. package/dist/board.js +173 -22
  59. package/dist/branch-de-estado.js +136 -0
  60. package/dist/canarios-hitl.js +177 -0
  61. package/dist/canarios-i43.js +543 -0
  62. package/dist/canarios-pulse.js +147 -0
  63. package/dist/canarios-sensores.js +129 -0
  64. package/dist/canarios.js +111 -2
  65. package/dist/catalogo.js +9 -0
  66. package/dist/ci.js +216 -0
  67. package/dist/ciclos.js +2 -1
  68. package/dist/claim-lint.js +64 -0
  69. package/dist/claims.js +60 -0
  70. package/dist/company-brain-capture.js +195 -0
  71. package/dist/company-brain-cli.js +123 -0
  72. package/dist/company-brain-client.js +61 -0
  73. package/dist/company-brain-contract.js +166 -0
  74. package/dist/company-brain-journal.js +192 -0
  75. package/dist/company-brain-mcp.js +33 -0
  76. package/dist/company-brain-migration.js +60 -0
  77. package/dist/company-brain-source.js +177 -0
  78. package/dist/company-brain-worker.js +18 -0
  79. package/dist/conducao-texto.js +61 -0
  80. package/dist/conducao.js +876 -0
  81. package/dist/contrato-publico.js +39 -0
  82. package/dist/creation-operation-store.js +251 -0
  83. package/dist/creation-operation.js +148 -0
  84. package/dist/decisao-autonoma.js +183 -0
  85. package/dist/delegation.js +79 -0
  86. package/dist/demo.js +120 -0
  87. package/dist/docs.js +828 -0
  88. package/dist/doctor.js +183 -24
  89. package/dist/entrega-pr.js +117 -0
  90. package/dist/escopo-escrita.js +71 -0
  91. package/dist/estado-thread.js +222 -0
  92. package/dist/evalrunner.js +12 -0
  93. package/dist/fabrica-estado.js +329 -0
  94. package/dist/fabrica-publicar.js +76 -0
  95. package/dist/fix.js +21 -0
  96. package/dist/gates.js +55 -9
  97. package/dist/handoff.js +39 -23
  98. package/dist/hitl-canais.js +333 -0
  99. package/dist/hitl-classificacao.js +131 -0
  100. package/dist/hitl-contract.js +465 -0
  101. package/dist/hitl-estado.js +136 -0
  102. package/dist/hitl-gates.js +554 -0
  103. package/dist/hitl-ingress-receipt.js +382 -0
  104. package/dist/hitl-local-atestado.js +57 -0
  105. package/dist/hitl-local-receipt.js +328 -0
  106. package/dist/hitl-local.js +143 -0
  107. package/dist/hitl-lock.js +139 -0
  108. package/dist/hitl-lote.js +223 -0
  109. package/dist/hitl-native-offer.js +97 -0
  110. package/dist/hitl-native.js +65 -0
  111. package/dist/hitl-presentation.js +209 -0
  112. package/dist/hitl-public-receipt.js +176 -0
  113. package/dist/hitl-resumo.js +209 -0
  114. package/dist/hitl-sessions.js +475 -0
  115. package/dist/hitl.js +711 -0
  116. package/dist/horario.js +269 -0
  117. package/dist/hosts.js +198 -22
  118. package/dist/index.js +1736 -93
  119. package/dist/indice.js +99 -0
  120. package/dist/init.js +28 -3
  121. package/dist/integracoes-locais.js +17 -0
  122. package/dist/leases.js +65 -21
  123. package/dist/ledger-stats.js +272 -0
  124. package/dist/ledger.js +107 -2
  125. package/dist/licoes.js +215 -0
  126. package/dist/liveness.js +218 -0
  127. package/dist/maestro-actions.js +51 -0
  128. package/dist/maestro-authority.js +152 -0
  129. package/dist/maestro-cli.js +97 -0
  130. package/dist/maestro-contract.js +55 -0
  131. package/dist/maestro-discovery.js +132 -0
  132. package/dist/maestro-runtime.js +268 -0
  133. package/dist/maestro-snapshot.js +86 -0
  134. package/dist/maestro-sources.js +224 -0
  135. package/dist/manifest.js +165 -6
  136. package/dist/maquina.js +102 -0
  137. package/dist/master-audit.js +101 -0
  138. package/dist/master-batch.js +43 -0
  139. package/dist/master-digest.js +149 -0
  140. package/dist/master-migracao.js +155 -0
  141. package/dist/master.js +361 -77
  142. package/dist/mcp-artifacts.js +234 -0
  143. package/dist/mcp-git.js +433 -0
  144. package/dist/mcp-install.js +310 -0
  145. package/dist/mcp-maestro.js +25 -0
  146. package/dist/mcp-server.js +469 -0
  147. package/dist/mcp-ship.js +436 -0
  148. package/dist/mcp-verify.js +173 -0
  149. package/dist/memoria-humana.js +207 -0
  150. package/dist/memoria.js +314 -78
  151. package/dist/memory-migration.js +279 -0
  152. package/dist/memory-prospective.js +148 -0
  153. package/dist/modos-migracao.js +191 -0
  154. package/dist/modos.js +151 -15
  155. package/dist/monitor-lock.js +110 -0
  156. package/dist/objective.js +449 -0
  157. package/dist/ocupacao.js +267 -0
  158. package/dist/onboarding.js +303 -0
  159. package/dist/orkmind.js +389 -90
  160. package/dist/orquestracao.js +96 -69
  161. package/dist/phase.js +596 -150
  162. package/dist/playbook-capabilities.js +150 -0
  163. package/dist/playbook-contracts.js +188 -0
  164. package/dist/portfolio-context.js +61 -0
  165. package/dist/portfolio.js +180 -0
  166. package/dist/preflight.js +207 -0
  167. package/dist/process-audit.js +112 -0
  168. package/dist/project-state.js +93 -0
  169. package/dist/prompts.js +25 -5
  170. package/dist/prova-minima.js +112 -0
  171. package/dist/pulse-cadencia.js +163 -0
  172. package/dist/pulse-consentimento.js +260 -0
  173. package/dist/pulse-delivery.js +323 -0
  174. package/dist/pulse-resposta.js +542 -0
  175. package/dist/pulse.js +262 -0
  176. package/dist/ratelimit.js +35 -2
  177. package/dist/recall.js +80 -3
  178. package/dist/redacao-saida.js +45 -0
  179. package/dist/redacao-url.js +66 -0
  180. package/dist/retry.js +637 -115
  181. package/dist/roadmap-reservas.js +243 -0
  182. package/dist/runtime-ambiente.js +38 -0
  183. package/dist/runtime-context.js +215 -0
  184. package/dist/runtime-profiles.js +869 -0
  185. package/dist/runtimes.js +103 -0
  186. package/dist/sandbox.js +9 -0
  187. package/dist/session-events.js +203 -0
  188. package/dist/session-watcher-claude.js +637 -0
  189. package/dist/session-watcher.js +683 -0
  190. package/dist/sessoes-adopt.js +154 -0
  191. package/dist/sessoes-inventario.js +159 -0
  192. package/dist/sessoes.js +16 -35
  193. package/dist/setup.js +691 -0
  194. package/dist/ship.js +150 -15
  195. package/dist/slug.js +1 -1
  196. package/dist/thread-close.js +115 -0
  197. package/dist/thread.js +142 -28
  198. package/dist/tokens.js +1 -1
  199. package/dist/util.js +4 -2
  200. package/dist/verify-sandbox.js +265 -0
  201. package/dist/verify.js +270 -25
  202. package/dist/versao.js +60 -0
  203. package/dist/worktree.js +31 -2
  204. package/dist/write-activation.js +291 -0
  205. package/dist/yaml.js +2 -0
  206. package/eval/casos/onboarding.json +102 -0
  207. package/eval/casos/orkastery-bootstrap.json +35 -1
  208. package/eval/casos/scope-check-capability-map.json +45 -7
  209. package/eval/casos/ship-release.json +2 -2
  210. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  211. package/eval/fixtures/b2-master-log/caso.json +1 -1
  212. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  213. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  214. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  215. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  216. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  217. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  218. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  219. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  220. package/eval/fixtures/fx-happy/caso.json +6 -4
  221. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  222. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  223. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  224. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  225. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  226. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  227. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  228. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  229. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  230. package/monitor/company-brain.cjs +17 -0
  231. package/monitor/pulse-scope.cjs +45 -0
  232. package/monitor/pulse.cron +18 -0
  233. package/monitor/varredura-pulse.sh +27 -0
  234. package/package.json +25 -4
  235. package/schemas/claims.schema.json +25 -0
  236. package/schemas/company-brain.schema.json +1158 -0
  237. package/schemas/creation-operation.schema.json +365 -0
  238. package/schemas/maestro-snapshot.schema.json +2716 -0
  239. package/skills/core/onboarding/SKILL.md +50 -0
  240. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  241. package/skills/core/thread-state/SKILL.md +3 -1
  242. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
package/dist/ledger.js CHANGED
@@ -40,12 +40,17 @@ var __importStar = (this && this.__importStar) || (function () {
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.TIPOS_DE_EVENTO = void 0;
43
+ exports.exigirRastroDeDecisaoAutonoma = exigirRastroDeDecisaoAutonoma;
43
44
  exports.caminhoLedger = caminhoLedger;
44
45
  exports.registrar = registrar;
46
+ exports.threadPresente = threadPresente;
47
+ exports.registrarSeExiste = registrarSeExiste;
45
48
  exports.lerLedger = lerLedger;
46
49
  const fs = __importStar(require("node:fs"));
47
50
  const path = __importStar(require("node:path"));
48
51
  const util_1 = require("./util");
52
+ const node_crypto_1 = require("node:crypto");
53
+ const company_brain_journal_1 = require("./company-brain-journal");
49
54
  /** Tipos de evento do ledger. B0 abriu a lista; o B1 acrescenta os seus. */
50
55
  exports.TIPOS_DE_EVENTO = {
51
56
  // Bloco B0
@@ -67,6 +72,24 @@ exports.TIPOS_DE_EVENTO = {
67
72
  shipIniciado: 'ship_started',
68
73
  shipConcluido: 'ship_done',
69
74
  shipBloqueado: 'ship_blocked',
75
+ /**
76
+ * I-43 (D3): a entrega foi revertida na base depois do ship.
77
+ *
78
+ * Ele ja existia na allowlist do ciclo (`company-brain-source.ts`) e tinha ZERO
79
+ * escritor no nucleo: o insumo de MAIOR peso do indice de qualidade nao era
80
+ * gravado por ninguem. Quem o escreve e `ship.ts`, que e quem sabe de merge e de
81
+ * base, e so quando o git prova a reversao.
82
+ */
83
+ rollbackConcluido: 'rollback_done',
84
+ /**
85
+ * I-43 (D3): a entrega foi aceita porque ninguem reclamou, e isso ficou REGISTRADO.
86
+ *
87
+ * Aceitacao por default nao pode ser silencio. O evento carrega o indice, os
88
+ * insumos que o produziram e quem decidiu, para o dono conseguir ver depois o que
89
+ * passou sem ele olhar. Nota humana posterior sobrescreve o score; este evento
90
+ * permanece, porque o ledger e append-only.
91
+ */
92
+ aceitePorOmissao: 'aceite_por_omissao',
70
93
  gateDeTokens: 'token_gate',
71
94
  handoffExportado: 'handoff_exported',
72
95
  handoffRecuperado: 'handoff_recalled',
@@ -78,6 +101,10 @@ exports.TIPOS_DE_EVENTO = {
78
101
  leaseEnfileirado: 'lease_queued',
79
102
  postmortemGravado: 'postmortem_recorded',
80
103
  masterConcluido: 'master_done',
104
+ scoreProposto: 'score_proposto',
105
+ masterMigrado: 'master_migrated',
106
+ threadFechadaAdmin: 'thread_closed_admin',
107
+ artefatoEntregue: 'artifact_delivered',
81
108
  // Bloco B5: auditores periodicos (rodada, achados, propostas e board de divida)
82
109
  auditoriaDespachada: 'audit_dispatch',
83
110
  auditoriaBloqueada: 'audit_blocked',
@@ -100,19 +127,97 @@ exports.TIPOS_DE_EVENTO = {
100
127
  rateLimitDetectado: 'rate_limit_detected',
101
128
  rateLimitEnfileirado: 'rate_limit_queued',
102
129
  rateLimitRetomado: 'rate_limit_resumed',
130
+ // I-33 (D5): troca de perfil ou de runtime depois de falha da conta (quem, de qual para
131
+ // qual, evidencia e razao). Faz parte do catalogo, nao de literal solto.
132
+ perfilRotacionado: 'runtime_profile_rotated',
103
133
  fixAberto: 'go_fix_opened',
104
134
  fixDespachado: 'go_fix_dispatched',
105
135
  reverifyConcluido: 'check_reverify',
136
+ // Feature #setup: customizacao de runtime/modelo/esforco por bloco de cada modo
137
+ setupConfigurado: 'setup_configured',
138
+ onboardingRegistrado: 'onboarding_recorded',
139
+ // Correcao do escalonador: vaga devolvida por thread sem procura ativa (`ork board reap`)
140
+ vagaLiberada: 'slot_released',
141
+ // I-07: estimativa humana no PLAN para comparacao economica posterior.
142
+ estimativaPlano: 'plan_estimate',
143
+ // I-42 (D5): ciclo sem CHECK que nao achou teste nem comando honesto declara a ausencia de
144
+ // prova, com os caminhos e o motivo. Ausencia registrada, nunca silenciosa.
145
+ provaAusente: 'prova_ausente',
146
+ // I-53 (RM-037, P6): o `ci prepare` avisou ou recusou comando de claim pelo lint.
147
+ lintDeClaim: 'claim_lint',
148
+ // I-55 (RM-008): a mesma falha em 3+ threads fechadas virou proposta de policy (so proposta).
149
+ politicaProposta: 'policy_proposta',
150
+ // I-36 (RM-036): conducao multicanal. O segundo pedido recusado, o despacho repetido que nao abriu
151
+ // sessao nova, a liberacao com prova (fim da sessao ou dono morto), o handoff e a renovacao do prazo.
152
+ conducaoRecusada: 'conducao_recusada',
153
+ despachoIdempotente: 'despacho_idempotente',
154
+ conducaoLiberada: 'conducao_liberada',
155
+ conducaoOrfaLiberada: 'conducao_orfa_liberada',
156
+ conducaoAssumida: 'conducao_assumida',
157
+ conducaoRenovada: 'conducao_renovada',
106
158
  };
159
+ /**
160
+ * I-41 (GO-FIX 1, B4 e D11): o rastro tipado da decisao autonoma.
161
+ *
162
+ * O cabecalho deste arquivo sempre disse que "toda decisao autonoma precisa estar aqui com quem
163
+ * decidiu, evidencia e razao", e o registro nunca conferiu: 849 eventos com 215 chaves distintas,
164
+ * oito nomes para "quem decidiu" e 45% sem os tres campos (M6 do PLAN). A partir daqui o registro
165
+ * recusa `autonomous_decision` sem `quemDecidiu`, `evidencia` e `razao`, com esses nomes. Evento
166
+ * antigo continua legivel (a leitura normaliza os nomes historicos em `decisao-autonoma.ts`) e
167
+ * nenhuma linha e reescrita: a exigencia vale para a escrita nova, como v1 e v2 no contrato HITL.
168
+ */
169
+ function exigirRastroDeDecisaoAutonoma(dados) {
170
+ for (const campo of ['quemDecidiu', 'evidencia', 'razao']) {
171
+ const v = dados[campo];
172
+ if (typeof v !== 'string' || !v.trim() || v.length > 1000 || /[\x00-\x08\x0b-\x1f\x7f]/.test(v)) {
173
+ throw new Error(`decisão autônoma exige ${campo}: quem decidiu, com que evidência e por quê`);
174
+ }
175
+ }
176
+ }
107
177
  /** Caminho do ledger de uma thread. */
108
178
  function caminhoLedger(dirThread) {
109
179
  return path.join(dirThread, 'ledger.jsonl');
110
180
  }
111
181
  /** Anexa um evento ao ledger da thread e devolve o evento gravado. */
112
182
  function registrar(dirThread, threadId, tipo, dados = {}) {
113
- const evento = { ts: (0, util_1.agora)(), thread: threadId, tipo, ...dados };
183
+ if (tipo === exports.TIPOS_DE_EVENTO.decisaoAutonoma)
184
+ exigirRastroDeDecisaoAutonoma(dados);
185
+ const evento = { ts: (0, util_1.agora)(), thread: threadId, tipo, ...dados, eventId: (0, node_crypto_1.randomUUID)() };
114
186
  fs.mkdirSync(dirThread, { recursive: true });
115
- fs.appendFileSync(caminhoLedger(dirThread), JSON.stringify(evento) + '\n', 'utf8');
187
+ (0, company_brain_journal_1.durableAppend)(caminhoLedger(dirThread), evento);
188
+ return evento;
189
+ }
190
+ /** A thread ainda existe em disco? `thread.json` e ledger presentes; nada é criado aqui. */
191
+ function threadPresente(dirThread) {
192
+ return fs.existsSync(path.join(dirThread, 'thread.json')) && fs.existsSync(caminhoLedger(dirThread));
193
+ }
194
+ /**
195
+ * Variante do `registrar` para processos destacados (watcher): anexa só a um ledger que já
196
+ * existe, sem criar pasta nem arquivo (`O_APPEND` sem `O_CREAT`). Thread apagada devolve
197
+ * `null` em vez de renascer com um ledger de um evento só.
198
+ */
199
+ function registrarSeExiste(dirThread, threadId, tipo, dados = {}) {
200
+ if (tipo === exports.TIPOS_DE_EVENTO.decisaoAutonoma)
201
+ exigirRastroDeDecisaoAutonoma(dados);
202
+ if (!fs.existsSync(path.join(dirThread, 'thread.json')))
203
+ return null;
204
+ let fd;
205
+ try {
206
+ fd = fs.openSync(caminhoLedger(dirThread), fs.constants.O_WRONLY | fs.constants.O_APPEND);
207
+ }
208
+ catch (e) {
209
+ if (e.code === 'ENOENT')
210
+ return null;
211
+ throw e;
212
+ }
213
+ const evento = { ts: (0, util_1.agora)(), thread: threadId, tipo, ...dados, eventId: (0, node_crypto_1.randomUUID)() };
214
+ try {
215
+ fs.writeFileSync(fd, JSON.stringify(evento) + '\n');
216
+ fs.fsyncSync(fd);
217
+ }
218
+ finally {
219
+ fs.closeSync(fd);
220
+ }
116
221
  return evento;
117
222
  }
118
223
  /** Le o ledger inteiro. Linha corrompida vira evento `ledger_corrupted` em vez de quebrar a leitura. */
package/dist/licoes.js ADDED
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PISO_DA_PROPOSTA = exports.JANELA_DA_PROPOSTA_DIAS = void 0;
37
+ exports.lerLicoes = lerLicoes;
38
+ exports.resumoDasLicoes = resumoDasLicoes;
39
+ exports.textoDasLicoes = textoDasLicoes;
40
+ exports.propostasDePolicy = propostasDePolicy;
41
+ exports.registrarPropostasNovas = registrarPropostasNovas;
42
+ exports.textoDeLicoes = textoDeLicoes;
43
+ /**
44
+ * I-55 (RM-008): o loop de aprendizado.
45
+ *
46
+ * Havia dezenas de POSTMORTEMs e nenhuma licao voltando no ciclo seguinte: a licao so existia na
47
+ * colecao `learning` do OrkMind, e so no GOAL. Aqui ela sai direto dos arquivos que o MASTER ja
48
+ * grava (`POSTMORTEM.json` e `master-log.json`), em qualquer regime de memoria, e volta no GOAL e
49
+ * no PLAN da thread seguinte do mesmo produto. So conta thread fechada pelo MASTER: licao de
50
+ * thread aberta seria auto-relato.
51
+ *
52
+ * Quando a mesma falha se repete, o loop nao cria regra sozinho: ele PROPOE a policy, com as
53
+ * threads que a sustentam, e a proposta fica no ledger do projeto e em `ork licoes`. Transformar
54
+ * proposta em policy (`policies:` no manifesto) muda o que bloqueia a fabrica, e isso e do dono.
55
+ */
56
+ const fs = __importStar(require("node:fs"));
57
+ const path = __importStar(require("node:path"));
58
+ const estado_thread_1 = require("./estado-thread");
59
+ const ledger_1 = require("./ledger");
60
+ /** O que evita cada bloqueio, na forma de comando. Sem dica, a licao so conta a recorrencia. */
61
+ const DICA_DO_MOTIVO = {
62
+ 'claims.failed': 'rode o comando da claim antes de registra-la; claim sem prova local volta como GO-FIX',
63
+ 'verify.regression': 'grave a baseline antes do GO (`ork verify <thread> --baseline`) e rode os testes focados antes do CHECK',
64
+ 'verify.failed': 'grave a baseline antes do GO, para a falha ter com que ser comparada',
65
+ 'verify.timeout': 'divida o comando lento ou suba `verify.timeout_ms` no manifesto',
66
+ 'runtime.unavailable': 'declare a ordem de fallback do bloco (`ork setup <modo> --bloco N --fallback runtime:modelo`)',
67
+ 'runtime.quota-exhausted': 'tenha um segundo perfil da conta (`ork accounts add`) ou fallback no bloco',
68
+ 'tree.blocked': 'sincronize a worktree com a base antes do SHIP (`ork worktree sync <thread>`)',
69
+ 'ci.failed': 'rode a suite hermetica (`npm --prefix core run test:ci`) antes do push',
70
+ 'artifact.missing': 'grave o artefato da fase exatamente no caminho que o prompt pede',
71
+ };
72
+ const DICA_DA_CLASSE = {
73
+ 'erro-de-spec': 'declare criterios de pronto executaveis na criacao (`ork thread new ... --done`)',
74
+ 'base-avancou': 'sincronize com a base antes do CHECK, nao so antes do SHIP',
75
+ 'conflito': 'reserve o item do roadmap antes de comecar (`ork roadmap pegar`)',
76
+ 'rate-limit': 'use o fallback do bloco em vez de esperar a janela',
77
+ 'processo': 'siga o ciclo do modo: GOAL e PLAN antes do GO, e toda afirmacao com claim e comando',
78
+ 'scope-creep': 'corte o pedido em fatias com item proprio no roadmap',
79
+ };
80
+ /** Classes que nao ensinam nada por si: nao entram na recorrencia. */
81
+ const CLASSES_SEM_LICAO = new Set(['sem-falha', 'outra']);
82
+ function lerJson(arquivo) {
83
+ try {
84
+ return JSON.parse(fs.readFileSync(arquivo, 'utf8'));
85
+ }
86
+ catch {
87
+ return null;
88
+ }
89
+ }
90
+ /** As licoes das threads fechadas pelo MASTER no estado deste projeto. */
91
+ function lerLicoes(raiz) {
92
+ const dir = path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery', 'threads');
93
+ if (!fs.existsSync(dir))
94
+ return [];
95
+ const licoes = [];
96
+ for (const id of fs.readdirSync(dir)) {
97
+ const pm = lerJson(path.join(dir, id, 'POSTMORTEM.json'));
98
+ const master = lerJson(path.join(dir, id, 'master-log.json'));
99
+ if (!pm || !master || pm.thread !== id)
100
+ continue;
101
+ licoes.push({
102
+ thread: id,
103
+ score: typeof master.score === 'number' ? master.score : null,
104
+ justificativa: String(master.justificativa ?? '').replace(/\s+/g, ' ').trim(),
105
+ classes: (pm.classesDeFalha ?? []).filter((c) => typeof c === 'string'),
106
+ motivos: [...new Set((pm.gatesBloqueados ?? []).map((g) => g.motivo).filter((m) => typeof m === 'string'))],
107
+ bloqueios: (pm.gatesBloqueados ?? []).length,
108
+ fechadaEm: master.avaliadoEm ?? pm.geradoEm ?? '',
109
+ });
110
+ }
111
+ return licoes.sort((a, b) => b.fechadaEm.localeCompare(a.fechadaEm));
112
+ }
113
+ function recorrencias(licoes) {
114
+ const motivos = new Map();
115
+ const classes = new Map();
116
+ for (const l of licoes) {
117
+ for (const m of l.motivos) {
118
+ const r = motivos.get(m) ?? { chave: `motivo:${m}`, tipo: 'motivo', nome: m, threads: [], vezes: 0, dica: DICA_DO_MOTIVO[m] ?? null };
119
+ r.threads.push(l.thread);
120
+ motivos.set(m, r);
121
+ }
122
+ for (const c of l.classes) {
123
+ if (CLASSES_SEM_LICAO.has(c))
124
+ continue;
125
+ const r = classes.get(c) ?? { chave: `classe:${c}`, tipo: 'classe', nome: c, threads: [], vezes: 0, dica: DICA_DA_CLASSE[c] ?? null };
126
+ r.threads.push(l.thread);
127
+ classes.set(c, r);
128
+ }
129
+ }
130
+ const ordenar = (a, b) => b.threads.length - a.threads.length || a.nome.localeCompare(b.nome);
131
+ for (const r of motivos.values())
132
+ r.vezes = r.threads.length;
133
+ for (const r of classes.values())
134
+ r.vezes = r.threads.length;
135
+ return { motivos: [...motivos.values()].sort(ordenar), classes: [...classes.values()].sort(ordenar) };
136
+ }
137
+ /** O resumo que volta no GOAL e no PLAN: a thread corrente nunca aprende consigo mesma. */
138
+ function resumoDasLicoes(raiz, threadCorrente) {
139
+ const licoes = lerLicoes(raiz).filter((l) => l.thread !== threadCorrente);
140
+ const { motivos, classes } = recorrencias(licoes);
141
+ return {
142
+ threads: licoes.length,
143
+ motivos: motivos.slice(0, 3),
144
+ classes: classes.slice(0, 2),
145
+ // Nota 0 e, na pratica, encerramento de thread orfa sem entrega: nao ensina nada ao proximo ciclo.
146
+ recentes: licoes.filter((l) => l.score !== null && l.score >= 1 && l.score <= 3 && l.justificativa).slice(0, 3),
147
+ };
148
+ }
149
+ const curto = (t, teto) => (t.length > teto ? `${t.slice(0, teto - 3)}...` : t);
150
+ /** O texto da licao para o prompt. Vazio quando nao ha thread fechada para ensinar. */
151
+ function textoDasLicoes(r) {
152
+ if (r.threads === 0 || (r.motivos.length === 0 && r.classes.length === 0 && r.recentes.length === 0))
153
+ return '';
154
+ const linhas = [`Das ${r.threads} threads ja fechadas pelo MASTER neste produto:`];
155
+ for (const m of r.motivos) {
156
+ linhas.push(`- o bloqueio ${m.nome} apareceu em ${m.threads.length} ${m.threads.length === 1 ? 'thread' : 'threads'}` +
157
+ (m.dica ? `; o que evita: ${m.dica}` : ''));
158
+ }
159
+ for (const c of r.classes) {
160
+ linhas.push(`- a classe de falha ${c.nome} fechou ${c.threads.length} ${c.threads.length === 1 ? 'thread' : 'threads'}` +
161
+ (c.dica ? `; o que evita: ${c.dica}` : ''));
162
+ }
163
+ for (const l of r.recentes)
164
+ linhas.push(`- ${l.thread} fechou com ${l.score}/5: ${curto(l.justificativa, 160)}`);
165
+ return linhas.join('\n');
166
+ }
167
+ /** Janela e piso da recorrencia que vira proposta de policy. */
168
+ exports.JANELA_DA_PROPOSTA_DIAS = 30;
169
+ exports.PISO_DA_PROPOSTA = 3;
170
+ /**
171
+ * A mesma falha em pelo menos 3 threads fechadas nos ultimos 30 dias vira PROPOSTA de policy.
172
+ * So proposta: a policy muda o que bloqueia a fabrica, e isso e do dono.
173
+ */
174
+ function propostasDePolicy(raiz, agoraIso = new Date().toISOString()) {
175
+ const limite = Date.parse(agoraIso) - exports.JANELA_DA_PROPOSTA_DIAS * 86_400_000;
176
+ const recentes = lerLicoes(raiz).filter((l) => Date.parse(l.fechadaEm) >= limite);
177
+ const { motivos, classes } = recorrencias(recentes);
178
+ return [...motivos, ...classes].filter((r) => r.threads.length >= exports.PISO_DA_PROPOSTA).map((r) => ({
179
+ chave: r.chave, tipo: r.tipo, nome: r.nome, threads: [...r.threads], janelaDias: exports.JANELA_DA_PROPOSTA_DIAS,
180
+ sugestao: `policy \`${r.nome.replace(/[^a-z0-9]+/gi, '_')}\` em warn: ` + (r.dica ?? 'revisar a causa comum antes da proxima thread'),
181
+ }));
182
+ }
183
+ /**
184
+ * Grava no ledger do projeto a proposta que ainda nao foi registrada nesta janela. Idempotente:
185
+ * rodar de novo nao duplica. Devolve so as novas.
186
+ */
187
+ function registrarPropostasNovas(raiz, agoraIso = new Date().toISOString()) {
188
+ const dirProjeto = path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery');
189
+ const limite = Date.parse(agoraIso) - exports.JANELA_DA_PROPOSTA_DIAS * 86_400_000;
190
+ const jaFeitas = new Set((0, ledger_1.lerLedger)(dirProjeto)
191
+ .filter((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.politicaProposta && Date.parse(e.ts) >= limite)
192
+ .map((e) => String(e.chave)));
193
+ const novas = propostasDePolicy(raiz, agoraIso).filter((p) => !jaFeitas.has(p.chave));
194
+ for (const p of novas) {
195
+ // `categoria`, nao `tipo`: o `registrar` espalha os dados por cima do tipo do evento.
196
+ (0, ledger_1.registrar)(dirProjeto, 'projeto', ledger_1.TIPOS_DE_EVENTO.politicaProposta, { chave: p.chave, categoria: p.tipo, nome: p.nome,
197
+ threads: p.threads, janelaDias: p.janelaDias, sugestao: p.sugestao });
198
+ }
199
+ return novas;
200
+ }
201
+ /** `ork licoes`: o que volta no proximo GOAL e PLAN, e as propostas de policy. */
202
+ function textoDeLicoes(raiz, agoraIso = new Date().toISOString()) {
203
+ const resumo = resumoDasLicoes(raiz, null);
204
+ const linhas = ['Licoes que voltam no GOAL e no PLAN da proxima thread', ''];
205
+ linhas.push(textoDasLicoes(resumo) || 'Nenhuma thread fechada pelo MASTER ainda: nada a ensinar.');
206
+ const propostas = propostasDePolicy(raiz, agoraIso);
207
+ linhas.push('');
208
+ linhas.push(`Propostas de policy (a mesma falha em ${exports.PISO_DA_PROPOSTA}+ threads nos ultimos ${exports.JANELA_DA_PROPOSTA_DIAS} dias):`);
209
+ if (propostas.length === 0)
210
+ linhas.push(' nenhuma');
211
+ for (const p of propostas)
212
+ linhas.push(` ${p.chave} em ${p.threads.length} threads (${p.threads.slice(0, 5).join(', ')})`, ` ${p.sugestao}`);
213
+ linhas.push('', 'Proposta nao bloqueia nada: vira policy so quando o dono a declara em `policies:` no orkastery.yaml.');
214
+ return linhas.join('\n');
215
+ }
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.transcricaoClaude = transcricaoClaude;
37
+ exports.detectarFasesOrfas = detectarFasesOrfas;
38
+ const escopo_escrita_1 = require("./escopo-escrita");
39
+ /** D3: silêncio é ausência de progresso verificável, não ausência de PID. */
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
+ const node_crypto_1 = require("node:crypto");
43
+ const codex_1 = require("./adapters/codex");
44
+ const runtime_profiles_1 = require("./runtime-profiles");
45
+ const thread_1 = require("./thread");
46
+ const ledger_1 = require("./ledger");
47
+ const retry_1 = require("./retry");
48
+ const util_1 = require("./util");
49
+ /**
50
+ * Transcrição local do Claude. O UUID evita interpretar identificador como caminho.
51
+ * I-33 (D4): `config` é o diretório já resolvido pelo perfil da sessão (ou o implícito, sem
52
+ * perfil); o default pelo env do processo deixou de existir aqui.
53
+ */
54
+ function transcricaoClaude(sessionId, cwd, config) {
55
+ if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(sessionId))
56
+ return undefined;
57
+ const projetos = path.join(config, 'projects');
58
+ const candidato = path.join(projetos, path.resolve(cwd).replace(/[^a-zA-Z0-9-]/g, '-'), `${sessionId}.jsonl`);
59
+ if (fs.existsSync(candidato))
60
+ return candidato;
61
+ if (!fs.existsSync(projetos))
62
+ return undefined;
63
+ // Também cobre a chave abreviada de projetos com caminhos extensos.
64
+ for (const entrada of fs.readdirSync(projetos, { withFileTypes: true })) {
65
+ if (!entrada.isDirectory())
66
+ continue;
67
+ const arquivo = path.join(projetos, entrada.name, `${sessionId}.jsonl`);
68
+ if (fs.existsSync(arquivo))
69
+ return arquivo;
70
+ }
71
+ return undefined;
72
+ }
73
+ function fontesReais(t, d) {
74
+ const commit = t.worktree ? (0, util_1.exec)('git', ['log', '-1', '--format=%cI'], t.worktree) : null;
75
+ const commitEm = commit?.ok ? commit.stdout.trim() : undefined;
76
+ if (typeof d.sessionId !== 'string')
77
+ return { commitEm };
78
+ // I-33 (D4): a fonte de vida mora no diretório do perfil gravado no `phase_dispatch`. Perfil
79
+ // inválido não vira leitura pela conta do processo: sem rollout, a prova de vida fica no commit.
80
+ let perfil;
81
+ try {
82
+ perfil = (0, runtime_profiles_1.perfilDoRegistro)([d], { sessionId: d.sessionId });
83
+ }
84
+ catch {
85
+ return { commitEm };
86
+ }
87
+ const rollout = d.runtime === 'codex' ? (0, codex_1.acharRollout)(d.sessionId, 3, (0, codex_1.casaDoCodex)(perfil))
88
+ : d.runtime === 'claude-bg' ? transcricaoClaude(d.sessionId, t.worktree ?? process.cwd(), (0, runtime_profiles_1.diretorioEfetivo)('claude-bg', perfil)) : null;
89
+ return { commitEm, rollout: rollout ?? undefined };
90
+ }
91
+ /** Último evento do rollout, com leitura limitada. Não carrega o histórico inteiro. */
92
+ function instanteDoRollout(arquivo) {
93
+ const fd = fs.openSync(arquivo, 'r');
94
+ try {
95
+ const size = fs.fstatSync(fd).size, n = Math.min(size, 65536), buf = Buffer.alloc(n);
96
+ fs.readSync(fd, buf, 0, n, size - n);
97
+ for (const linha of buf.toString('utf8').split('\n').reverse()) {
98
+ try {
99
+ const e = JSON.parse(linha);
100
+ if (typeof e.timestamp === 'string' && Number.isFinite(Date.parse(e.timestamp)))
101
+ return e.timestamp;
102
+ }
103
+ catch { /* última linha incompleta ou primeira linha truncada */ }
104
+ }
105
+ return null;
106
+ }
107
+ finally {
108
+ fs.closeSync(fd);
109
+ }
110
+ }
111
+ function detectarFasesOrfas(carregado, opcoes = {}) {
112
+ const autorizadas = opcoes.registrar ? (0, escopo_escrita_1.exigirEscopoDeEscrita)(opcoes.escopo) : new Set();
113
+ const quando = opcoes.quando ?? (0, util_1.agora)(), now = Date.parse(quando);
114
+ const limite = carregado.manifesto.liveness?.silencio_max_min ?? 10;
115
+ if (!Number.isFinite(now) || !Number.isFinite(limite) || limite <= 0)
116
+ throw new Error('instante ou limite de liveness inválido');
117
+ const orfas = [];
118
+ for (const id of (0, thread_1.listarIds)(carregado.raiz)) {
119
+ const escrever = opcoes.registrar === true && autorizadas.has(id);
120
+ const t = (0, thread_1.lerThread)(carregado.raiz, id), dir = (0, thread_1.dirThread)(carregado.raiz, id);
121
+ if (t.status !== 'aberta')
122
+ continue;
123
+ const eventos = (0, ledger_1.lerLedger)(dir), di = eventos.map(e => e.tipo).lastIndexOf('phase_dispatch');
124
+ if (di < 0)
125
+ continue;
126
+ const d = eventos[di], inicio = Date.parse(d.ts), fase = d.fase;
127
+ if (opcoes.runtimes && !opcoes.runtimes.includes(String(d.runtime)))
128
+ continue;
129
+ if (!Number.isFinite(inicio) || inicio > now)
130
+ continue;
131
+ const apos = eventos.slice(di + 1);
132
+ const terminal = apos.some(e => ['ship_done', 'master_done', 'thread_closed_admin'].includes(e.tipo) ||
133
+ (e.tipo === 'phase_result' && e.fase === fase && (!e.sessionId || e.sessionId === d.sessionId) &&
134
+ (e.estado === 'concluida' || e.ok === true || e.exitCode === 0 || e.status === 'ok')));
135
+ if (terminal || opcoes.estados?.get(String(d.sessionId)) === 'blocked')
136
+ continue;
137
+ // Gate explícito em aberto não é falta de progresso. Pausa futura do modo não conta.
138
+ const gate = apos.filter(e => (!e.fase || e.fase === fase) && (!e.sessionId || e.sessionId === d.sessionId) &&
139
+ (e.tipo === 'gate_blocked' || e.tipo === 'gate_passed' || (e.tipo === 'human_gate' && e.acao === 'approve'))).at(-1);
140
+ if (gate?.tipo === 'gate_blocked' && gate.motivo !== 'runtime.silencio' &&
141
+ !(gate.motivo === 'human.pending' && gate.origem === 'retry.run'))
142
+ continue;
143
+ let heartbeat = inicio;
144
+ const evidencia = [`phase_dispatch ${d.ts} sessão ${String(d.sessionId ?? '')}`];
145
+ const incorporar = (ts, fonte) => {
146
+ const n = ts ? Date.parse(ts) : NaN;
147
+ if (n > heartbeat && n <= now) {
148
+ heartbeat = n;
149
+ evidencia.push(`${fonte}: ${ts}`);
150
+ }
151
+ };
152
+ for (const e of apos) {
153
+ if (['runtime_event', 'runtime_heartbeat', 'phase_heartbeat', 'sessao_heartbeat', 'commit',
154
+ 'runtime_stop', 'runtime_subagent_stop', 'sessao_destravada'].includes(e.tipo) &&
155
+ typeof d.sessionId === 'string' && e.sessionId === d.sessionId && (!e.fase || e.fase === fase)) {
156
+ incorporar(e.ts, e.tipo);
157
+ }
158
+ }
159
+ const fontes = (opcoes.fontes ?? fontesReais)(t, d);
160
+ incorporar(fontes.commitEm, 'commit na worktree');
161
+ const file = path.join(dir, 'liveness.json'), chave = `${d.ts}|${d.sessionId}`;
162
+ let anterior = null;
163
+ let snapshotInvalido = false;
164
+ if (fs.existsSync(file)) {
165
+ try {
166
+ anterior = JSON.parse(fs.readFileSync(file, 'utf8'));
167
+ if (!anterior || typeof anterior.despacho !== 'string' || typeof anterior.arquivo !== 'string' ||
168
+ !Number.isFinite(anterior.tamanho) || anterior.tamanho < 0 || !Number.isFinite(Date.parse(anterior.heartbeatEm))) {
169
+ throw new Error('snapshot invalido');
170
+ }
171
+ }
172
+ catch {
173
+ anterior = null;
174
+ snapshotInvalido = true;
175
+ const diagnostico = `liveness.snapshot.invalid:${id}`;
176
+ evidencia.push(diagnostico);
177
+ opcoes.diagnosticos?.push(diagnostico);
178
+ }
179
+ }
180
+ if (anterior?.despacho === chave)
181
+ incorporar(anterior.heartbeatEm, 'rollout observado');
182
+ if (fontes.rollout && fs.existsSync(fontes.rollout)) {
183
+ const stat = fs.statSync(fontes.rollout);
184
+ if (anterior?.despacho !== chave || anterior.arquivo !== fontes.rollout || stat.size > anterior.tamanho) {
185
+ incorporar(instanteDoRollout(fontes.rollout), 'evento no rollout em crescimento');
186
+ }
187
+ if (escrever && !snapshotInvalido) {
188
+ const snapshot = { despacho: chave, tamanho: stat.size, heartbeatEm: new Date(heartbeat).toISOString(), arquivo: fontes.rollout };
189
+ const tmp = file + `.${(0, node_crypto_1.randomUUID)()}.tmp`;
190
+ fs.writeFileSync(tmp, JSON.stringify(snapshot) + '\n');
191
+ fs.renameSync(tmp, file);
192
+ }
193
+ }
194
+ const silencio = (now - heartbeat) / 60000;
195
+ const episodio = apos.filter(e => ['gate_blocked', 'gate_passed'].includes(e.tipo) &&
196
+ e.motivo === 'runtime.silencio' && e.despacho === chave).at(-1);
197
+ if (silencio < limite) {
198
+ if (escrever && gate === episodio && episodio?.tipo === 'gate_blocked') {
199
+ (0, ledger_1.registrar)(dir, id, 'gate_passed', { fase, motivo: 'runtime.silencio', despacho: chave,
200
+ sessionId: d.sessionId, origem: 'pulse', detalhe: 'heartbeat observado após silêncio', evidencia });
201
+ }
202
+ continue;
203
+ }
204
+ const estado = opcoes.estados?.get(String(d.sessionId));
205
+ const retry = (0, retry_1.planejarRetry)(carregado, id, { motivo: 'runtime.silencio', fase,
206
+ estadoDaSessao: estado ? { sessionId: String(d.sessionId), estado } : undefined });
207
+ const resultado = { classe: 'fase_orfa', motivo: 'runtime.silencio', thread: id, fase,
208
+ sessionId: String(d.sessionId ?? ''), despachadaEm: d.ts, ultimoHeartbeatEm: new Date(heartbeat).toISOString(),
209
+ silencioHaMin: Math.floor(silencio), desdeEm: new Date(heartbeat + limite * 60000).toISOString(), evidencia, retry };
210
+ orfas.push(resultado);
211
+ if (escrever && episodio?.tipo !== 'gate_blocked') {
212
+ (0, ledger_1.registrar)(dir, id, 'gate_blocked', { fase, motivo: 'runtime.silencio', gate: 'phase.dispatch',
213
+ despacho: chave, sessionId: d.sessionId, detalhe: `${resultado.silencioHaMin} minutos sem heartbeat`,
214
+ origem: 'pulse', correcao: `ork retry run ${id} --motivo runtime.silencio --fase ${fase}`, evidencia });
215
+ }
216
+ }
217
+ return orfas;
218
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ACTION_TRANSPORT = void 0;
4
+ exports.proposeMaestroActions = proposeMaestroActions;
5
+ exports.performMaestroAction = performMaestroAction;
6
+ /** Ações são propostas. A autoridade continua nos endpoints existentes do núcleo. */
7
+ const zod_1 = require("zod");
8
+ const maestro_discovery_1 = require("./maestro-discovery");
9
+ const maestro_sources_1 = require("./maestro-sources");
10
+ exports.ACTION_TRANSPORT = {
11
+ 'thread.status': 'ork_thread_status', 'thread.observe': 'ork_observe', 'hitl.decide': 'ork_request_decision',
12
+ 'git.status': 'ork_git_status', 'git.commit': 'ork_git_commit', verify: 'ork_verify', ship: 'ork_ship',
13
+ retry: 'ork retry', master: 'ork master', phase: 'ork_phase_run', creation: 'ork creation',
14
+ };
15
+ function proposeMaestroActions(threads, host) {
16
+ const items = [];
17
+ for (const t of threads) {
18
+ const operations = ['thread.status', 'thread.observe', 'git.status', 'git.commit', 'verify', 'ship', 'hitl.decide', 'retry', 'master', 'phase'];
19
+ for (const operation of operations) {
20
+ const tool = exports.ACTION_TRANSPORT[operation], ownerOnly = ['hitl.decide', 'phase', 'master', 'creation'].includes(operation);
21
+ const supported = host.tools.includes(tool), available = supported && !(host.child && ownerOnly);
22
+ items.push({ ...(0, maestro_sources_1.item)(`${operation}:${t.id}`, operation, available ? 'proposed' : 'unavailable', [{ kind: 'thread', id: t.id }], {}),
23
+ action: { operation, available, reason: available ? '' : host.child && ownerOnly ? 'authority.conductor_required' : 'transport.unavailable',
24
+ preconditions: ['state.revalidate', ...(!['thread.status', 'thread.observe', 'git.status'].includes(operation) ? ['native.authorization', 'core.gates', 'operation.required_arguments'] : [])], readback: 'ork_thread_status' } });
25
+ }
26
+ }
27
+ return { source: 'ork.maestro.actions/v1', items, gaps: [] };
28
+ }
29
+ const requestSchema = zod_1.z.object({ id: zod_1.z.string().min(1).max(160), expectedFingerprint: zod_1.z.string().regex(/^[a-f0-9]{64}$/) }).strict();
30
+ function performMaestroAction(context, input, ports) {
31
+ const request = requestSchema.parse(input);
32
+ (0, maestro_discovery_1.revalidateMaestroContext)(context);
33
+ const current = ports.snapshot();
34
+ const selected = current.sections.nextActions.items.find(a => a.id === request.id), action = selected?.action;
35
+ if (!selected || !action?.available)
36
+ throw Error(action?.reason || 'maestro.action.unavailable');
37
+ const target = selected.refs.find(r => r.kind === 'thread')?.id;
38
+ if (!target || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(target))
39
+ throw Error('maestro.project.scope');
40
+ const previous = ports.receipts(request.id, request.expectedFingerprint);
41
+ if (previous !== null)
42
+ return { receipt: previous, readback: ports.readback(target), repeated: true };
43
+ if (current.fingerprint !== request.expectedFingerprint || current.conflicts.length || Object.values(current.sections).some(s => ['stale', 'conflict'].includes(s.state)))
44
+ throw Error('maestro.snapshot.stale');
45
+ const execute = ports.operations[action.operation];
46
+ if (!execute)
47
+ throw Error('transport.unavailable');
48
+ (0, maestro_discovery_1.revalidateMaestroContext)(context);
49
+ const receipt = execute(target);
50
+ return { receipt, readback: ports.readback(target), repeated: false };
51
+ }