@orkastery/cli 0.2.0 → 0.4.1

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 (257) 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/check.md +4 -3
  7. package/adapters/claude-code/commands/goal.md +3 -2
  8. package/adapters/claude-code/commands/master.md +3 -2
  9. package/adapters/claude-code/commands/onboarding.md +21 -0
  10. package/adapters/claude-code/commands/ork.md +99 -27
  11. package/adapters/claude-code/hooks/hooks.json +6 -1
  12. package/adapters/claude-code/hooks/ork-guard.js +1 -1
  13. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  14. package/adapters/codex/skills/ork/SKILL.md +57 -0
  15. package/adapters/hermes/README.md +161 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  17. package/adapters/hermes/bin/ork-brain.sh +4 -0
  18. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  19. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  20. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  21. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  22. package/adapters/hermes/hermes.plugin.json +24 -4
  23. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  24. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  25. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  26. package/adapters/openclaw/README.md +136 -27
  27. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  28. package/adapters/openclaw/construir.sh +19 -0
  29. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  30. package/adapters/openclaw/dist/index.js +437 -0
  31. package/adapters/openclaw/openclaw.plugin.json +39 -134
  32. package/adapters/openclaw/package.json +26 -0
  33. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  34. package/adapters/openclaw/src/index.ts +460 -0
  35. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  36. package/adapters/openclaw/tsconfig.json +15 -0
  37. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  38. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  39. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  40. package/assets/docs/produto/README.md +14 -0
  41. package/assets/docs/produto/_modelo-feature.md +59 -0
  42. package/assets/docs/roadmap/README.md +14 -0
  43. package/assets/docs/roadmap/_modelo-item.md +73 -0
  44. package/assets/orkmind-native-schema.json +32 -0
  45. package/assets/orkmind_bridge.py +357 -0
  46. package/assets/orkmind_fixture.py +67 -0
  47. package/assets/orkmind_prospective.py +138 -0
  48. package/assets/reference-tariffs-i07.json +23 -0
  49. package/dist/adapters/claude-bg.js +488 -39
  50. package/dist/adapters/codex-controller-sensor.js +449 -0
  51. package/dist/adapters/codex-controller-worker.js +361 -0
  52. package/dist/adapters/codex-controller.js +252 -0
  53. package/dist/adapters/codex-events.js +205 -0
  54. package/dist/adapters/codex-question.js +26 -0
  55. package/dist/adapters/codex-runner.js +133 -0
  56. package/dist/adapters/codex.js +394 -0
  57. package/dist/agents-md.js +84 -0
  58. package/dist/auditoria.js +12 -9
  59. package/dist/auditrun.js +5 -4
  60. package/dist/board.js +174 -23
  61. package/dist/branch-de-estado.js +136 -0
  62. package/dist/canarios-hitl.js +177 -0
  63. package/dist/canarios-i43.js +543 -0
  64. package/dist/canarios-pulse.js +147 -0
  65. package/dist/canarios-sensores.js +129 -0
  66. package/dist/canarios.js +111 -2
  67. package/dist/catalogo.js +9 -0
  68. package/dist/ci.js +223 -0
  69. package/dist/ciclos.js +2 -1
  70. package/dist/claim-lint.js +64 -0
  71. package/dist/claims.js +60 -0
  72. package/dist/company-brain-capture.js +195 -0
  73. package/dist/company-brain-cli.js +123 -0
  74. package/dist/company-brain-client.js +61 -0
  75. package/dist/company-brain-contract.js +166 -0
  76. package/dist/company-brain-journal.js +192 -0
  77. package/dist/company-brain-mcp.js +33 -0
  78. package/dist/company-brain-migration.js +60 -0
  79. package/dist/company-brain-source.js +177 -0
  80. package/dist/company-brain-worker.js +18 -0
  81. package/dist/conducao-texto.js +61 -0
  82. package/dist/conducao.js +876 -0
  83. package/dist/contrato-publico.js +39 -0
  84. package/dist/creation-operation-store.js +251 -0
  85. package/dist/creation-operation.js +148 -0
  86. package/dist/decisao-autonoma.js +183 -0
  87. package/dist/delegation.js +79 -0
  88. package/dist/demo.js +120 -0
  89. package/dist/docs.js +828 -0
  90. package/dist/doctor.js +184 -25
  91. package/dist/entrega-pr.js +117 -0
  92. package/dist/escopo-escrita.js +71 -0
  93. package/dist/estado-thread.js +222 -0
  94. package/dist/evalrunner.js +12 -0
  95. package/dist/fabrica-estado.js +329 -0
  96. package/dist/fabrica-publicar.js +76 -0
  97. package/dist/fix.js +22 -1
  98. package/dist/gates.js +59 -11
  99. package/dist/handoff.js +39 -23
  100. package/dist/hitl-canais.js +333 -0
  101. package/dist/hitl-classificacao.js +131 -0
  102. package/dist/hitl-contract.js +465 -0
  103. package/dist/hitl-estado.js +136 -0
  104. package/dist/hitl-gates.js +554 -0
  105. package/dist/hitl-ingress-receipt.js +382 -0
  106. package/dist/hitl-local-atestado.js +57 -0
  107. package/dist/hitl-local-receipt.js +328 -0
  108. package/dist/hitl-local.js +143 -0
  109. package/dist/hitl-lock.js +139 -0
  110. package/dist/hitl-lote.js +223 -0
  111. package/dist/hitl-native-offer.js +97 -0
  112. package/dist/hitl-native.js +65 -0
  113. package/dist/hitl-presentation.js +209 -0
  114. package/dist/hitl-public-receipt.js +176 -0
  115. package/dist/hitl-resumo.js +209 -0
  116. package/dist/hitl-sessions.js +475 -0
  117. package/dist/hitl.js +711 -0
  118. package/dist/horario.js +269 -0
  119. package/dist/hosts.js +198 -22
  120. package/dist/index.js +1741 -94
  121. package/dist/indice.js +99 -0
  122. package/dist/init.js +28 -3
  123. package/dist/integracoes-locais.js +17 -0
  124. package/dist/leases.js +65 -21
  125. package/dist/ledger-stats.js +272 -0
  126. package/dist/ledger.js +109 -2
  127. package/dist/licoes.js +221 -0
  128. package/dist/liveness.js +218 -0
  129. package/dist/maestro-actions.js +51 -0
  130. package/dist/maestro-authority.js +152 -0
  131. package/dist/maestro-cli.js +97 -0
  132. package/dist/maestro-contract.js +55 -0
  133. package/dist/maestro-discovery.js +132 -0
  134. package/dist/maestro-runtime.js +268 -0
  135. package/dist/maestro-snapshot.js +86 -0
  136. package/dist/maestro-sources.js +224 -0
  137. package/dist/manifest.js +165 -6
  138. package/dist/maquina.js +102 -0
  139. package/dist/master-audit.js +101 -0
  140. package/dist/master-batch.js +43 -0
  141. package/dist/master-digest.js +149 -0
  142. package/dist/master-migracao.js +155 -0
  143. package/dist/master.js +361 -77
  144. package/dist/mcp-artifacts.js +234 -0
  145. package/dist/mcp-git.js +433 -0
  146. package/dist/mcp-install.js +310 -0
  147. package/dist/mcp-maestro.js +25 -0
  148. package/dist/mcp-server.js +469 -0
  149. package/dist/mcp-ship.js +436 -0
  150. package/dist/mcp-verify.js +173 -0
  151. package/dist/memoria-humana.js +207 -0
  152. package/dist/memoria.js +314 -78
  153. package/dist/memory-migration.js +279 -0
  154. package/dist/memory-prospective.js +148 -0
  155. package/dist/modos-migracao.js +191 -0
  156. package/dist/modos.js +151 -15
  157. package/dist/monitor-lock.js +110 -0
  158. package/dist/objective.js +449 -0
  159. package/dist/ocupacao.js +267 -0
  160. package/dist/onboarding.js +303 -0
  161. package/dist/orkmind.js +389 -90
  162. package/dist/orquestracao.js +96 -69
  163. package/dist/phase.js +612 -151
  164. package/dist/playbook-capabilities.js +150 -0
  165. package/dist/playbook-contracts.js +188 -0
  166. package/dist/policies.js +72 -0
  167. package/dist/portfolio-context.js +61 -0
  168. package/dist/portfolio.js +180 -0
  169. package/dist/preflight.js +207 -0
  170. package/dist/process-audit.js +112 -0
  171. package/dist/project-state.js +93 -0
  172. package/dist/prompts.js +25 -5
  173. package/dist/prova-minima.js +112 -0
  174. package/dist/pulse-cadencia.js +163 -0
  175. package/dist/pulse-consentimento.js +260 -0
  176. package/dist/pulse-delivery.js +323 -0
  177. package/dist/pulse-resposta.js +542 -0
  178. package/dist/pulse.js +262 -0
  179. package/dist/ratelimit.js +35 -2
  180. package/dist/recall.js +80 -3
  181. package/dist/redacao-saida.js +45 -0
  182. package/dist/redacao-url.js +66 -0
  183. package/dist/retry.js +640 -118
  184. package/dist/roadmap-reservas.js +243 -0
  185. package/dist/runtime-ambiente.js +38 -0
  186. package/dist/runtime-context.js +215 -0
  187. package/dist/runtime-profiles.js +869 -0
  188. package/dist/runtimes.js +103 -0
  189. package/dist/sandbox.js +9 -0
  190. package/dist/session-events.js +203 -0
  191. package/dist/session-watcher-claude.js +637 -0
  192. package/dist/session-watcher.js +700 -0
  193. package/dist/sessoes-adopt.js +154 -0
  194. package/dist/sessoes-inventario.js +159 -0
  195. package/dist/sessoes.js +16 -35
  196. package/dist/setup.js +691 -0
  197. package/dist/ship.js +168 -19
  198. package/dist/slug.js +1 -1
  199. package/dist/thread-close.js +115 -0
  200. package/dist/thread.js +142 -28
  201. package/dist/tokens.js +1 -1
  202. package/dist/util.js +4 -2
  203. package/dist/verify-sandbox.js +265 -0
  204. package/dist/verify.js +270 -25
  205. package/dist/versao.js +60 -0
  206. package/dist/worktree.js +31 -2
  207. package/dist/write-activation.js +291 -0
  208. package/dist/yaml.js +5 -1
  209. package/eval/casos/master-metrics.json +1 -1
  210. package/eval/casos/onboarding.json +102 -0
  211. package/eval/casos/orkastery-bootstrap.json +37 -3
  212. package/eval/casos/scope-check-capability-map.json +45 -7
  213. package/eval/casos/ship-release.json +3 -3
  214. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  215. package/eval/fixtures/b2-master-log/caso.json +1 -1
  216. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  217. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  218. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  219. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  220. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  221. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  222. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  223. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  224. package/eval/fixtures/fx-happy/caso.json +6 -4
  225. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  226. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  227. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  228. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  229. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  230. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  231. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  232. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  233. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  234. package/monitor/company-brain.cjs +17 -0
  235. package/monitor/pulse-scope.cjs +45 -0
  236. package/monitor/pulse.cron +18 -0
  237. package/monitor/varredura-pulse.sh +27 -0
  238. package/package.json +28 -7
  239. package/references/definition-of-done.md +2 -2
  240. package/schemas/claims.schema.json +25 -0
  241. package/schemas/company-brain.schema.json +1158 -0
  242. package/schemas/creation-operation.schema.json +365 -0
  243. package/schemas/maestro-snapshot.schema.json +2716 -0
  244. package/skills/README.md +3 -3
  245. package/skills/core/onboarding/SKILL.md +50 -0
  246. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  247. package/skills/core/thread-state/SKILL.md +3 -1
  248. package/skills/governance/decision-triage/SKILL.md +4 -4
  249. package/skills/governance/narrative-guardian/SKILL.md +1 -1
  250. package/skills/governance/roadmap-keeper/SKILL.md +1 -1
  251. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
  252. package/skills/observability/thread-tracing/SKILL.md +1 -1
  253. package/skills/phases/check-quality/SKILL.md +2 -2
  254. package/skills/phases/goal-definition/SKILL.md +1 -1
  255. package/skills/phases/master-metrics/SKILL.md +9 -7
  256. package/skills/phases/plan-specification/SKILL.md +1 -1
  257. package/skills/phases/ship-release/SKILL.md +1 -1
@@ -0,0 +1,449 @@
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.CONTRATO_FIXACAO = exports.LIMITE_METADADO_BYTES = void 0;
37
+ exports.registrarFonteController = registrarFonteController;
38
+ exports.lerSnapshotController = lerSnapshotController;
39
+ /** D1/D2: leitor validado da fonte do controller. Sem RPC, resposta, sinal ou resume. */
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path"));
42
+ const codex_controller_1 = require("./codex-controller");
43
+ exports.LIMITE_METADADO_BYTES = 65536;
44
+ const MODO_METADADO = 0o600;
45
+ const UUID = /^[a-f0-9-]{36}$/;
46
+ const recusar = (motivo) => { throw new Error('runtime.unavailable: ' + motivo); };
47
+ const uidAtual = () => process.getuid?.() ?? -1;
48
+ /** Diretório canônico, ancestrais sem link nem escrita alheia, fonte 0700 do uid autenticado. */
49
+ function conferirDiretorioDaFonte(dir, dirSessoes, uid) {
50
+ const raiz = fs.realpathSync(dirSessoes);
51
+ if (fs.lstatSync(dir).isSymbolicLink())
52
+ recusar('fonte de controller acessada por link');
53
+ const real = fs.realpathSync(dir);
54
+ if (real !== dir)
55
+ recusar('fonte de controller fora do caminho real registrado');
56
+ if (!real.startsWith(raiz + path.sep))
57
+ recusar('fonte de controller fora do diretório canônico de sessões');
58
+ for (let atual = real;; atual = path.dirname(atual)) {
59
+ const st = fs.lstatSync(atual);
60
+ if (!st.isDirectory() || st.isSymbolicLink())
61
+ recusar('ancestral da fonte de controller não é diretório próprio');
62
+ if (st.uid !== uid)
63
+ recusar('ancestral da fonte de controller de outro uid');
64
+ if (atual === real ? (st.mode & 0o077) !== 0 : (st.mode & 0o022) !== 0)
65
+ recusar('ancestral da fonte de controller com permissão alheia');
66
+ if (atual === raiz)
67
+ break;
68
+ if (atual === path.dirname(atual))
69
+ recusar('ancestral da fonte de controller sem raiz canônica');
70
+ }
71
+ return real;
72
+ }
73
+ /** Abre sem seguir link, confere descritor/inode, modo, dono e limite antes de decodificar. */
74
+ function lerMetadado(dir, nome, uid, obrigatorio = true) {
75
+ const file = path.join(dir, nome);
76
+ let antes;
77
+ try {
78
+ antes = fs.lstatSync(file);
79
+ }
80
+ catch (e) {
81
+ if (e.code === 'ENOENT' && !obrigatorio)
82
+ return null;
83
+ return recusar(`metadado ${nome} de controller ausente`);
84
+ }
85
+ if (!antes.isFile() || antes.isSymbolicLink())
86
+ recusar(`metadado ${nome} de controller não é arquivo regular`);
87
+ const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
88
+ try {
89
+ const st = fs.fstatSync(fd);
90
+ if (!st.isFile() || st.ino !== antes.ino || st.dev !== antes.dev)
91
+ recusar(`descritor de ${nome} divergente do inode conferido`);
92
+ if (st.uid !== uid)
93
+ recusar(`metadado ${nome} de controller de outro uid`);
94
+ if ((st.mode & 0o777) !== MODO_METADADO)
95
+ recusar(`metadado ${nome} de controller não é privado 0600`);
96
+ if (st.size > exports.LIMITE_METADADO_BYTES)
97
+ recusar(`metadado ${nome} de controller excessivo`);
98
+ const buffer = Buffer.alloc(st.size);
99
+ const n = fs.readSync(fd, buffer, 0, st.size, 0);
100
+ // Nenhuma mensagem carrega o conteúdo lido, nem o recorte do SyntaxError.
101
+ try {
102
+ return JSON.parse(buffer.subarray(0, n).toString('utf8'));
103
+ }
104
+ catch {
105
+ return recusar(`metadado ${nome} de controller inválido`);
106
+ }
107
+ }
108
+ finally {
109
+ fs.closeSync(fd);
110
+ }
111
+ }
112
+ function mesmoVinculo(a, b) {
113
+ const v = a;
114
+ return !!v && v.thread === b.thread && v.fase === b.fase && v.promptSha256 === b.promptSha256 &&
115
+ Object.keys(v).length === 3;
116
+ }
117
+ function mesmaIdentidade(a, b) {
118
+ if (!a || !b)
119
+ return a === undefined || b === undefined ? false : a === b;
120
+ return a.pid === b.pid && a.uid === b.uid && a.inicio === b.inicio && a.bootId === b.bootId &&
121
+ a.executavel === b.executavel && a.cwd === b.cwd;
122
+ }
123
+ function identidadeValida(p, uid) {
124
+ if (p === undefined || p === null)
125
+ return null;
126
+ const i = p;
127
+ if (!Number.isSafeInteger(i.pid) || i.pid <= 0 || i.uid !== uid || !/^\d+$/.test(String(i.inicio)) ||
128
+ typeof i.bootId !== 'string' || !i.bootId || typeof i.executavel !== 'string' || typeof i.cwd !== 'string') {
129
+ return recusar('identidade de processo do controller inválida');
130
+ }
131
+ return i;
132
+ }
133
+ /**
134
+ * Identidade viva é reconferida contra o `/proc` real; processo já morto conserva a
135
+ * identidade capturada no spawn e nunca é redescoberto por PID.
136
+ */
137
+ function conferirIdentidadeViva(p, papel) {
138
+ const estado = estadoDoProcesso(p);
139
+ if (!p || estado !== 'vivo')
140
+ return estado;
141
+ let executavel, cwd;
142
+ try {
143
+ executavel = fs.readlinkSync(`/proc/${p.pid}/exe`);
144
+ cwd = fs.readlinkSync(`/proc/${p.pid}/cwd`);
145
+ }
146
+ catch (e) {
147
+ return e.code === 'ENOENT' ? 'ausente' : 'desconhecido';
148
+ }
149
+ if (executavel !== p.executavel)
150
+ recusar(`executável real do ${papel} divergente do capturado`);
151
+ if (cwd !== p.cwd)
152
+ recusar(`cwd real do ${papel} divergente do capturado`);
153
+ return 'vivo';
154
+ }
155
+ /** PID sozinho não autentica: exige boot, starttime, uid e ausência de zumbi. */
156
+ function estadoDoProcesso(p) {
157
+ if (!p)
158
+ return 'desconhecido';
159
+ try {
160
+ const st = fs.readFileSync(`/proc/${p.pid}/stat`, 'utf8');
161
+ const campos = st.slice(st.lastIndexOf(')') + 2).split(' ');
162
+ const boot = fs.readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim();
163
+ if (boot !== p.bootId || campos[19] !== p.inicio || campos[0] === 'Z')
164
+ return 'ausente';
165
+ return fs.statSync(`/proc/${p.pid}`).uid === p.uid ? 'vivo' : 'ausente';
166
+ }
167
+ catch (e) {
168
+ return e.code === 'ENOENT' ? 'ausente' : 'desconhecido';
169
+ }
170
+ }
171
+ /** Cabeçalho do rollout: identidade da sessão e cwd nativo são obrigatórios. */
172
+ function conferirSessionMeta(fd, tamanho, sessionId, cwd) {
173
+ const buffer = Buffer.alloc(Math.min(exports.LIMITE_METADADO_BYTES, tamanho));
174
+ const n = fs.readSync(fd, buffer, 0, buffer.length, 0);
175
+ const fim = buffer.subarray(0, n).lastIndexOf(10);
176
+ if (fim < 0)
177
+ recusar('rollout do controller sem session_meta conferível');
178
+ for (const linha of buffer.subarray(0, fim + 1).toString('utf8').split('\n')) {
179
+ let e;
180
+ try {
181
+ e = JSON.parse(linha);
182
+ }
183
+ catch {
184
+ continue;
185
+ }
186
+ if (!e || e.type !== 'session_meta')
187
+ continue;
188
+ if (e.payload?.id !== sessionId)
189
+ recusar('session_meta do rollout de outra sessão');
190
+ if (e.payload?.cwd !== cwd)
191
+ recusar('session_meta do rollout com cwd divergente do despacho');
192
+ return;
193
+ }
194
+ recusar('rollout do controller sem session_meta conferível');
195
+ }
196
+ /**
197
+ * Abre o rollout sem seguir links e reconfere o descritor contra o inode observado.
198
+ * Não há atomicidade contra troca entre lstat e open: a garantia é a reconferência do
199
+ * descritor aberto e do vínculo com a fonte fixada, com recusa quando a prova não se sustenta.
200
+ */
201
+ function conferirFonteDeRollout(rollout, uid, sessionId, cwd, fixado) {
202
+ if (typeof rollout !== 'string' || !rollout || !path.isAbsolute(rollout))
203
+ recusar('rollout do controller não confirmado');
204
+ const file = rollout;
205
+ if (fixado && file !== fixado.file)
206
+ recusar('rollout do controller divergente do registrado');
207
+ const antes = fs.lstatSync(file, { throwIfNoEntry: false });
208
+ // Fonte ausente nunca autentica nada: o terminal em cache deixa de valer com ela.
209
+ if (!antes)
210
+ return recusar('rollout do controller ausente');
211
+ if (!antes.isFile() || antes.isSymbolicLink())
212
+ recusar('rollout do controller não é arquivo regular');
213
+ if (fs.realpathSync(file) !== file)
214
+ recusar('rollout do controller acessado por ancestral link');
215
+ const pai = fs.lstatSync(path.dirname(file));
216
+ if (!pai.isDirectory() || pai.uid !== uid || (pai.mode & 0o022) !== 0)
217
+ recusar('diretório do rollout do controller com permissão alheia');
218
+ const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
219
+ try {
220
+ const st = fs.fstatSync(fd);
221
+ if (!st.isFile() || st.ino !== antes.ino || st.dev !== antes.dev)
222
+ recusar('descritor de rollout divergente do inode conferido');
223
+ if (st.uid !== uid)
224
+ recusar('rollout do controller de outro uid');
225
+ if ((st.mode & 0o022) !== 0)
226
+ recusar('rollout do controller com permissão de escrita alheia');
227
+ // Rotação não é permitida neste transporte: sem regra de vínculo com a fonte anterior, recusa.
228
+ if (fixado && (st.ino !== fixado.ino || st.dev !== fixado.dev))
229
+ recusar('rollout do controller rotacionado sem vínculo provado com a fonte fixada');
230
+ conferirSessionMeta(fd, st.size, sessionId, cwd);
231
+ return { file, ino: st.ino, dev: st.dev };
232
+ }
233
+ finally {
234
+ fs.closeSync(fd);
235
+ }
236
+ }
237
+ /**
238
+ * Fixacao privada da fonte: escrita uma unica vez, antes de qualquer efeito de observacao,
239
+ * e reconferida em cada poll e em cada restart do observador. Sem redescoberta de processo.
240
+ */
241
+ exports.CONTRATO_FIXACAO = 'ork.controller-source-pin/v1';
242
+ function persistirFonte(file, fonte) {
243
+ const parcial = `${file}.${process.pid}.parcial`;
244
+ fs.mkdirSync(path.dirname(file), { recursive: true });
245
+ fs.rmSync(parcial, { force: true });
246
+ fs.writeFileSync(parcial, JSON.stringify({ contratoFixacao: exports.CONTRATO_FIXACAO, ...fonte }), { mode: 0o600, flag: 'wx' });
247
+ try {
248
+ fs.renameSync(parcial, file);
249
+ }
250
+ catch (e) {
251
+ fs.rmSync(parcial, { force: true });
252
+ throw e;
253
+ }
254
+ }
255
+ /** Devolve a fonte ja fixada, ou `null` quando ainda nao existe fixacao para este despacho. */
256
+ function lerFonteFixada(file, esperado, uid) {
257
+ const bruto = lerMetadado(path.dirname(file), path.basename(file), uid, false);
258
+ if (!bruto)
259
+ return null;
260
+ if (bruto.contratoFixacao !== exports.CONTRATO_FIXACAO)
261
+ recusar('fixacao da fonte de controller com contrato divergente');
262
+ const f = bruto;
263
+ if (f.contrato !== 'ork.controller-launch/v1' || typeof f.dir !== 'string' || typeof f.instancia !== 'string' ||
264
+ typeof f.rollout !== 'string' || !Number.isSafeInteger(f.rolloutIno) || !Number.isSafeInteger(f.rolloutDev) ||
265
+ typeof f.criadoEm !== 'string' || f.uid !== uid)
266
+ recusar('fixacao da fonte de controller invalida');
267
+ if (!mesmoVinculo(f.vinculo, esperado.vinculo))
268
+ recusar('vinculo da fixacao divergente do despacho');
269
+ if (f.sessionId !== esperado.sessionId)
270
+ recusar('sessao da fixacao divergente do despacho');
271
+ if (f.cwd !== esperado.cwd)
272
+ recusar('cwd da fixacao divergente do despacho');
273
+ // Identidades vem da fixacao, nunca de nova descoberta por PID.
274
+ const controlador = identidadeValida(f.processoController, uid);
275
+ const runtime = identidadeValida(f.processoRuntime, uid);
276
+ if (!controlador || !runtime)
277
+ recusar('fixacao da fonte de controller sem identidade capturada');
278
+ return { contrato: 'ork.controller-launch/v1', dir: f.dir, instancia: f.instancia, vinculo: esperado.vinculo,
279
+ cwd: esperado.cwd, sessionId: esperado.sessionId, rollout: f.rollout, rolloutIno: f.rolloutIno,
280
+ rolloutDev: f.rolloutDev, criadoEm: f.criadoEm, processoController: controlador, processoRuntime: runtime, uid };
281
+ }
282
+ /**
283
+ * Espera humana so suspende o prazo com o tuple nativo completo: thread, turno, `requestId`
284
+ * inclusive o numero `0`, item e hash iguais aos da pergunta projetada.
285
+ */
286
+ function esperaAutenticada(estado, fonte) {
287
+ if (estado.estado !== 'blocked' || typeof estado.bloqueio !== 'string')
288
+ return false;
289
+ const pergunta = estado.perguntaNativa;
290
+ if (!pergunta || typeof pergunta.sha256 !== 'string' || !/^[a-f0-9]{64}$/.test(pergunta.sha256))
291
+ return false;
292
+ let tuple;
293
+ try {
294
+ tuple = JSON.parse(estado.bloqueio);
295
+ }
296
+ catch {
297
+ return false;
298
+ }
299
+ if (!Array.isArray(tuple) || tuple.length !== 4)
300
+ return false;
301
+ const [turno, requestId, item, hash] = tuple;
302
+ // `requestId` 0 e um id valido: so a ausencia de numero inteiro recusa a excecao.
303
+ if (typeof turno !== 'string' || !turno || turno !== (estado.turno ?? null))
304
+ return false;
305
+ if (!Number.isInteger(requestId) || requestId < 0)
306
+ return false;
307
+ if (typeof item !== 'string' || !item)
308
+ return false;
309
+ if (hash !== pergunta.sha256)
310
+ return false;
311
+ return estado.sessionId === fonte.sessionId;
312
+ }
313
+ function conferirEstado(bruto, esperado) {
314
+ const s = bruto;
315
+ if (s.instancia !== esperado.instancia)
316
+ recusar('instância do controller divergente');
317
+ if (!mesmoVinculo(s.vinculo, esperado.vinculo))
318
+ recusar('vínculo thread/fase/prompt do controller divergente');
319
+ if (s.cwd !== esperado.cwd)
320
+ recusar('cwd do controller divergente');
321
+ if (s.sessionId !== esperado.sessionId)
322
+ recusar('sessão do controller divergente');
323
+ if (typeof s.estado !== 'string' || !s.estado)
324
+ recusar('estado do controller ausente');
325
+ return s;
326
+ }
327
+ /**
328
+ * Registra a fonte de um despacho já concluído, ANTES de qualquer efeito de observação.
329
+ * Fixa identidades e rollout; toda leitura posterior reconfere os mesmos valores.
330
+ */
331
+ function registrarFonteController(dir, esperado) {
332
+ const uid = esperado.uid ?? uidAtual();
333
+ const agora = esperado.agoraMs ?? Date.now();
334
+ const despachoMs = Date.parse(esperado.despachoEm);
335
+ if (!Number.isFinite(despachoMs))
336
+ recusar('despacho sem carimbo de tempo válido');
337
+ const real = conferirDiretorioDaFonte(dir, esperado.dirSessoes, uid);
338
+ // Fonte já fixada: poll e restart reconferem a mesma fixação, sem redescoberta.
339
+ const fixada = esperado.fixacao ? lerFonteFixada(esperado.fixacao, esperado, uid) : null;
340
+ if (fixada) {
341
+ if (fixada.dir !== real)
342
+ recusar('fonte de controller divergente da fixada');
343
+ return fixada;
344
+ }
345
+ const launch = lerMetadado(real, 'launch.json', uid);
346
+ if (launch.contrato !== 'ork.controller-launch/v1')
347
+ recusar('contrato de launch do controller divergente');
348
+ if (typeof launch.instancia !== 'string' || !UUID.test(launch.instancia))
349
+ recusar('instância de launch do controller inválida');
350
+ if (!mesmoVinculo(launch.vinculo, esperado.vinculo))
351
+ recusar('vínculo thread/fase/prompt do launch divergente');
352
+ if (launch.cwd !== esperado.cwd)
353
+ recusar('cwd do launch divergente');
354
+ const criadoMs = Date.parse(String(launch.criadoEm));
355
+ if (!Number.isFinite(criadoMs) || criadoMs > despachoMs || criadoMs > agora)
356
+ recusar('launch do controller fora da janela do despacho');
357
+ // `process-launch` é obrigatório: sem a identidade capturada no spawn não há o que autenticar.
358
+ const processo = lerMetadado(real, 'process-launch.json', uid);
359
+ const estado = conferirEstado(lerMetadado(real, 'state.json', uid), {
360
+ instancia: launch.instancia, vinculo: esperado.vinculo, cwd: esperado.cwd, sessionId: esperado.sessionId,
361
+ });
362
+ const processoController = identidadeValida(estado.processoController, uid);
363
+ const processoRuntime = identidadeValida(estado.processoRuntime, uid);
364
+ if (!processoController)
365
+ recusar('identidade do controller ausente na fonte');
366
+ if (!processoRuntime)
367
+ recusar('identidade do runtime ausente na fonte');
368
+ if (processo.instancia !== launch.instancia)
369
+ recusar('instância do process-launch divergente');
370
+ if (!Number.isSafeInteger(processo.pid) || processo.pid <= 0 || processo.pid !== estado.pid)
371
+ recusar('pid do process-launch divergente do estado');
372
+ const capturado = identidadeValida(processo.processoController, uid);
373
+ if (!capturado)
374
+ recusar('identidade capturada no spawn ausente no process-launch');
375
+ if (!mesmaIdentidade(capturado, processoController))
376
+ recusar('identidade do controller divergente do spawn');
377
+ if (processoController.pid !== estado.pid)
378
+ recusar('identidade do controller não corresponde ao pid do estado');
379
+ // O worker nasce no diretório de IPC e o runtime no cwd do despacho: identidade capturada prova os dois.
380
+ if (processoController.cwd !== real)
381
+ recusar('cwd do controller divergente do IPC');
382
+ if (processoRuntime.cwd !== esperado.cwd)
383
+ recusar('cwd do runtime divergente do despacho');
384
+ conferirIdentidadeViva(processoController, 'controller');
385
+ conferirIdentidadeViva(processoRuntime, 'runtime');
386
+ const rollout = conferirFonteDeRollout(estado.rollout, uid, esperado.sessionId, esperado.cwd);
387
+ const fonte = { contrato: 'ork.controller-launch/v1', dir: real, instancia: launch.instancia,
388
+ vinculo: esperado.vinculo, cwd: esperado.cwd, sessionId: esperado.sessionId, rollout: rollout.file,
389
+ rolloutIno: rollout.ino, rolloutDev: rollout.dev, criadoEm: new Date(criadoMs).toISOString(),
390
+ processoController, processoRuntime, uid };
391
+ // Fixação persistida ANTES de devolver a fonte, logo antes de qualquer efeito de observação.
392
+ if (esperado.fixacao)
393
+ persistirFonte(esperado.fixacao, fonte);
394
+ return fonte;
395
+ }
396
+ /** Releitura da fonte fixada. Nunca descobre outro processo, nem aceita override de rollout. */
397
+ function lerSnapshotController(fonte, opcoes = {}) {
398
+ const agora = opcoes.agoraMs ?? Date.now();
399
+ const real = conferirDiretorioDaFonte(fonte.dir, path.dirname(fonte.dir), fonte.uid);
400
+ if (real !== fonte.dir)
401
+ recusar('fonte de controller mudou de caminho real');
402
+ const estado = conferirEstado(lerMetadado(real, 'state.json', fonte.uid), fonte);
403
+ if (!mesmaIdentidade(identidadeValida(estado.processoController, fonte.uid), fonte.processoController))
404
+ recusar('identidade do controller divergente da registrada');
405
+ if (!mesmaIdentidade(identidadeValida(estado.processoRuntime, fonte.uid), fonte.processoRuntime))
406
+ recusar('identidade do runtime divergente da registrada');
407
+ const rollout = conferirFonteDeRollout(estado.rollout, fonte.uid, fonte.sessionId, fonte.cwd, { file: fonte.rollout, ino: fonte.rolloutIno, dev: fonte.rolloutDev });
408
+ if (rollout.file !== fonte.rollout)
409
+ recusar('rollout do controller divergente do registrado');
410
+ let fechamento = null;
411
+ const close = estado.processoEncerrado;
412
+ if (close !== undefined) {
413
+ const em = Date.parse(String(close.em));
414
+ if (!Number.isFinite(em) || em > agora || em < Date.parse(fonte.criadoEm))
415
+ recusar('close do controller fora da janela do despacho');
416
+ if (close.code !== null && (!Number.isInteger(close.code) || close.code < 0))
417
+ recusar('code do close do controller inválido');
418
+ if (close.signal !== null && typeof close.signal !== 'string')
419
+ recusar('signal do close do controller inválido');
420
+ // Única origem de exit: o `close` do ChildProcess dono do stdin, nunca turn/completed.
421
+ fechamento = { em: new Date(em).toISOString(), exitCode: close.code, signal: close.signal,
422
+ duracaoMs: em - Date.parse(fonte.criadoEm), fonte: 'controller.close' };
423
+ }
424
+ let terminalNativo = null;
425
+ if (estado.terminal !== undefined) {
426
+ const t = estado.terminal;
427
+ if (t.metodo !== 'turn/completed' || t.threadId !== fonte.sessionId || typeof t.turnId !== 'string' ||
428
+ typeof t.status !== 'string')
429
+ recusar('terminal nativo do controller divergente');
430
+ if (t.erro !== undefined && !(0, codex_controller_1.erroNativoValido)(t.erro))
431
+ recusar('erro nativo do terminal do controller invalido');
432
+ terminalNativo = { metodo: 'turn/completed', threadId: t.threadId, turnId: t.turnId, status: t.status,
433
+ ...(t.erro !== undefined ? { erro: { codigo: t.erro.codigo, mensagem: t.erro.mensagem } } : {}) };
434
+ }
435
+ const estadoController = conferirIdentidadeViva(fonte.processoController, 'controller');
436
+ const estadoRuntime = fechamento ? 'ausente' : conferirIdentidadeViva(fonte.processoRuntime, 'runtime');
437
+ if (estado.erro !== undefined && (typeof estado.erro !== 'string' || !estado.erro))
438
+ recusar('erro do controller invalido');
439
+ if (estado.limitacao !== undefined && (typeof estado.limitacao !== 'object' || estado.limitacao === null ||
440
+ estado.limitacao.motivo !== 'runtime.unavailable' || typeof estado.limitacao.codigo !== 'string' ||
441
+ typeof estado.limitacao.metodo !== 'string'))
442
+ recusar('limitacao do controller invalida');
443
+ return { fonte, estado: estado.estado, turno: estado.turno ?? null, rollout: fonte.rollout, terminalNativo,
444
+ erro: estado.erro ?? null, limitacao: estado.limitacao ?? null,
445
+ esperaHumana: esperaAutenticada(estado, fonte) &&
446
+ !fechamento && estadoRuntime === 'vivo' && estadoController === 'vivo',
447
+ fechamento, exitCode: fechamento ? fechamento.exitCode : null,
448
+ exitCodeFonte: fechamento ? 'controller.close' : 'unavailable', estadoController, estadoRuntime };
449
+ }