@orkastery/cli 0.5.6 → 0.6.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 (396) 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 +123 -9
  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/adapters/grok-events.js +227 -0
  105. package/dist/adapters/grok-mcp-servidor.js +612 -0
  106. package/dist/adapters/grok-mcp.js +178 -0
  107. package/dist/adapters/grok.js +686 -0
  108. package/dist/agendador-cpu.js +92 -0
  109. package/dist/atualizar-branch.js +245 -0
  110. package/dist/auditoria.js +13 -11
  111. package/dist/auditrun.js +51 -46
  112. package/dist/autorizacao-duravel.js +327 -0
  113. package/dist/board.js +94 -40
  114. package/dist/branch-de-estado.js +23 -10
  115. package/dist/busca-semantica.js +7 -5
  116. package/dist/catalogo.js +2 -1
  117. package/dist/changelog-reconciliacao.js +290 -0
  118. package/dist/check-agil.js +528 -0
  119. package/dist/check-modo.js +41 -0
  120. package/dist/check-paralelo.js +238 -0
  121. package/dist/ci.js +248 -45
  122. package/dist/ciclos.js +8 -6
  123. package/dist/claim-lint.js +12 -8
  124. package/dist/claims-conferir.js +47 -39
  125. package/dist/claims.js +10 -9
  126. package/dist/company-brain-client.js +10 -3
  127. package/dist/company-brain-migration.js +11 -5
  128. package/dist/conducao-batida.js +759 -0
  129. package/dist/conducao-sentinela.js +25 -8
  130. package/dist/conducao.js +89 -29
  131. package/dist/conhecimento-consulta.js +270 -0
  132. package/dist/conhecimento.js +111 -87
  133. package/dist/conta-esgotada.js +127 -0
  134. package/dist/dado-privado.js +816 -0
  135. package/dist/decisao-autonoma.js +5 -4
  136. package/dist/demo.js +14 -12
  137. package/dist/dependencias-da-worktree.js +25 -0
  138. package/dist/divida.js +38 -36
  139. package/dist/docs.js +89 -89
  140. package/dist/doctor-forja.js +343 -0
  141. package/dist/doctor-pulse-cron.js +113 -1
  142. package/dist/doctor.js +164 -6
  143. package/dist/dsn-da-memoria.js +417 -0
  144. package/dist/entrega-por-mod.js +503 -0
  145. package/dist/entrega-pr.js +154 -54
  146. package/dist/esgotamentos.js +13 -11
  147. package/dist/estado-thread.js +21 -18
  148. package/dist/evalrunner.js +35 -32
  149. package/dist/fabrica-batida.js +34 -21
  150. package/dist/fabrica-estado.js +33 -21
  151. package/dist/fix.js +21 -19
  152. package/dist/forja/adaptador.js +6 -0
  153. package/dist/forja/ambiente-de-ci.js +27 -0
  154. package/dist/forja/api.js +256 -0
  155. package/dist/forja/cache.js +89 -0
  156. package/dist/forja/cli.js +60 -0
  157. package/dist/forja/contrato.js +9 -0
  158. package/dist/forja/endereco.js +43 -0
  159. package/dist/forja/estado.js +22 -0
  160. package/dist/forja/executor.js +73 -0
  161. package/dist/forja/github/ci.js +95 -0
  162. package/dist/forja/github/dono-da-rede.js +18 -0
  163. package/dist/forja/github/metadados.js +15 -0
  164. package/dist/forja/github/pedidos.js +200 -0
  165. package/dist/forja/gitlab/ci.js +141 -0
  166. package/dist/forja/gitlab/consultas.js +59 -0
  167. package/dist/forja/gitlab/dono-da-rede.js +43 -0
  168. package/dist/forja/gitlab/metadados.js +15 -0
  169. package/dist/forja/gitlab/pedidos-abertos.js +158 -0
  170. package/dist/forja/gitlab/pedidos.js +141 -0
  171. package/dist/forja/produtor.js +32 -0
  172. package/dist/forja/registro.js +31 -0
  173. package/dist/forja/resolver.js +121 -0
  174. package/dist/forja/texto.js +13 -0
  175. package/dist/forja/versao.js +71 -0
  176. package/dist/forja.js +123 -80
  177. package/dist/handoff.js +23 -13
  178. package/dist/hitl-contract.js +46 -43
  179. package/dist/hitl-curto.js +37 -25
  180. package/dist/hitl-gates.js +13 -11
  181. package/dist/hitl-local-receipt.js +51 -0
  182. package/dist/hitl-local.js +11 -2
  183. package/dist/hitl-lock.js +5 -11
  184. package/dist/hitl-public-receipt.js +11 -0
  185. package/dist/hitl-resumo.js +44 -1
  186. package/dist/hitl-sessions.js +62 -9
  187. package/dist/hitl-texto-livre.js +7 -4
  188. package/dist/hitl.js +34 -31
  189. package/dist/horario.js +20 -1
  190. package/dist/hosts.js +104 -134
  191. package/dist/index.js +864 -554
  192. package/dist/indice-vetorial.js +14 -12
  193. package/dist/init.js +11 -2
  194. package/dist/integracoes-locais.js +4 -0
  195. package/dist/intelligence-graph-cli.js +123 -69
  196. package/dist/intelligence-graph-query.js +37 -22
  197. package/dist/leases.js +19 -18
  198. package/dist/ledger-stats.js +17 -16
  199. package/dist/ledger.js +31 -1
  200. package/dist/licoes.js +12 -11
  201. package/dist/locale-accounts.js +228 -0
  202. package/dist/locale-adapter.js +291 -0
  203. package/dist/locale-ajuda.js +86 -10
  204. package/dist/locale-audit.js +199 -0
  205. package/dist/locale-claims.js +213 -0
  206. package/dist/locale-conducao.js +138 -0
  207. package/dist/locale-conhecimento.js +181 -0
  208. package/dist/locale-decisao.js +205 -0
  209. package/dist/locale-docs.js +230 -0
  210. package/dist/locale-estado.js +101 -0
  211. package/dist/locale-forja.js +288 -0
  212. package/dist/locale-gerados.js +5 -0
  213. package/dist/locale-grafo.js +129 -0
  214. package/dist/locale-master.js +83 -0
  215. package/dist/locale-network.js +524 -0
  216. package/dist/locale-operacao-restante.js +931 -0
  217. package/dist/locale-projetos.js +100 -0
  218. package/dist/locale-prompts.js +194 -0
  219. package/dist/locale-pulse.js +140 -2
  220. package/dist/locale-reservas.js +87 -0
  221. package/dist/locale-retry.js +183 -6
  222. package/dist/locale-security-scan.js +69 -0
  223. package/dist/locale-setup.js +192 -0
  224. package/dist/locale-ship.js +177 -66
  225. package/dist/locale-thread.js +149 -5
  226. package/dist/locale-verify.js +80 -4
  227. package/dist/locale-worktree.js +246 -0
  228. package/dist/locale.js +553 -9
  229. package/dist/maestro-runtime.js +22 -3
  230. package/dist/manifest.js +293 -12
  231. package/dist/maquina-ociosa.js +211 -0
  232. package/dist/maquina.js +10 -5
  233. package/dist/master-nota-local.js +200 -0
  234. package/dist/master-nota.js +10 -2
  235. package/dist/master.js +118 -41
  236. package/dist/mcp-conhecimento.js +52 -0
  237. package/dist/mcp-experiencia.js +26 -5
  238. package/dist/mcp-install.js +90 -15
  239. package/dist/mcp-noctum.js +101 -0
  240. package/dist/mcp-server.js +116 -22
  241. package/dist/mcp-ship-transporte.js +977 -0
  242. package/dist/mcp-ship.js +68 -24
  243. package/dist/mcp-transportes.js +17 -0
  244. package/dist/memoria.js +63 -58
  245. package/dist/merge-da-entrega.js +85 -0
  246. package/dist/modos-migracao.js +8 -6
  247. package/dist/modos.js +17 -18
  248. package/dist/network-roadmap.js +94 -54
  249. package/dist/noctum-aceite.js +929 -0
  250. package/dist/noctum-arco.js +540 -33
  251. package/dist/noctum-capacidade.js +3 -3
  252. package/dist/noctum-changelog.js +399 -0
  253. package/dist/noctum-cli.js +539 -0
  254. package/dist/noctum-coordenacao.js +1225 -0
  255. package/dist/noctum-entrega.js +1217 -0
  256. package/dist/noctum-envelope.js +253 -17
  257. package/dist/noctum-execucao.js +100 -24
  258. package/dist/noctum-fechamento.js +416 -0
  259. package/dist/noctum-fila.js +49 -10
  260. package/dist/noctum-guarda.js +333 -0
  261. package/dist/noctum-integracao.js +507 -0
  262. package/dist/noctum-maquinas.js +387 -0
  263. package/dist/noctum-medicao.js +450 -0
  264. package/dist/noctum-modo.js +390 -0
  265. package/dist/noctum-pergunta-canal.js +96 -0
  266. package/dist/noctum-pergunta.js +115 -0
  267. package/dist/noctum-provas.js +838 -0
  268. package/dist/noctum-reconciliacao.js +594 -0
  269. package/dist/noctum-rede.js +102 -0
  270. package/dist/noctum-registro.js +215 -0
  271. package/dist/noctum-relatorio.js +861 -0
  272. package/dist/noctum-resposta.js +207 -0
  273. package/dist/noctum-retomada-rede.js +71 -0
  274. package/dist/noctum-sessoes-em-voo.js +93 -0
  275. package/dist/noctum-supervisao.js +649 -0
  276. package/dist/noctum-terminal.js +459 -0
  277. package/dist/noctum-transporte.js +655 -0
  278. package/dist/noctum-vigia.js +679 -0
  279. package/dist/ocupacao.js +3 -1
  280. package/dist/onboarding.js +16 -5
  281. package/dist/orkmind.js +39 -23
  282. package/dist/orquestracao.js +31 -35
  283. package/dist/parado-no-condutor.js +160 -139
  284. package/dist/phase.js +96 -42
  285. package/dist/policies.js +33 -0
  286. package/dist/postura-local.js +11 -6
  287. package/dist/preflight.js +2 -1
  288. package/dist/procedencia.js +9 -14
  289. package/dist/projeto-alvo.js +59 -20
  290. package/dist/prompts.js +136 -42
  291. package/dist/prova-minima.js +5 -6
  292. package/dist/pulse-cadencia.js +5 -4
  293. package/dist/pulse-consentimento.js +53 -1
  294. package/dist/pulse-delivery.js +143 -27
  295. package/dist/pulse-resposta.js +368 -4
  296. package/dist/pulse.js +136 -3
  297. package/dist/ratelimit.js +13 -4
  298. package/dist/recall.js +14 -13
  299. package/dist/rede-adesao.js +13 -8
  300. package/dist/rede-forja.js +108 -24
  301. package/dist/rede-status.js +63 -45
  302. package/dist/rede.js +86 -46
  303. package/dist/retomada-checkpoint.js +101 -0
  304. package/dist/retry.js +326 -78
  305. package/dist/roadmap-reservas.js +32 -32
  306. package/dist/runtime-ambiente.js +5 -0
  307. package/dist/runtime-context.js +279 -85
  308. package/dist/runtime-escada.js +429 -0
  309. package/dist/runtime-profiles.js +130 -63
  310. package/dist/runtimes.js +42 -5
  311. package/dist/saida-segura.js +3 -2
  312. package/dist/security-scan/agil.js +366 -0
  313. package/dist/security-scan/cli.js +76 -0
  314. package/dist/security-scan/compare.js +149 -0
  315. package/dist/security-scan/config.js +93 -0
  316. package/dist/security-scan/detect.js +97 -0
  317. package/dist/security-scan/executor.js +196 -0
  318. package/dist/security-scan/guard.js +180 -0
  319. package/dist/security-scan/imagem-de-lint.js +96 -0
  320. package/dist/security-scan/normalize/actionlint.js +12 -0
  321. package/dist/security-scan/normalize/eslint.js +12 -0
  322. package/dist/security-scan/normalize/gitleaks.js +13 -0
  323. package/dist/security-scan/normalize/golangci-lint.js +13 -0
  324. package/dist/security-scan/normalize/govulncheck.js +36 -0
  325. package/dist/security-scan/normalize/index.js +25 -0
  326. package/dist/security-scan/normalize/npm-audit.js +30 -0
  327. package/dist/security-scan/normalize/osv-scanner.js +32 -0
  328. package/dist/security-scan/normalize/oxlint.js +51 -0
  329. package/dist/security-scan/normalize/pip-audit.js +16 -0
  330. package/dist/security-scan/normalize/ruff.js +12 -0
  331. package/dist/security-scan/normalize/semgrep.js +20 -0
  332. package/dist/security-scan/normalize/trivy.js +33 -0
  333. package/dist/security-scan/normalize/util.js +204 -0
  334. package/dist/security-scan/normalize/zizmor.js +19 -0
  335. package/dist/security-scan/report.js +156 -0
  336. package/dist/security-scan/run.js +448 -0
  337. package/dist/security-scan/tools.js +62 -0
  338. package/dist/security-scan/trabalhador.js +74 -0
  339. package/dist/security-scan/types.js +15 -0
  340. package/dist/session-events.js +19 -2
  341. package/dist/session-watcher-claude.js +74 -19
  342. package/dist/session-watcher-grok.js +425 -0
  343. package/dist/session-watcher.js +174 -13
  344. package/dist/sessoes-contas.js +42 -5
  345. package/dist/sessoes-inventario.js +1 -1
  346. package/dist/sessoes.js +25 -23
  347. package/dist/setup.js +67 -66
  348. package/dist/ship-publicar.js +263 -92
  349. package/dist/ship.js +160 -17
  350. package/dist/superficie.js +14 -11
  351. package/dist/thread-close.js +9 -9
  352. package/dist/thread.js +121 -18
  353. package/dist/tokens.js +15 -11
  354. package/dist/trabalho-thread.js +297 -0
  355. package/dist/transporte-do-canal.js +189 -0
  356. package/dist/types.js +12 -1
  357. package/dist/util.js +5 -2
  358. package/dist/varredura-acoes.js +500 -0
  359. package/dist/verify.js +491 -32
  360. package/dist/worktree-local.js +12 -10
  361. package/dist/worktree.js +81 -85
  362. package/eval/casos/check-quality.json +77 -0
  363. package/eval/casos/security-auditor.json +148 -0
  364. package/eval/casos/security-remediation.json +161 -0
  365. package/eval/fixtures/security-scan/README.md +8 -0
  366. package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
  367. package/eval/fixtures/security-scan/go/Dockerfile +4 -0
  368. package/eval/fixtures/security-scan/go/README.md +4 -0
  369. package/eval/fixtures/security-scan/go/config.go +4 -0
  370. package/eval/fixtures/security-scan/go/go.mod +5 -0
  371. package/eval/fixtures/security-scan/go/go.sum +2 -0
  372. package/eval/fixtures/security-scan/go/main.go +31 -0
  373. package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
  374. package/eval/fixtures/security-scan/js/Dockerfile +3 -0
  375. package/eval/fixtures/security-scan/js/README.md +4 -0
  376. package/eval/fixtures/security-scan/js/package-lock.json +844 -0
  377. package/eval/fixtures/security-scan/js/package.json +10 -0
  378. package/eval/fixtures/security-scan/js/src/config.js +4 -0
  379. package/eval/fixtures/security-scan/js/src/server.js +17 -0
  380. package/eval/fixtures/security-scan/js/src/util.ts +4 -0
  381. package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
  382. package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
  383. package/eval/fixtures/security-scan/python/Dockerfile +3 -0
  384. package/eval/fixtures/security-scan/python/README.md +4 -0
  385. package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
  386. package/eval/fixtures/security-scan/python/app/config.py +2 -0
  387. package/eval/fixtures/security-scan/python/app/main.py +19 -0
  388. package/eval/fixtures/security-scan/python/requirements.txt +1 -0
  389. package/package.json +10 -5
  390. package/references/security-checklist.md +3 -3
  391. package/skills/README.md +1 -0
  392. package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
  393. package/skills/phases/check-quality/SKILL.md +16 -0
  394. package/skills/phases/go-implementation/SKILL.md +6 -0
  395. package/skills/phases/security-remediation/SKILL.md +70 -0
  396. package/skills/reviewers/security-auditor/SKILL.md +25 -0
@@ -42,7 +42,25 @@ nos perfis `coding` e `messaging` (`toolMetadata`): sem isso, no perfil `coding`
42
42
  plugin chega ao modelo. `ork_network_status` espera a RM-053 na `main`. `network-roadmap-hosts.test.ts` prova a rota de cada host e o aceite do incidente de 29/09
43
43
  pela extensão do OpenClaw com o `ork` real.
44
44
 
45
+ ## Paridade do conhecimento escrito
46
+
47
+ O conhecimento escrito ([RM-026](../docs/roadmap/RM-026-workspace-empresarial.md) K7) chega aos quatro hosts pelas
48
+ mesmas quatro tools `ork_conhecimento_*`: tools do MCP no Claude Code e no Codex, tool argv no OpenClaw (só no
49
+ perfil `coding`) e wrapper no Hermes, cada uma uma chamada de `ork conhecimento <consulta> --json`. A descrição
50
+ das tools do OpenClaw e a skill do Hermes dizem a mesma regra: a lacuna tipada é lacuna, nunca resposta.
51
+ `conhecimento-hosts.test.ts` confere os nomes, o schema e a frase e, com o `ork` real, o mesmo JSON nas três
52
+ superfícies.
53
+
45
54
  Usabilidade HITL é prioridade máxima: recomendação, opções claras e canal disponível
46
55
  associado ao pedido. MCP local conserva elicitation; Telegram segue disponível
47
56
  quando configurado. Ingresso nativo Hermes/Discord e OpenClaw depende de callback
48
57
  autenticado e binding privado; terminal Hermes/ACP não está homologado.
58
+
59
+ ## Batida do host e canal (RM-063)
60
+
61
+ Os dois hosts de canal ganham a mesma segunda linha da fábrica: `bin/ork-vigia-batida.js` numa
62
+ automação de comando do OpenClaw e `bin/ork-vigia-batida.py` no cron do Hermes leem o
63
+ `ork doctor --json` a cada 30 min e avisam o dono quando a batida passou de 30 min, sem chamada de
64
+ modelo. `#OrkRetomar` e `#OrkFabrica` entram pelo mesmo ingresso assinado do pulse nos dois, e o
65
+ `ork onboarding` grava o `pulse-host.json` do host escolhido. `conducao-canal.test.mjs` e
66
+ `conducao_canal_test.py` provam os dois lados com `ork` e host SIMULADOS.
@@ -20,6 +20,7 @@
20
20
  "./skills/phases/goal-definition",
21
21
  "./skills/phases/master-metrics",
22
22
  "./skills/phases/plan-specification",
23
+ "./skills/phases/security-remediation",
23
24
  "./skills/phases/ship-release",
24
25
  "./skills/reviewers/code-reviewer",
25
26
  "./skills/reviewers/security-auditor",
@@ -72,11 +72,11 @@ descartável; o recibo traz o sha256 dos arquivos globais antes e depois. Modelo
72
72
  | `/ork` | Painel: doctor, board, escalonador, modos, fila de score |
73
73
 
74
74
  Mais seis subagentes (`ork-goal`, `ork-plan`, `ork-go`, `ork-check`, `ork-ship`, `ork-master`) para
75
- isolar o contexto de cada fase, e o guard `PreToolUse`.
75
+ isolar o contexto de cada fase, o guard `PreToolUse` e o hook `UserPromptSubmit` da resposta curta do dono.
76
76
 
77
77
  ## O guard PreToolUse
78
78
 
79
- Um hook, em `Bash`, chamando `hooks/ork-guard.js`. Ele bloqueia seis classes de comando:
79
+ Um hook, em `Bash`, chamando `hooks/ork-guard.js`. Ele bloqueia sete classes de comando:
80
80
 
81
81
  | Bloqueio | Por que |
82
82
  |---|---|
@@ -86,12 +86,44 @@ Um hook, em `Bash`, chamando `hooks/ork-guard.js`. Ele bloqueia seis classes de
86
86
  | `git push` | Push na mao nao e provado: a entrega passa por `ork ship` |
87
87
  | `git reset --hard`, `git clean -fd`, `git checkout -- .` | Descarte em massa sem rastro |
88
88
  | `rm -rf` com alvo amplo ou variavel | Apaga o que ninguem pediu |
89
+ | `ork noctum terminal` e o hook da resposta chamados pela ferramenta | A resposta do dono no terminal vem do hook da sessão dele; o agente que chama esse ingresso se passa pelo dono (RM-057) |
89
90
 
90
91
  **O guard nao tem regra de negocio.** Ele nao le ledger, nao sabe quem autorizou o que e nao
91
92
  conhece thread nenhuma: ele reconhece a forma do comando e manda o agente pelo caminho que o `ork`
92
93
  verifica. Comando que comeca com `ork` passa direto, porque quem prova o push e serializa o merge e
93
- o nucleo. E se o proprio guard quebrar, ele **libera**: um hook que derruba a sessao por bug proprio
94
- e pior que nenhum hook.
94
+ o nucleo; a exceção é o ingresso da resposta do dono (`ork noctum terminal`), barrado antes dessa
95
+ passagem. E se o proprio guard quebrar, ele **libera**: um hook que derruba a sessao por bug proprio
96
+ e pior que nenhum hook. A barreira do ingresso da resposta é lombada, não prova: quem roda como o
97
+ mesmo usuário do sistema a contorna, e o limite está dito abaixo.
98
+
99
+ ## A resposta curta do dono no terminal (RM-057)
100
+
101
+ **Desligada.** Desde o GO-FIX 2 da RM-057, o núcleo não grava nada pelo terminal. Numa sessão interativa do
102
+ Claude Code, quando o dono digita a resposta curta a uma pergunta que espera por ele (`sim`, `a` ou
103
+ `<código> a`), o hook `UserPromptSubmit` (`hooks/ork-resposta.js`) leva o evento ao núcleo pelo
104
+ `ork noctum terminal --hook-stdin`, e o núcleo só devolve a recusa `noctum.terminal.desligado`: com alguém
105
+ presente, o dono vê um aviso (`systemMessage`) para responder pelo Telegram, em reply à mensagem da
106
+ pergunta ou com o código e a letra, ou pela janela de confirmação do Claude Code (o diálogo nativo, um
107
+ clique). O prompt segue ao modelo, e nada é gravado nem encaminhado, nem a resposta a um gate. Conversa
108
+ comum nem chama o núcleo, e o prompt que a máquina escreveu (o campo `source` do evento diferente de
109
+ `user`) também não.
110
+
111
+ **Por que desligada:** o Claude Code instalado (2.1.306) ainda não manda o `source` do evento, e sem ele
112
+ nada do dono gravaria. E o agente da própria sessão do dono, pela ferramenta Bash, troca o shell pelo
113
+ núcleo com `exec`, tira a marca `AI_AGENT` e forja o evento com `source` igual a `user`: a cadeia de
114
+ processos e o guard são lombadas, não prova. Ligado, o ingresso não serviria ao dono e serviria a quem
115
+ forja o evento.
116
+
117
+ **O que falta para voltar**, numa fatia própria: o Claude Code mandar a origem humana do evento
118
+ (`source`); uma prova de que o evento veio do hook do harness, e não de um processo do mesmo usuário; e,
119
+ para a palavra solta, a pergunta mostrada exigida como a linha que o núcleo monta para ela, ou só o código
120
+ com a letra. O código do ingresso segue no núcleo atrás da chave `TERMINAL_LIGADO`, desligada; só os
121
+ testes a ligam, e o CLI e o hook nunca.
122
+
123
+ **Limite:** a fronteira é a conta do sistema. No diálogo nativo, qualquer cliente MCP do mesmo usuário que
124
+ declare o formulário passa, sem chave. Para separar o núcleo dos agentes, rode os agentes em outra conta
125
+ ou sandbox. O aviso só aparece depois de reinstalar o plugin (`ork adapter install claude-code`) e do
126
+ `ork` com o `noctum terminal`.
95
127
 
96
128
  ## Sensores de sessão
97
129
 
@@ -332,7 +364,7 @@ tres e o `--dry-run` mostra o que ele vai fazer sobre cada um.
332
364
  (`core/`, `phases/`, `reviewers/`, ...) que este catalogo usa. Por isso `plugin.json` declara os
333
365
  caminhos um a um. O teste compara esses caminhos com o catálogo fonte e exige
334
366
  `onboarding`, acrescentada por I15. Neste catálogo, `claude plugin details orkastery`
335
- deve reportar 28 entradas: 20 skills e 8 comandos (a linha `Skills (28)`). O startup registra
367
+ deve reportar 29 entradas: 21 skills e 8 comandos (a linha `Skills (29)`). O startup registra
336
368
  separadamente skills e comandos. As provas anteriores, com 17 e 18 skills, são históricas.
337
369
  Confira também os seis agentes e seis eventos de hooks, sem erros de carregamento.
338
370
 
@@ -27,6 +27,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
27
27
 
28
28
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
29
29
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
30
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
30
31
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
31
32
  fica registrada no ledger.
32
33
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -27,6 +27,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
27
27
 
28
28
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
29
29
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
30
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
30
31
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
31
32
  fica registrada no ledger.
32
33
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -28,6 +28,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
28
28
 
29
29
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
30
30
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
31
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
31
32
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
32
33
  fica registrada no ledger.
33
34
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -29,6 +29,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
29
29
 
30
30
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
31
31
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
32
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
32
33
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
33
34
  fica registrada no ledger.
34
35
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -27,6 +27,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
27
27
 
28
28
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
29
29
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
30
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
30
31
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
31
32
  fica registrada no ledger.
32
33
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -27,6 +27,7 @@ ork phase list <thread> # o que ja aconteceu, com evidencia
27
27
 
28
28
  - O modo de conducao afrouxa a PAUSA, nunca a VERIFICACAO.
29
29
  - Nada de self-report: toda alegacao vem com o comando que a comprova e a saida real.
30
+ - Esperas: nunca dispare verify, build ou suite com `&` dentro do comando, porque o processo se perde e a sessao espera um aviso que nunca vem; rode o `ork verify` em primeiro plano, com `timeout` (ele espera a vez na fila de recursos pesados), ou use a execucao em segundo plano do host, que avisa quando termina; nunca espere com `pgrep -f` cujo padrao aparece no proprio comando, porque o laco acha a si mesmo e nao termina: espere pelo arquivo de saida com prazo, ou pelo PID guardado.
30
31
  - Passo irreversivel (push, merge, delecao) so acontece quando o modo autoriza, e a autorizacao
31
32
  fica registrada no ledger.
32
33
  - Termine dizendo, em uma linha, em que ponto a thread esta e o que acontece agora.
@@ -17,6 +17,7 @@
17
17
  "Notification": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
18
18
  "Stop": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
19
19
  "SubagentStop": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
20
- "PostToolUse": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }]
20
+ "PostToolUse": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
21
+ "UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-resposta.js\"", "timeout": 10 }] }]
21
22
  }
22
23
  }
@@ -62,11 +62,25 @@ const BLOQUEIOS = [
62
62
  },
63
63
  ];
64
64
 
65
+ /**
66
+ * RM-057 (resposta curta, D11 da ork-rm057respost): a resposta do dono no terminal vem do hook `UserPromptSubmit` da
67
+ * sessao dele. Um agente que chama esse ingresso pela ferramenta se passa pelo dono, e por isso esta regra roda ANTES da
68
+ * passagem livre do `ork`. E lombada, nao prova: quem roda como o mesmo usuario contorna (o limite dito na RM-058), ate
69
+ * com o subcomando entre aspas. Desde o GO-FIX 2 (D22) o ingresso do terminal esta desligado e nao grava nada.
70
+ */
71
+ const RESPOSTA_DO_DONO = {
72
+ nome: 'resposta-do-dono-por-ferramenta',
73
+ regex: /\bnoctum\s+terminal\b|ork-resposta\.js/,
74
+ motivo: 'a resposta do dono no terminal vem do hook UserPromptSubmit da sessao dele; o agente que chama esse ingresso se passa pelo dono',
75
+ caminho: 'mostre a pergunta ao dono e espere a resposta dele no Telegram ou pela janela de confirmacao do host; nunca responda por ele',
76
+ };
77
+
65
78
  function decidir(entrada) {
66
79
  const nome = entrada && entrada.tool_name;
67
80
  if (nome !== 'Bash') return null;
68
81
  const comando = String((entrada.tool_input && entrada.tool_input.command) || '');
69
82
  if (comando.trim() === '') return null;
83
+ if (RESPOSTA_DO_DONO.regex.test(comando)) return RESPOSTA_DO_DONO;
70
84
  // Comando do proprio `ork` passa: quem verifica o push provado e o merge serializado e ele.
71
85
  if (/^\s*(?:[A-Za-z0-9_]+=\S*\s+)*(?:\S*\/)?ork\s/.test(comando)) return null;
72
86
  for (const b of BLOQUEIOS) {
@@ -127,4 +141,4 @@ process.stdin.on('end', () => {
127
141
  process.exitCode = codigo;
128
142
  });
129
143
 
130
- module.exports = { BLOQUEIOS, decidir };
144
+ module.exports = { BLOQUEIOS, RESPOSTA_DO_DONO, decidir };
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ /**
4
+ * Hook `UserPromptSubmit` do adaptador Claude Code: a resposta curta do dono no terminal (RM-057, ork-rm057respost).
5
+ *
6
+ * GO-FIX 2 (D22): o ingresso do terminal esta DESLIGADO no nucleo. Quando o dono digita a resposta curta a uma pergunta
7
+ * que espera por ele, o nucleo nao grava nada e devolve so a recusa `noctum.terminal.desligado`, que este hook mostra ao
8
+ * dono (`systemMessage`): responda pelo Telegram (em reply a mensagem da pergunta, ou com o codigo) ou pela janela de
9
+ * confirmacao do Claude Code (o dialogo nativo). O transporte abaixo continua o mesmo, para quando uma fatia propria
10
+ * religar o ingresso.
11
+ *
12
+ * O dono aprova onde estiver. Numa sessao interativa, ele responde a pergunta do arco #Noctum com "sim", "a" ou
13
+ * "<codigo> a"; este hook leva o evento ao nucleo (`ork noctum terminal --hook-stdin`) e transporta a decisao dele:
14
+ *
15
+ * - gravada (ou sem efeito, detalhe, ou a pergunta de volta): a frase do nucleo substitui o prompt (`decision: block`),
16
+ * e o "sim" nao chega ao modelo;
17
+ * - resposta a um gate: o contexto vai ao modelo (`additionalContext`), para o condutor abrir o dialogo nativo;
18
+ * - recusa pela origem com alguem presente: um aviso ao dono (`systemMessage`), e o prompt segue ao modelo;
19
+ * - o resto: nada, e o prompt segue como sempre.
20
+ *
21
+ * Ele NAO tem regra de negocio: nao le ledger, nao conhece pergunta e nao prova nada; quem confere a origem da sessao e o
22
+ * nucleo. So texto curto de uma linha chama o nucleo. Erro do hook ou do nucleo nunca bloqueia nem quebra a sessao.
23
+ *
24
+ * GO-FIX 1 (achado 1): o prompt que a maquina injeta na sessao do dono (a tarefa agendada, a volta do /loop, a mensagem
25
+ * de canal ou de outra sessao, o SDK) nunca chega ao nucleo: o evento diz quem o escreveu (`source`), e so `user`, o
26
+ * compositor interativo, passa. Sem o campo (versao do Claude Code que ainda nao o manda), o nucleo recebe o evento,
27
+ * recusa e diz ao dono por que; ele tambem exige `user`, para quem chamar o nucleo sem este hook.
28
+ */
29
+ const fs = require('node:fs');
30
+ const path = require('node:path');
31
+ const { spawnSync } = require('node:child_process');
32
+
33
+ /**
34
+ * A forma da resposta curta, larga o bastante para o nucleo decidir e estreita o bastante para conversa comum nem chamar o
35
+ * nucleo: o codigo com a resposta ("NX4K a"), o numero com a letra ("1a") ou uma palavra solta de ate duas palavras e 20
36
+ * caracteres ("sim", "pode seguir"). Tudo numa linha so, ate 64 caracteres.
37
+ */
38
+ const TETO_DO_PROMPT = 64;
39
+ const CODIGO_E_RESPOSTA = /^[A-HJKMNP-TV-Z](?=[2-9A-HJKMNP-TV-Z]{0,2}[2-9])[2-9A-HJKMNP-TV-Z]{3}\s+\S/i;
40
+ const NUMERO_E_LETRA = /^[0-9]{1,2}\s*[a-e][.!]?$/i;
41
+ const PALAVRA_SOLTA = /^\S+(?:\s\S+)?$/;
42
+ const TETO_DA_ENTRADA = 1024 * 1024;
43
+
44
+ function pareceRespostaCurta(t) {
45
+ if (!t || t.length > TETO_DO_PROMPT || /[\r\n]/.test(t)) return false;
46
+ return CODIGO_E_RESPOSTA.test(t) || NUMERO_E_LETRA.test(t) || (t.length <= 20 && PALAVRA_SOLTA.test(t));
47
+ }
48
+
49
+ function lerEntrada() {
50
+ const buffer = Buffer.alloc(TETO_DA_ENTRADA + 1);
51
+ let bytes = 0;
52
+ while (bytes <= TETO_DA_ENTRADA) {
53
+ const n = fs.readSync(0, buffer, bytes, buffer.length - bytes, null);
54
+ if (!n) break;
55
+ bytes += n;
56
+ }
57
+ if (bytes > TETO_DA_ENTRADA) return null;
58
+ return JSON.parse(buffer.subarray(0, bytes).toString('utf8'));
59
+ }
60
+
61
+ /** O texto que o nucleo montou, com teto: o hook transporta, nunca reescreve. */
62
+ const texto = (v, teto) => (typeof v === 'string' && v.trim() ? v.slice(0, teto) : '');
63
+
64
+ function executar() {
65
+ const h = lerEntrada();
66
+ if (!h || h.hook_event_name !== 'UserPromptSubmit' || typeof h.prompt !== 'string' ||
67
+ typeof h.cwd !== 'string' || !path.isAbsolute(h.cwd)) return;
68
+ // O prompt que a maquina escreveu nao e do dono: nao chega ao nucleo, e segue ao modelo como sempre.
69
+ if (h.source !== undefined && h.source !== 'user') return;
70
+ if (!pareceRespostaCurta(h.prompt.trim())) return;
71
+ const r = spawnSync(process.env.ORK_SENSOR_CLI || 'ork', ['noctum', 'terminal', '--hook-stdin'], {
72
+ cwd: h.cwd, input: JSON.stringify(h), encoding: 'utf8', timeout: 8000, maxBuffer: 256 * 1024, windowsHide: true,
73
+ });
74
+ if (r.status !== 0 || typeof r.stdout !== 'string' || !r.stdout.trim()) return;
75
+ let d;
76
+ try { d = JSON.parse(r.stdout); } catch { return; }
77
+ if (!d || d.contrato !== 'ork.noctum-terminal/v1') return;
78
+ let saida = null;
79
+ if (['registrada', 'sem-efeito', 'detalhe', 'pergunta'].includes(d.acao) && texto(d.mensagem, 8000)) {
80
+ saida = { decision: 'block', reason: texto(d.mensagem, 8000) };
81
+ } else if (d.acao === 'encaminhar' && texto(d.contexto, 2000)) {
82
+ saida = { hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: texto(d.contexto, 2000) } };
83
+ } else if (d.acao === 'recusada' && d.presenca === true && texto(d.mensagem, 2000)) {
84
+ saida = { systemMessage: texto(d.mensagem, 2000) };
85
+ }
86
+ if (saida) process.stdout.write(JSON.stringify(saida) + '\n');
87
+ }
88
+
89
+ try { executar(); }
90
+ catch { process.stderr.write('ork resposta: entrada invalida ou nucleo indisponivel; o prompt segue sem mudanca.\n'); }
91
+ process.exitCode = 0;
@@ -5,6 +5,7 @@ const fs = require('node:fs');
5
5
  const path = require('node:path');
6
6
  const { spawnSync } = require('node:child_process');
7
7
  const { createHash, randomUUID } = require('node:crypto');
8
+ const { accountFailure } = require('./quota-signal');
8
9
 
9
10
  function executar() {
10
11
  const limite = 1024 * 1024;
@@ -25,6 +26,15 @@ function executar() {
25
26
  if (!tipo) return;
26
27
  const payload = { observedAt: new Date().toISOString() };
27
28
  if (h.hook_event_name === 'Notification') payload.notificationType = h.notification_type;
29
+ // RM-037 (CHECK 3 da ork-rm037defeit2): o Stop conta o trabalho que ainda vai acordar a sessão. Com despertar agendado
30
+ // (CronCreate, ScheduleWakeup, /loop) ou tarefa MCP, o Claude Code mostra a sessão `idle`; só a entrada do Stop separa
31
+ // a sessão encerrada da que vai voltar a escrever. Runtime sem os campos não manda nada, e o ork não supõe zero.
32
+ if (h.hook_event_name === 'Stop') {
33
+ if (Array.isArray(h.background_tasks)) payload.backgroundTasks = h.background_tasks.length;
34
+ if (Array.isArray(h.session_crons)) payload.sessionCrons = h.session_crons.length;
35
+ }
36
+ const falhaDaConta = accountFailure(h);
37
+ if (falhaDaConta && (tipo === 'notification' || tipo === 'stop')) payload.accountFailure = falhaDaConta;
28
38
  // tool_use_id identifica replay da mesma ferramenta. Sem id do protocolo,
29
39
  // cada invocação é uma ocorrência; stat do transcript não identifica eventos.
30
40
  payload.eventId = typeof h.tool_use_id === 'string'
@@ -47,11 +57,17 @@ function executar() {
47
57
  }
48
58
  }
49
59
  }
50
- const r = spawnSync(process.env.ORK_SENSOR_CLI || 'ork',
60
+ const enviar = (p) => spawnSync(process.env.ORK_SENSOR_CLI || 'ork',
51
61
  ['sessions', 'event', '--tipo', tipo, '--sessao', h.session_id], {
52
- cwd: h.cwd, input: JSON.stringify(payload), encoding: 'utf8', timeout: 3000,
62
+ cwd: h.cwd, input: JSON.stringify(p), encoding: 'utf8', timeout: 3000,
53
63
  maxBuffer: 32768, windowsHide: true,
54
64
  });
65
+ let r = enviar(payload);
66
+ // O `ork` de antes das contagens recusa o campo novo antes de gravar qualquer coisa: o Stop vai de novo sem elas, como ia.
67
+ if (r.status === 1 && /^evento recusado: campo de payload inválido: (?:backgroundTasks|sessionCrons)$/m.test(r.stderr || '')) {
68
+ const { backgroundTasks: _tarefas, sessionCrons: _despertares, ...semContagens } = payload;
69
+ r = enviar(semContagens);
70
+ }
55
71
  if (r.status !== 0) {
56
72
  // Recusa conhecida não identifica o papel da sessão nem comprova ingestão.
57
73
  const semVinculo = r.status === 1 && !r.error && !r.stdout?.trim() &&
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * RM-064 T1: reconhece apenas o fato de a conta ter esgotado. O chamador persiste
5
+ * o código devolvido, nunca os textos que serviram de entrada.
6
+ */
7
+ function accountFailure(h) {
8
+ const partes = [h?.message, h?.reason, h?.stop_reason, h?.error?.message, h?.error?.code]
9
+ .filter((v) => typeof v === 'string').join('\n');
10
+ return /(?:you(?:'|’)ve hit your (?:weekly|session|individual spend|usage) limit|seu limite de uso foi atingido|usage_limit_(?:exceeded|reached)|insufficient_quota|out of credits|spend (?:cap|limit))/i.test(partes)
11
+ ? 'runtime.quota-exhausted' : null;
12
+ }
13
+
14
+ module.exports = { accountFailure };
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "ork-mensageiro",
3
+ "version": "0.1.0",
4
+ "description": "Mensageiro de Sessões do Orkastery no Claude Code: leva a resposta que o dono deu pelo diálogo nativo à sessão de fase claude-bg que parou esperando por ele, como mensagem entre sessões, e na sessão de fase só deixa chegar ao modelo a mensagem que o núcleo confirmou como aquela resposta. Nunca responde nem aprova pelo dono.",
5
+ "author": {
6
+ "name": "Orkastery contributors",
7
+ "url": "https://github.com/orkastery"
8
+ },
9
+ "homepage": "https://orkastery.com/",
10
+ "repository": "https://github.com/orkastery/orkastery",
11
+ "license": "MIT",
12
+ "types": "./types/index.d.ts",
13
+ "dependencies": ["ork-ponte"]
14
+ }
@@ -0,0 +1,215 @@
1
+ // O lado do dono do Mensageiro de Sessoes (RM-059, fatia F9, T9.2), em funcoes puras. A sessao do dono que recebeu a
2
+ // resposta pelo dialogo nativo tem a mensagem na caixa de saida do servidor MCP dela (`ork_session_outbox`), so na
3
+ // memoria; o Mensageiro a leva a sessao de fase por `$.session.send`, sem mexer no texto, e anota o envio no nucleo.
4
+ // O que segue incerto noutra sessao do dono sai do retrato da ponte (secao `hitl`). Nada daqui guarda o texto da
5
+ // resposta no estado (D12 da thread ork-rm059mensag). So importa tipos.
6
+ import type { MensageiroDono, MensageiroEntrega, MensageiroEstadoDaEntrega, MensageiroIncerta } from '../types'
7
+
8
+ export const SERVIDOR = 'orkastery'
9
+ /** A ferramenta da caixa de saida, so no servidor do dono do Claude Code (T9.1). */
10
+ export const FERRAMENTA_DA_CAIXA = 'ork_session_outbox'
11
+ /** O contrato da entrega no nucleo (`core/src/entrega-por-mod.ts`), conferido pelo teste do nucleo. */
12
+ export const CONTRATO_DA_ENTREGA = 'ork.session-delivery/v1'
13
+ /** D10: o envio que nao entrou na fila volta depois do recuo; o que entrou e nao foi reservado, depois da espera. */
14
+ export const RECUO_DO_ENVIO_MS = 30000
15
+ export const ESPERA_DA_RESERVA_MS = 60000
16
+ export const MAXIMO_DE_ENVIOS = 10
17
+ /** D21: a reserva sem recibo por este tempo deixa de ser "confirmando" e pede o dono. */
18
+ export const ESPERA_DO_RECIBO_MS = 5 * 60000
19
+ /** A faixa diz "entregue" por este tempo; o painel guarda o que terminou por este outro. */
20
+ export const FAIXA_DA_ENTREGA_MS = 10 * 60000
21
+ export const GUARDA_DO_TERMINADO_MS = 30 * 60000
22
+ export const MAXIMO_DE_ENTREGAS = 50
23
+ export const DONO_VAZIO: MensageiroDono = { entregas: [], incertas: [], lidoEm: null, erro: null }
24
+
25
+ const UUID = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/
26
+ const ID_DE_THREAD = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/
27
+ const VIVOS: readonly MensageiroEstadoDaEntrega[] = ['na-fila', 'a-caminho', 'reservada', 'nao-chegou']
28
+
29
+ /** Uma entrega da caixa de saida como o nucleo a lista, com o ultimo envio em ms. */
30
+ export type EntradaDaCaixa = {
31
+ thread: string; pedidoId: string; envioId: string; sessionId: string
32
+ /** A mensagem inteira, com o cabecalho do nucleo: vai ao `$.session.send` como esta e nunca ao estado. */
33
+ mensagem: string
34
+ tentativas: number
35
+ ultimoEnvio: { em: number; entregue: boolean; motivo: string | null } | null
36
+ reservada: boolean
37
+ /** Quando a entrega entrou na caixa (ms desde a epoca); conta o sem-recibo quando o envio nao foi anotado. */
38
+ criadaEm: number | null
39
+ }
40
+
41
+ const objeto = (v: unknown): v is Record<string, any> => !!v && typeof v === 'object' && !Array.isArray(v)
42
+ const uuid = (v: unknown): v is string => typeof v === 'string' && UUID.test(v)
43
+
44
+ /** Uma linha so, sem caractere de controle e com teto: o que vem do nucleo ou de um erro nunca quebra a tela. */
45
+ export function umaLinha(v: unknown, teto = 200): string {
46
+ const s = typeof v === 'string' ? v : v instanceof Error ? v.message : String(v)
47
+ return Array.from(s.replace(/\p{Cc}/gu, ' ').replace(/\s+/g, ' ').trim()).slice(0, teto).join('')
48
+ }
49
+
50
+ /** O JSON que uma ferramenta do nucleo devolveu; a recusa vira erro com o motivo dela. */
51
+ export function jsonDoMcp(r: unknown, ferramenta: string): unknown {
52
+ const o = objeto(r) ? r : {}
53
+ const conteudo = Array.isArray(o.content) ? o.content : []
54
+ const texto = conteudo.filter(c => objeto(c) && c.type === 'text' && typeof c.text === 'string').map(c => c.text).join('')
55
+ let dados: unknown
56
+ try { dados = JSON.parse(texto) } catch { throw new Error(`${ferramenta} respondeu fora do JSON`) }
57
+ if (o.isError === true) throw new Error(`${ferramenta} recusou: ${umaLinha(objeto(dados) && typeof dados.erro === 'string' ? dados.erro : texto)}`)
58
+ return dados
59
+ }
60
+
61
+ function lerEntrada(e: unknown): EntradaDaCaixa[] {
62
+ if (!objeto(e) || typeof e.thread !== 'string' || !ID_DE_THREAD.test(e.thread) || !uuid(e.pedidoId) || !uuid(e.envioId) ||
63
+ !uuid(e.sessionId) || typeof e.mensagem !== 'string' ||
64
+ !e.mensagem.startsWith(`[${CONTRATO_DA_ENTREGA} pedido=${e.pedidoId} entrega=${e.envioId}] `)) return []
65
+ const u = objeto(e.ultimoEnvio) ? e.ultimoEnvio : null
66
+ const em = u && typeof u.em === 'string' ? Date.parse(u.em) : NaN
67
+ const criadaEm = typeof e.criadaEm === 'string' ? Date.parse(e.criadaEm) : NaN
68
+ return [{ thread: e.thread, pedidoId: e.pedidoId, envioId: e.envioId, sessionId: e.sessionId, mensagem: e.mensagem,
69
+ tentativas: Number.isSafeInteger(e.tentativas) && e.tentativas > 0 ? e.tentativas : 0,
70
+ ultimoEnvio: u && Number.isFinite(em) ? { em, entregue: u.entregue === true, motivo: typeof u.motivo === 'string' ? umaLinha(u.motivo) : null } : null,
71
+ reservada: e.reservada === true, criadaEm: Number.isFinite(criadaEm) ? criadaEm : null }]
72
+ }
73
+
74
+ /** A caixa de saida do `listar`; o que nao bate com o contrato fica de fora, e a resposta fora do contrato e erro. */
75
+ export function lerCaixa(dados: unknown): EntradaDaCaixa[] {
76
+ if (!objeto(dados) || dados.contrato !== CONTRATO_DA_ENTREGA || !Array.isArray(dados.entregas)) {
77
+ throw new Error('a caixa de saída respondeu fora do contrato ork.session-delivery/v1')
78
+ }
79
+ return dados.entregas.flatMap(lerEntrada)
80
+ }
81
+
82
+ /** A entrega que o `enviada` devolveu, com a reserva que ela tinha na lista (o nucleo so a le no `listar`). */
83
+ export function entradaAnotada(dados: unknown, reservada: boolean): EntradaDaCaixa | null {
84
+ const lida = objeto(dados) && dados.contrato === CONTRATO_DA_ENTREGA ? lerEntrada({ ...(objeto(dados.entrega) ? dados.entrega : {}), reservada }) : []
85
+ return lida[0] ?? null
86
+ }
87
+
88
+ /** D10: envia o que nunca foi, o que nao entrou na fila depois do recuo e o que entrou e ninguem reservou depois da espera. */
89
+ export function deveEnviar(e: EntradaDaCaixa, agora: number): boolean {
90
+ if (e.reservada || e.tentativas >= MAXIMO_DE_ENVIOS) return false
91
+ if (!e.ultimoEnvio) return true
92
+ return agora - e.ultimoEnvio.em >= (e.ultimoEnvio.entregue ? ESPERA_DA_RESERVA_MS : RECUO_DO_ENVIO_MS)
93
+ }
94
+
95
+ /** O argumento do `$.session.send`: a sessao do pedido e a mensagem do nucleo, sem mexer em nada. */
96
+ export function argsDoEnvio(e: EntradaDaCaixa): { to: { sessionId: string }; text: string } {
97
+ return { to: { sessionId: e.sessionId }, text: e.mensagem }
98
+ }
99
+
100
+ /** O resultado do `$.session.send` como o nucleo o anota. */
101
+ export function resultadoDoEnvio(r: unknown): { entregue: boolean; motivo: string | null } {
102
+ if (objeto(r) && r.isDelivered === true) return { entregue: true, motivo: null }
103
+ return { entregue: false, motivo: umaLinha(objeto(r) && typeof r.reason === 'string' && r.reason ? r.reason : 'a sessão não recebeu a mensagem') }
104
+ }
105
+
106
+ export function argsDaAnotacao(e: EntradaDaCaixa, r: { entregue: boolean; motivo: string | null }): Record<string, unknown> {
107
+ return { operacao: 'enviada', threadId: e.thread, envioId: e.envioId, entregue: r.entregue, ...(r.motivo ? { motivo: r.motivo } : {}) }
108
+ }
109
+
110
+ /** A secao `hitl` do retrato, quando ela veio lida (disponivel ou vazia); `null` quando nao da para concluir nada. */
111
+ function secaoHitl(retrato: unknown): Record<string, any>[] | null {
112
+ const secoes = objeto(retrato) && objeto(retrato.sections) ? retrato.sections : {}
113
+ const hitl = objeto(secoes.hitl) ? secoes.hitl : null
114
+ if (!hitl || (hitl.state !== 'available' && hitl.state !== 'empty')) return null
115
+ return Array.isArray(hitl.items) ? hitl.items.filter(objeto) : []
116
+ }
117
+
118
+ const threadDoItem = (i: Record<string, any>): string | null => {
119
+ const ref = Array.isArray(i.refs) ? i.refs.find((r: unknown) => objeto(r) && r.kind === 'thread' && typeof r.id === 'string') : null
120
+ return ref && ID_DE_THREAD.test(ref.id) ? ref.id : null
121
+ }
122
+
123
+ /** Os pedidos abertos que o retrato mostra (respondido sai da secao); `null` quando a secao nao veio lida. */
124
+ export function pedidosNoRetrato(retrato: unknown): Set<string> | null {
125
+ const itens = secaoHitl(retrato)
126
+ return itens === null ? null : new Set(itens.flatMap(i => (typeof i.id === 'string' ? [i.id] : [])))
127
+ }
128
+
129
+ /** Os pedidos de sessao com a entrega incerta no retrato (`delivery.uncertain`): a entrega segue em alguma sessao do dono. */
130
+ export function incertasDoRetrato(retrato: unknown): MensageiroIncerta[] {
131
+ return (secaoHitl(retrato) ?? []).flatMap(i => {
132
+ const thread = threadDoItem(i)
133
+ return i.status === 'delivery.uncertain' && objeto(i.facts) && i.facts.target === 'session' && uuid(i.id) && thread
134
+ ? [{ thread, pedidoId: i.id }] : []
135
+ })
136
+ }
137
+
138
+ /** O estado de uma entrega que esta na caixa, agora. */
139
+ export function estadoDaEntrada(e: EntradaDaCaixa, agora: number): MensageiroEstadoDaEntrega {
140
+ if (e.reservada) {
141
+ const desde = e.ultimoEnvio?.em ?? e.criadaEm
142
+ return typeof desde === 'number' && agora - desde >= ESPERA_DO_RECIBO_MS ? 'sem-recibo' : 'reservada'
143
+ }
144
+ if (!e.ultimoEnvio) return 'na-fila'
145
+ if (e.tentativas >= MAXIMO_DE_ENVIOS) return 'desistiu'
146
+ return e.ultimoEnvio.entregue ? 'a-caminho' : 'nao-chegou'
147
+ }
148
+
149
+ function motivoDaEntrada(e: EntradaDaCaixa, estado: MensageiroEstadoDaEntrega): string | null {
150
+ if (estado === 'sem-recibo') return 'a sessão de fase reservou a entrega e não gravou o recibo em 5 min'
151
+ if (estado === 'desistiu') {
152
+ return e.ultimoEnvio?.entregue
153
+ ? `a sessão de fase não confirmou a entrega depois de ${e.tentativas} envios`
154
+ : e.ultimoEnvio?.motivo ?? `a mensagem não entrou na fila da sessão em ${e.tentativas} envios`
155
+ }
156
+ return estado === 'nao-chegou' ? e.ultimoEnvio?.motivo ?? null : null
157
+ }
158
+
159
+ /**
160
+ * As entregas desta sessao depois de uma leitura da caixa. A que saiu da caixa terminou: entregue, quando o retrato
161
+ * nao mostra mais o pedido (respondido); "saiu da caixa", quando o pedido segue aberto. Sem o retrato, nada se conclui.
162
+ */
163
+ export function atualizarEntregas(anteriores: readonly MensageiroEntrega[], caixa: readonly EntradaDaCaixa[],
164
+ noRetrato: Set<string> | null, agora: number): MensageiroEntrega[] {
165
+ const restantes = new Map(anteriores.map(e => [e.envioId, e]))
166
+ const saida: MensageiroEntrega[] = []
167
+ for (const c of caixa) {
168
+ const estado = estadoDaEntrada(c, agora)
169
+ const antes = restantes.get(c.envioId)
170
+ restantes.delete(c.envioId)
171
+ saida.push({ thread: c.thread, pedidoId: c.pedidoId, envioId: c.envioId, sessionId: c.sessionId, estado, tentativas: c.tentativas,
172
+ motivo: motivoDaEntrada(c, estado), em: antes && antes.estado === estado ? antes.em : agora })
173
+ }
174
+ for (const e of restantes.values()) {
175
+ if (!VIVOS.includes(e.estado) && e.estado !== 'desistiu' && e.estado !== 'sem-recibo') {
176
+ if (agora - e.em <= GUARDA_DO_TERMINADO_MS) saida.push(e)
177
+ continue
178
+ }
179
+ if (noRetrato === null) { saida.push(e); continue }
180
+ const aberto = noRetrato.has(e.pedidoId)
181
+ saida.push({ ...e, estado: aberto ? 'saiu-da-caixa' : 'entregue', em: agora,
182
+ motivo: aberto ? 'a caixa de saída soltou a entrega sem recibo; responda pelo claude attach' : null })
183
+ }
184
+ return saida.slice(-MAXIMO_DE_ENTREGAS)
185
+ }
186
+
187
+ /** A thread do ledger que mudou, pelos caminhos que a ponte vigia (`.orkastery/threads/<thread>/ledger.jsonl`). */
188
+ export function threadDoLedger(caminho: unknown): string | null {
189
+ if (typeof caminho !== 'string') return null
190
+ const m = /\.orkastery\/threads\/([^/]+)\/ledger\.jsonl$/.exec(caminho)
191
+ return m && ID_DE_THREAD.test(m[1]) ? m[1] : null
192
+ }
193
+
194
+ function daThread(entregas: readonly MensageiroEntrega[], um: string, varios: (n: number) => string): string {
195
+ return entregas.length === 1 ? `${um} ${entregas[0].thread}` : varios(entregas.length)
196
+ }
197
+
198
+ /**
199
+ * A linha da faixa (D7 do plano dos mods): o que nao chegou e precisa do dono vem primeiro; depois o que esta a caminho;
200
+ * depois o que acabou de ser entregue. Sem nada disso, a linha sai da faixa.
201
+ */
202
+ export function textoDaFaixa(dono: MensageiroDono, agora: number): string | undefined {
203
+ const falhas = dono.entregas.filter(e => e.estado === 'desistiu' || e.estado === 'saiu-da-caixa')
204
+ if (falhas.length) return falhas.length === 1
205
+ ? `a resposta para a ${falhas[0].thread} não chegou; responda pelo claude attach` : `${falhas.length} respostas não chegaram; abra /mensageiro`
206
+ // Sem recibo, a resposta pode ter entrado na conversa: o dono confere antes de responder de novo.
207
+ const semRecibo = dono.entregas.filter(e => e.estado === 'sem-recibo')
208
+ if (semRecibo.length) return semRecibo.length === 1
209
+ ? `a resposta para a ${semRecibo[0].thread} ficou sem recibo; confira pelo claude attach` : `${semRecibo.length} respostas sem recibo; abra /mensageiro`
210
+ const vivas = dono.entregas.filter(e => VIVOS.includes(e.estado))
211
+ if (vivas.length) return daThread(vivas, 'resposta a caminho da', n => `${n} respostas a caminho das sessões de fase`)
212
+ const entregues = dono.entregas.filter(e => e.estado === 'entregue' && agora - e.em <= FAIXA_DA_ENTREGA_MS)
213
+ if (entregues.length) return daThread(entregues, 'resposta entregue à', n => `${n} respostas entregues às sessões de fase`)
214
+ return undefined
215
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "modules": ["./register.tsx"]
3
+ }