@orkastery/cli 0.5.6 → 0.6.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 (385) hide show
  1. package/adapters/README.md +18 -0
  2. package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
  3. package/adapters/claude-code/README.md +37 -5
  4. package/adapters/claude-code/agents/ork-check.md +1 -0
  5. package/adapters/claude-code/agents/ork-go.md +1 -0
  6. package/adapters/claude-code/agents/ork-goal.md +1 -0
  7. package/adapters/claude-code/agents/ork-master.md +1 -0
  8. package/adapters/claude-code/agents/ork-plan.md +1 -0
  9. package/adapters/claude-code/agents/ork-ship.md +1 -0
  10. package/adapters/claude-code/hooks/hooks.json +2 -1
  11. package/adapters/claude-code/hooks/ork-guard.js +15 -1
  12. package/adapters/claude-code/hooks/ork-resposta.js +91 -0
  13. package/adapters/claude-code/hooks/ork-sensor.js +18 -2
  14. package/adapters/claude-code/hooks/quota-signal.js +14 -0
  15. package/adapters/claude-code/mods/ork-mensageiro/.claude-plugin/plugin.json +14 -0
  16. package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
  17. package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
  18. package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
  19. package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
  20. package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
  21. package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
  22. package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -0
  23. package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +9 -5
  24. package/adapters/claude-code/mods/ork-ritual/.claude-plugin/plugin.json +14 -0
  25. package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
  26. package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
  27. package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
  28. package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
  29. package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
  30. package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
  31. package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -0
  32. package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +1 -1
  33. package/adapters/codex/skills/ork/SKILL.md +2 -0
  34. package/adapters/hermes/README.md +64 -1
  35. package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
  36. package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
  37. package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
  38. package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
  39. package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
  40. package/adapters/hermes/hermes.plugin.json +4 -0
  41. package/adapters/hermes/hitl-ingress/__init__.py +101 -8
  42. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +2 -2
  43. package/adapters/openclaw/README.md +81 -9
  44. package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
  45. package/adapters/openclaw/dist/hitl-ingress.js +106 -9
  46. package/adapters/openclaw/dist/index.js +86 -0
  47. package/adapters/openclaw/openclaw.plugin.json +34 -4
  48. package/adapters/openclaw/package.json +2 -2
  49. package/adapters/openclaw/src/hitl-ingress.ts +103 -9
  50. package/adapters/openclaw/src/index.ts +94 -0
  51. package/assets/adapters-en/claude-code/README.md +403 -0
  52. package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
  53. package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
  54. package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
  55. package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
  56. package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
  57. package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
  58. package/assets/adapters-en/claude-code/commands/check.md +46 -0
  59. package/assets/adapters-en/claude-code/commands/go.md +46 -0
  60. package/assets/adapters-en/claude-code/commands/goal.md +55 -0
  61. package/assets/adapters-en/claude-code/commands/master.md +54 -0
  62. package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
  63. package/assets/adapters-en/claude-code/commands/ork.md +126 -0
  64. package/assets/adapters-en/claude-code/commands/plan.md +47 -0
  65. package/assets/adapters-en/claude-code/commands/ship.md +45 -0
  66. package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
  67. package/assets/adapters-en/hermes/README.md +273 -0
  68. package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
  69. package/assets/references-en/README.md +25 -0
  70. package/assets/references-en/code-review-axes.md +82 -0
  71. package/assets/references-en/definition-of-done.md +74 -0
  72. package/assets/references-en/performance-checklist.md +53 -0
  73. package/assets/references-en/security-checklist.md +101 -0
  74. package/assets/references-en/testing-patterns.md +51 -0
  75. package/assets/security-scan/defaults/.golangci.yml +2 -0
  76. package/assets/security-scan/defaults/eslint.config.mjs +11 -0
  77. package/assets/security-scan/defaults/gitleaks.toml +3 -0
  78. package/assets/security-scan/defaults/ruff.toml +1 -0
  79. package/assets/security-scan/tools-agil.json +87 -0
  80. package/assets/security-scan/tools.json +625 -0
  81. package/assets/skills-en/core/onboarding/SKILL.md +58 -0
  82. package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
  83. package/assets/skills-en/core/thread-state/SKILL.md +88 -0
  84. package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
  85. package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
  86. package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
  87. package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
  88. package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
  89. package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
  90. package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
  91. package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
  92. package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
  93. package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
  94. package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
  95. package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
  96. package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
  97. package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
  98. package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
  99. package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
  100. package/dist/adapters/claude-bg.js +118 -4
  101. package/dist/adapters/codex-controller-worker.js +12 -5
  102. package/dist/adapters/codex-events.js +16 -4
  103. package/dist/adapters/codex.js +3 -1
  104. package/dist/atualizar-branch.js +245 -0
  105. package/dist/auditoria.js +13 -11
  106. package/dist/auditrun.js +51 -46
  107. package/dist/autorizacao-duravel.js +327 -0
  108. package/dist/board.js +94 -40
  109. package/dist/branch-de-estado.js +16 -8
  110. package/dist/busca-semantica.js +7 -5
  111. package/dist/catalogo.js +2 -1
  112. package/dist/changelog-reconciliacao.js +290 -0
  113. package/dist/check-agil.js +500 -0
  114. package/dist/check-modo.js +41 -0
  115. package/dist/check-paralelo.js +183 -0
  116. package/dist/ci.js +248 -45
  117. package/dist/ciclos.js +8 -6
  118. package/dist/claim-lint.js +12 -8
  119. package/dist/claims-conferir.js +47 -39
  120. package/dist/claims.js +10 -9
  121. package/dist/company-brain-client.js +10 -3
  122. package/dist/company-brain-migration.js +11 -5
  123. package/dist/conducao-batida.js +759 -0
  124. package/dist/conducao-sentinela.js +25 -8
  125. package/dist/conducao.js +84 -29
  126. package/dist/conhecimento-consulta.js +270 -0
  127. package/dist/conhecimento.js +111 -87
  128. package/dist/conta-esgotada.js +127 -0
  129. package/dist/dado-privado.js +816 -0
  130. package/dist/decisao-autonoma.js +5 -4
  131. package/dist/demo.js +14 -12
  132. package/dist/dependencias-da-worktree.js +25 -0
  133. package/dist/divida.js +38 -36
  134. package/dist/docs.js +81 -74
  135. package/dist/doctor-forja.js +345 -0
  136. package/dist/doctor-pulse-cron.js +113 -1
  137. package/dist/doctor.js +164 -6
  138. package/dist/dsn-da-memoria.js +417 -0
  139. package/dist/entrega-por-mod.js +503 -0
  140. package/dist/entrega-pr.js +143 -43
  141. package/dist/esgotamentos.js +13 -11
  142. package/dist/estado-thread.js +21 -18
  143. package/dist/evalrunner.js +35 -32
  144. package/dist/fabrica-batida.js +34 -21
  145. package/dist/fabrica-estado.js +13 -10
  146. package/dist/fix.js +21 -19
  147. package/dist/forja/adaptador.js +6 -0
  148. package/dist/forja/ambiente-de-ci.js +27 -0
  149. package/dist/forja/api.js +256 -0
  150. package/dist/forja/cache.js +89 -0
  151. package/dist/forja/cli.js +60 -0
  152. package/dist/forja/contrato.js +9 -0
  153. package/dist/forja/endereco.js +43 -0
  154. package/dist/forja/estado.js +22 -0
  155. package/dist/forja/executor.js +73 -0
  156. package/dist/forja/github/ci.js +95 -0
  157. package/dist/forja/github/dono-da-rede.js +18 -0
  158. package/dist/forja/github/metadados.js +15 -0
  159. package/dist/forja/github/pedidos.js +200 -0
  160. package/dist/forja/gitlab/ci.js +141 -0
  161. package/dist/forja/gitlab/consultas.js +59 -0
  162. package/dist/forja/gitlab/dono-da-rede.js +43 -0
  163. package/dist/forja/gitlab/metadados.js +15 -0
  164. package/dist/forja/gitlab/pedidos-abertos.js +158 -0
  165. package/dist/forja/gitlab/pedidos.js +141 -0
  166. package/dist/forja/produtor.js +32 -0
  167. package/dist/forja/registro.js +31 -0
  168. package/dist/forja/resolver.js +121 -0
  169. package/dist/forja/texto.js +13 -0
  170. package/dist/forja/versao.js +71 -0
  171. package/dist/forja.js +123 -80
  172. package/dist/handoff.js +23 -13
  173. package/dist/hitl-contract.js +46 -43
  174. package/dist/hitl-curto.js +37 -25
  175. package/dist/hitl-gates.js +13 -11
  176. package/dist/hitl-local-receipt.js +51 -0
  177. package/dist/hitl-local.js +11 -2
  178. package/dist/hitl-lock.js +5 -11
  179. package/dist/hitl-public-receipt.js +11 -0
  180. package/dist/hitl-resumo.js +44 -1
  181. package/dist/hitl-sessions.js +62 -9
  182. package/dist/hitl-texto-livre.js +7 -4
  183. package/dist/hitl.js +34 -31
  184. package/dist/horario.js +16 -0
  185. package/dist/hosts.js +104 -134
  186. package/dist/index.js +848 -548
  187. package/dist/indice-vetorial.js +14 -12
  188. package/dist/init.js +11 -2
  189. package/dist/integracoes-locais.js +2 -0
  190. package/dist/intelligence-graph-cli.js +123 -69
  191. package/dist/intelligence-graph-query.js +37 -22
  192. package/dist/leases.js +19 -18
  193. package/dist/ledger-stats.js +17 -16
  194. package/dist/ledger.js +31 -1
  195. package/dist/licoes.js +12 -11
  196. package/dist/locale-accounts.js +220 -0
  197. package/dist/locale-adapter.js +291 -0
  198. package/dist/locale-ajuda.js +76 -4
  199. package/dist/locale-audit.js +199 -0
  200. package/dist/locale-claims.js +213 -0
  201. package/dist/locale-conducao.js +138 -0
  202. package/dist/locale-conhecimento.js +181 -0
  203. package/dist/locale-decisao.js +205 -0
  204. package/dist/locale-docs.js +230 -0
  205. package/dist/locale-estado.js +101 -0
  206. package/dist/locale-forja.js +290 -0
  207. package/dist/locale-gerados.js +5 -0
  208. package/dist/locale-grafo.js +129 -0
  209. package/dist/locale-master.js +83 -0
  210. package/dist/locale-network.js +524 -0
  211. package/dist/locale-operacao-restante.js +931 -0
  212. package/dist/locale-projetos.js +100 -0
  213. package/dist/locale-prompts.js +194 -0
  214. package/dist/locale-pulse.js +140 -2
  215. package/dist/locale-reservas.js +87 -0
  216. package/dist/locale-retry.js +145 -6
  217. package/dist/locale-security-scan.js +69 -0
  218. package/dist/locale-setup.js +192 -0
  219. package/dist/locale-ship.js +169 -66
  220. package/dist/locale-thread.js +149 -5
  221. package/dist/locale-verify.js +80 -4
  222. package/dist/locale-worktree.js +246 -0
  223. package/dist/locale.js +553 -9
  224. package/dist/maestro-runtime.js +22 -3
  225. package/dist/manifest.js +287 -11
  226. package/dist/maquina-ociosa.js +211 -0
  227. package/dist/maquina.js +10 -5
  228. package/dist/master-nota-local.js +200 -0
  229. package/dist/master-nota.js +10 -2
  230. package/dist/master.js +118 -41
  231. package/dist/mcp-conhecimento.js +52 -0
  232. package/dist/mcp-experiencia.js +26 -5
  233. package/dist/mcp-install.js +73 -8
  234. package/dist/mcp-noctum.js +101 -0
  235. package/dist/mcp-server.js +82 -14
  236. package/dist/mcp-ship-transporte.js +977 -0
  237. package/dist/mcp-ship.js +68 -24
  238. package/dist/mcp-transportes.js +17 -0
  239. package/dist/memoria.js +63 -58
  240. package/dist/modos-migracao.js +8 -6
  241. package/dist/modos.js +17 -18
  242. package/dist/network-roadmap.js +85 -49
  243. package/dist/noctum-aceite.js +789 -0
  244. package/dist/noctum-arco.js +540 -33
  245. package/dist/noctum-capacidade.js +3 -3
  246. package/dist/noctum-changelog.js +399 -0
  247. package/dist/noctum-cli.js +482 -0
  248. package/dist/noctum-coordenacao.js +1225 -0
  249. package/dist/noctum-entrega.js +1169 -0
  250. package/dist/noctum-envelope.js +252 -16
  251. package/dist/noctum-execucao.js +95 -23
  252. package/dist/noctum-fechamento.js +405 -0
  253. package/dist/noctum-fila.js +43 -9
  254. package/dist/noctum-guarda.js +256 -0
  255. package/dist/noctum-integracao.js +507 -0
  256. package/dist/noctum-maquinas.js +383 -0
  257. package/dist/noctum-medicao.js +450 -0
  258. package/dist/noctum-modo.js +362 -0
  259. package/dist/noctum-pergunta-canal.js +96 -0
  260. package/dist/noctum-pergunta.js +115 -0
  261. package/dist/noctum-provas.js +838 -0
  262. package/dist/noctum-reconciliacao.js +591 -0
  263. package/dist/noctum-registro.js +215 -0
  264. package/dist/noctum-relatorio.js +827 -0
  265. package/dist/noctum-resposta.js +207 -0
  266. package/dist/noctum-sessoes-em-voo.js +93 -0
  267. package/dist/noctum-supervisao.js +649 -0
  268. package/dist/noctum-terminal.js +459 -0
  269. package/dist/noctum-transporte.js +655 -0
  270. package/dist/noctum-vigia.js +639 -0
  271. package/dist/ocupacao.js +3 -1
  272. package/dist/onboarding.js +16 -5
  273. package/dist/orkmind.js +39 -23
  274. package/dist/orquestracao.js +31 -35
  275. package/dist/parado-no-condutor.js +146 -124
  276. package/dist/phase.js +53 -27
  277. package/dist/policies.js +33 -0
  278. package/dist/postura-local.js +4 -3
  279. package/dist/procedencia.js +9 -14
  280. package/dist/projeto-alvo.js +59 -20
  281. package/dist/prompts.js +136 -42
  282. package/dist/prova-minima.js +5 -6
  283. package/dist/pulse-cadencia.js +5 -4
  284. package/dist/pulse-consentimento.js +53 -1
  285. package/dist/pulse-delivery.js +143 -27
  286. package/dist/pulse-resposta.js +368 -4
  287. package/dist/pulse.js +136 -3
  288. package/dist/ratelimit.js +12 -4
  289. package/dist/recall.js +14 -13
  290. package/dist/rede-adesao.js +13 -8
  291. package/dist/rede-forja.js +108 -24
  292. package/dist/rede-status.js +63 -45
  293. package/dist/rede.js +86 -46
  294. package/dist/retomada-checkpoint.js +101 -0
  295. package/dist/retry.js +228 -73
  296. package/dist/roadmap-reservas.js +32 -32
  297. package/dist/runtime-ambiente.js +5 -0
  298. package/dist/runtime-context.js +117 -43
  299. package/dist/runtime-escada.js +423 -0
  300. package/dist/runtime-profiles.js +103 -46
  301. package/dist/saida-segura.js +3 -2
  302. package/dist/security-scan/agil.js +355 -0
  303. package/dist/security-scan/cli.js +76 -0
  304. package/dist/security-scan/compare.js +149 -0
  305. package/dist/security-scan/config.js +93 -0
  306. package/dist/security-scan/detect.js +97 -0
  307. package/dist/security-scan/executor.js +188 -0
  308. package/dist/security-scan/guard.js +180 -0
  309. package/dist/security-scan/imagem-de-lint.js +96 -0
  310. package/dist/security-scan/normalize/actionlint.js +12 -0
  311. package/dist/security-scan/normalize/eslint.js +12 -0
  312. package/dist/security-scan/normalize/gitleaks.js +13 -0
  313. package/dist/security-scan/normalize/golangci-lint.js +13 -0
  314. package/dist/security-scan/normalize/govulncheck.js +36 -0
  315. package/dist/security-scan/normalize/index.js +25 -0
  316. package/dist/security-scan/normalize/npm-audit.js +30 -0
  317. package/dist/security-scan/normalize/osv-scanner.js +32 -0
  318. package/dist/security-scan/normalize/oxlint.js +51 -0
  319. package/dist/security-scan/normalize/pip-audit.js +16 -0
  320. package/dist/security-scan/normalize/ruff.js +12 -0
  321. package/dist/security-scan/normalize/semgrep.js +20 -0
  322. package/dist/security-scan/normalize/trivy.js +33 -0
  323. package/dist/security-scan/normalize/util.js +204 -0
  324. package/dist/security-scan/normalize/zizmor.js +19 -0
  325. package/dist/security-scan/report.js +156 -0
  326. package/dist/security-scan/run.js +448 -0
  327. package/dist/security-scan/tools.js +62 -0
  328. package/dist/security-scan/trabalhador.js +74 -0
  329. package/dist/security-scan/types.js +15 -0
  330. package/dist/session-events.js +19 -2
  331. package/dist/session-watcher-claude.js +74 -19
  332. package/dist/session-watcher.js +156 -10
  333. package/dist/sessoes-contas.js +9 -0
  334. package/dist/sessoes-inventario.js +1 -1
  335. package/dist/sessoes.js +25 -23
  336. package/dist/setup.js +59 -58
  337. package/dist/ship-publicar.js +263 -92
  338. package/dist/ship.js +160 -17
  339. package/dist/superficie.js +14 -11
  340. package/dist/thread-close.js +9 -9
  341. package/dist/thread.js +121 -18
  342. package/dist/tokens.js +15 -11
  343. package/dist/trabalho-thread.js +297 -0
  344. package/dist/transporte-do-canal.js +189 -0
  345. package/dist/types.js +12 -1
  346. package/dist/util.js +5 -2
  347. package/dist/varredura-acoes.js +507 -0
  348. package/dist/verify.js +472 -29
  349. package/dist/worktree-local.js +12 -10
  350. package/dist/worktree.js +81 -85
  351. package/eval/casos/check-quality.json +77 -0
  352. package/eval/casos/security-auditor.json +148 -0
  353. package/eval/casos/security-remediation.json +161 -0
  354. package/eval/fixtures/security-scan/README.md +8 -0
  355. package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
  356. package/eval/fixtures/security-scan/go/Dockerfile +4 -0
  357. package/eval/fixtures/security-scan/go/README.md +4 -0
  358. package/eval/fixtures/security-scan/go/config.go +4 -0
  359. package/eval/fixtures/security-scan/go/go.mod +5 -0
  360. package/eval/fixtures/security-scan/go/go.sum +2 -0
  361. package/eval/fixtures/security-scan/go/main.go +31 -0
  362. package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
  363. package/eval/fixtures/security-scan/js/Dockerfile +3 -0
  364. package/eval/fixtures/security-scan/js/README.md +4 -0
  365. package/eval/fixtures/security-scan/js/package-lock.json +844 -0
  366. package/eval/fixtures/security-scan/js/package.json +10 -0
  367. package/eval/fixtures/security-scan/js/src/config.js +4 -0
  368. package/eval/fixtures/security-scan/js/src/server.js +17 -0
  369. package/eval/fixtures/security-scan/js/src/util.ts +4 -0
  370. package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
  371. package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
  372. package/eval/fixtures/security-scan/python/Dockerfile +3 -0
  373. package/eval/fixtures/security-scan/python/README.md +4 -0
  374. package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
  375. package/eval/fixtures/security-scan/python/app/config.py +2 -0
  376. package/eval/fixtures/security-scan/python/app/main.py +19 -0
  377. package/eval/fixtures/security-scan/python/requirements.txt +1 -0
  378. package/package.json +9 -4
  379. package/references/security-checklist.md +3 -3
  380. package/skills/README.md +1 -0
  381. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  382. package/skills/phases/check-quality/SKILL.md +16 -0
  383. package/skills/phases/go-implementation/SKILL.md +6 -0
  384. package/skills/phases/security-remediation/SKILL.md +70 -0
  385. package/skills/reviewers/security-auditor/SKILL.md +25 -0
@@ -43,6 +43,9 @@ exports.threadsComPerguntaViva = threadsComPerguntaViva;
43
43
  exports.gatesJaServidos = gatesJaServidos;
44
44
  exports.avaliarFila = avaliarFila;
45
45
  exports.servirLote = servirLote;
46
+ exports.chatDoTelegram = chatDoTelegram;
47
+ exports.servirPerguntaDoArco = servirPerguntaDoArco;
48
+ exports.restoDoCodigo = restoDoCodigo;
46
49
  exports.pedidoParaResponder = pedidoParaResponder;
47
50
  exports.pedidosComCodigo = pedidosComCodigo;
48
51
  exports.codigosEmUso = codigosEmUso;
@@ -83,6 +86,7 @@ const horario_1 = require("./horario");
83
86
  const hitl_gates_1 = require("./hitl-gates");
84
87
  const hitl_contract_1 = require("./hitl-contract");
85
88
  const monitor_lock_1 = require("./monitor-lock");
89
+ const hitl_1 = require("./hitl");
86
90
  const hitl_lote_1 = require("./hitl-lote");
87
91
  const hitl_curto_1 = require("./hitl-curto");
88
92
  const hitl_texto_livre_1 = require("./hitl-texto-livre");
@@ -97,6 +101,9 @@ const pulse_cadencia_1 = require("./pulse-cadencia");
97
101
  const ledger_1 = require("./ledger");
98
102
  const thread_1 = require("./thread");
99
103
  const pulse_consentimento_1 = require("./pulse-consentimento");
104
+ const noctum_arco_1 = require("./noctum-arco");
105
+ const noctum_pergunta_1 = require("./noctum-pergunta");
106
+ const noctum_resposta_1 = require("./noctum-resposta");
100
107
  exports.CONTRATO_RESPOSTA_DO_PULSE = 'ork.pulse-resposta/v1';
101
108
  exports.CONTRATO_LOTE_SERVIDO = 'ork.pulse-lote-servido/v1';
102
109
  /**
@@ -126,11 +133,21 @@ exports.GRAMATICA_DO_PULSE = Object.freeze({
126
133
  // RM-048 (item 8): o teclado do digest semanal ("ratificar <thread> <assinatura> <classe>" e
127
134
  // "ratificar-lote <semana> <assinatura>") passa pelo mesmo endereco assinado, e nao pelo agente.
128
135
  ratificacao: '^[ \\t]*ratificar(?:-lote)?(?:[ \\t]+[A-Za-z0-9._-]{1,80}){2,3}[ \\t]*$',
136
+ // RM-063 (fatia 3, H2): os comandos de conducao do canal, sozinhos na mensagem: `#OrkRetomar` roda a batida da
137
+ // conducao e responde o que voltou a andar; `#OrkFabrica` responde o `ork fabrica`. Comecam por `#`, como a cadencia.
138
+ conducao: '^[ \\t]*#Ork(?:Retomar|Fabrica)[ \\t]*[.!]?[ \\t]*$',
139
+ // RM-057 (resposta curta, D3 da ork-rm057respost; GO-FIX 1, achado 2): o título da pergunta do arco, a primeira linha
140
+ // da mensagem do bot a que o dono respondeu (reply), como `textoDaPerguntaDoArco` o monta no Telegram. Só ele dá a
141
+ // referência, e o código sai dele: confirmação, recusa, lembrete e conversa nunca têm esta linha. O gateway assina o
142
+ // código e o id da mensagem respondida no endereço `resposta:<código>:<id>`, e o núcleo confere que o id é o da mensagem
143
+ // em que a pergunta foi entregue. Não é forma de resposta: é a referência dela.
144
+ referencia: '^🔔 (?:[1-9][0-9]?\\. )?arco [a-z0-9][a-z0-9-]{0,62} · ((?=[A-HJKMNP-TV-Z][2-9A-HJKMNP-TV-Z]{0,2}[2-9])[A-HJKMNP-TV-Z][2-9A-HJKMNP-TV-Z]{3})$',
129
145
  });
130
146
  const RATIFICACAO = new RegExp(exports.GRAMATICA_DO_PULSE.ratificacao, 'i');
131
147
  const CONSENTIMENTO = new RegExp(exports.GRAMATICA_DO_PULSE.consentimento, 'i');
132
148
  const LOTE = new RegExp(exports.GRAMATICA_DO_PULSE.lote);
133
149
  const CADENCIA = new RegExp(exports.GRAMATICA_DO_PULSE.cadencia, 'i');
150
+ const CONDUCAO = new RegExp(exports.GRAMATICA_DO_PULSE.conducao, 'i');
134
151
  /** O que o dono quis dizer, pela forma. Nada aqui le intencao: ou a forma bate, ou nao. */
135
152
  function interpretarRespostaDoPulse(texto) {
136
153
  if (typeof texto !== 'string' || texto.length > hitl_texto_livre_1.TETO_DA_FORMA)
@@ -154,6 +171,8 @@ function interpretarRespostaDoPulse(texto) {
154
171
  const tag = CADENCIA.test(texto) ? (0, pulse_cadencia_1.extrairTagDoPulse)(texto) : null;
155
172
  if (tag)
156
173
  return { forma: 'cadencia', tag };
174
+ if (CONDUCAO.test(texto))
175
+ return { forma: 'conducao', comando: /#OrkRetomar/i.test(texto) ? 'retomar' : 'fabrica' };
157
176
  const solta = (0, hitl_texto_livre_1.lerSolta)(texto);
158
177
  if (solta)
159
178
  return { forma: 'livre', trecho: solta };
@@ -199,6 +218,9 @@ function perguntaViva(p, quando) {
199
218
  * guarda de 24 h desde que saiu: depois do prazo do pedido ela vai ao pedido renovado.
200
219
  */
201
220
  function perguntaEmAberto(p, quando) {
221
+ // RM-057 (resposta curta): a pergunta do arco não se renova; vencida, ela deixa de esperar o dono.
222
+ if (p.arco)
223
+ return perguntaViva(p, quando);
202
224
  return !p.respondida && (perguntaViva(p, quando) || Date.parse(quando) - Date.parse(p.servidaEm) < exports.GUARDA_DA_PERGUNTA_MS);
203
225
  }
204
226
  /** O que sai do registro: vencida sem resposta, ou respondida ha mais de um dia. */
@@ -451,6 +473,182 @@ function recomendadaDoRegistro(raiz, p) {
451
473
  }
452
474
  }
453
475
  // ---------------------------------------------------------------------------
476
+ // RM-057 (resposta curta, ork-rm057respost): a pergunta do arco #Noctum no canal do pulse.
477
+ // ---------------------------------------------------------------------------
478
+ /** O número livre para UMA pergunta servida sozinha: o seguinte aos do registro, ou o menor livre quando passaria de 99. */
479
+ function numeroLivreParaUma(servido) {
480
+ const usados = new Set(servido.perguntas.map(p => p.numero));
481
+ const seguinte = Math.max(0, ...usados) + 1;
482
+ if (seguinte <= MAIOR_NUMERO)
483
+ return seguinte;
484
+ for (let n = 1; n <= MAIOR_NUMERO; n++)
485
+ if (!usados.has(n))
486
+ return n;
487
+ return 1;
488
+ }
489
+ /** O chat de um envelope do Telegram (`telegram:<chat>:<mensagem>`), ou de um destino (`telegram:<chat>[:<tópico>]`). */
490
+ function chatDoTelegram(ref) {
491
+ const m = /^telegram:(-?\d+)(?::[^:]+)?$/.exec(String(ref ?? ''));
492
+ return m ? m[1] : null;
493
+ }
494
+ /**
495
+ * Serve UMA pergunta do arco no canal, com número, sob o lock da conversa do pulse: o número é reservado, a mensagem sai
496
+ * pelo `entregar` (com o número no título) e o registro só acontece com o recibo do transporte. A mesma pergunta já
497
+ * servida e ainda em aberto não sai de novo. A janela da palavra solta acompanha.
498
+ */
499
+ function servirPerguntaDoArco(raiz, p, opcoes) {
500
+ const estadoDir = opcoes.estadoDir ?? path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery', 'monitor');
501
+ return (0, monitor_lock_1.comLockDaConversa)(estadoDir, () => {
502
+ let servido = podar(lerLoteServido(raiz, estadoDir), opcoes.quando);
503
+ const ja = servido.perguntas.find(q => q.arco?.codigo === p.codigo && perguntaEmAberto(q, opcoes.quando));
504
+ if (ja)
505
+ return { numero: ja.numero, entregue: false, jaServida: true, host: null, destino: ja.arco.destino, mensagens: [...(ja.arco.mensagens ?? [])] };
506
+ const numero = numeroLivreParaUma(servido);
507
+ const r = opcoes.entregar(numero);
508
+ if (!r.ok)
509
+ return { numero: null, entregue: false, jaServida: false, host: r.host, destino: null, mensagens: [] };
510
+ const alternativas = (0, noctum_pergunta_1.alternativasDaPergunta)(p);
511
+ const recomendada = alternativas.find(a => a.porque);
512
+ const nova = {
513
+ numero, thread: `arco:${p.arco}`, fase: null, pedidoId: `noctum:${p.arco}:${p.codigo}`,
514
+ pedidoSha256: sha(JSON.stringify([p.arco, p.ato, p.codigo, p.versao, p.envelopeSha256, p.prazo])),
515
+ letras: alternativas.map(a => a.letra), alternativas: alternativas.map(a => a.texto), consequencias: alternativas.map(a => a.consequencia),
516
+ recomendada: { letra: recomendada.letra, porque: recomendada.porque }, desde: p.criadaEm,
517
+ pergunta: (0, noctum_pergunta_1.fraseDaPergunta)(p), prazo: p.prazo, servidaEm: opcoes.quando,
518
+ arco: { arco: p.arco, ato: p.ato, codigo: p.codigo, destino: r.destino, mensagens: [...(r.mensagens ?? [])] },
519
+ };
520
+ servido = { ...servido, perguntas: [...servido.perguntas, nova] };
521
+ gravarLoteServido(raiz, servido, estadoDir);
522
+ try {
523
+ atualizarEscuta(raiz, opcoes.quando, estadoDir);
524
+ }
525
+ catch { /* dica de rota; a prova não depende dela */ }
526
+ return { numero, entregue: true, jaServida: false, host: r.host, destino: r.destino, mensagens: [...(r.mensagens ?? [])] };
527
+ });
528
+ }
529
+ /**
530
+ * O que vem depois do código no texto do dono. Sem o código na frente (o reply, que traz o código pelo endereço), o texto
531
+ * inteiro é a resposta.
532
+ */
533
+ function restoDoCodigo(texto, codigo) {
534
+ const t = texto.trim();
535
+ return t.toUpperCase().startsWith(codigo.toUpperCase()) && (t.length === codigo.length || /\s/.test(t[codigo.length]))
536
+ ? t.slice(codigo.length).trim() : t;
537
+ }
538
+ /** A prova do pulse para o ato do arco: o envelope como o gateway o assinou, o endereço e o hash do texto do dono. */
539
+ function provaDoPulse(envelope, endereco) {
540
+ return r => ({ via: 'pulse', envelope, endereco, pergunta: { ...r, respostaSha256: sha(envelope.resposta) } });
541
+ }
542
+ /** Marca a pergunta do arco servida como respondida, quando ela está no registro. */
543
+ function marcarArcoRespondido(raiz, estadoDir, codigo, letra, quando, mensagem, estado) {
544
+ const servido = lerLoteServido(raiz, estadoDir);
545
+ if (!servido.perguntas.some(q => q.arco?.codigo === codigo && !q.respondida))
546
+ return;
547
+ gravarLoteServido(raiz, { ...servido, perguntas: servido.perguntas.map(q => q.arco?.codigo === codigo && !q.respondida
548
+ ? { ...q, respondida: { letra, em: quando, mensagem, estado } } : q) }, estadoDir);
549
+ }
550
+ /** O resultado do pulse para o desfecho da resposta à pergunta do arco. */
551
+ function resultadoDoArco(tipo, p, d, envelope, numero = 0) {
552
+ if (d.tipo === 'registrada') {
553
+ // `repetida` para o canal é a MESMA mensagem entregue de novo pelo gateway: aí ele não confirma de novo ao dono.
554
+ return resultado(tipo, d.mensagem, { repetida: d.mesmaProva,
555
+ registradas: [{ numero, thread: `arco:${p.arco}`, letra: 'a', estado: p.ato === 'autorizar' ? 'autorizado' : 'revogado', repetida: d.mesmaProva }] });
556
+ }
557
+ if (d.tipo === 'sem-efeito')
558
+ return resultado(tipo, d.mensagem, { registradas: [{ numero, thread: `arco:${p.arco}`, letra: d.letra, estado: 'sem-efeito', repetida: false }] });
559
+ if (d.tipo === 'detalhe')
560
+ return resultado(tipo, d.mensagem.slice(0, hitl_lote_1.TETO_DA_MENSAGEM));
561
+ void envelope;
562
+ return resultado(tipo, d.mensagem, { recusas: [{ ...(numero ? { numero } : {}), motivo: d.motivo }] });
563
+ }
564
+ /** O trecho depois do código ("NX4K a"), ou `null` quando ele não é resposta; "?" pede o detalhe. */
565
+ function trechoDepoisDoCodigo(resto) {
566
+ return (0, hitl_texto_livre_1.lerTrecho)(resto) ?? (/^\?$/.test(resto) ? (0, hitl_texto_livre_1.lerTrecho)('detalhes') : null);
567
+ }
568
+ /**
569
+ * "<código> a" a uma pergunta do arco: lê o resto, chama a resposta ao arco com a prova do pulse e marca a pergunta
570
+ * servida. Nunca escolhe pelo dono: fora do vocabulário, volta com as alternativas reais.
571
+ */
572
+ function responderAoArcoPorCodigo(raiz, envelope, p, resto, opcoes) {
573
+ const { quando, canal } = opcoes, tg = canal === 'telegram';
574
+ const trecho = trechoDepoisDoCodigo(resto);
575
+ if (!trecho) {
576
+ return resultado('codigo', `${tg ? '⚠️ ' : '! '}Não entendi "${resto.slice(0, 40)}" para ${p.codigo}; nada foi registrado. ` +
577
+ `Responda com uma destas: ${(0, noctum_pergunta_1.alternativasDaPergunta)(p).map(a => `${a.letra} (${a.texto})`).join(', ')}.`, { recusas: [{ motivo: 'nao-entendida' }] });
578
+ }
579
+ const d = (0, noctum_resposta_1.responderPerguntaDoArco)(raiz, p, trecho, { quando, canal, provar: provaDoPulse(envelope, pulse_consentimento_1.ENDERECO_DA_RESPOSTA) });
580
+ if (d.tipo === 'registrada' || d.tipo === 'sem-efeito') {
581
+ marcarArcoRespondido(raiz, opcoes.estadoDir, p.codigo, d.letra, quando, envelope.mensagem, d.tipo === 'registrada' ? 'registrada' : 'sem-efeito');
582
+ }
583
+ return resultadoDoArco('codigo', p, d, envelope);
584
+ }
585
+ /**
586
+ * RM-057 (resposta curta, D3; GO-FIX 1, achados 2 e 4 da ork-rm057respost): a resposta EM REPLY à mensagem de uma
587
+ * pergunta do arco. A referência assinada traz o código e o id da mensagem respondida, e o reply só vale quando esse id é
588
+ * o da mensagem em que a pergunta foi entregue, no mesmo chat: a confirmação do "b", a recusa, o lembrete e a mensagem de
589
+ * qualquer outra pessoa nunca são a pergunta, mesmo com o código. A resposta vale só para a pergunta respondida: a letra, a
590
+ * palavra do vocabulário que cai numa alternativa dela, o código dela com a letra ou o número dela com a letra; "1a" em
591
+ * reply à mensagem de outra pergunta, a lista e o código de outra pergunta voltam sem gravar nada.
592
+ */
593
+ function responderEmReply(raiz, envelope, lido, referencia, opcoes) {
594
+ const { quando, canal, estadoDir } = opcoes, tg = canal === 'telegram';
595
+ const volta = (texto, motivo) => resultado('codigo', `${tg ? '⚠️ ' : '! '}${texto}`, { recusas: [{ motivo }] });
596
+ const ref = (0, pulse_consentimento_1.lerReferenciaDoReply)(referencia);
597
+ const chat = chatDoTelegram(envelope.mensagem);
598
+ const servida = lerLoteServido(raiz, estadoDir).perguntas.find(q => q.arco?.codigo === ref.codigo &&
599
+ (q.arco.mensagens ?? []).includes(ref.mensagem) && chat !== null && chatDoTelegram(q.arco.destino) === chat);
600
+ if (!servida) {
601
+ return volta(`A mensagem que você respondeu não é a da pergunta ${ref.codigo} como o Orkastery a entregou neste chat; nada foi ` +
602
+ `registrado. Responda à mensagem da pergunta, ou mande ${ref.codigo} com a letra.`, 'reply.fora-da-pergunta');
603
+ }
604
+ const numero = servida.numero;
605
+ let trecho = null;
606
+ if (lido.forma === 'livre')
607
+ trecho = lido.trecho;
608
+ else if (lido.forma === 'consentimento') {
609
+ // O código digitado diferente do código da mensagem respondida não é escolhido pelo dono: nada é registrado.
610
+ if (lido.codigo !== ref.codigo) {
611
+ return volta(`Você respondeu com o código ${lido.codigo} à mensagem da pergunta ${ref.codigo}; nada foi registrado. ` +
612
+ 'Responda à mensagem só com a letra, ou mande o código certo.', 'codigo.divergente');
613
+ }
614
+ trecho = trechoDepoisDoCodigo(restoDoCodigo(envelope.resposta, ref.codigo));
615
+ }
616
+ else if (lido.forma === 'lote' && lido.escolhas.length === 1 && lido.escolhas[0].numero === numero) {
617
+ trecho = { tipo: 'letra', letra: lido.escolhas[0].letra };
618
+ }
619
+ if (!trecho) {
620
+ return volta(`Em reply à pergunta ${numero} (${ref.codigo}), mande só a resposta a ela: a letra, ${numero} com a letra, ou ` +
621
+ `${ref.codigo} com a letra. Nada foi registrado.`, 'reply.outra-pergunta');
622
+ }
623
+ const q = (0, noctum_resposta_1.perguntasPorCodigo)(raiz, ref.codigo, quando).find(x => x.arco === servida.arco.arco);
624
+ if (!q)
625
+ return volta(`A pergunta ${ref.codigo} já não existe no arco ${servida.arco.arco}; nada foi registrado.`, 'sem-pergunta-recente');
626
+ const d = (0, noctum_resposta_1.responderPerguntaDoArco)(raiz, q, trecho, { quando, canal, numero, provar: provaDoPulse(envelope, opcoes.endereco) });
627
+ if (d.tipo === 'registrada' || d.tipo === 'sem-efeito') {
628
+ marcarArcoRespondido(raiz, estadoDir, q.codigo, d.letra, quando, envelope.mensagem, d.tipo === 'registrada' ? 'registrada' : 'sem-efeito');
629
+ }
630
+ return resultadoDoArco('codigo', q, d, envelope, numero);
631
+ }
632
+ /**
633
+ * RM-057 (GO-FIX 2, R1 do CHECK da ork-rm057respost): a palavra solta EM REPLY a uma mensagem que não é a pergunta do arco
634
+ * (a confirmação de um gate, a mensagem de outra pessoa do grupo, a do assistente). O dono respondeu àquela mensagem, e o
635
+ * Orkastery não adivinha que era à pergunta: a palavra nunca vira palavra solta, nada é gravado, e a resposta diz por
636
+ * onde responder. A palavra solta só vale sem reply, com uma só pergunta pendente no chat, ou em reply à mensagem da
637
+ * pergunta; o código e o número dizem a pergunta e o gateway os manda sem esta marca.
638
+ */
639
+ function respostaAOutraMensagem(raiz, opcoes) {
640
+ const tg = opcoes.canal === 'telegram';
641
+ let abertos = [];
642
+ try {
643
+ abertos = abertosDoDono(raiz, opcoes.quando, opcoes.estadoDir);
644
+ }
645
+ catch { /* a recusa não depende da lista */ }
646
+ const lista = abertos.slice(0, 5).map(a => a.rotulo).join('; ') + (abertos.length > 5 ? `; e mais ${abertos.length - 5}` : '');
647
+ return resultado('nao-entendida', `${tg ? '⚠️ ' : '! '}A mensagem que você respondeu não é a de uma pergunta do Orkastery, e em reply ` +
648
+ 'a palavra solta só vale para a mensagem da pergunta; nada foi registrado. ' + (abertos.length
649
+ ? `Responda à mensagem da pergunta, ou pelo número ou pelo código: ${lista}.` : 'Não há pergunta esperando você agora.'), { recusas: [{ motivo: 'reply.outra-mensagem' }] });
650
+ }
651
+ // ---------------------------------------------------------------------------
454
652
  // RM-048 (D4): a linha que o dono recebeu vale enquanto o gate esperar a mesma pergunta.
455
653
  // ---------------------------------------------------------------------------
456
654
  /**
@@ -507,6 +705,8 @@ function codigosEmUso(raiz, estadoDir) {
507
705
  }
508
706
  catch { /* thread ilegivel nao contribui */ }
509
707
  }
708
+ // RM-057 (resposta curta): as perguntas dos arcos #Noctum também usam o alfabeto do código curto.
709
+ codigos.push(...(0, noctum_arco_1.codigosDosArcos)(raiz));
510
710
  return codigos;
511
711
  }
512
712
  /** O bloco de evidencia a um pedido de distancia (item 4): artefato, claims, riscos e diff. */
@@ -664,6 +864,16 @@ function pedidoDaServida(raiz, p) {
664
864
  * pergunta, com as letras reais.
665
865
  */
666
866
  function letraDaPalavra(raiz, p, trecho, quando) {
867
+ if (p.arco) {
868
+ // RM-057 (resposta curta): a pergunta do arco não tem pedido de thread; a palavra casa pelas ações das alternativas dela.
869
+ const r = (0, noctum_pergunta_1.escolhaDaPergunta)({ ato: p.arco.ato }, trecho);
870
+ const reais = p.letras.map((l, i) => `${p.numero}${l} (${p.alternativas[i]})`).join(', ');
871
+ if (r.tipo === 'detalhe')
872
+ return { recusa: `o envelope da pergunta ${p.numero} sai com ${p.arco.codigo} detalhes.` };
873
+ if (r.tipo !== 'escolha')
874
+ return { recusa: `para a pergunta ${p.numero}, mande uma destas: ${reais}.` };
875
+ return { letra: p.letras[r.indice], ...(trecho.tipo === 'intencao' ? { palavra: trecho.palavra } : {}) };
876
+ }
667
877
  const pedido = pedidoDaServida(raiz, p);
668
878
  if (!pedido)
669
879
  return { recusa: `não consegui ler a pergunta ${p.numero}; responda com o número e a letra.` };
@@ -723,6 +933,13 @@ function abertosDoDono(raiz, quando, estadoDir) {
723
933
  const vistas = new Set(estado && !estado.respondido
724
934
  ? estado.pedido.candidatos.map(c => `${c.thread}|g:${c.fase ?? ''}`) : []);
725
935
  for (const p of lerLoteServido(raiz, estadoDir).perguntas.filter(q => perguntaEmAberto(q, quando))) {
936
+ if (p.arco) {
937
+ vistas.add(`arco:${p.arco.codigo}`);
938
+ // A pergunta do arco sempre tem código: o rótulo dá os dois jeitos de dizer qual (D9 da ork-rm057respost).
939
+ abertos.push({ tipo: 'pergunta', servida: p, codigo: p.arco.codigo,
940
+ rotulo: `${p.numero} ou ${p.arco.codigo}, com a letra (arco ${p.arco.arco}: ${p.arco.ato})`, recente: agora - Date.parse(p.servidaEm) < janela });
941
+ continue;
942
+ }
726
943
  const pedido = pedidoDaServida(raiz, p);
727
944
  if (pedido)
728
945
  vistas.add(chave(pedido));
@@ -769,6 +986,14 @@ function abertosDoDono(raiz, quando, estadoDir) {
769
986
  }
770
987
  catch { /* thread ilegivel nao entra na conta; a palavra solta so fica mais cautelosa */ }
771
988
  }
989
+ // RM-057 (resposta curta): a pergunta do arco que espera o dono e não saiu por aqui também conta, para a palavra solta
990
+ // nunca cair numa pergunta quando há outra esperando.
991
+ for (const q of (0, noctum_resposta_1.perguntasPendentes)(raiz, quando)) {
992
+ if (vistas.has(`arco:${q.codigo}`))
993
+ continue;
994
+ vistas.add(`arco:${q.codigo}`);
995
+ abertos.push({ tipo: 'arco', codigo: q.codigo, rotulo: (0, noctum_resposta_1.rotuloDaPergunta)(q), recente: false });
996
+ }
772
997
  return abertos;
773
998
  }
774
999
  /**
@@ -797,6 +1022,29 @@ function responderLivre(raiz, envelope, trecho, opcoes) {
797
1022
  return responderAoResumo(raiz, envelope, unico.codigo, { quando, canal, estadoDir, palavra: trecho });
798
1023
  }
799
1024
  const p = unico.servida;
1025
+ if (p.arco) {
1026
+ // RM-057 (resposta curta, D3 e D4): "sem reply, vale se houver uma só pendente no canal". O canal é o chat em que a
1027
+ // pergunta saiu: a palavra de outro chat volta como pergunta, com o código.
1028
+ const destino = chatDoTelegram(p.arco.destino), chat = chatDoTelegram(envelope.mensagem);
1029
+ if (destino && chat && destino !== chat) {
1030
+ return volta(`A pergunta que espera você saiu por outro chat; palavra solta não registra. Responda: ${p.arco.codigo} a ` +
1031
+ `(arco ${p.arco.arco}: ${p.arco.ato}), ou responda à mensagem dela.`, 'outro-chat');
1032
+ }
1033
+ // GO-FIX 1 (achado 6): a mensagem de antes de a pergunta sair não responde a ela, nem entregue de novo dentro dos 60 s.
1034
+ if (!(Date.parse(envelope.recebidoEm) >= Date.parse(p.servidaEm))) {
1035
+ return volta(`A sua mensagem é de antes de a pergunta ${p.numero} sair; palavra solta não registra. Responda: ${p.arco.codigo} a ` +
1036
+ `(arco ${p.arco.arco}: ${p.arco.ato}), ou responda à mensagem dela.`, 'anterior-a-pergunta');
1037
+ }
1038
+ const q = (0, noctum_resposta_1.perguntasPorCodigo)(raiz, p.arco.codigo, quando).find(x => x.arco === p.arco.arco);
1039
+ if (!q)
1040
+ return volta(`A pergunta ${p.numero} já não existe no arco ${p.arco.arco}; nada foi registrado.`, 'sem-pergunta-recente');
1041
+ const d = (0, noctum_resposta_1.responderPerguntaDoArco)(raiz, q, trecho, { quando, canal, numero: p.numero,
1042
+ provar: provaDoPulse(envelope, pulse_consentimento_1.ENDERECO_DA_RESPOSTA) });
1043
+ if (d.tipo === 'registrada' || d.tipo === 'sem-efeito') {
1044
+ marcarArcoRespondido(raiz, estadoDir, q.codigo, d.letra, quando, envelope.mensagem, d.tipo === 'registrada' ? 'registrada' : 'sem-efeito');
1045
+ }
1046
+ return resultadoDoArco('lote', q, d, envelope, p.numero);
1047
+ }
800
1048
  const pedido = pedidoDaServida(raiz, p);
801
1049
  if (pedido && (0, hitl_contract_1.ehV2)(pedido) && pedido.classe === 'pergunta' && pedido.irreversivel) {
802
1050
  return volta(`${tg ? '🔒 ' : '! '}A pergunta ${p.numero} é sem volta; palavra solta não registra. Responda com o número e a letra: ` +
@@ -928,19 +1176,50 @@ function resultado(tipo, mensagem, extra = {}) {
928
1176
  function responderPeloPulse(raiz, envelope, opcoes = {}) {
929
1177
  const quando = opcoes.quando ?? new Date().toISOString();
930
1178
  const canal = opcoes.canal ?? 'telegram';
931
- (0, hitl_gates_1.autenticarResposta)(pulse_consentimento_1.ALVO_DO_PULSE, pulse_consentimento_1.ENDERECO_DA_RESPOSTA, envelope, envelope.recebidoEm);
932
- (0, hitl_gates_1.autenticarResposta)(pulse_consentimento_1.ALVO_DO_PULSE, pulse_consentimento_1.ENDERECO_DA_RESPOSTA, envelope, quando);
1179
+ const endereco = (0, pulse_consentimento_1.enderecoDoPulse)(opcoes.referencia);
1180
+ (0, hitl_gates_1.autenticarResposta)(pulse_consentimento_1.ALVO_DO_PULSE, endereco, envelope, envelope.recebidoEm);
1181
+ (0, hitl_gates_1.autenticarResposta)(pulse_consentimento_1.ALVO_DO_PULSE, endereco, envelope, quando);
933
1182
  const lido = interpretarRespostaDoPulse(envelope.resposta);
934
1183
  if (lido.forma === 'desconhecida')
935
1184
  return resultado('nao-entendida', `Não entendi. ${EXEMPLO}`);
1185
+ // A conversa do pulse tem dois escritores (a varredura e este receptor): um de cada vez.
1186
+ const estadoDir = opcoes.estadoDir ?? path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery', 'monitor');
1187
+ if (opcoes.referencia) {
1188
+ // RM-057 (GO-FIX 1, achados 2 e 4): o reply responde só à pergunta da mensagem respondida, e só como resposta a ela.
1189
+ const referencia = opcoes.referencia;
1190
+ return (0, monitor_lock_1.comLockDaConversa)(estadoDir, () => {
1191
+ const r = (() => {
1192
+ try {
1193
+ // GO-FIX 2 (R1): em reply a outra mensagem, nada vira palavra solta; o dono ouve por onde responder.
1194
+ if (referencia === pulse_consentimento_1.REPLY_A_OUTRA)
1195
+ return respostaAOutraMensagem(raiz, { quando, canal, estadoDir });
1196
+ if (!['livre', 'consentimento', 'lote'].includes(lido.forma)) {
1197
+ return resultado('codigo', `${canal === 'telegram' ? '⚠️ ' : '! '}Em reply à pergunta, mande só a resposta a ela (a letra, ` +
1198
+ 'o número com a letra ou o código com a letra). Nada foi registrado.', { recusas: [{ motivo: 'reply.outra-pergunta' }] });
1199
+ }
1200
+ return responderEmReply(raiz, envelope, lido, referencia, { quando, canal, estadoDir, endereco });
1201
+ }
1202
+ catch (e) {
1203
+ console.error(`pulse responder: ${e.message}`);
1204
+ return resultado('nao-entendida', 'Não consegui concluir esta resposta agora (erro interno do núcleo). ' +
1205
+ 'Confira em ork pulse e mande de novo em um minuto.', { recusas: [{ motivo: 'erro-interno' }] });
1206
+ }
1207
+ })();
1208
+ try {
1209
+ atualizarEscuta(raiz, quando, estadoDir);
1210
+ }
1211
+ catch { /* dica de rota; a prova nao depende dela */ }
1212
+ return r;
1213
+ });
1214
+ }
936
1215
  if (lido.forma === 'cadencia') {
937
1216
  // I-50: preferencia de entrega, nao decisao de gate. Grava quem mandou, pelo remetente autenticado.
938
1217
  const repetida = (0, pulse_cadencia_1.lerCadencia)(raiz, opcoes.estadoDir).gravada?.tag === lido.tag;
939
1218
  (0, pulse_cadencia_1.gravarCadencia)(raiz, lido.tag, { por: envelope.por, canal: envelope.canal ?? envelope.origem, em: quando }, opcoes.estadoDir);
940
1219
  return resultado('cadencia', (0, pulse_cadencia_1.textoDaCadencia)(pulse_cadencia_1.CADENCIAS[lido.tag], quando), { cadencia: lido.tag, repetida });
941
1220
  }
942
- // A conversa do pulse tem dois escritores (a varredura e este receptor): um de cada vez.
943
- const estadoDir = opcoes.estadoDir ?? path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery', 'monitor');
1221
+ if (lido.forma === 'conducao')
1222
+ return responderConducao(raiz, envelope, lido.comando, opcoes);
944
1223
  return (0, monitor_lock_1.comLockDaConversa)(estadoDir, () => {
945
1224
  const r = (() => {
946
1225
  try {
@@ -987,6 +1266,16 @@ function responderAoResumo(raiz, envelope, codigo, opcoes) {
987
1266
  return resultado('codigo', `O código ${codigo} é de uma nota e de uma pergunta ao mesmo tempo; nada foi registrado. ` +
988
1267
  'Responda a pergunta pelo número do lote e peça outro código de nota (ork master pedir).', { recusas: [{ motivo: 'codigo.ambiguo' }] });
989
1268
  }
1269
+ // RM-057 (resposta curta, D3 da ork-rm057respost): o código de uma pergunta do arco #Noctum ("NX4K a"). Código que
1270
+ // também é de gate, de nota ou de duas perguntas é ambíguo: nada é escolhido pelo dono.
1271
+ const doArco = (0, noctum_resposta_1.perguntasPorCodigo)(raiz, codigo, quando);
1272
+ if (doArco.length && (nota || doArco.length > 1 || pedidosComCodigo(raiz, codigo).length)) {
1273
+ return resultado('codigo', `O código ${codigo} está em mais de uma pergunta ao mesmo tempo; nada foi registrado. ` +
1274
+ 'Responda pelo número da pergunta, por exemplo 1a.', { recusas: [{ motivo: 'codigo.ambiguo' }] });
1275
+ }
1276
+ if (doArco.length === 1) {
1277
+ return responderAoArcoPorCodigo(raiz, envelope, doArco[0], restoDoCodigo(envelope.resposta, codigo), { quando, canal, estadoDir });
1278
+ }
990
1279
  // RM-048 (D4): o codigo curto de um gate ("DE6H a") responde ao gate, pelo mesmo endereco assinado.
991
1280
  const peloGate = responderPorCodigoDeGate(raiz, envelope, codigo, { quando, canal });
992
1281
  if (peloGate)
@@ -1103,6 +1392,33 @@ function responderAsPerguntas(raiz, envelope, escolhas, opcoes) {
1103
1392
  linhas.push(`${telegram ? '⚠️ ' : '! '}${motivo}`);
1104
1393
  continue;
1105
1394
  }
1395
+ if (p.arco) {
1396
+ // RM-057 (resposta curta, D4): a pergunta do arco servida responde pelo número, com a prova do pulse. O ato confere a
1397
+ // pergunta de agora, o prazo e a prova sob o lock do arco; a resposta repetida não grava de novo.
1398
+ const q = (0, noctum_resposta_1.perguntasPorCodigo)(raiz, p.arco.codigo, quando).find(x => x.arco === p.arco.arco);
1399
+ if (!q) {
1400
+ const motivo = `a pergunta ${numero} já não existe no arco ${p.arco.arco}.`;
1401
+ recusas.push({ numero, motivo });
1402
+ linhas.push(`${telegram ? '⚠️ ' : '! '}${motivo}`);
1403
+ continue;
1404
+ }
1405
+ const d = (0, noctum_resposta_1.responderPerguntaDoArco)(raiz, q, { tipo: 'letra', letra }, { quando, canal, numero,
1406
+ provar: provaDoPulse(envelope, pulse_consentimento_1.ENDERECO_DA_RESPOSTA) });
1407
+ if (d.tipo === 'recusada') {
1408
+ recusas.push({ numero, motivo: d.motivo });
1409
+ linhas.push(d.mensagem);
1410
+ continue;
1411
+ }
1412
+ linhas.push(d.mensagem);
1413
+ if (d.tipo === 'detalhe')
1414
+ continue;
1415
+ registradas.push({ numero, thread: p.thread, letra, estado: d.tipo === 'registrada' ? 'registrada' : 'sem-efeito',
1416
+ repetida: d.tipo === 'registrada' && d.mesmaProva });
1417
+ servido = { ...servido, perguntas: servido.perguntas.map(x => x.numero === numero
1418
+ ? { ...x, respondida: { letra, em: quando, mensagem: envelope.mensagem, estado: d.tipo === 'registrada' ? 'registrada' : 'sem-efeito' } } : x) };
1419
+ gravarLoteServido(raiz, servido, estadoDir);
1420
+ continue;
1421
+ }
1106
1422
  if (!p.respondida && !perguntaEmAberto(p, quando)) {
1107
1423
  const motivo = `a pergunta ${numero} saiu há mais de 24 h; ela volta no próximo resumo se ainda esperar você.`;
1108
1424
  recusas.push({ numero, motivo });
@@ -1165,3 +1481,51 @@ function responderAsPerguntas(raiz, envelope, escolhas, opcoes) {
1165
1481
  return resultado('lote', texto, { registradas, recusas: [...(opcoes.avisos ?? []).map(motivo => ({ motivo })), ...recusas],
1166
1482
  repetida: registradas.length > 0 && recusas.length === 0 && registradas.every(r => r.repetida) });
1167
1483
  }
1484
+ // ---------------------------------------------------------------------------
1485
+ // RM-063 (fatia 3, H2): `#OrkRetomar` e `#OrkFabrica` no canal do dono.
1486
+ // ---------------------------------------------------------------------------
1487
+ /** Os canais de conducao que o envelope pode declarar; o resto fica com o que o adaptador ja exporta. */
1488
+ const CANAIS_DO_HOST = ['hermes', 'openclaw', 'claude-code', 'codex', 'cli'];
1489
+ /**
1490
+ * A batida da conducao em segundo plano: o ingresso do host espera ate 10 s, e a batida traz a base, le os PRs e pode
1491
+ * despachar uma fase. O processo filho entrega o que voltou a andar pelo transporte do pulse (`--entregar`).
1492
+ */
1493
+ function retomarEmSegundoPlano(raiz, canal) {
1494
+ const { spawn } = require('node:child_process');
1495
+ const env = { ...process.env, ...(canal && CANAIS_DO_HOST.includes(canal) ? { ORK_CANAL: canal } : {}) };
1496
+ const filho = spawn(process.execPath, [path.join(__dirname, 'index.js'), 'conducao', 'batida', '--entregar'], { cwd: (0, estado_thread_1.raizDoEstado)(raiz), detached: true, stdio: 'ignore', env });
1497
+ filho.unref();
1498
+ }
1499
+ /** O `ork fabrica` desta maquina, da ultima copia local da branch da fabrica (sem rede: o ingresso tem prazo curto). */
1500
+ function fabricaDestaMaquina(raiz) {
1501
+ const { exigirManifesto } = require('./manifest');
1502
+ const { lerFabrica, textoDaFabrica } = require('./fabrica-estado');
1503
+ const { nomeDaMaquina } = require('./maquina');
1504
+ const carregado = exigirManifesto((0, estado_thread_1.raizDoEstado)(raiz));
1505
+ const painel = lerFabrica(carregado.raiz, { remoto: carregado.manifesto.fabrica.remoto, semRemoto: true });
1506
+ return textoDaFabrica(painel, nomeDaMaquina());
1507
+ }
1508
+ function responderConducao(raiz, envelope, comando, opcoes) {
1509
+ if (comando === 'fabrica') {
1510
+ let texto;
1511
+ try {
1512
+ texto = (opcoes.fabrica ?? fabricaDestaMaquina)(raiz);
1513
+ }
1514
+ catch (e) {
1515
+ console.error(`pulse responder: fabrica: ${e.message}`);
1516
+ return resultado('fabrica', 'Não consegui ler a fábrica agora. Confira com ork fabrica no terminal.', { recusas: [{ motivo: 'erro-interno' }] });
1517
+ }
1518
+ const limpo = (0, hitl_1.redigirSegredos)(texto).trim();
1519
+ return resultado('fabrica', limpo.length > hitl_lote_1.TETO_DA_MENSAGEM ? `${limpo.slice(0, hitl_lote_1.TETO_DA_MENSAGEM - 40)}\n… (cortado; ork fabrica)` : limpo);
1520
+ }
1521
+ const canal = typeof envelope.canal === 'string' && envelope.canal ? envelope.canal : null;
1522
+ try {
1523
+ (opcoes.retomar ?? retomarEmSegundoPlano)(raiz, canal);
1524
+ }
1525
+ catch (e) {
1526
+ console.error(`pulse responder: retomar: ${e.message}`);
1527
+ return resultado('retomar', 'Não consegui disparar a batida da condução agora. Rode ork conducao batida no terminal.', { recusas: [{ motivo: 'erro-interno' }] });
1528
+ }
1529
+ return resultado('retomar', 'Retomando: a batida da condução está rodando nesta máquina agora (merge do PR pronto, registro da ' +
1530
+ 'entrega, MASTER por omissão e a fase seguinte, dentro da sua autorização durável). O que voltou a andar chega em seguida, por este canal.');
1531
+ }