@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,268 @@
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.operationalSources = operationalSources;
37
+ exports.nativeForThread = nativeForThread;
38
+ exports.observeWithDeadline = observeWithDeadline;
39
+ const zod_1 = require("zod");
40
+ const hitl_contract_1 = require("./hitl-contract");
41
+ const master_1 = require("./master");
42
+ const maestro_sources_1 = require("./maestro-sources");
43
+ const path = __importStar(require("node:path"));
44
+ const node_child_process_1 = require("node:child_process");
45
+ const claude_bg_1 = require("./adapters/claude-bg");
46
+ const hitl_sessions_1 = require("./hitl-sessions");
47
+ const thread_1 = require("./thread");
48
+ const hitl_gates_1 = require("./hitl-gates");
49
+ const ocupacao_1 = require("./ocupacao");
50
+ const horario_1 = require("./horario");
51
+ const conducao_1 = require("./conducao");
52
+ const conducao_texto_1 = require("./conducao-texto");
53
+ /** Valida todos os campos consumidos antes de deduplicar, filtrar ou publicar a fila. */
54
+ const retryView = zod_1.z.object({
55
+ id: zod_1.z.string().max(160).regex(/^R[1-9]\d*$/),
56
+ thread: zod_1.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/),
57
+ estado: zod_1.z.enum(['aguardando', 'retomado', 'escalado', 'cancelado']),
58
+ liberaEm: zod_1.z.string().max(512).datetime({ offset: true }).refine(v => Number.isFinite(Date.parse(v))),
59
+ tentativas: zod_1.z.number().int().nonnegative().safe(),
60
+ });
61
+ /** Referências e datas só entram na projeção depois de validar a fonte inteira. */
62
+ const leaseView = zod_1.z.object({
63
+ nome: zod_1.z.string().min(1).refine(v => v.trim().length > 0 && !/[\u0000-\u001f\u007f]/.test(v)),
64
+ thread: zod_1.z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/),
65
+ expiraEm: zod_1.z.string().max(512).datetime({ offset: true }).refine(v => Number.isFinite(Date.parse(v))),
66
+ });
67
+ /**
68
+ * Recibo de SHIP validado em todos os campos consumidos antes de projetar. Push verificado
69
+ * que contradiz o próprio remoto ou a fonte da prova é recibo inválido, não entrega incompleta.
70
+ */
71
+ const shipSha = zod_1.z.string().regex(/^[a-f0-9]{40}$/);
72
+ const shipTs = zod_1.z.string().max(512).datetime({ offset: true }).refine(v => Number.isFinite(Date.parse(v)));
73
+ const shipView = zod_1.z.union([
74
+ zod_1.z.object({
75
+ tipo: zod_1.z.literal('ship_done'), ts: shipTs, pushVerificado: zod_1.z.boolean(), mergeSha: shipSha,
76
+ shaRemoto: shipSha.nullable().optional(),
77
+ fonteDaProva: zod_1.z.string().min(1).max(512).refine(v => !/[\u0000-\u001f\u007f]/.test(v)).nullable().optional(),
78
+ }).refine(s => !s.pushVerificado || (s.shaRemoto === s.mergeSha && typeof s.fonteDaProva === 'string')),
79
+ zod_1.z.object({ tipo: zod_1.z.enum(['ship_started', 'ship_blocked']), ts: shipTs }),
80
+ ]);
81
+ function operationalSources(reader, threads, native = [], now = new Date().toISOString(), threadScope) {
82
+ const names = ['sessions', 'blockers', 'leases', 'retries', 'hitl', 'ship', 'master'];
83
+ const sections = {};
84
+ for (const name of names)
85
+ sections[name] = { source: `ork.${name}`, items: [], gaps: [] };
86
+ // I-35: fato local absoluto e rotulado ao lado do ISO, nunca relativo (o fingerprint conta).
87
+ const local = (iso) => (0, horario_1.formatarDataHoraRotulada)(iso, { agora: now });
88
+ for (const t of threads) {
89
+ const refs = [{ kind: 'thread', id: t.id }];
90
+ let events;
91
+ try {
92
+ const raw = reader.read(`.orkastery/threads/${t.id}/ledger.jsonl`);
93
+ if (raw === null)
94
+ throw Error('missing');
95
+ events = raw.split('\n').filter(Boolean).map(line => JSON.parse(line));
96
+ if (events.some(e => typeof e.tipo !== 'string' || e.thread !== t.id))
97
+ throw Error('invalid');
98
+ }
99
+ catch {
100
+ for (const name of names.filter(n => !['leases', 'retries'].includes(n)))
101
+ sections[name].gaps.push(`ledger.unavailable:${t.id}`);
102
+ continue;
103
+ }
104
+ // I-36 (T17): quem conduz, pela mesma leitura das outras superficies. O leitor confinado nao sonda
105
+ // processo: conducao de processo vale ate o lease sair, como nas demais telas sem prova de morte.
106
+ let conducao = null;
107
+ try {
108
+ conducao = (0, conducao_1.conducaoDosDados)(reader.json(`.orkastery/leases/${encodeURIComponent((0, conducao_1.nomeDaConducao)(t.id))}.json`), events, { agora: new Date(now) });
109
+ }
110
+ catch {
111
+ sections.sessions.gaps.push(`conducao.unavailable:${t.id}`);
112
+ }
113
+ const linhaDaConducao = conducao ? (0, conducao_texto_1.linhaDeConducao)(conducao, { agora: now }) : null;
114
+ if (conducao && !t.sessoes.some(s => s.sessionId === conducao.sessao))
115
+ sections.sessions.items.push((0, maestro_sources_1.item)(`conducao:${t.id}`, 'Conducao em andamento', 'active', refs, { conduction: (0, maestro_sources_1.safeText)(linhaDaConducao) }));
116
+ for (const s of t.sessoes) {
117
+ const observed = native.filter(n => n.sessionId === s.sessionId && n.runtime === (s.runtime ?? 'claude-bg'));
118
+ const n = observed.length === 1 ? observed[0] : undefined;
119
+ const divergence = !!n?.state && !!n.status && n.state !== n.status;
120
+ const phaseResult = events.some(e => e.tipo === 'phase_result' && e.sessionId === s.sessionId && e.fase === s.fase);
121
+ const terminal = ['done', 'completed', 'exited', 'stopped'].includes(n?.state ?? n?.status ?? '');
122
+ sections.sessions.items.push((0, maestro_sources_1.item)(s.sessionId, `${s.runtime ?? 'claude-bg'} · ${s.fase}`, divergence ? 'conflict' : n?.state ?? n?.status ?? 'unknown', refs, { runtime: s.runtime ?? 'claude-bg', phase: s.fase, nativeConfirmed: !!n && !n.reason, phaseResult,
123
+ ...(conducao && conducao.sessao === s.sessionId ? { conduction: (0, maestro_sources_1.safeText)(linhaDaConducao) } : {}),
124
+ reason: (0, maestro_sources_1.safeText)(divergence ? 'runtime.state_conflict' : n?.reason ?? (!n ? 'runtime.unavailable' : terminal && !phaseResult ? 'phase.result_missing' : '')) }));
125
+ }
126
+ const lastGate = events.filter(e => e.tipo === 'gate_blocked' ||
127
+ ocupacao_1.EVENTOS_QUE_DESTRAVAM.includes(e.tipo) || (0, ocupacao_1.ehAprovacaoHumana)(e)).at(-1);
128
+ if (lastGate?.tipo === 'gate_blocked')
129
+ sections.blockers.items.push((0, maestro_sources_1.item)(`gate:${t.id}`, lastGate.motivo, 'blocked', refs, { reason: (0, maestro_sources_1.safeText)(lastGate.motivo) }));
130
+ const currentHitlContext = (0, hitl_gates_1.contextoHitlDosEventos)(t, events);
131
+ for (const e of events.filter(e => e.tipo === 'hitl_requested')) {
132
+ try {
133
+ (0, hitl_contract_1.validarPedidoHitl)(e.pedido);
134
+ const p = e.pedido;
135
+ if (p.thread !== t.id)
136
+ throw Error('scope');
137
+ const answered = events.some(r => ['human_gate', 'session_answered'].includes(r.tipo) && r.pedidoId === p.id);
138
+ if (answered)
139
+ continue;
140
+ const sending = events.some(r => r.tipo === 'session_answer_sending' && r.pedidoId === p.id);
141
+ const stale = e.contexto !== currentHitlContext;
142
+ const prazo = (0, hitl_contract_1.prazoDoPedido)(p) ?? '';
143
+ sections.hitl.items.push((0, maestro_sources_1.item)(p.id, (0, hitl_contract_1.textoDoPedido)(p), stale ? 'stale' : sending ? 'delivery.uncertain' : (0, hitl_contract_1.estadoDoPedido)(p, now), refs, { deadline: prazo, deadlineLocal: local(prazo), target: (0, hitl_contract_1.alvoDoPedido)(p)?.tipo ?? 'decidido', recommendation: (0, maestro_sources_1.safeText)((0, hitl_contract_1.recomendacaoDoPedido)(p)),
144
+ deliveryUncertain: sending, reason: stale ? 'hitl.context.stale' : '' }));
145
+ }
146
+ catch {
147
+ sections.hitl.gaps.push(`hitl.invalid:${t.id}`);
148
+ }
149
+ }
150
+ const lastShip = events.filter(e => ['ship_done', 'ship_started', 'ship_blocked'].includes(e.tipo)).at(-1);
151
+ if (lastShip) {
152
+ const ship = shipView.safeParse(lastShip);
153
+ if (!ship.success)
154
+ sections.ship.gaps.push(`ship.invalid:${t.id}`);
155
+ else {
156
+ const done = ship.data.tipo === 'ship_done' ? ship.data : null, proven = done?.pushVerificado === true;
157
+ sections.ship.items.push((0, maestro_sources_1.item)(`ship:${t.id}`, 'Entrega', proven ? 'delivered' : 'incomplete', refs, { pushVerified: proven, mergeSha: done?.mergeSha ?? null, receiptAt: ship.data.ts, receiptAtLocal: local(ship.data.ts) }));
158
+ }
159
+ }
160
+ try {
161
+ const receipt = reader.json(`.orkastery/threads/${t.id}/master-log.json`);
162
+ if (receipt) {
163
+ const pending = receipt.contrato === master_1.CONTRATO_MASTER_PENDENTE;
164
+ if ((pending ? (0, master_1.validarMasterPendente)(receipt) : (0, master_1.validarMasterLog)(receipt)).length || receipt.thread !== t.id)
165
+ throw Error('invalid');
166
+ sections.master.items.push((0, maestro_sources_1.item)(`master:${t.id}`, pending ? 'Ratificação humana pendente' : 'MASTER', pending ? 'ratificacao-pendente' : 'recorded', refs, { score: pending ? null : typeof receipt.score === 'number' ? receipt.score : null }));
167
+ }
168
+ else if (lastShip || t.faseAtual === 'MASTER')
169
+ sections.master.items.push((0, maestro_sources_1.item)(`master:${t.id}`, 'Score humano pendente', 'pending', refs, { score: null }));
170
+ }
171
+ catch {
172
+ sections.master.gaps.push(`master.invalid:${t.id}`);
173
+ }
174
+ }
175
+ try {
176
+ const leases = reader.list('.orkastery/leases').filter(f => f.endsWith('.json') && f !== 'fila.json')
177
+ .map(file => leaseView.parse(reader.json(`.orkastery/leases/${file}`)));
178
+ sections.leases.items = leases.filter(lease => !threadScope || lease.thread === threadScope)
179
+ .map(lease => (0, maestro_sources_1.item)(lease.nome.slice(0, 160), 'Região reservada', Date.parse(lease.expiraEm) <= Date.parse(now) ? 'expired' : 'active', [{ kind: 'thread', id: lease.thread }], { expiresAt: lease.expiraEm, expiresAtLocal: local(lease.expiraEm) }));
180
+ }
181
+ catch {
182
+ sections.leases.state = 'unavailable';
183
+ sections.leases.gaps.push('leases.unavailable');
184
+ }
185
+ try {
186
+ const raw = reader.read('.orkastery/retry/fila.jsonl') ?? '';
187
+ const queue = new Map();
188
+ for (const line of raw.split('\n').filter(Boolean)) {
189
+ const retry = retryView.parse(JSON.parse(line));
190
+ queue.set(retry.id, retry);
191
+ }
192
+ sections.retries.items = [...queue.values()].filter(retry => !threadScope || retry.thread === threadScope)
193
+ .map(retry => (0, maestro_sources_1.item)(retry.id, 'Retomada', retry.estado === 'aguardando' && Date.parse(retry.liberaEm) <= Date.parse(now) ? 'due' : retry.estado, [{ kind: 'thread', id: retry.thread }], { availableAt: retry.liberaEm, availableAtLocal: local(retry.liberaEm), attempts: retry.tentativas }));
194
+ }
195
+ catch {
196
+ sections.retries.state = 'unavailable';
197
+ sections.retries.gaps.push('retries.unavailable');
198
+ }
199
+ for (const section of Object.values(sections))
200
+ if (section.gaps.length)
201
+ section.state = 'unavailable';
202
+ return sections;
203
+ }
204
+ /** Detalhe nativo isolado do event loop, com deadline efetivo inclusive para CLI síncrono. */
205
+ function nativeForThread(root, threadId) {
206
+ if (!path.isAbsolute(root) || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(threadId))
207
+ throw Error('maestro.project.scope');
208
+ const result = (0, node_child_process_1.spawnSync)(process.execPath, [__filename, '--native', root, threadId], {
209
+ encoding: 'utf8', timeout: 2000, killSignal: 'SIGKILL', maxBuffer: 1048576,
210
+ env: { PATH: process.env.PATH, HOME: process.env.HOME, LANG: 'C.UTF-8' },
211
+ });
212
+ if (result.status !== 0 || result.error)
213
+ return [];
214
+ try {
215
+ const list = JSON.parse(result.stdout);
216
+ return Array.isArray(list) ? list : [];
217
+ }
218
+ catch {
219
+ return [];
220
+ }
221
+ }
222
+ if (require.main === module && process.argv[2] === '--native') {
223
+ try {
224
+ const root = process.argv[3], id = process.argv[4], t = (0, thread_1.lerThread)(root, id), cwd = path.resolve(t.worktree ?? root);
225
+ const result = [];
226
+ const claude = t.sessoes.some(s => s.runtime === 'claude-bg') ? (0, claude_bg_1.consultarSessoes)(cwd, true) : null;
227
+ for (const s of t.sessoes) {
228
+ try {
229
+ if (s.runtime === 'claude-bg') {
230
+ const matches = claude?.sessoes.filter(n => n.sessionId === s.sessionId && n.cwd === cwd) ?? [];
231
+ if (claude?.ok && matches.length === 1)
232
+ result.push({ sessionId: s.sessionId, runtime: s.runtime, state: matches[0].state, status: matches[0].status });
233
+ }
234
+ else if (s.runtime === 'codex') {
235
+ const obs = (0, hitl_sessions_1.controleNativo)(s.runtime, root, id, s.sessionId).consultar();
236
+ const matches = obs.sessoes.filter(n => n.sessionId === s.sessionId && n.cwd === cwd);
237
+ if (obs.ok && matches.length === 1)
238
+ result.push({ sessionId: s.sessionId, runtime: s.runtime, state: matches[0].estado });
239
+ }
240
+ }
241
+ catch {
242
+ result.push({ sessionId: s.sessionId, runtime: s.runtime ?? 'claude-bg', reason: 'runtime.unavailable' });
243
+ }
244
+ }
245
+ process.stdout.write(JSON.stringify(result));
246
+ }
247
+ catch {
248
+ process.exitCode = 1;
249
+ }
250
+ }
251
+ /** Deadline cancela a consulta; nunca transforma indisponibilidade em sessão encerrada. */
252
+ async function observeWithDeadline(read, timeoutMs = 2000) {
253
+ const controller = new AbortController();
254
+ let timer;
255
+ const duration = Number.isFinite(timeoutMs) ? Math.min(2000, Math.max(1, timeoutMs)) : 2000;
256
+ try {
257
+ return await Promise.race([new Promise(resolve => {
258
+ timer = setTimeout(() => { controller.abort(); resolve([]); }, duration);
259
+ }), Promise.resolve().then(() => read(controller.signal))]);
260
+ }
261
+ catch {
262
+ return [];
263
+ }
264
+ finally {
265
+ clearTimeout(timer);
266
+ controller.abort();
267
+ }
268
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.maestroSnapshot = maestroSnapshot;
4
+ const maestro_contract_1 = require("./maestro-contract");
5
+ const maestro_discovery_1 = require("./maestro-discovery");
6
+ const maestro_sources_1 = require("./maestro-sources");
7
+ /** Defesa final para TODOS os campos públicos, inclusive facts e identificadores. */
8
+ function publicItem(raw) {
9
+ const identity = (v) => (0, maestro_sources_1.safeText)(v) === v && v.length <= 160 ? v : `redacted:${(0, maestro_sources_1.digest)(v)}`;
10
+ const clean = { id: identity(raw.id), title: (0, maestro_sources_1.safeText)(raw.title), status: (0, maestro_sources_1.safeText)(raw.status),
11
+ refs: raw.refs.slice(0, 16).map(r => ({ kind: identity(r.kind), id: identity(r.id) })),
12
+ facts: Object.fromEntries(Object.entries(raw.facts).filter(([k]) => /^[a-zA-Z][a-zA-Z0-9_]{0,63}$/.test(k)).slice(0, 24)
13
+ .map(([k, v]) => [k, /password|senha|secret|token|authorization|api_?key/i.test(k) ? '[redigido]' : typeof v === 'string' ? (0, maestro_sources_1.safeText)(v) : v])),
14
+ ...(raw.action ? { action: { ...raw.action, reason: (0, maestro_sources_1.safeText)(raw.action.reason),
15
+ preconditions: raw.action.preconditions.slice(0, 10).map(maestro_sources_1.safeText), readback: (0, maestro_sources_1.safeText)(raw.action.readback) } } : {}) };
16
+ if (JSON.stringify(raw) !== JSON.stringify(clean)) {
17
+ if (clean.action)
18
+ clean.action = { ...clean.action, available: false, reason: 'maestro.source.redacted_identity' };
19
+ }
20
+ if (Buffer.byteLength(JSON.stringify(clean)) > 2048)
21
+ return { ...clean, title: clean.title.slice(0, 160),
22
+ refs: [], facts: { reason: 'maestro.item.limit' },
23
+ ...(clean.action ? { action: { ...clean.action, available: false, reason: 'maestro.item.limit', preconditions: [], readback: '' } } : {}) };
24
+ return clean;
25
+ }
26
+ function publicMessages(values, limit) {
27
+ return [...values.slice(0, limit).map(maestro_sources_1.safeText), ...(values.length > limit ? [`maestro.messages.omitted:${values.length - limit}`] : [])];
28
+ }
29
+ function maestroSnapshot(context, options = {}) {
30
+ const clock = options.clock ?? Date.now, started = clock();
31
+ (0, maestro_discovery_1.revalidateMaestroContext)(context);
32
+ const collect = options.collect ?? (ctx => (0, maestro_sources_1.collectMaestroSources)(ctx, options));
33
+ let sources = collect(context), stable = sources.unchanged();
34
+ if (!stable && clock() - started < maestro_contract_1.MAESTRO_LIMITS.totalMs) {
35
+ sources = collect(context);
36
+ stable = sources.unchanged();
37
+ }
38
+ const timedOut = clock() - started >= maestro_contract_1.MAESTRO_LIMITS.totalMs;
39
+ if (timedOut)
40
+ sources = { ...sources, sections: {}, gaps: ['maestro.snapshot.timeout'], conflicts: [] };
41
+ const observedAt = new Date().toISOString(), sections = {};
42
+ for (const name of maestro_contract_1.SECTION_NAMES) {
43
+ const src = sources.sections[name], all = [...(src?.items ?? [])].sort((a, b) => a.id.localeCompare(b.id));
44
+ const requested = options.offsets?.[name] ?? 0;
45
+ if (!Number.isSafeInteger(requested) || requested < 0)
46
+ throw Error('maestro.page.invalid');
47
+ const offset = Math.min(requested, all.length), items = all.slice(offset, offset + 50).map(publicItem), omitted = all.length - offset - items.length;
48
+ const unavailable = !src || src.state === 'unavailable';
49
+ const state = timedOut ? 'unavailable' : !stable ? 'conflict' : unavailable ? 'unavailable' : src.state ?? (all.length ? 'available' : 'empty');
50
+ sections[name] = { state, source: (0, maestro_sources_1.safeText)(src?.source ?? name).slice(0, 160), observedAt, fingerprint: src ? (0, maestro_sources_1.digest)(src) : null,
51
+ coverage: { total: unavailable ? null : all.length, offset, returned: items.length, omitted: unavailable ? null : omitted,
52
+ nextOffset: omitted ? offset + items.length : null, limit: 50 }, items, gaps: publicMessages(src?.gaps ?? ['maestro.source.unavailable'], 4) };
53
+ }
54
+ const result = { schema: maestro_contract_1.MAESTRO_SCHEMA, observedAt, fingerprint: (0, maestro_sources_1.digest)([context.fingerprint, sources.fingerprint]),
55
+ project: { ...context.project, name: (0, maestro_sources_1.safeText)(context.project.name) }, limits: maestro_contract_1.MAESTRO_LIMITS, sections, gaps: publicMessages(sources.gaps, 12),
56
+ conflicts: publicMessages([...sources.conflicts, ...(!stable ? ['maestro.snapshot.stale'] : [])], 12) };
57
+ // Orçamento incremental; mantém um item por seção para nextOffset avançar.
58
+ const sizes = new Map(Object.values(sections).map(s => [s, Buffer.byteLength(JSON.stringify(s))]));
59
+ let bytes = Buffer.byteLength(JSON.stringify(result));
60
+ while (bytes > maestro_contract_1.MAESTRO_LIMITS.bytes) {
61
+ const section = Object.values(sections).filter(s => s.items.length > 1).sort((a, b) => sizes.get(b) - sizes.get(a))[0];
62
+ if (!section)
63
+ throw Error('maestro.snapshot.size');
64
+ section.items.pop();
65
+ section.coverage.returned = section.items.length;
66
+ if (section.coverage.omitted !== null)
67
+ section.coverage.omitted++;
68
+ section.coverage.nextOffset = section.items.length ? section.coverage.offset + section.items.length : null;
69
+ if (!section.gaps.includes('maestro.page.byte_limit'))
70
+ section.gaps.push('maestro.page.byte_limit');
71
+ const size = Buffer.byteLength(JSON.stringify(section));
72
+ bytes += size - sizes.get(section);
73
+ sizes.set(section, size);
74
+ }
75
+ // Inclui projeção e serialização no prazo total; vence sem ações utilizáveis.
76
+ if (clock() - started >= maestro_contract_1.MAESTRO_LIMITS.totalMs) {
77
+ result.gaps = ['maestro.snapshot.timeout'];
78
+ for (const section of Object.values(sections)) {
79
+ section.state = 'unavailable';
80
+ section.items = [];
81
+ section.coverage = { total: null, offset: 0, returned: 0, omitted: null, nextOffset: null, limit: 50 };
82
+ }
83
+ }
84
+ (0, maestro_discovery_1.revalidateMaestroContext)(context);
85
+ return (0, maestro_contract_1.validateMaestroSnapshot)(result);
86
+ }
@@ -0,0 +1,224 @@
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.MaestroReader = exports.item = exports.safeText = exports.digest = void 0;
37
+ exports.collectMaestroSources = collectMaestroSources;
38
+ /** Projeções das fontes canônicas. Nunca cria estado nem usa títulos como vínculo. */
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const node_crypto_1 = require("node:crypto");
42
+ const zod_1 = require("zod");
43
+ const hitl_1 = require("./hitl");
44
+ const maestro_discovery_1 = require("./maestro-discovery");
45
+ const maestro_runtime_1 = require("./maestro-runtime");
46
+ const digest = (value) => (0, node_crypto_1.createHash)('sha256').update(JSON.stringify(value)).digest('hex');
47
+ exports.digest = digest;
48
+ const safeText = (value) => (0, hitl_1.redigirSegredos)(String(value ?? ''))
49
+ .replace(/\/(?:home|tmp|etc|root)\/[^\s]+/g, '[caminho privado]').slice(0, 512);
50
+ exports.safeText = safeText;
51
+ const item = (id, title, status, refs = [], facts = {}) => ({ id, title: (0, exports.safeText)(title), status: (0, exports.safeText)(status), refs: refs.slice(0, 16), facts });
52
+ exports.item = item;
53
+ /** Bounded, regular, physical files only. Re-check tracks missing files and directories too. */
54
+ class MaestroReader {
55
+ root;
56
+ versions = new Map();
57
+ bytes = 0;
58
+ start = Date.now();
59
+ constructor(root) {
60
+ this.root = root;
61
+ }
62
+ inspect(relative, file) {
63
+ if (Date.now() - this.start > 2000)
64
+ throw Error('maestro.source.timeout');
65
+ if (path.isAbsolute(relative) || relative.split('/').some(x => x === '..' || x === '.'))
66
+ throw Error('maestro.project.scope');
67
+ const name = path.join(this.root, relative);
68
+ let cursor = this.root;
69
+ for (const part of relative.split('/')) {
70
+ cursor = path.join(cursor, part);
71
+ const s = fs.lstatSync(cursor, { throwIfNoEntry: false });
72
+ if (s?.isSymbolicLink())
73
+ throw Error('maestro.project.scope');
74
+ }
75
+ if (!fs.existsSync(name))
76
+ return 'missing';
77
+ const stat = fs.statSync(name);
78
+ if (file ? !stat.isFile() || stat.size > 1048576 : !stat.isDirectory())
79
+ throw Error('maestro.source.invalid');
80
+ return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeMs}:${stat.ctimeMs}`;
81
+ }
82
+ list(relative) {
83
+ const version = this.inspect(relative, false);
84
+ this.versions.set(relative + '/', version);
85
+ if (version === 'missing')
86
+ return [];
87
+ const names = fs.readdirSync(path.join(this.root, relative)).sort();
88
+ if (names.length > 10000)
89
+ throw Error('maestro.source.limit');
90
+ return names;
91
+ }
92
+ read(relative) {
93
+ const version = this.inspect(relative, true);
94
+ this.versions.set(relative, version);
95
+ if (version === 'missing')
96
+ return null;
97
+ const fd = fs.openSync(path.join(this.root, relative), fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
98
+ try {
99
+ const s = fs.fstatSync(fd);
100
+ if (!s.isFile() || s.size > 1048576 || (this.bytes += s.size) > 33554432)
101
+ throw Error('maestro.source.limit');
102
+ const bytes = Buffer.alloc(s.size + 1), count = fs.readSync(fd, bytes, 0, bytes.length, 0);
103
+ if (count > s.size || this.inspect(relative, true) !== version)
104
+ throw Error('maestro.snapshot.stale');
105
+ return bytes.subarray(0, count).toString('utf8');
106
+ }
107
+ finally {
108
+ fs.closeSync(fd);
109
+ }
110
+ }
111
+ json(relative) { const text = this.read(relative); return text === null ? null : JSON.parse(text); }
112
+ fingerprint() { return (0, exports.digest)([...this.versions].sort()); }
113
+ unchanged() {
114
+ try {
115
+ return [...this.versions].every(([file, version]) => this.inspect(file.replace(/\/$/, ''), !file.endsWith('/')) === version);
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ }
122
+ exports.MaestroReader = MaestroReader;
123
+ const validId = (s) => /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(s);
124
+ // Validar os campos consumidos antes de publicar um valor para outras fontes.
125
+ const sourceId = zod_1.z.string().refine(validId);
126
+ const entityView = zod_1.z.object({ id: sourceId, title: zod_1.z.string(), status: zod_1.z.string() });
127
+ const portfolioView = zod_1.z.object({ schema: zod_1.z.literal('ork.portfolio/v1'),
128
+ products: zod_1.z.array(entityView.extend({ kind: zod_1.z.literal('product') })),
129
+ projects: zod_1.z.array(entityView.extend({ kind: zod_1.z.literal('project'), productId: sourceId })),
130
+ initiatives: zod_1.z.array(entityView.extend({ kind: zod_1.z.literal('initiative'), projectId: sourceId })),
131
+ });
132
+ const objectiveView = zod_1.z.object({ schema: zod_1.z.literal('ork.objective/v1'), id: sourceId,
133
+ title: zod_1.z.string(), status: zod_1.z.string(), threads: zod_1.z.array(zod_1.z.object({ id: sourceId })),
134
+ envelope: zod_1.z.object({ schema: zod_1.z.literal('ork.objective-envelope/v1'), hash: zod_1.z.string().regex(/^[a-f0-9]{64}$/),
135
+ portfolio: zod_1.z.object({ productId: sourceId, projectId: sourceId, initiativeIds: zod_1.z.array(sourceId) }).nullable() }),
136
+ });
137
+ const threadView = zod_1.z.object({ id: sourceId, nome: zod_1.z.string(), status: zod_1.z.string(), faseAtual: zod_1.z.string(), modo: zod_1.z.string(),
138
+ sessoes: zod_1.z.array(zod_1.z.object({ sessionId: sourceId, fase: zod_1.z.string(), runtime: zod_1.z.string().optional() })),
139
+ blocos: zod_1.z.array(zod_1.z.object({ fases: zod_1.z.array(zod_1.z.string()), slugFases: zod_1.z.string() })),
140
+ });
141
+ function collectMaestroSources(context, options = {}) {
142
+ (0, maestro_discovery_1.revalidateMaestroContext)(context);
143
+ const reader = new MaestroReader(context.root), sections = {}, gaps = [], conflicts = [];
144
+ const source = (name, reference, read) => {
145
+ try {
146
+ sections[name] = { source: reference, items: read(), gaps: [] };
147
+ }
148
+ catch {
149
+ sections[name] = { source: reference, items: [], gaps: ['maestro.source.unavailable'], state: 'unavailable' };
150
+ }
151
+ };
152
+ let objectives = [], threads = [];
153
+ source('portfolio', 'ork.portfolio/v1', () => {
154
+ const portfolio = reader.json('.orkastery/portfolio.json');
155
+ if (!portfolio || !portfolioView.safeParse(portfolio).success)
156
+ throw Error('unavailable');
157
+ return [...portfolio.products, ...portfolio.projects, ...portfolio.initiatives].map(p => (0, exports.item)(p.id, p.title, p.status, 'productId' in p ? [{ kind: 'product', id: p.productId }] : 'projectId' in p ? [{ kind: 'project', id: p.projectId }] : [], { kind: p.kind, deliveryProven: false, origin: 'creationOperationId' in p && p.creationOperationId ? 'creation.operation' : 'legacy' }));
158
+ });
159
+ source('demands', 'ork.objective/v1', () => {
160
+ let loaded = reader.list('.orkastery/objectives').map(id => {
161
+ if (!validId(id))
162
+ throw Error('invalid');
163
+ const value = reader.json(`.orkastery/objectives/${id}/objective.json`);
164
+ if (!value || value.id !== id || !objectiveView.safeParse(value).success)
165
+ throw Error('invalid');
166
+ return value;
167
+ });
168
+ if (options.threadId)
169
+ loaded = loaded.filter(o => o.threads.some(t => t.id === options.threadId));
170
+ const items = loaded.map(o => {
171
+ const p = o.envelope.portfolio;
172
+ return (0, exports.item)(o.id, o.title, o.status, [...(p ? [{ kind: 'product', id: p.productId }, { kind: 'project', id: p.projectId },
173
+ ...p.initiativeIds.map(id => ({ kind: 'initiative', id }))] : []), ...o.threads.map(t => ({ kind: 'thread', id: t.id }))], { threadCount: o.threads.length, envelopeHash: o.envelope.hash });
174
+ });
175
+ objectives = loaded;
176
+ for (const o of loaded)
177
+ if (!o.threads.length)
178
+ gaps.push(`demand.without_thread:${o.id}`);
179
+ return items;
180
+ });
181
+ source('threads', 'ork.thread', () => {
182
+ const ids = options.threadId ? [options.threadId] : reader.list('.orkastery/threads');
183
+ const loaded = ids.map(id => {
184
+ if (!validId(id))
185
+ throw Error('invalid');
186
+ const t = reader.json(`.orkastery/threads/${id}/thread.json`);
187
+ if (!t || t.id !== id || !threadView.safeParse(t).success)
188
+ throw Error('invalid');
189
+ return t;
190
+ });
191
+ const items = loaded.map(t => {
192
+ const matches = objectives.filter(o => o.threads.some(v => v.id === t.id));
193
+ return (0, exports.item)(t.id, t.nome, t.status, matches.map(o => ({ kind: 'objective', id: o.id })), { phase: t.faseAtual, mode: t.modo, sessionCount: t.sessoes.length, block: t.blocos.find(b => b.fases.includes(t.faseAtual))?.slugFases ?? null });
194
+ });
195
+ threads = loaded;
196
+ if (sections.demands?.state !== 'unavailable')
197
+ for (const t of loaded) {
198
+ if (!objectives.some(o => o.threads.some(v => v.id === t.id)))
199
+ gaps.push(`thread.without_objective:${t.id}`);
200
+ }
201
+ return items;
202
+ });
203
+ if (sections.demands?.state === 'unavailable') {
204
+ sections.threads?.gaps.push('demands.unavailable');
205
+ sections.portfolio?.gaps.push('demands.unavailable');
206
+ }
207
+ for (const p of sections.demands?.state === 'unavailable' ? [] : sections.portfolio?.items ?? []) {
208
+ const matches = objectives.filter(o => o.envelope.portfolio && (o.envelope.portfolio.productId === p.id ||
209
+ o.envelope.portfolio.projectId === p.id || o.envelope.portfolio.initiativeIds.includes(p.id)));
210
+ if (!matches.length)
211
+ gaps.push(`portfolio.without_demand:${p.id}`);
212
+ if (p.status === 'delivered' && matches.some(o => ['running', 'paused', 'awaiting_approval'].includes(o.status)))
213
+ conflicts.push(`entity.delivered_cycle_open:${p.id}`);
214
+ }
215
+ Object.assign(sections, (0, maestro_runtime_1.operationalSources)(reader, threads, options.native, undefined, options.threadId));
216
+ if (sections.threads?.state === 'unavailable') {
217
+ for (const name of ['sessions', 'blockers', 'hitl', 'ship', 'master']) {
218
+ const section = sections[name];
219
+ section.state = 'unavailable';
220
+ section.gaps.push('threads.unavailable');
221
+ }
222
+ }
223
+ return { sections, fingerprint: reader.fingerprint(), gaps, conflicts, unchanged: () => reader.unchanged() };
224
+ }