@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,323 @@
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.adquirirLockMonitor = void 0;
37
+ exports.assinaturaPulse = assinaturaPulse;
38
+ exports.assinaturaDoResumo = assinaturaDoResumo;
39
+ exports.mensagemPulse = mensagemPulse;
40
+ exports.varrerPulse = varrerPulse;
41
+ exports.enviarPayloadHost = enviarPayloadHost;
42
+ const manifest_1 = require("./manifest");
43
+ const write_activation_1 = require("./write-activation");
44
+ const escopo_escrita_1 = require("./escopo-escrita");
45
+ /** D5: transporte determinístico, cache só depois do recibo, sem inferência. */
46
+ const fs = __importStar(require("node:fs"));
47
+ const path = __importStar(require("node:path"));
48
+ const node_crypto_1 = require("node:crypto");
49
+ const node_child_process_1 = require("node:child_process");
50
+ const pulse_1 = require("./pulse");
51
+ const estado_thread_1 = require("./estado-thread");
52
+ const hitl_1 = require("./hitl");
53
+ const horario_1 = require("./horario");
54
+ const hitl_resumo_1 = require("./hitl-resumo");
55
+ const pulse_consentimento_1 = require("./pulse-consentimento");
56
+ const pulse_resposta_1 = require("./pulse-resposta");
57
+ const hitl_classificacao_1 = require("./hitl-classificacao");
58
+ const hitl_contract_1 = require("./hitl-contract");
59
+ const monitor_lock_1 = require("./monitor-lock");
60
+ const fabrica_estado_1 = require("./fabrica-estado");
61
+ const maquina_1 = require("./maquina");
62
+ const pulse_cadencia_1 = require("./pulse-cadencia");
63
+ // O lock dos monitores mudou de modulo (I-41, GO-FIX 1); quem o importava daqui continua importando.
64
+ var monitor_lock_2 = require("./monitor-lock");
65
+ Object.defineProperty(exports, "adquirirLockMonitor", { enumerable: true, get: function () { return monitor_lock_2.adquirirLockMonitor; } });
66
+ /**
67
+ * I-41 (D9): a assinatura de deduplicacao NAO inclui `apresentacao`.
68
+ *
69
+ * `apresentacao.diff` vem de um `git diff` entre a base e o HEAD. Enquanto ela estava aqui, todo
70
+ * commit em qualquer worktree mudava a assinatura de TODOS os itens daquela thread e reenviava
71
+ * todos eles. Com 25 threads e GO ativo, isso era uma fabrica de mensagens: nao volume de
72
+ * perguntas, e sim assinatura instavel. Evidencia que muda a cada commit nao e novidade para o
73
+ * dono, e a pergunta dele continua sendo a mesma.
74
+ */
75
+ function assinaturaPulse(i) {
76
+ return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([i.id, i.classe, i.motivo, i.desdeEm, i.pergunta, i.opcoes, i.pedido])).digest('hex');
77
+ }
78
+ /** A assinatura do que o dono LE. Dois resumos iguais nao sao duas noticias. */
79
+ function assinaturaDoResumo(r) {
80
+ return (0, node_crypto_1.createHash)('sha256').update(JSON.stringify([r.total, r.urgentes, r.bloqueantes, r.criticos, r.threadsBloqueadas, r.acumuladas, r.prontas, r.consertos,
81
+ r.decisoes.map(d => d.id), r.acimaDoLimiar.map(f => [f.thread, f.fase, f.decididas])])).digest('hex');
82
+ }
83
+ function mensagemPulse(i, agora) {
84
+ // Redigir antes de cortar evita partir tokens e blocos PEM. Campos não expulsam o cabeçalho.
85
+ const campo = (texto, limite) => (0, hitl_1.redigirSegredos)(texto).replace(/[\r\n]+/g, ' ').slice(0, limite);
86
+ // I-35: o item guarda ISO (a assinatura não muda); a mensagem ao dono sai no fuso dele,
87
+ // com o fuso dito uma vez: no prazo ou, sem pedido, logo abaixo da pergunta.
88
+ const pergunta = (0, horario_1.localizarTexto)(i.pergunta, { agora }), legenda = pergunta !== i.pergunta;
89
+ // I-41: so quem tem relogio ganha a linha do relogio. Um `decidido` e fato consumado: nao tem
90
+ // prazo nem acao ao expirar, e imprimir `prazo:` vazio inventaria um cronometro inexistente.
91
+ const prazo = i.pedido ? (0, hitl_contract_1.prazoDoPedido)(i.pedido) : undefined;
92
+ const preparado = i.apresentacao;
93
+ const contexto = preparado ? [
94
+ `Profundidade: ${preparado.profundidade}`,
95
+ `Claims: ${preparado.claims}`, `Riscos: ${preparado.riscos}`,
96
+ ...(preparado.artefato ? [`Artefato:\n${preparado.artefato}`] : []),
97
+ ...(preparado.diff ? [`Diff:\n${preparado.diff}`] : [])
98
+ ] : (0, hitl_1.contextoSeguro)(i.contextoLogs.join('\n'), 8);
99
+ return [`Orkastery: ${campo(i.thread ?? i.sessionId ?? 'sem identificação', 140)} [${campo(i.classe, 40)}]`,
100
+ `Espera: ${i.paradaHaMin == null ? 'desconhecida' : i.paradaHaMin < 1 ? 'menos de 1' : i.paradaHaMin} min`, campo(pergunta, 700), ...(legenda ? [(0, horario_1.legendaDoFuso)()] : []),
101
+ ...i.opcoes.slice(0, 8).map(o => `Opção: ${campo(o, 180)}`),
102
+ `Recomendação: ${campo(i.recomendacao, 500)}`, `Responder: ${campo(i.comandoResposta, 500)}`,
103
+ ...(i.pedido && prazo ? [`Pedido: ${campo(i.pedido.id, 80)}; prazo: ${campo((0, horario_1.formatarPrazo)(prazo, { rotulo: !legenda, agora }), 80)}; expirar: ${campo((0, hitl_contract_1.expiracaoDoPedido)(i.pedido) ?? '', 10)}`] : []),
104
+ ...contexto.map(c => (0, hitl_1.redigirSegredos)(c))].join('\n').slice(0, 3900);
105
+ }
106
+ function gravarCache(file, vistas) {
107
+ const tmp = file + '.tmp';
108
+ fs.writeFileSync(tmp, JSON.stringify({ versao: 1, vistas }) + '\n', { mode: 0o600 });
109
+ fs.renameSync(tmp, file);
110
+ }
111
+ /**
112
+ * I-41 (escopo do dono, 20/09 16:5x): a varredura entrega UMA mensagem, nunca uma por item.
113
+ *
114
+ * Em 20/09 as 16:00 o cron religado disparou e esta funcao mandou 75 mensagens em minutos no
115
+ * Telegram do dono, porque o laco abaixo era `for (const item of itens) enviar(...)`. A frase
116
+ * dele: "de uma forma que humanos simplesmente nao compreendem, mude isso imediatamente".
117
+ *
118
+ * Agora sao duas camadas:
119
+ *
120
+ * CAMADA 1, toda varredura com novidade: UM resumo com as contagens, as threads travadas e a
121
+ * pergunta "Posso te mandar as perguntas agora?". N itens produzem 1 mensagem, sempre.
122
+ *
123
+ * CAMADA 2, so depois do sim: as perguntas, de cinco em cinco, com alternativas a-d. Um sim
124
+ * libera UM lote, nao um canal aberto, senao a inundacao volta por outra porta. I-41 (GO-FIX 1):
125
+ * o lote e a RESPOSTA ao sim, no mesmo canal, montada pelo receptor (`pulse-resposta.ts`); a
126
+ * varredura nunca manda pergunta, so o resumo.
127
+ *
128
+ * A cadencia e parametro. O dono pediu de hora em hora; as tags dele preveem 8h, 2h, 60min,
129
+ * 30min e 15min. `janelaMin` e o que da sentido a palavra "urgente" no resumo.
130
+ */
131
+ function varrerPulse(opcoes) {
132
+ if (opcoes.escopo)
133
+ (0, escopo_escrita_1.exigirEscopoDeEscrita)(opcoes.escopo);
134
+ const raiz = (0, estado_thread_1.raizDoEstado)(opcoes.raiz), dir = opcoes.estadoDir ?? path.join(raiz, '.orkastery', 'monitor');
135
+ fs.mkdirSync(dir, { recursive: true });
136
+ const lock = path.join(dir, 'pulse.lock'), cache = path.join(dir, 'pulse-avisado.json');
137
+ const quando = opcoes.quando ?? new Date().toISOString();
138
+ // I-50: a cadencia duravel do dono decide o status periodico; a janela dela e o horizonte de "urgente".
139
+ const cadencia = (0, pulse_cadencia_1.lerCadencia)(opcoes.raiz, dir);
140
+ const canal = opcoes.canal ?? 'telegram', janelaMin = opcoes.janelaMin ?? (opcoes.comCadencia ? cadencia.janelaMin : hitl_classificacao_1.JANELA_PADRAO_MIN);
141
+ const log = (r) => {
142
+ fs.appendFileSync(path.join(dir, 'hitl.log'), JSON.stringify({ ts: quando, tipo: 'pulse_scan', ...r }) + '\n', { mode: 0o600 });
143
+ return r;
144
+ };
145
+ const trava = (0, monitor_lock_1.adquirirLockMonitor)(lock);
146
+ if (!trava.ok)
147
+ return log({ code: trava.ativo ? 0 : 1, novas: 0, enviadas: 0, detalhe: trava.detalhe });
148
+ let enviadas = 0, novas = 0;
149
+ try {
150
+ let pulse;
151
+ if (opcoes.consultar)
152
+ pulse = opcoes.consultar();
153
+ else {
154
+ const r = (0, node_child_process_1.spawnSync)(process.execPath, [path.join(__dirname, 'index.js'), 'pulse', '--json',
155
+ ...(opcoes.escopo ? ['--registrar', '--escopo', opcoes.escopo.join(',')] : [])], { cwd: raiz, encoding: 'utf8', timeout: 240000, maxBuffer: 8 * 1024 * 1024 });
156
+ if (r.status !== 0)
157
+ throw new Error(`pulse falhou (código ${r.status ?? 'timeout'})`);
158
+ pulse = JSON.parse(r.stdout);
159
+ }
160
+ if (pulse.contrato !== pulse_1.CONTRATO_PULSE || !pulse.runtime?.ok || !Array.isArray(pulse.precisaDeHumanoAgora)) {
161
+ throw new Error('consulta incompleta ou contrato inválido; cache preservado');
162
+ }
163
+ let vistas = {};
164
+ if (fs.existsSync(cache)) {
165
+ const salvo = JSON.parse(fs.readFileSync(cache, 'utf8'));
166
+ if (salvo.versao !== 1 || !salvo.vistas || typeof salvo.vistas !== 'object' || Array.isArray(salvo.vistas))
167
+ throw new Error('cache inválido; exige inspeção');
168
+ vistas = salvo.vistas;
169
+ }
170
+ const itens = pulse.precisaDeHumanoAgora;
171
+ // I-41 (GO-FIX 1, B4): as decisoes tomadas sem perguntar tambem sao noticia, uma vez cada.
172
+ const decisoes = pulse.decisoes ?? [];
173
+ const chaveDaDecisao = (id) => `decisao:${id}`;
174
+ const presentes = new Set([...itens.map(i => i.id), ...decisoes.map(d => chaveDaDecisao(d.id))]);
175
+ // I-51: quem espera o dono em outra maquina tambem e noticia, uma vez por thread e fase.
176
+ let outras = [];
177
+ try {
178
+ outras = opcoes.outrasMaquinas?.() ?? [];
179
+ }
180
+ catch {
181
+ outras = [];
182
+ }
183
+ const esperasFora = outras.flatMap(m => m.esperando.map(e => `maquina:${m.maquina}:${e.thread}:${e.fase}`));
184
+ for (const k of esperasFora)
185
+ presentes.add(k);
186
+ vistas = Object.fromEntries(Object.entries(vistas).filter(([id]) => presentes.has(id)));
187
+ const esperaNovaFora = esperasFora.some(k => vistas[k] === undefined);
188
+ const decisoesNovas = decisoes.filter(d => vistas[chaveDaDecisao(d.id)] === undefined);
189
+ // I-41 (GO-FIX 1): a thread que ja recebeu a pergunta e ainda nao respondeu nao e noticia. A
190
+ // mudanca no item dela (o pedido que o sim do dono abriu) e obra nossa, e avisar sobre ela seria
191
+ // mandar ao dono um resumo sobre a pergunta que ele acabou de receber.
192
+ const servidas = (0, pulse_resposta_1.threadsComPerguntaViva)(raiz, quando, dir);
193
+ const jaServida = (i) => !!i.thread && servidas.has(i.thread);
194
+ novas = itens.filter(i => vistas[i.id] !== assinaturaPulse(i) && !jaServida(i)).length;
195
+ for (const i of itens)
196
+ if (jaServida(i))
197
+ vistas[i.id] = assinaturaPulse(i);
198
+ const entregar = (mensagem, oQue) => {
199
+ let entregue;
200
+ if (opcoes.enviar)
201
+ entregue = opcoes.enviar(mensagem);
202
+ else {
203
+ const config = opcoes.transporte ?? JSON.parse(fs.readFileSync(path.join(dir, 'pulse-host.json'), 'utf8'));
204
+ if (typeof config.executavel !== 'string' || !config.executavel || !Array.isArray(config.argumentos) ||
205
+ !config.argumentos.every(a => typeof a === 'string') || !config.argumentos.some(a => a.includes('{{mensagem}}'))) {
206
+ throw new Error('transporte requer executavel e argumentos com {{mensagem}}');
207
+ }
208
+ const r = (0, node_child_process_1.spawnSync)(config.executavel, config.argumentos.map(a => a.replaceAll('{{mensagem}}', mensagem)), { cwd: raiz, encoding: 'utf8', input: mensagem, timeout: 30000, maxBuffer: 1024 * 1024 });
209
+ entregue = r.status === 0;
210
+ }
211
+ if (!entregue)
212
+ throw new Error(`transporte não confirmou ${oQue}; novidade preservada`);
213
+ enviadas++;
214
+ };
215
+ // I-41 (GO-FIX 1, B3): quais itens sao perguntas que vao DE FATO sair. Um gate que ainda
216
+ // espera o dono e pergunta; um pedido velho de thread que ja seguiu e historia; um pedido que
217
+ // espera mas nao vira pergunta e conserto nosso. Nada disso escreve: o pedido so e (re)aberto
218
+ // quando o dono diz sim, e e ai que o prazo dele comeca.
219
+ const fila = (0, pulse_resposta_1.avaliarFila)(raiz, itens, quando, { excluir: servidas });
220
+ const anterior = (0, pulse_consentimento_1.lerConsentimento)(raiz, dir)?.pedido;
221
+ // Pergunta que o dono ainda nao viu oferecida vale um resumo, uma vez. O gate ja oferecido
222
+ // (no resumo anterior ou num lote servido) nao volta a tocar sozinho, respondido com "agora
223
+ // nao", com "continuar esperando" ou deixado sem resposta: silencio e resposta, e o proximo
224
+ // resumo com novidade o traz de novo entre as perguntas.
225
+ const oferecidos = new Set([...(anterior?.candidatos ?? []).map(c => (0, pulse_resposta_1.chaveDoGate)(c.thread, c.fase)), ...(0, pulse_resposta_1.gatesJaServidos)(raiz, dir)]);
226
+ const conjuntoNovo = fila.candidatos.some(c => !oferecidos.has((0, pulse_resposta_1.chaveDoGate)(c.thread, c.fase)));
227
+ // CAMADA 1: UMA mensagem por varredura, e nenhuma quando nada mudou. A CAMADA 2 nao sai daqui:
228
+ // ela e a resposta ao sim do dono, no mesmo canal, pelo receptor (`pulse-resposta.ts`).
229
+ // I-50: pergunta nova sai na hora; o resto (status, decisoes informadas) espera a janela da
230
+ // cadencia do dono, e a novidade que esperou continua nao vista ate sair.
231
+ const noPrazo = !opcoes.comCadencia || (0, pulse_cadencia_1.janelaAberta)(cadencia, (0, pulse_cadencia_1.lerUltimoResumo)(opcoes.raiz, dir), quando);
232
+ const adiada = !conjuntoNovo && !esperaNovaFora && (novas > 0 || decisoesNovas.length > 0) && !noPrazo;
233
+ if (conjuntoNovo || esperaNovaFora || (noPrazo && (novas > 0 || decisoesNovas.length > 0))) {
234
+ const guardadas = anterior ? fila.candidatos.filter(c => anterior.candidatos.some(a => a.thread === c.thread)).length : 0;
235
+ const resumo = (0, hitl_resumo_1.resumirHitl)(itens, { quando, janelaMin, prontas: fila.candidatos.length, acumuladas: guardadas,
236
+ consertos: fila.consertos, atoDoItem: i => fila.atos.get(`${i.thread}|${i.fase}`),
237
+ decisoes: decisoesNovas, acimaDoLimiar: pulse.acimaDoLimiar ?? [], outrasMaquinas: outras });
238
+ // Pedir licenca para mandar zero perguntas era o defeito: sem pergunta, nao ha codigo.
239
+ // I-50: cadencia curta nao encurta o prazo do dono para responder ao resumo (minimo de 60 min).
240
+ const consentimento = fila.candidatos.length ? (0, monitor_lock_1.comLockDaConversa)(dir, () => (0, pulse_consentimento_1.abrirConsentimento)(raiz, { quando,
241
+ resumoSha256: assinaturaDoResumo(resumo), candidatos: fila.candidatos, prazoMin: Math.max(janelaMin, pulse_consentimento_1.PRAZO_PADRAO_MIN), estadoDir: dir })) : undefined;
242
+ entregar((0, hitl_resumo_1.textoDoResumo)(resumo, { canal, codigo: consentimento?.codigo }), 'o resumo');
243
+ // Marcado so depois do recibo do transporte: envio que falhou preserva a novidade.
244
+ for (const item of itens)
245
+ vistas[item.id] = assinaturaPulse(item);
246
+ for (const d of decisoes)
247
+ vistas[chaveDaDecisao(d.id)] = 'informada';
248
+ for (const k of esperasFora)
249
+ vistas[k] = 'informada';
250
+ (0, pulse_cadencia_1.gravarUltimoResumo)(opcoes.raiz, quando, dir);
251
+ }
252
+ gravarCache(cache, vistas);
253
+ return log({ code: 0, novas, enviadas,
254
+ detalhe: enviadas ? `${enviadas} mensagem(ns) confirmada(s) pelo transporte para ${novas} novidade(s)`
255
+ : adiada ? `novidade guardada para a janela seguinte da cadencia ${cadencia.tag}` : 'sem novidade' });
256
+ }
257
+ catch (e) {
258
+ return log({ code: 1, novas, enviadas, detalhe: e.message });
259
+ }
260
+ finally {
261
+ trava.liberar();
262
+ }
263
+ }
264
+ if (require.main === module) {
265
+ try {
266
+ const raiz = process.argv[2] ?? process.cwd();
267
+ const carregado = (0, manifest_1.exigirManifesto)(raiz);
268
+ // I-35: o cron chama esta entrada direto, sem o main do CLI; o fuso do dono vem do manifesto do projeto.
269
+ (0, horario_1.registrarFonteDoFuso)(() => (0, horario_1.fusoDoManifesto)(carregado));
270
+ let escopo;
271
+ try {
272
+ const a = (0, write_activation_1.lerAtivacao)(carregado);
273
+ if (a.ativa && a.plano?.alvos.includes('pulse'))
274
+ escopo = a.plano.threads;
275
+ }
276
+ catch (e) {
277
+ console.error('pulse.activation.pending: ' + (e.message.startsWith('write.activation.') ? e.message : 'invalid receipt'));
278
+ }
279
+ const ambiente = process.env.ORK_PULSE_WRITE_SCOPE;
280
+ if (ambiente && ambiente !== (escopo ?? []).join(','))
281
+ throw Error('pulse.scope.activation-conflict');
282
+ // I-51 (RM-047): com a fabrica compartilhada, a batida publica esta maquina e le as outras.
283
+ const compartilhada = (0, maquina_1.fabricaCompartilhada)(carregado.manifesto), remoto = carregado.manifesto.fabrica.remoto;
284
+ if (compartilhada) {
285
+ try {
286
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { ...(0, fabrica_estado_1.publicarMaquina)(carregado), origem: 'pulse' });
287
+ }
288
+ catch (e) {
289
+ (0, fabrica_estado_1.registrarPublicacao)(carregado.raiz, { acao: 'falhou', origem: 'pulse', erro: e.message });
290
+ }
291
+ }
292
+ const outrasMaquinas = compartilhada
293
+ ? () => (0, fabrica_estado_1.resumoDasOutrasMaquinas)((0, fabrica_estado_1.lerFabrica)(carregado.raiz, { remoto, semRemoto: true }), (0, maquina_1.nomeDaMaquina)()) : undefined;
294
+ const r = varrerPulse({ raiz, escopo, comCadencia: true, outrasMaquinas });
295
+ console.log(JSON.stringify(r));
296
+ process.exitCode = r.code;
297
+ }
298
+ catch (e) {
299
+ console.error(e.message);
300
+ process.exitCode = 1;
301
+ }
302
+ }
303
+ /** Payload JSON via stdin; saída estruturada do host confirma a mensagem. */
304
+ function enviarPayloadHost(raiz, config, payload) {
305
+ if (!config || typeof config.executavel !== 'string' || !config.executavel || !Array.isArray(config.argumentos) ||
306
+ !config.argumentos.every(a => typeof a === 'string'))
307
+ throw new Error('transporte de digest inválido');
308
+ const r = (0, node_child_process_1.spawnSync)(config.executavel, config.argumentos, { cwd: raiz, encoding: 'utf8',
309
+ input: JSON.stringify(payload), timeout: 30000, maxBuffer: 1024 * 1024 });
310
+ if (r.status !== 0)
311
+ throw new Error('host não confirmou digest');
312
+ let recibo;
313
+ try {
314
+ recibo = JSON.parse(r.stdout);
315
+ }
316
+ catch {
317
+ throw new Error('recibo do host inválido');
318
+ }
319
+ if (recibo.success !== true || !Number.isInteger(recibo.message_id) || recibo.message_id <= 0 ||
320
+ typeof recibo.platform !== 'string' || !recibo.platform.trim())
321
+ throw new Error('recibo do host inválido');
322
+ return { success: true, message_id: recibo.message_id, platform: recibo.platform };
323
+ }