@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
@@ -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.readObjective = readObjective;
37
+ exports.listObjectives = listObjectives;
38
+ exports.listObjectiveMessages = listObjectiveMessages;
39
+ exports.messageObjective = messageObjective;
40
+ exports.createObjective = createObjective;
41
+ exports.createReservedObjective = createReservedObjective;
42
+ exports.approveObjective = approveObjective;
43
+ exports.reviseObjective = reviseObjective;
44
+ exports.validateObjective = validateObjective;
45
+ exports.stopObjective = stopObjective;
46
+ exports.compensateReservedObjective = compensateReservedObjective;
47
+ exports.objectivePhases = objectivePhases;
48
+ exports.objectiveText = objectiveText;
49
+ /**
50
+ * Maestro Mode B7: objetivos duráveis acima de uma única thread.
51
+ *
52
+ * I-43 (T11): O COMANDO `ork objective` FOI APOSENTADO. Este módulo continua aqui, e
53
+ * a razão está escrita abaixo porque ela é exatamente o tipo de coisa que, sem estar
54
+ * escrita, vira "sobrou um arquivo morto".
55
+ *
56
+ * O que SAIU, que é o que o GOAL pediu: a superfície de produto. `ork objective` em
57
+ * qualquer subcomando devolve `objective.aposentado` com saída != 0; o ramo de
58
+ * `phase.ts` que consultava o envelope no despacho saiu; e `fx-objective-oscillation`
59
+ * saiu junto com o mecanismo que ele exercitava (D9).
60
+ *
61
+ * O que FICOU, e por quê: este arquivo é carregado por três consumidores que NÃO são
62
+ * o envelope e que esta thread não tem escopo para remover:
63
+ * - `creation-operation.ts`, o journal durável de criação (portfolio/creation);
64
+ * - `portfolio-context.ts`, que alimenta `ork portfolio inspect`;
65
+ * - `maestro-sources.ts`, que lê `objective.json` para o snapshot do Maestro.
66
+ * Arrancar o módulo levaria os três junto, e nenhum deles é uma das cinco remoções.
67
+ * O item está no roadmap com esta medida, em vez de virar uma remoção no escuro.
68
+ *
69
+ * As DUAS VIGAS que o envelope guardava saíram VIVAS, como propriedade de thread
70
+ * comum, e é o que torna a remoção da superfície honesta:
71
+ * - validação por runtime diferente -> `thread.exigeRuntimeDiferente` (T9);
72
+ * - `doneWhen` executável -> `thread.doneWhen`, que vira claim do núcleo (T10).
73
+ *
74
+ * Os envelopes já gravados em `.orkastery/objectives/` ficam em disco, intocados: é
75
+ * estado, e estado pertence ao núcleo. Contrato `ork.objective/v1`, um arquivo
76
+ * `objective.json` por diretório, legível por `cat` e `jq`.
77
+ */
78
+ const fs = __importStar(require("node:fs"));
79
+ const path = __importStar(require("node:path"));
80
+ const node_crypto_1 = require("node:crypto");
81
+ const manifest_1 = require("./manifest");
82
+ const slug_1 = require("./slug");
83
+ const thread_1 = require("./thread");
84
+ const ledger_1 = require("./ledger");
85
+ const util_1 = require("./util");
86
+ const types_1 = require("./types");
87
+ const sessoes_1 = require("./sessoes");
88
+ const portfolio_1 = require("./portfolio");
89
+ const creation_operation_store_1 = require("./creation-operation-store");
90
+ const hitl_gates_1 = require("./hitl-gates");
91
+ const maestro_authority_1 = require("./maestro-authority");
92
+ const OBJECTIVE_ID = /^obj-[a-z0-9-]{1,48}$/;
93
+ const clean = (values) => (values ?? []).map((v) => v.trim()).filter(Boolean);
94
+ function objectiveDir(root) { return path.join((0, manifest_1.dirEstado)(root), 'objectives'); }
95
+ function objectiveFile(root, id) {
96
+ if (!OBJECTIVE_ID.test(id))
97
+ throw new Error('objective id inválido');
98
+ return path.join(objectiveDir(root), id, 'objective.json');
99
+ }
100
+ function messagesFile(root, id) {
101
+ return path.join(path.dirname(objectiveFile(root, id)), 'messages.jsonl');
102
+ }
103
+ function digest(value) {
104
+ return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(value)).digest('hex');
105
+ }
106
+ function envelope(input, version = 1, root) {
107
+ const maxThreads = input.maxThreads ?? 3;
108
+ if (!Number.isInteger(maxThreads) || maxThreads < 1 || maxThreads > 8)
109
+ throw new Error('maxThreads deve estar entre 1 e 8');
110
+ const executionRuntime = input.executionRuntime?.trim() || 'claude-bg';
111
+ const validationRuntimes = [...new Set(clean(input.validationRuntimes).length ? clean(input.validationRuntimes) : ['codex', 'claude-bg'])];
112
+ if (input.independence !== undefined && input.independence !== 'sessions')
113
+ throw Error('maestro.authority.mode');
114
+ if (input.independence === 'sessions')
115
+ validationRuntimes.forEach(maestro_authority_1.requireSessionReviewRuntime);
116
+ if (!input.independence && validationRuntimes.length < 2)
117
+ throw new Error('ensemble exige ao menos dois runtimes de validação');
118
+ if (!input.independence && !validationRuntimes.some((runtime) => runtime !== executionRuntime))
119
+ throw new Error('CHECK deve incluir runtime diferente do GO');
120
+ const base = {
121
+ schema: 'ork.objective-envelope/v1',
122
+ version,
123
+ request: input.request.trim(),
124
+ outcomes: clean(input.outcomes),
125
+ constraints: clean(input.constraints),
126
+ doneWhen: clean(input.doneWhen),
127
+ maxThreads,
128
+ executionRuntime,
129
+ validationRuntimes,
130
+ ...(input.independence ? { independence: input.independence } : {}),
131
+ portfolio: input.productId && input.projectId
132
+ ? { productId: input.productId, projectId: input.projectId, delivery: input.delivery ?? 'project', initiativeIds: clean(input.initiativeIds) }
133
+ : null,
134
+ };
135
+ if (!base.request)
136
+ throw new Error('objective exige request');
137
+ if (!base.doneWhen.length)
138
+ throw new Error('objective exige ao menos um critério de pronto');
139
+ if ((input.productId && !input.projectId) || (!input.productId && input.projectId))
140
+ throw new Error('vínculo de portfólio exige productId e projectId');
141
+ if (base.portfolio && root) {
142
+ const scope = (0, portfolio_1.assertCycleScope)(root, base.portfolio);
143
+ const project = (0, portfolio_1.findEntity)(root, scope.projectId);
144
+ if (!project || project.kind !== 'project' || project.productId !== base.portfolio.productId)
145
+ throw new Error('projeto não pertence ao produto informado');
146
+ base.portfolio = { productId: base.portfolio.productId, ...scope };
147
+ }
148
+ return { ...base, hash: digest(base) };
149
+ }
150
+ function persist(root, objective) {
151
+ objective.updatedAt = (0, util_1.agora)();
152
+ (0, creation_operation_store_1.writeCreationJson)(objectiveFile(root, objective.id), objective);
153
+ return objective;
154
+ }
155
+ function readObjective(root, id) {
156
+ const file = objectiveFile(root, id);
157
+ if (!fs.existsSync(file))
158
+ throw new Error(`objective ${id} não encontrado`);
159
+ const value = (0, util_1.lerJson)(file);
160
+ const { hash: _hash, ...body } = value.envelope;
161
+ if (value.schema !== 'ork.objective/v1' || digest(body) !== value.envelope.hash)
162
+ throw new Error('Objective Envelope inválido ou alterado fora do ork');
163
+ return value;
164
+ }
165
+ function listObjectives(root) {
166
+ const dir = objectiveDir(root);
167
+ if (!fs.existsSync(dir))
168
+ return [];
169
+ return fs.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => readObjective(root, e.name))
170
+ .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
171
+ }
172
+ function listObjectiveMessages(root, id) {
173
+ readObjective(root, id);
174
+ const file = messagesFile(root, id);
175
+ if (!fs.existsSync(file))
176
+ return [];
177
+ return fs.readFileSync(file, 'utf8').split('\n').filter(Boolean).map((line) => JSON.parse(line));
178
+ }
179
+ function messageObjective(root, id, input) {
180
+ readObjective(root, id);
181
+ const text = input.text.trim(), by = input.by.trim();
182
+ if (!text || text.length > 10_000)
183
+ throw new Error('mensagem deve ter entre 1 e 10000 caracteres');
184
+ if (!by || by.length > 120)
185
+ throw new Error('mensagem exige autor válido');
186
+ const createdAt = (0, util_1.agora)();
187
+ const message = {
188
+ schema: 'ork.objective-message/v1',
189
+ id: `msg-${(0, node_crypto_1.createHash)('sha256').update(`${id}:${createdAt}:${by}:${text}`).digest('hex').slice(0, 16)}`,
190
+ objectiveId: id, role: input.role, by, text, createdAt,
191
+ };
192
+ fs.appendFileSync(messagesFile(root, id), `${JSON.stringify(message)}\n`, { encoding: 'utf8', mode: 0o600 });
193
+ return message;
194
+ }
195
+ function createObjective(loaded, input) {
196
+ return (0, creation_operation_store_1.withCreationLock)(loaded.raiz, 'objectives', () => createLegacyObjective(loaded, input));
197
+ }
198
+ function createLegacyObjective(loaded, input) {
199
+ const subject = (0, slug_1.normalizarAssunto)(input.title);
200
+ if (!subject)
201
+ throw new Error('título não produz id válido');
202
+ let id = `obj-${subject}`, suffix = 1;
203
+ while (fs.existsSync(objectiveFile(loaded.raiz, id)))
204
+ id = `obj-${subject.slice(0, 40)}-${++suffix}`;
205
+ const env = envelope(input, 1, loaded.raiz);
206
+ const roles = ['discovery', 'delivery', 'validation'];
207
+ const threads = Array.from({ length: env.maxThreads }, (_, index) => {
208
+ const role = roles[index] ?? 'delivery';
209
+ const result = (0, thread_1.novaThread)(loaded, { nome: `${input.title} · ${role} ${index + 1}`, modo: input.mode ?? 'maestro', assunto: `${subject.slice(0, 8)}${index + 1}` });
210
+ return { id: result.thread.id, role };
211
+ });
212
+ const now = (0, util_1.agora)();
213
+ const value = {
214
+ schema: 'ork.objective/v1', id, title: input.title.trim(), mode: input.mode ?? 'maestro', status: 'awaiting_approval',
215
+ createdAt: now, updatedAt: now, envelope: env, envelopeHistory: [], threads, approval: null,
216
+ validations: [], revisions: 0, pauseReason: 'human.approval.objective-envelope', stopStack: [],
217
+ };
218
+ persist(loaded.raiz, value);
219
+ const dir = path.dirname(objectiveFile(loaded.raiz, id));
220
+ fs.writeFileSync(path.join(dir, 'INTENT.md'), input.request.trim() + '\n', 'utf8');
221
+ fs.writeFileSync(path.join(dir, 'SPEC.md'), `# ${input.title.trim()}\n\n## Pronto quando\n${env.doneWhen.map((x) => `- ${x}`).join('\n')}\n`, 'utf8');
222
+ messageObjective(loaded.raiz, id, { role: 'human', by: 'maestro', text: input.request });
223
+ return value;
224
+ }
225
+ /** Ticket determinístico fica localizável antes de qualquer thread; nunca despacha runtime. */
226
+ function createReservedObjective(loaded, input, reservation) {
227
+ return (0, creation_operation_store_1.withCreationLock)(loaded.raiz, 'objectives', () => {
228
+ const op = (0, creation_operation_store_1.readCreationOperation)(loaded.raiz, reservation.operationId, reservation.principal);
229
+ const id = op.reserved.ticketId;
230
+ if (!id || ['compensating', 'compensated', 'compensation_failed'].includes(op.state)
231
+ || input.request.trim() !== op.request.request || input.mode !== op.request.mode
232
+ || JSON.stringify(clean(input.doneWhen)) !== JSON.stringify(op.request.doneWhen)) {
233
+ throw new Error('creation.conflict: ticket incompatível com intenção reservada');
234
+ }
235
+ const env = envelope(input, 1, loaded.raiz);
236
+ if (env.maxThreads !== op.reserved.threadIds.length)
237
+ throw new Error('creation.conflict: quantidade de threads não reservada');
238
+ const origin = { operationId: op.operationId, ticketId: id, requestHash: op.requestHash };
239
+ const roles = ['discovery', 'delivery', 'validation'];
240
+ const threads = op.reserved.threadIds.map((threadId, index) => ({ id: threadId, role: roles[index] ?? 'delivery' }));
241
+ let value;
242
+ if (fs.existsSync(objectiveFile(loaded.raiz, id))) {
243
+ value = readObjective(loaded.raiz, id);
244
+ if (value.creationOrigin?.operationId !== origin.operationId || value.creationOrigin?.requestHash !== origin.requestHash
245
+ || value.creationOrigin?.ticketId !== id || value.envelope.hash !== env.hash
246
+ || value.title !== input.title.trim() || value.mode !== input.mode || JSON.stringify(value.threads) !== JSON.stringify(threads)) {
247
+ throw new Error('creation.conflict: ticket reservado pertence a outra intenção ou foi revisado');
248
+ }
249
+ if (value.status !== 'awaiting_approval' || value.approval)
250
+ throw new Error('creation.started: ticket já saiu da criação');
251
+ }
252
+ else {
253
+ const now = (0, util_1.agora)();
254
+ value = { schema: 'ork.objective/v1', id, title: input.title.trim(), mode: input.mode, status: 'awaiting_approval',
255
+ createdAt: now, updatedAt: now, envelope: env, envelopeHistory: [], threads, approval: null,
256
+ validations: [], revisions: 0, pauseReason: 'human.approval.objective-envelope', stopStack: [], creationOrigin: origin };
257
+ persist(loaded.raiz, value);
258
+ }
259
+ for (const link of threads) {
260
+ if (fs.existsSync((0, thread_1.caminhoThread)(loaded.raiz, link.id))) {
261
+ const thread = (0, thread_1.lerThread)(loaded.raiz, link.id);
262
+ if (thread.sessoes.length || thread.decisoes.length || thread.faseAtual !== thread.fases[0] || thread.status !== 'aberta') {
263
+ throw new Error('creation.started: thread já iniciou execução');
264
+ }
265
+ }
266
+ }
267
+ for (const [index, link] of threads.entries()) {
268
+ (0, thread_1.novaThread)(loaded, { nome: `${value.title} · ${link.role} ${index + 1}`, modo: value.mode,
269
+ reservation: { ...reservation, threadId: link.id } });
270
+ }
271
+ const dir = path.dirname(objectiveFile(loaded.raiz, id));
272
+ if (!fs.existsSync(path.join(dir, 'INTENT.md')))
273
+ fs.writeFileSync(path.join(dir, 'INTENT.md'), input.request.trim() + '\n', { flag: 'wx', mode: 0o600 });
274
+ if (!fs.existsSync(path.join(dir, 'SPEC.md')))
275
+ fs.writeFileSync(path.join(dir, 'SPEC.md'), `# ${value.title}\n\n## Pronto quando\n${env.doneWhen.map((x) => `- ${x}`).join('\n')}\n`, { flag: 'wx', mode: 0o600 });
276
+ if (!listObjectiveMessages(loaded.raiz, id).some((message) => message.role === 'ork' && message.by === 'ork.creation')) {
277
+ messageObjective(loaded.raiz, id, { role: 'ork', by: 'ork.creation', text: input.request });
278
+ }
279
+ // A confirmação depende de leituras dos efeitos, não da passagem pelo loop.
280
+ for (const link of threads) {
281
+ const thread = (0, thread_1.lerThread)(loaded.raiz, link.id);
282
+ if (thread.creationOrigin?.operationId !== op.operationId || thread.creationOrigin?.requestHash !== op.requestHash) {
283
+ throw new Error('creation.conflict: confirmação da thread falhou');
284
+ }
285
+ }
286
+ return readObjective(loaded.raiz, id);
287
+ });
288
+ }
289
+ function approveObjective(root, id, by) {
290
+ return (0, creation_operation_store_1.withCreationLock)(root, 'objectives', () => approveObjectiveLocked(root, id, by));
291
+ }
292
+ function approveObjectiveLocked(root, id, by) {
293
+ const value = readObjective(root, id);
294
+ if (!by.trim())
295
+ throw new Error('aprovação exige --por');
296
+ if (value.status !== 'awaiting_approval')
297
+ throw new Error(`objective não aguarda aprovação: ${value.status}`);
298
+ value.approval = { by: by.trim(), at: (0, util_1.agora)(), envelopeHash: value.envelope.hash };
299
+ if (value.envelope.independence === 'sessions')
300
+ for (const thread of value.threads) {
301
+ (0, ledger_1.registrar)((0, thread_1.dirThread)(root, thread.id), thread.id, 'objective_envelope_approved', {
302
+ objectiveId: id, envelopeHash: value.envelope.hash, version: value.envelope.version,
303
+ approvedAt: value.approval.at, by: value.approval.by,
304
+ });
305
+ }
306
+ value.status = 'running';
307
+ value.pauseReason = null;
308
+ return persist(root, value);
309
+ }
310
+ function reviseObjective(root, id, request, doneWhen) {
311
+ return (0, creation_operation_store_1.withCreationLock)(root, 'objectives', () => reviseObjectiveLocked(root, id, request, doneWhen));
312
+ }
313
+ function reviseObjectiveLocked(root, id, request, doneWhen) {
314
+ const value = readObjective(root, id);
315
+ if (!request.trim())
316
+ throw new Error('revisão exige request');
317
+ value.envelopeHistory.push(value.envelope);
318
+ value.revisions += 1;
319
+ value.envelope = envelope({
320
+ title: value.title, request, mode: value.mode, outcomes: value.envelope.outcomes, constraints: value.envelope.constraints,
321
+ doneWhen: clean(doneWhen).length ? doneWhen : value.envelope.doneWhen, maxThreads: value.envelope.maxThreads,
322
+ executionRuntime: value.envelope.executionRuntime, validationRuntimes: value.envelope.validationRuntimes,
323
+ independence: value.envelope.independence,
324
+ productId: value.envelope.portfolio?.productId, projectId: value.envelope.portfolio?.projectId,
325
+ delivery: value.envelope.portfolio?.delivery, initiativeIds: value.envelope.portfolio?.initiativeIds,
326
+ }, value.envelope.version + 1, root);
327
+ value.approval = null;
328
+ value.validations = [];
329
+ value.status = value.revisions >= 3 ? 'paused' : 'awaiting_approval';
330
+ value.pauseReason = value.revisions >= 3 ? 'objective.oscillation' : 'human.approval.objective-envelope';
331
+ return persist(root, value);
332
+ }
333
+ function validateObjective(root, id, runtime, verdict, evidence, binding) {
334
+ return (0, creation_operation_store_1.withCreationLock)(root, 'objectives', () => validateObjectiveLocked(root, id, runtime, verdict, evidence, binding));
335
+ }
336
+ function validateObjectiveLocked(root, id, runtime, verdict, evidence, binding) {
337
+ const value = readObjective(root, id);
338
+ if (!['running', 'validated'].includes(value.status))
339
+ throw new Error(`objective não está em validação: ${value.status}`);
340
+ if (!value.envelope.validationRuntimes.includes(runtime))
341
+ throw new Error('runtime fora do ensemble fixado no envelope');
342
+ if (!evidence.trim())
343
+ throw new Error('validação exige evidência');
344
+ let identity;
345
+ if (value.envelope.independence === 'sessions') {
346
+ if (!binding)
347
+ throw Error('maestro.authority.unproven');
348
+ if (!value.approval || value.approval.envelopeHash !== value.envelope.hash)
349
+ throw Error('maestro.authority.envelope-stale');
350
+ const currentEnvelope = { objectiveId: id, hash: value.envelope.hash, version: value.envelope.version, approvedAt: value.approval.at };
351
+ const proved = (0, maestro_authority_1.verifyCompletedSessionReview)(root, binding, currentEnvelope, verdict);
352
+ // No envelope de uma thread, discovery também hospeda GO/CHECK. Os papéis de
353
+ // autoridade continuam separados pelas três sessões provadas, sem migrar o envelope.
354
+ const singleThread = value.envelope.maxThreads === 1 && value.threads.length === 1;
355
+ if (proved.runtime !== runtime || !value.threads.some(t => t.id === proved.executor.threadId && (t.role === 'delivery' || singleThread)) ||
356
+ !value.threads.some(t => t.id === proved.conductor.threadId))
357
+ throw Error('maestro.authority.scope');
358
+ identity = proved;
359
+ // Um voto de outro runtime também precisa continuar vinculado à execução
360
+ // e ao envelope atuais antes de compor o ensemble.
361
+ value.validations = value.validations.filter(v => {
362
+ const previous = v.identity;
363
+ if (!previous || JSON.stringify(previous.envelope) !== JSON.stringify(currentEnvelope))
364
+ return false;
365
+ try {
366
+ (0, maestro_authority_1.verifyCompletedSessionReview)(root, { conductor: previous.conductor, executor: previous.executor,
367
+ reviewer: previous.reviewer }, currentEnvelope, v.verdict);
368
+ return true;
369
+ }
370
+ catch {
371
+ return false;
372
+ }
373
+ });
374
+ }
375
+ value.validations = value.validations.filter((item) => item.runtime !== runtime);
376
+ value.validations.push({ runtime, verdict, evidence: evidence.trim(), at: (0, util_1.agora)(), ...(identity ? { identity } : {}) });
377
+ const complete = value.envelope.validationRuntimes.every((expected) => value.validations.some((item) => item.runtime === expected && item.verdict === 'approved'));
378
+ value.status = complete ? 'validated' : verdict === 'rejected' ? 'paused' : 'running';
379
+ value.pauseReason = verdict === 'rejected' ? 'ensemble.rejected' : null;
380
+ return persist(root, value);
381
+ }
382
+ function stopObjective(root, id, stop = sessoes_1.pararSessao) {
383
+ return (0, creation_operation_store_1.withCreationLock)(root, 'objectives', () => stopObjectiveLocked(root, id, stop));
384
+ }
385
+ function stopObjectiveLocked(root, id, stop) {
386
+ const value = readObjective(root, id);
387
+ if (value.status === 'stopped')
388
+ return value;
389
+ value.stopStack = [];
390
+ for (const link of value.threads) {
391
+ const thread = (0, thread_1.lerThread)(root, link.id);
392
+ for (const session of thread.sessoes) {
393
+ const result = stop(session.sessionId);
394
+ value.stopStack.push({ thread: link.id, session: session.sessionId, stopped: result.codigo === 0, detail: result.texto });
395
+ }
396
+ }
397
+ value.status = 'stopped';
398
+ value.pauseReason = 'stop.requested';
399
+ return persist(root, value);
400
+ }
401
+ /** Compensação não para runtimes: só cancela o ticket desta intenção antes da execução. */
402
+ function compensateReservedObjective(root, operationId, principal) {
403
+ return (0, creation_operation_store_1.withCreationLock)(root, 'objectives', () => {
404
+ const op = (0, creation_operation_store_1.readCreationOperation)(root, operationId, principal);
405
+ const id = op.reserved.ticketId;
406
+ if (!id || !fs.existsSync(objectiveFile(root, id)))
407
+ return null;
408
+ const value = readObjective(root, id);
409
+ if (value.creationOrigin?.operationId !== operationId || value.creationOrigin?.requestHash !== op.requestHash
410
+ || value.creationOrigin?.ticketId !== id || JSON.stringify(value.threads.map((t) => t.id)) !== JSON.stringify(op.reserved.threadIds)) {
411
+ throw new Error('creation.conflict: ticket não pertence à operação');
412
+ }
413
+ if (value.status === 'stopped' && value.pauseReason === 'creation.compensated')
414
+ return value;
415
+ if (value.approval || value.status !== 'awaiting_approval' || value.revisions || value.validations.length) {
416
+ throw new Error('creation.started: ticket aprovado ou alterado; ação operacional necessária');
417
+ }
418
+ const ids = value.threads.map((t) => t.id).filter((threadId) => fs.existsSync((0, thread_1.caminhoThread)(root, threadId))).sort();
419
+ const lock = (index) => index < ids.length ? (0, hitl_gates_1.comLockHitl)(root, ids[index], () => lock(index + 1)) : cancel();
420
+ const cancel = () => {
421
+ for (const threadId of ids) {
422
+ const thread = (0, thread_1.lerThread)(root, threadId);
423
+ if (thread.creationOrigin?.operationId !== operationId || thread.creationOrigin?.requestHash !== op.requestHash
424
+ || thread.sessoes.length || thread.decisoes.length || thread.faseAtual !== thread.fases[0] || thread.status !== 'aberta') {
425
+ throw new Error('creation.started: thread alheia, alterada ou despachada');
426
+ }
427
+ }
428
+ value.status = 'stopped';
429
+ value.pauseReason = 'creation.compensated';
430
+ persist(root, value);
431
+ return readObjective(root, id);
432
+ };
433
+ return lock(0);
434
+ });
435
+ }
436
+ function objectivePhases(root, value) {
437
+ const threads = value.threads.map((item) => (0, thread_1.lerThread)(root, item.id));
438
+ return types_1.FASES.map((phase, index) => {
439
+ if (value.status === 'awaiting_approval' || value.status === 'paused')
440
+ return { phase, state: 'waiting' };
441
+ const positions = threads.map((thread) => thread.status === 'fechada' ? types_1.FASES.length : types_1.FASES.indexOf(thread.faseAtual));
442
+ return { phase, state: positions.every((position) => position > index) ? 'done' : positions.some((position) => position === index) ? 'active' : 'waiting' };
443
+ });
444
+ }
445
+ function objectiveText(root, value) {
446
+ const rows = value.threads.map((item) => { const thread = (0, thread_1.lerThread)(root, item.id); return [item.role, item.id, thread.faseAtual, thread.status]; });
447
+ return [`Objective ${value.id}: ${value.title}`, `Estado: ${value.status}; envelope ${value.envelope.hash.slice(0, 12)}; pausa: ${value.pauseReason ?? 'nenhuma'}`,
448
+ `Execução: ${value.envelope.executionRuntime}; ensemble: ${value.envelope.validationRuntimes.join(', ')}`, (0, util_1.tabela)(['PAPEL', 'THREAD', 'FASE', 'ESTADO'], rows)].join('\n');
449
+ }