@orkastery/cli 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +86 -65
  3. package/adapters/README.md +30 -15
  4. package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
  5. package/adapters/claude-code/README.md +110 -8
  6. package/adapters/claude-code/commands/check.md +4 -3
  7. package/adapters/claude-code/commands/goal.md +3 -2
  8. package/adapters/claude-code/commands/master.md +3 -2
  9. package/adapters/claude-code/commands/onboarding.md +21 -0
  10. package/adapters/claude-code/commands/ork.md +99 -27
  11. package/adapters/claude-code/hooks/hooks.json +6 -1
  12. package/adapters/claude-code/hooks/ork-guard.js +1 -1
  13. package/adapters/claude-code/hooks/ork-sensor.js +66 -0
  14. package/adapters/codex/skills/ork/SKILL.md +57 -0
  15. package/adapters/hermes/README.md +161 -0
  16. package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
  17. package/adapters/hermes/bin/ork-brain.sh +4 -0
  18. package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
  19. package/adapters/hermes/bin/ork-maestro.sh +6 -0
  20. package/adapters/hermes/bin/ork-master-enviar.py +84 -0
  21. package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
  22. package/adapters/hermes/hermes.plugin.json +24 -4
  23. package/adapters/hermes/hitl-ingress/__init__.py +356 -0
  24. package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
  25. package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
  26. package/adapters/openclaw/README.md +136 -27
  27. package/adapters/openclaw/bin/ork-brain.sh +4 -0
  28. package/adapters/openclaw/construir.sh +19 -0
  29. package/adapters/openclaw/dist/hitl-ingress.js +199 -0
  30. package/adapters/openclaw/dist/index.js +437 -0
  31. package/adapters/openclaw/openclaw.plugin.json +39 -134
  32. package/adapters/openclaw/package.json +26 -0
  33. package/adapters/openclaw/src/hitl-ingress.ts +180 -0
  34. package/adapters/openclaw/src/index.ts +460 -0
  35. package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
  36. package/adapters/openclaw/tsconfig.json +15 -0
  37. package/assets/docs/markdownlint-cli2.jsonc +22 -0
  38. package/assets/docs/padroes/documentacao-de-produto.md +133 -0
  39. package/assets/docs/padroes/roadmap-de-produto.md +98 -0
  40. package/assets/docs/produto/README.md +14 -0
  41. package/assets/docs/produto/_modelo-feature.md +59 -0
  42. package/assets/docs/roadmap/README.md +14 -0
  43. package/assets/docs/roadmap/_modelo-item.md +73 -0
  44. package/assets/orkmind-native-schema.json +32 -0
  45. package/assets/orkmind_bridge.py +357 -0
  46. package/assets/orkmind_fixture.py +67 -0
  47. package/assets/orkmind_prospective.py +138 -0
  48. package/assets/reference-tariffs-i07.json +23 -0
  49. package/dist/adapters/claude-bg.js +488 -39
  50. package/dist/adapters/codex-controller-sensor.js +449 -0
  51. package/dist/adapters/codex-controller-worker.js +361 -0
  52. package/dist/adapters/codex-controller.js +252 -0
  53. package/dist/adapters/codex-events.js +205 -0
  54. package/dist/adapters/codex-question.js +26 -0
  55. package/dist/adapters/codex-runner.js +133 -0
  56. package/dist/adapters/codex.js +394 -0
  57. package/dist/agents-md.js +84 -0
  58. package/dist/auditoria.js +12 -9
  59. package/dist/auditrun.js +5 -4
  60. package/dist/board.js +174 -23
  61. package/dist/branch-de-estado.js +136 -0
  62. package/dist/canarios-hitl.js +177 -0
  63. package/dist/canarios-i43.js +543 -0
  64. package/dist/canarios-pulse.js +147 -0
  65. package/dist/canarios-sensores.js +129 -0
  66. package/dist/canarios.js +111 -2
  67. package/dist/catalogo.js +9 -0
  68. package/dist/ci.js +223 -0
  69. package/dist/ciclos.js +2 -1
  70. package/dist/claim-lint.js +64 -0
  71. package/dist/claims.js +60 -0
  72. package/dist/company-brain-capture.js +195 -0
  73. package/dist/company-brain-cli.js +123 -0
  74. package/dist/company-brain-client.js +61 -0
  75. package/dist/company-brain-contract.js +166 -0
  76. package/dist/company-brain-journal.js +192 -0
  77. package/dist/company-brain-mcp.js +33 -0
  78. package/dist/company-brain-migration.js +60 -0
  79. package/dist/company-brain-source.js +177 -0
  80. package/dist/company-brain-worker.js +18 -0
  81. package/dist/conducao-texto.js +61 -0
  82. package/dist/conducao.js +876 -0
  83. package/dist/contrato-publico.js +39 -0
  84. package/dist/creation-operation-store.js +251 -0
  85. package/dist/creation-operation.js +148 -0
  86. package/dist/decisao-autonoma.js +183 -0
  87. package/dist/delegation.js +79 -0
  88. package/dist/demo.js +120 -0
  89. package/dist/docs.js +828 -0
  90. package/dist/doctor.js +184 -25
  91. package/dist/entrega-pr.js +117 -0
  92. package/dist/escopo-escrita.js +71 -0
  93. package/dist/estado-thread.js +222 -0
  94. package/dist/evalrunner.js +12 -0
  95. package/dist/fabrica-estado.js +329 -0
  96. package/dist/fabrica-publicar.js +76 -0
  97. package/dist/fix.js +22 -1
  98. package/dist/gates.js +59 -11
  99. package/dist/handoff.js +39 -23
  100. package/dist/hitl-canais.js +333 -0
  101. package/dist/hitl-classificacao.js +131 -0
  102. package/dist/hitl-contract.js +465 -0
  103. package/dist/hitl-estado.js +136 -0
  104. package/dist/hitl-gates.js +554 -0
  105. package/dist/hitl-ingress-receipt.js +382 -0
  106. package/dist/hitl-local-atestado.js +57 -0
  107. package/dist/hitl-local-receipt.js +328 -0
  108. package/dist/hitl-local.js +143 -0
  109. package/dist/hitl-lock.js +139 -0
  110. package/dist/hitl-lote.js +223 -0
  111. package/dist/hitl-native-offer.js +97 -0
  112. package/dist/hitl-native.js +65 -0
  113. package/dist/hitl-presentation.js +209 -0
  114. package/dist/hitl-public-receipt.js +176 -0
  115. package/dist/hitl-resumo.js +209 -0
  116. package/dist/hitl-sessions.js +475 -0
  117. package/dist/hitl.js +711 -0
  118. package/dist/horario.js +269 -0
  119. package/dist/hosts.js +198 -22
  120. package/dist/index.js +1741 -94
  121. package/dist/indice.js +99 -0
  122. package/dist/init.js +28 -3
  123. package/dist/integracoes-locais.js +17 -0
  124. package/dist/leases.js +65 -21
  125. package/dist/ledger-stats.js +272 -0
  126. package/dist/ledger.js +109 -2
  127. package/dist/licoes.js +221 -0
  128. package/dist/liveness.js +218 -0
  129. package/dist/maestro-actions.js +51 -0
  130. package/dist/maestro-authority.js +152 -0
  131. package/dist/maestro-cli.js +97 -0
  132. package/dist/maestro-contract.js +55 -0
  133. package/dist/maestro-discovery.js +132 -0
  134. package/dist/maestro-runtime.js +268 -0
  135. package/dist/maestro-snapshot.js +86 -0
  136. package/dist/maestro-sources.js +224 -0
  137. package/dist/manifest.js +165 -6
  138. package/dist/maquina.js +102 -0
  139. package/dist/master-audit.js +101 -0
  140. package/dist/master-batch.js +43 -0
  141. package/dist/master-digest.js +149 -0
  142. package/dist/master-migracao.js +155 -0
  143. package/dist/master.js +361 -77
  144. package/dist/mcp-artifacts.js +234 -0
  145. package/dist/mcp-git.js +433 -0
  146. package/dist/mcp-install.js +310 -0
  147. package/dist/mcp-maestro.js +25 -0
  148. package/dist/mcp-server.js +469 -0
  149. package/dist/mcp-ship.js +436 -0
  150. package/dist/mcp-verify.js +173 -0
  151. package/dist/memoria-humana.js +207 -0
  152. package/dist/memoria.js +314 -78
  153. package/dist/memory-migration.js +279 -0
  154. package/dist/memory-prospective.js +148 -0
  155. package/dist/modos-migracao.js +191 -0
  156. package/dist/modos.js +151 -15
  157. package/dist/monitor-lock.js +110 -0
  158. package/dist/objective.js +449 -0
  159. package/dist/ocupacao.js +267 -0
  160. package/dist/onboarding.js +303 -0
  161. package/dist/orkmind.js +389 -90
  162. package/dist/orquestracao.js +96 -69
  163. package/dist/phase.js +612 -151
  164. package/dist/playbook-capabilities.js +150 -0
  165. package/dist/playbook-contracts.js +188 -0
  166. package/dist/policies.js +72 -0
  167. package/dist/portfolio-context.js +61 -0
  168. package/dist/portfolio.js +180 -0
  169. package/dist/preflight.js +207 -0
  170. package/dist/process-audit.js +112 -0
  171. package/dist/project-state.js +93 -0
  172. package/dist/prompts.js +25 -5
  173. package/dist/prova-minima.js +112 -0
  174. package/dist/pulse-cadencia.js +163 -0
  175. package/dist/pulse-consentimento.js +260 -0
  176. package/dist/pulse-delivery.js +323 -0
  177. package/dist/pulse-resposta.js +542 -0
  178. package/dist/pulse.js +262 -0
  179. package/dist/ratelimit.js +35 -2
  180. package/dist/recall.js +80 -3
  181. package/dist/redacao-saida.js +45 -0
  182. package/dist/redacao-url.js +66 -0
  183. package/dist/retry.js +640 -118
  184. package/dist/roadmap-reservas.js +243 -0
  185. package/dist/runtime-ambiente.js +38 -0
  186. package/dist/runtime-context.js +215 -0
  187. package/dist/runtime-profiles.js +869 -0
  188. package/dist/runtimes.js +103 -0
  189. package/dist/sandbox.js +9 -0
  190. package/dist/session-events.js +203 -0
  191. package/dist/session-watcher-claude.js +637 -0
  192. package/dist/session-watcher.js +700 -0
  193. package/dist/sessoes-adopt.js +154 -0
  194. package/dist/sessoes-inventario.js +159 -0
  195. package/dist/sessoes.js +16 -35
  196. package/dist/setup.js +691 -0
  197. package/dist/ship.js +168 -19
  198. package/dist/slug.js +1 -1
  199. package/dist/thread-close.js +115 -0
  200. package/dist/thread.js +142 -28
  201. package/dist/tokens.js +1 -1
  202. package/dist/util.js +4 -2
  203. package/dist/verify-sandbox.js +265 -0
  204. package/dist/verify.js +270 -25
  205. package/dist/versao.js +60 -0
  206. package/dist/worktree.js +31 -2
  207. package/dist/write-activation.js +291 -0
  208. package/dist/yaml.js +5 -1
  209. package/eval/casos/master-metrics.json +1 -1
  210. package/eval/casos/onboarding.json +102 -0
  211. package/eval/casos/orkastery-bootstrap.json +37 -3
  212. package/eval/casos/scope-check-capability-map.json +45 -7
  213. package/eval/casos/ship-release.json +3 -3
  214. package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
  215. package/eval/fixtures/b2-master-log/caso.json +1 -1
  216. package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
  217. package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
  218. package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
  219. package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
  220. package/eval/fixtures/fx-codex-dry/caso.json +18 -0
  221. package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
  222. package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
  223. package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
  224. package/eval/fixtures/fx-happy/caso.json +6 -4
  225. package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
  226. package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
  227. package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
  228. package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
  229. package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
  230. package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
  231. package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
  232. package/eval/fixtures/fx-omnicanal/caso.json +17 -0
  233. package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
  234. package/monitor/company-brain.cjs +17 -0
  235. package/monitor/pulse-scope.cjs +45 -0
  236. package/monitor/pulse.cron +18 -0
  237. package/monitor/varredura-pulse.sh +27 -0
  238. package/package.json +28 -7
  239. package/references/definition-of-done.md +2 -2
  240. package/schemas/claims.schema.json +25 -0
  241. package/schemas/company-brain.schema.json +1158 -0
  242. package/schemas/creation-operation.schema.json +365 -0
  243. package/schemas/maestro-snapshot.schema.json +2716 -0
  244. package/skills/README.md +3 -3
  245. package/skills/core/onboarding/SKILL.md +50 -0
  246. package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
  247. package/skills/core/thread-state/SKILL.md +3 -1
  248. package/skills/governance/decision-triage/SKILL.md +4 -4
  249. package/skills/governance/narrative-guardian/SKILL.md +1 -1
  250. package/skills/governance/roadmap-keeper/SKILL.md +1 -1
  251. package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
  252. package/skills/observability/thread-tracing/SKILL.md +1 -1
  253. package/skills/phases/check-quality/SKILL.md +2 -2
  254. package/skills/phases/goal-definition/SKILL.md +1 -1
  255. package/skills/phases/master-metrics/SKILL.md +9 -7
  256. package/skills/phases/plan-specification/SKILL.md +1 -1
  257. package/skills/phases/ship-release/SKILL.md +1 -1
@@ -1,37 +1,109 @@
1
1
  ---
2
- description: Painel do Orkastery: estado das threads, escalonador, modos e o que a maquina permite agora.
3
- argument-hint: "[board|plan|doctor|modos]"
4
- allowed-tools: Bash(ork:*), Read
2
+ description: Reconhece orkastery maestro e conduz pedidos, retomadas e status na conversa com o Maestro/Builder.
3
+ argument-hint: "[pedido em linguagem natural|thread|status|board|plan|doctor|modos]"
4
+ allowed-tools: Bash(ork:*), Read, mcp__orkastery__ork_thread_status, mcp__orkastery__ork_phase_list, mcp__orkastery__ork_hitl_pending, mcp__orkastery__ork_observe, mcp__orkastery__ork_artifact_read, mcp__orkastery__ork_claims_list, mcp__orkastery__ork_git_status, mcp__orkastery__ork_thread_new, mcp__orkastery__ork_phase_run, mcp__orkastery__ork_preflight
5
5
  ---
6
6
 
7
- # /ork
7
+ # /orkastery:ork
8
8
 
9
- Entrada geral do adaptador. Nao conduz fase nenhuma: mostra o estado e diz qual comando responde
10
- pela intencao do builder.
9
+ Entrada nativa do plugin ativado no projeto: `/orkastery:ork`. A copia dos arquivos pelo
10
+ instalador ainda exige ativacao nativa; `/ork` sozinho nao e um alias garantido.
11
11
 
12
- ## O que este comando faz
12
+ Esta entrada ja esta carregada pela invocacao do dono. Nao invoque `Skill(orkastery:ork)`
13
+ nem outro comando para recarregar estas instrucoes. Conduza o pedido com as ferramentas
14
+ ja permitidas.
15
+ As oito consultas MCP e criar/despachar thread desta entrada valem no turno da invocacao;
16
+ nao persistem por si nas proximas mensagens. Criar/despachar exige demanda e escopo autorizados
17
+ pelo dono, modo resolvido e preflight do nucleo. Nao recarregue a skill para obter permissoes.
18
+ Esses grants nao ativam MCP, nao autorizam outras mutacoes nem aprovam gates ou respostas humanas.
19
+
20
+ Leia o contrato comum com `Read`, sem chamar `Skill` para carregar o bootstrap:
21
+ @${CLAUDE_PLUGIN_ROOT}/skills/core/orkastery-bootstrap/SKILL.md
22
+
23
+ Se o contrato ja estiver no contexto, use-o sem reler. Se o arquivo estiver ausente,
24
+ informe instalacao incompleta; nao invente outro fluxo.
25
+
26
+ Entrada conversacional do Orkastery. Use o contrato comum para conduzir a intencao do dono pelo nucleo. Nao limite um pedido de execucao a indicar outro
27
+ slash command. Se recebeu um pedido e possui as ferramentas necessarias, execute o roteamento.
28
+ Os comandos de fase continuam disponiveis como atalhos; o dono nao precisa conhece-los.
29
+
30
+ ## Reconhecer a intencao
31
+
32
+ A frase literal `orkastery maestro`, em sessão limpa, pede leitura do panorama.
33
+ Descubra a ferramenta com `ToolSearch` em `select:mcp__orkastery__ork_maestro`,
34
+ então consulte o projeto fixado. Não abre thread nem despacho por consulta.
35
+ Projeto ausente/ambíguo exige resolver o contexto permitido pelo núcleo.
36
+ Se já recebeu fase/thread/worktree, execute o bloco recebido, sem recursão.
37
+ MCP ausente ou autenticação negada permanece impedimento; não troque runtime,
38
+ provider ou sandbox. A consulta CLI `ork maestro --json` não concede mutações.
39
+
40
+ Usabilidade HITL é prioridade máxima: tópicos, recomendação e opções rotuladas,
41
+ UUID interno e cancelamento preservado. A condutora usa
42
+ `mcp__orkastery__ork_request_decision`; o filho nunca responde em nome do dono.
43
+
44
+ | Pedido do dono | Acao do agente |
45
+ |---|---|
46
+ | Demanda nova | Resolva o modo pelo nucleo, confira o preflight e abra/despache a thread correspondente. |
47
+ | "Continue" ou thread/roadmap existente | Leia o estado e o ultimo resultado; retome o proximo passo autorizado, sem duplicar despacho. |
48
+ | "Como esta?" ou status | Consulte a thread conhecida; apresente progresso comprovado, impedimento e proximo passo. |
49
+ | Decisao ou resposta | Correlacione com o pedido/gate apresentado, transporte pelo caminho suportado e confira o resultado. |
50
+ | Onboarding | Use a pauta de `ork onboarding` e retome as etapas existentes. |
51
+ | board, plan, doctor ou modos | Execute a consulta correspondente e interprete o resultado para a intencao do dono. |
52
+
53
+ ## Fontes do nucleo
54
+
55
+ Priorize as ferramentas MCP do Orkastery quando descobertas nesta sessao, com o projeto
56
+ fixado pelo servidor. No Claude, o servidor instalado `orkastery` expoe nomes completos como
57
+ `mcp__orkastery__ork_thread_status`. Se houver ferramentas adiadas, use `ToolSearch` com
58
+ `select:mcp__orkastery__ork_thread_status,mcp__orkastery__ork_artifact_read` para essas leituras;
59
+ para outra operacao, selecione seu nome completo realmente exposto. Nao tente `select:ork_thread_status`
60
+ nem adivinhe outro namespace. Ativacao inicial do MCP e consentimento do dono continuam nativos. `ork_thread_status`, `ork_phase_list` e `ork_hitl_pending` leem
61
+ estado; `ork_thread_new` e `ork_phase_run` abrem/despacham; `ork_observe` consulta a sessao
62
+ nativa despachada. Quando pausa/escalacao real permitir e faltar pedido, use
63
+ `ork_gate_request(threadId, motivo?)`; nunca crie pedido para uma consulta de status.
64
+ `ork_request_decision(threadId, pedidoId)` apresenta o dialogo ao dono:
65
+ a resposta vem pelo host, nunca por argumento de resposta ou identidade inventada pelo modelo.
66
+
67
+ As consultas CLI abaixo continuam uteis quando a ferramenta correspondente nao esta disponivel:
13
68
 
14
69
  ```bash
15
- ork doctor # o que vale nesta maquina agora (sai != 0 se bloqueado)
16
- ork board # todas as threads em uma visao
17
- ork board plan # quem avanca agora, quem espera e por que
18
- ork modos # a tabela dos 5 modos de conducao por #TAG
19
- ork master --batch # o que fechou e ainda espera score humano
70
+ ork thread status <thread>
71
+ ork phase list <thread>
72
+ ork pulse --json
73
+ ork board plan
74
+ ork doctor
75
+ ork modos
76
+ ork master
20
77
  ```
21
78
 
22
- ## Roteamento
79
+ Use apenas as consultas necessarias. Nao rode todas a cada mensagem. O preflight pertence ao
80
+ inicio de despacho ou a uma mudanca relevante de ambiente; uma pergunta de status nao reinicia
81
+ onboarding nem trabalho. Se a thread estiver ambigua, esclareca antes de alterar seu estado.
82
+ Pausas listadas nos blocos do modo sao previstas. Para dizer que o dono precisa responder
83
+ agora, identifique uma pendencia atual no estado/ultimo resultado da thread, com gate,
84
+ pedido ou evento correspondente. Uma thread nova sem fase executada nao aguarda premissas
85
+ so porque o bloco f12 do modo preve essa pausa.
23
86
 
24
- | O builder quer | Comando |
25
- |---|---|
26
- | abrir demanda nova | `/goal <pedido com #TAG>` |
27
- | especificar | `/plan <thread>` |
28
- | implementar | `/go <thread>` |
29
- | verificar | `/check <thread>` |
30
- | entregar | `/ship <thread>` |
31
- | fechar e dar o score | `/master <thread>` |
32
-
33
- ## Regras do adaptador
34
-
35
- - **Zero regra de negocio aqui.** Este comando le e apresenta; quem decide e o humano e quem
36
- verifica e o `ork`.
37
- - Um `fail` do `ork doctor` para o ciclo antes de ele abrir, e isso e economia, nao obstaculo.
87
+ ## Continuidade
88
+
89
+ Preserve modo, decisoes e autorizacoes da thread/sessao. Prossiga com trabalho autorizado em
90
+ vez de encerrar com "posso continuar?". Pergunte quando o modo ou uma ambiguidade real exigir
91
+ intervencao do dono e explique o que a resposta destrava. Nao aprove gates em nome dele.
92
+
93
+ Com despacho existente, consulte `ork_observe` e trate a espera nativa atual. Nao substitua
94
+ observacao por loops longos de `phase list`, sleeps ou regex de conclusao sobre historico.
95
+ Se faltar MCP e o sandbox impedir `.git`, informe instalacao pendente do transporte nativo;
96
+ nao repita a mutacao negada nem altere o sandbox. Diferencie permissao nativa de gate do Ork.
97
+
98
+ Antes do despacho, use `ork_preflight({modo})`; alternativa CLI: `ork doctor --modo <modo>`. A sonda segue setup por bloco, sem inventário global, e não comprova autenticação, gates ou entrega.
99
+ Para HEADs e estado Git, consulte `ork_git_status`; nao invente SHAs nem substitua o transporte por Bash Git.
100
+ O perfil filho `worktree` e opt-in da instalacao do projeto; nao o habilite por argumento de ferramenta
101
+ ou edicao de configuracao para contornar bloqueio. Preserve o perfil configurado e as permissoes nativas.
102
+
103
+ A sessao condutora despacha e acompanha; uma sessao que ja recebeu uma fase executa essa fase,
104
+ sem redespachar a si mesma. O nucleo continua validando fases, evidencias e gates.
105
+
106
+ Mostre o resultado, o ultimo progresso confirmado e o que acontece agora. Registre checkpoint
107
+ antes de uma retomada futura; nao prometa notificacao fora das capacidades da sessao.
108
+ Conclua com entrega e validacao efetivas, distinguindo o que ainda depende de CHECK, SHIP ou
109
+ score humano. A lista de comandos executados e diagnostico auxiliar, nao a experiencia do dono.
@@ -12,6 +12,11 @@
12
12
  }
13
13
  ]
14
14
  }
15
- ]
15
+ ],
16
+ "PermissionRequest": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
17
+ "Notification": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
18
+ "Stop": [{ "hooks": [{ "type": "command", "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/ork-sensor.js\"", "timeout": 5 }] }],
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 }] }]
16
21
  }
17
22
  }
@@ -52,7 +52,7 @@ const BLOQUEIOS = [
52
52
  nome: 'reset-destrutivo',
53
53
  regex: /\bgit\s+(?:reset\s+--hard|clean\s+-[a-zA-Z]*[fd]|checkout\s+--\s+\.)/,
54
54
  motivo: 'descarte em massa apaga trabalho nao commitado sem deixar rastro',
55
- caminho: 'descarte por arquivo, ou registre a decisao antes: ork gate approve <thread> <sobre> --por <quem>',
55
+ caminho: 'descarte por arquivo; se o descarte amplo for mesmo necessario, peca a decisao ao dono: ork gate request <thread>',
56
56
  },
57
57
  {
58
58
  nome: 'remocao-recursiva-ampla',
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Sensor passivo: stdout vazio e exit 0 não aprovam nem negam uma ferramenta.
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { spawnSync } = require('node:child_process');
7
+ const { createHash, randomUUID } = require('node:crypto');
8
+
9
+ function executar() {
10
+ const limite = 1024 * 1024;
11
+ const buffer = Buffer.alloc(limite + 1);
12
+ let bytes = 0;
13
+ while (bytes <= limite) {
14
+ const n = fs.readSync(0, buffer, bytes, buffer.length - bytes, null);
15
+ if (!n) break;
16
+ bytes += n;
17
+ if (bytes > limite) return;
18
+ }
19
+ const h = JSON.parse(buffer.subarray(0, bytes).toString('utf8'));
20
+ if (!h || typeof h.cwd !== 'string' || !path.isAbsolute(h.cwd) ||
21
+ typeof h.session_id !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(h.session_id)) return;
22
+ const tipos = { PermissionRequest: 'permission_request', Notification: 'notification',
23
+ Stop: 'stop', SubagentStop: 'subagent_stop', PostToolUse: 'heartbeat' };
24
+ let tipo = tipos[h.hook_event_name];
25
+ if (!tipo) return;
26
+ const payload = { observedAt: new Date().toISOString() };
27
+ if (h.hook_event_name === 'Notification') payload.notificationType = h.notification_type;
28
+ // tool_use_id identifica replay da mesma ferramenta. Sem id do protocolo,
29
+ // cada invocação é uma ocorrência; stat do transcript não identifica eventos.
30
+ payload.eventId = typeof h.tool_use_id === 'string'
31
+ ? createHash('sha256').update(JSON.stringify([h.hook_event_name, h.tool_use_id, h.agent_id])).digest('hex')
32
+ : randomUUID();
33
+ if (h.hook_event_name === 'PostToolUse' && h.tool_name === 'Bash') {
34
+ const resposta = h.tool_response;
35
+ if (resposta?.interrupted || (resposta?.exit_code !== undefined && resposta.exit_code !== 0) ||
36
+ (resposta?.exitCode !== undefined && resposta.exitCode !== 0)) return;
37
+ const comando = h.tool_input?.command;
38
+ const saida = typeof resposta === 'string' ? resposta : resposta?.stdout;
39
+ const shaCurto = typeof saida === 'string' ? /^\[[^\]\n]+ ([a-f0-9]{7,64})\]/m.exec(saida)?.[1] : null;
40
+ if (typeof comando === 'string' && /(?:^|[;&|\n])\s*git\s+commit(?:\s|$)/.test(comando) && shaCurto) {
41
+ const git = spawnSync('git', ['log', '-1', '--format=%H'], {
42
+ cwd: h.cwd, encoding: 'utf8', timeout: 1000, maxBuffer: 4096,
43
+ });
44
+ const sha = git.stdout?.trim();
45
+ if (git.status === 0 && /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(sha) && sha.startsWith(shaCurto)) {
46
+ tipo = 'commit'; payload.commit = sha;
47
+ }
48
+ }
49
+ }
50
+ const r = spawnSync(process.env.ORK_SENSOR_CLI || 'ork',
51
+ ['sessions', 'event', '--tipo', tipo, '--sessao', h.session_id], {
52
+ cwd: h.cwd, input: JSON.stringify(payload), encoding: 'utf8', timeout: 3000,
53
+ maxBuffer: 32768, windowsHide: true,
54
+ });
55
+ if (r.status !== 0) {
56
+ // Recusa conhecida não identifica o papel da sessão nem comprova ingestão.
57
+ const semVinculo = r.status === 1 && !r.error && !r.stdout?.trim() &&
58
+ r.stderr?.trim() === 'evento recusado: sessão desconhecida; confira ork thread status';
59
+ process.stderr.write(semVinculo
60
+ ? 'ork sensor: sessão sem fase vinculada; evento não ingerido. Se foi despachada pelo Ork, confira o vínculo com ork thread status.\n'
61
+ : 'ork sensor: evento não ingerido; confira o CLI e a sessão registrada.\n');
62
+ }
63
+ }
64
+ try { executar(); }
65
+ catch { process.stderr.write('ork sensor: entrada inválida ou sensor indisponível.\n'); }
66
+ process.exitCode = 0;
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: ork
3
+ description: "Reconhece orkastery maestro em sessão limpa: consulta panorama, retoma threads e apresenta decisões nativas na conversa Codex com o Maestro/Builder."
4
+ license: MIT
5
+ ---
6
+
7
+ # Orkastery no Codex
8
+
9
+ Ao receber literalmente `orkastery maestro`, descubra `ork_maestro` no namespace
10
+ efetivamente exposto e consulte o projeto fixado pelo MCP. A frase pede panorama,
11
+ sem abrir trabalho. Siga a seleção de contexto e os limites do bootstrap comum.
12
+ Sem MCP, a consulta `ork maestro --json` continua somente leitura se o CLI estiver
13
+ disponível; mutações sem transporte nativo permanecem pendentes. Nunca use Bash Git
14
+ ou mudança de sandbox como substitutos. Sessão filha continua a fase recebida.
15
+
16
+ HITL tem prioridade máxima na apresentação: tópicos curtos, recomendação e opções
17
+ com rótulos claros; UUID interno. Use `ork_request_decision` na condutora e preserve
18
+ a resposta literal/cancelamento da elicitation. Não use pergunta genérica do agente
19
+ como aprovação de gate nem texto em toolargs como identidade humana.
20
+
21
+ Use a skill `orkastery-bootstrap` do mesmo catalogo instalado para conduzir o pedido.
22
+ O dono conversa sobre o objetivo; voce opera o nucleo `ork` e apresenta o resultado e o proximo
23
+ passo. Preserve o modo e as autorizacoes da thread. Se ja recebeu uma fase do Orkastery,
24
+ execute essa fase no escopo recebido, sem redespachar a si mesmo.
25
+
26
+ Quando descobertas, prefira as ferramentas MCP vinculadas ao projeto pelo servidor:
27
+ `ork_thread_status`, `ork_phase_list`, `ork_hitl_pending`, `ork_thread_new(nome, modo)`,
28
+ `ork_phase_run(threadId, fase, prompt, runtime?, model?, effort?, dryRun?)`, `ork_observe(threadId)`
29
+ e `ork_request_decision(threadId, pedidoId)`. Use o namespace efetivamente exposto, sem supor outro projeto.
30
+
31
+ - Pedido novo: resolva o modo pelo `ork`, confira preflight e abra/despache a thread.
32
+ - Retomada: leia `ork thread status <thread>` e o ultimo resultado em `ork phase list <thread>`;
33
+ continue o trabalho autorizado sem repetir onboarding, aprovacao ou implementacao.
34
+ - Status: apresente a evidencia da thread; `ork pulse --json` mostra quem precisa agir.
35
+ As pausas dos blocos do modo sao previstas: so diga "aguardando voce" com pendencia
36
+ humana atual comprovada no estado/ultimo resultado, identificando gate, pedido ou evento.
37
+ Uma thread nova sem fase executada nem pedido aberto ainda nao aguarda veredito.
38
+ - Despacho existente: consulte `ork_observe` para progresso ou bloqueio nativo atual;
39
+ nao espere conclusao com loops longos de `phase list`, sleeps ou regex sobre historico.
40
+ - Decisao: se pausa/escalacao real permitir e faltar pedido, use `ork_gate_request(threadId, motivo?)`;
41
+ nunca crie pedido por status. Correlacione thread/pedido e use `ork_request_decision` para apresentar
42
+ o dialogo nativo. A resposta e fornecida pelo dono ao host; nunca invente identidade humana
43
+ nem passe resposta como argumento do modelo. Permissao nativa nao aprova outro gate.
44
+ - Entrega: distinga o que foi implementado, validado, publicado e o que ainda esta pendente.
45
+
46
+ As fases, verificacoes e gates pertencem ao nucleo. As skills de fase e as checklists do
47
+ catalogo acompanham esta entrada. Se a skill comum estiver ausente, informe instalacao
48
+ incompleta em vez de inventar outra metodologia.
49
+
50
+ Use o executavel `ork` do projeto. Se nao estiver no PATH da sessao, o instalador registrou
51
+ este caminho: `{{ork_bin}}`. Nao altere configuracao global para resolver o PATH.
52
+
53
+ Sem MCP e com `.git` protegido pelo sandbox, informe instalacao pendente do transporte
54
+ nativo; nao repita a mutacao negada, nao crie a thread por fora e nao amplie o sandbox.
55
+
56
+ Nao ha monitor em segundo plano criado por esta skill. Acompanhe enquanto a sessao estiver
57
+ ativa e deixe checkpoint para a retomada, com ultimo resultado e proximo passo comprovados.
@@ -1,5 +1,30 @@
1
1
  # Adaptador Hermes
2
2
 
3
+ Na callback Discord autenticada, `/ork offer <thread> <pedido>` apresenta a
4
+ pergunta e a oferta nativa sem responder. O gateway assina uma prova efêmera de
5
+ host, sessão, identidade e mensagem e consulta `gate context --native-offer-stdin`.
6
+ Somente a prova aceita pelo núcleo anuncia o canal nativo disponível naquela
7
+ conversa, sem exigir Telegram. Chave/binding isolados ou payload do modelo não
8
+ comprovam callback. Testes simulados não substituem homologação live pós-SHIP.
9
+
10
+ ## Transporte determinístico do pulse
11
+
12
+ `bin/ork-pulse-enviar.py` chama a API `send_message_tool` do Hermes instalado e retorna
13
+ código 0 somente com `success: true`. Não abre chat nem chama modelo. Use o Python do
14
+ venv do Hermes e um destino explícito `telegram:chat_id[:topic_id]`:
15
+
16
+ ```json
17
+ {
18
+ "executavel": "/caminho/hermes-agent/venv/bin/python3",
19
+ "argumentos": ["/repo/adapters/hermes/bin/ork-pulse-enviar.py", "--target", "telegram:CHAT_ID", "--message", "{{mensagem}}"]
20
+ }
21
+ ```
22
+
23
+ Grave a configuração em `.orkastery/monitor/pulse-host.json`. `HERMES_HOME` e
24
+ `HERMES_AGENT_DIR` permitem localizar outra instalação; por padrão usa `~/.hermes`.
25
+ O adaptador carrega o ambiente do host internamente, sem imprimir credenciais. Marcadores
26
+ `MEDIA:` presentes no texto do runtime são neutralizados para não anexar arquivos locais.
27
+
3
28
  O Hermes vira **podio** do Orkastery: uma skill roteadora fina, um plugin que a declara e um script
4
29
  que abre thread a partir do pedido cru do builder.
5
30
 
@@ -18,6 +43,15 @@ ork adapter install hermes --dry-run # lista o que seria escrito
18
43
  | `skills/orkastery-devmaster/SKILL.md` | O roteador: le a #TAG, chama o `ork`, apresenta os gates |
19
44
  | `hermes.plugin.json` | Declara a skill, o binario do `ork` e as tags de conducao |
20
45
  | `bin/ork-abrir-thread.sh` | Abre a thread com o modo lido do pedido, em um comando |
46
+ | `bin/ork-brain.sh` | Consulta o Company Brain pelo contrato e identidade autenticada do OrkMind |
47
+
48
+ ## Tickets `obj-*` aposentados
49
+
50
+ `ork_objective_status` e `ork_objective_message` sairam com o `ork objective` na I-43: o nucleo
51
+ recusa qualquer subcomando com `objective.aposentado` e saida != 0. O estado de uma entrega vem de
52
+ `ork thread status <thread>`; os ciclos ligados a um produto, projeto ou iniciativa, de
53
+ `ork portfolio inspect <id> --json`. Mensagem de conversa continua sem aprovar gate: a decisao do
54
+ dono passa pelo `/ork gate <thread> <pedido> <resposta>` correlacionado.
21
55
 
22
56
  ## O encolhimento, que e o ponto
23
57
 
@@ -29,6 +63,31 @@ real roda antes e depois; o que mudou e quem garante.
29
63
  Se esta skill comecar a crescer de novo com metodologia, isso e bandeira vermelha: a regra nova
30
64
  pertence ao nucleo, com teste, e nao a esta prosa.
31
65
 
66
+ ## Contas por runtime (I-33)
67
+
68
+ Este host tem superfície CLI, e a paridade com os hosts MCP vem pelos mesmos comandos do
69
+ núcleo; a superfície MCP de `accounts` não existe neste ciclo (o `add` é interativo e local, e
70
+ a leitura de estado já sai de `ork_observe`).
71
+
72
+ ```bash
73
+ ork accounts list [--json] # perfis por runtime, sem segredo
74
+ ork accounts add <id> --runtime claude-bg|codex --dir <diretorio>
75
+ ork accounts check [<id>] # confere o login pelo proprio CLI
76
+ ork accounts remove <id> # desativa; diretorio e login ficam
77
+ ork setup <modo> --bloco N --fallback codex:<modelo>
78
+ ```
79
+
80
+ O login roda no terminal do operador, pelo próprio CLI do runtime com o env do perfil; o
81
+ adaptador nunca recebe, guarda ou repassa credencial, e a conversa nunca é canal de login.
82
+ Quando uma conta esgota a cota, o crédito ou o limite do plano, ou perde o login, o
83
+ `ork retry run` rotaciona e grava `runtime_profile_rotated`; o host só apresenta o evento e a
84
+ pendência humana quando houver. A troca para outro perfil do mesmo runtime por esgotamento vem
85
+ ligada por padrão desde a decisão do dono de 19/09/2026
86
+ (`runtime_profiles.rotate_same_runtime_on_quota: true`; `false` desliga), vale só para perfis
87
+ que o operador cadastrou e autenticou pelo CLI oficial, para contas que ele tem direito de usar
88
+ sob os termos do provedor, e nunca acontece no rate limit comum, que espera a janela na fila
89
+ (ver `SECURITY.md` e `docs/guias/verificacao.md` na raiz do repositório).
90
+
32
91
  ## Os 3 pitfalls de instalacao
33
92
 
34
93
  1. **`ork` fora do PATH do Hermes.** O host costuma rodar com um ambiente mais enxuto que o do
@@ -43,3 +102,105 @@ pertence ao nucleo, com teste, e nao a esta prosa.
43
102
  3. **Validar `allowed_modes` no host.** Um host que recusa o modo antes de chamar o `ork` recusa
44
103
  com a regra que ele tem em cache, nao com a do manifesto do projeto. Deixe o
45
104
  `ork thread new` recusar: o erro vem tipado, com a lista permitida do projeto certo.
105
+
106
+ ## Transporte do digest MASTER
107
+
108
+ `bin/ork-master-enviar.py --target telegram:<chat_id>[:<topico>]` recebe no stdin uma
109
+ página JSON `ork.master-digest-page/v1`, com `texto` e `opcoes`. Usa a configuração Telegram
110
+ do Hermes e só devolve `success: true` quando recebe `message_id`. Um erro não imprime
111
+ credencial nem resposta bruta da API. O transporte não executa comandos do Ork.
112
+
113
+ As opções são um teclado de respostas: o toque envia o texto escolhido como mensagem do
114
+ humano pelo gateway já autenticado. Não há callback privado para o host interpretar.
115
+ O núcleo gera o texto com thread, classe e identificador da proposta, e o host encaminha
116
+ a resposta ao comando de ratificação com o nome do humano autenticado. Enviar a página
117
+ não ratifica nada. Cada página oferece no máximo doze opções e cabe em 3.900 unidades UTF-16.
118
+
119
+ Contrato do teclado: [Telegram ReplyKeyboardMarkup](https://core.telegram.org/bots/api#replykeyboardmarkup).
120
+ Prova local: `python3 -m unittest discover -s adapters/hermes/test -p master_transport_test.py`.
121
+
122
+ ## Respostas HITL no Telegram
123
+
124
+ O gateway autenticado entrega o update original por stdin a `bin/ork-hitl-answer.py ork_gate_answer <thread> <pedido>` ou `ork_session_answer`. Configure `ORK_BIN`, `ORK_HITL_TELEGRAM_USERS` e `ORK_HITL_TELEGRAM_CHATS` com os ids permitidos. Responda ao alerta que contém a linha `ork-hitl <thread> <pedido>`; botões usam `ork:<thread>:<pedido>:<número>`. O transporte recusa bots, chat/usuário não autorizado e resposta sem correlação. O núcleo decide sobre prazo, modo e validade do pedido.
125
+
126
+ O script deve receber eventos diretamente do gateway, cuja autenticação do Telegram é a fronteira de confiança. JSON criado por um agente não é evidência humana. O canário usa um transporte controlado; ele não mede a rede Telegram real. Para aposentar `ork-watchdog-5min`, desative o job no agendador do host e guarde o recibo; nenhum watchdog deve chamar aprovação em nome do builder.
127
+
128
+ Verificação: `python3 -m unittest discover -s adapters/hermes/test -p hitl_answer_test.py -v`.
129
+
130
+ ## Confirmação pelo plugin nativo HITL
131
+
132
+ O plugin `hitl-ingress/` recebe `/ork gate <thread> <pedido> <resposta>` e
133
+ `/ork session <thread> <pedido> <resposta>` em `pre_gateway_dispatch`. Esse hook
134
+ instalado é **síncrono e anterior à autenticação do gateway**: o callback valida
135
+ `MessageEvent`/`telegram.Message`, a autorização do host, usuário, chat, bot,
136
+ texto/id coincidentes, encaminhamento, data de até 60 s e configuração HMAC.
137
+ Todo comando `/ork ` é consumido com `action: skip`, inclusive quando recusado.
138
+ Sem loop ativo, ele recusa; não cria outro loop para o cliente HTTP do bot.
139
+
140
+ O callback reserva a mensagem e agenda o trabalho no loop do gateway. O CLI recebe
141
+ o envelope HMAC por stdin UTF-8, sem shell, em executor, com timeout de 10 s
142
+ (11 s incluindo espera pelo executor). Somente `ok: true`, `pedidoId` coincidente,
143
+ `estado` compatível e `repetida` booleano permitem confirmar o efeito. Sessão exige
144
+ também `sessionId`. A correlação de thread e mensagem vem da invocação CLI exata
145
+ e do envelope validado pelo núcleo; o recibo atual do CLI não ecoa esses campos.
146
+ A prova dirigida simula esse núcleo e não substitui seu CHECK integrado.
147
+
148
+ `Message.reply_text` usa o bot e chat do objeto autenticado no mesmo loop. Os únicos
149
+ textos são “Orkastery: resposta ao gate registrada pelo núcleo.” e “Orkastery:
150
+ resposta entregue à sessão pelo núcleo.” Não há quote da resposta humana,
151
+ parse mode, stdout ou exceção no conteúdo. Recusa de gate também é uma resposta
152
+ registrada; a mensagem não diz que houve aprovação. A confirmação tem orçamento
153
+ total de 3 s e os quatro timeouts do PTB explícitos. Sucesso exige um `Message`
154
+ nativo retornado, id positivo e bot/chat/texto correspondentes.
155
+
156
+ Retorno do hook e logs distinguem `effect` de `confirmation`:
157
+
158
+ | Situação | effect | confirmation |
159
+ |---|---|---|
160
+ | Validação recusada, sem loop ou limite atingido | unconfirmed | not_attempted |
161
+ | Trabalho agendado | pending | not_attempted |
162
+ | CLI iniciado sem recibo válido, timeout ou cancelamento | unknown | not_attempted |
163
+ | Recibo do núcleo válido; confirmação falhou ou ficou ambígua | confirmed | unknown |
164
+ | Recibo do núcleo e recibo Telegram válidos | confirmed | sent |
165
+
166
+ O retorno inicial é um retrato do agendamento; o log de conclusão registra o
167
+ resultado final com referência opaca derivada da identidade da mensagem. Não é
168
+ um ledger durável de entrega. Há no máximo 16 trabalhos pendentes e 1.024 reservas;
169
+ reservas concluídas podem ser removidas após 61 s, e mensagens com data vencida são
170
+ recusadas. O cache guarda apenas metadados, sem resposta humana, chave ou stdout.
171
+
172
+ Replay idêntico no mesmo processo apenas consulta o estado: não chama o CLI nem
173
+ repete a confirmação. Reutilizar a mesma mensagem com operação, resposta, usuário,
174
+ thread ou pedido divergente é recusado. Após restart/perda do cache, a idempotência
175
+ durável é do núcleo: `repetida: true` confirma o efeito, mas deixa o canal como
176
+ `unknown` e suprime novo envio. Timeout do CLI pode ocorrer depois do efeito;
177
+ timeout do Telegram pode ocorrer depois da entrega. Não há rollback do efeito,
178
+ retry automático ou garantia de entrega/leitura exatamente uma vez. Em particular,
179
+ um crash entre efeito e confirmação pode deixar o remetente sem confirmação.
180
+
181
+ Prova dirigida com ambiente removido antes dos imports, casas temporárias, bloqueio
182
+ de rede no verificador e transportes **SIMULADOS**. Exercita as classes, o loader,
183
+ a descoberta opt-in/cache e `invoke_hook` do Hermes instalado, além das regressões
184
+ Python deste adaptador. Não inicia gateway, não usa chaves operacionais nem API real:
185
+
186
+ ```sh
187
+ env -i HOME="$HOME" PATH=/usr/bin:/bin PYTHONDONTWRITEBYTECODE=1 "$HOME/.hermes/hermes-agent/venv/bin/python" adapters/hermes/test/verify_hitl_confirmation.py
188
+ ```
189
+
190
+ O comando imprime contagem, falhas, limites e hashes das fontes instaladas; falha
191
+ se faltar o contrato local, houver teste ignorado ou tentativa bloqueada de ler
192
+ segredo operacional/rede. Não exige build de core. O plano de instalação revisável,
193
+ hashes do pacote e preservação/rollback do agente Hermes instalado pertencem ao
194
+ checkpoint de instalação; instalação e aceite Telegram real são etapas posteriores.
195
+ # HITL nativo e Maestro
196
+
197
+ `orkastery maestro` consulta panorama por `ork_maestro`. Prioridade máxima da
198
+ conversa: tópicos, recomendação e escolhas claras, preservando resposta e cancelamento.
199
+ Telegram é opcional. O callback instalado `pre_gateway_dispatch` pode receber
200
+ Discord sem Telegram, com `discord.Message`, usuário autorizado, sessão existente
201
+ e binding privado `ORK_HITL_NATIVE_BINDING_HERMES`/`ORK_HITL_NATIVE_KEY_HERMES`.
202
+ Chaves e bindings nunca são publicados ao modelo ou herdados pela sessão filha.
203
+ Terminal/ACP sem callback de identidade homologado permanece indisponível; hooks de
204
+ aprovação de comando são observadores e não aprovam gates Orkastery.
205
+ O plugin lê o pedido pelo CLI do núcleo e responde na mesma conversa só após recibo.
206
+ Loader fixture não prova homologação live; instalação e sessão nova pós-SHIP são pendentes.
@@ -8,6 +8,8 @@
8
8
  # Uso: ork-abrir-thread.sh "<nome curto>" "<pedido inteiro do builder>" [--worktree auto]
9
9
 
10
10
  set -eu
11
+ # I-36 (D6): o adaptador declara o canal de conducao do Hermes; descreve a porta, nao da autoridade.
12
+ export ORK_CANAL="${ORK_CANAL:-hermes}"
11
13
 
12
14
  if [ "$#" -lt 2 ]; then
13
15
  echo "uso: ork-abrir-thread.sh \"<nome curto>\" \"<pedido do builder>\" [argumentos extras]" >&2
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ # Host routing only. Authenticated principal and grants belong to the transport.
3
+ set -eu
4
+ exec "{{ork_bin}}" brain "$@"
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+ """Responde HITL a partir de um update Telegram entregue pelo gateway autenticado."""
3
+ import argparse
4
+ import json
5
+ import os
6
+ import re
7
+ import subprocess
8
+ import sys
9
+
10
+
11
+ def lista_permitida(nome):
12
+ return {v.strip() for v in os.environ.get(nome, '').split(',') if v.strip()}
13
+
14
+
15
+ def argumentos(update, operacao, thread, pedido):
16
+ if operacao not in ('ork_gate_answer', 'ork_session_answer'):
17
+ raise ValueError('comando HITL inválido')
18
+ if not re.fullmatch(r'[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}', thread):
19
+ raise ValueError('thread inválida')
20
+ if not re.fullmatch(r'[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}', pedido):
21
+ raise ValueError('pedido inválido')
22
+ callback = update.get('callback_query')
23
+ mensagem = callback.get('message', {}) if callback else update.get('message', {})
24
+ remetente = callback.get('from', {}) if callback else mensagem.get('from', {})
25
+ usuario = str(remetente.get('id', ''))
26
+ chat = str(mensagem.get('chat', {}).get('id', ''))
27
+ if (not usuario or not chat or remetente.get('is_bot') is not False
28
+ or usuario not in lista_permitida('ORK_HITL_TELEGRAM_USERS')
29
+ or chat not in lista_permitida('ORK_HITL_TELEGRAM_CHATS')
30
+ or mensagem.get('forward_origin')):
31
+ raise ValueError('origem humana não autorizada pelo gateway')
32
+ marker = f'ork-hitl {thread} {pedido}'
33
+ if callback:
34
+ prefixo = f'ork:{thread}:{pedido}:'
35
+ dado = callback.get('data', '')
36
+ if not isinstance(dado, str) or not dado.startswith(prefixo):
37
+ raise ValueError('callback não corresponde ao pedido')
38
+ resposta = dado[len(prefixo):]
39
+ if not re.fullmatch(r'[1-9][0-9]?', resposta):
40
+ raise ValueError('opção de callback inválida')
41
+ referencia = callback.get('id')
42
+ else:
43
+ origem = mensagem.get('reply_to_message', {}).get('text', '')
44
+ if marker not in origem.splitlines():
45
+ raise ValueError('responda à mensagem do pedido HITL')
46
+ resposta = mensagem.get('text', '')
47
+ referencia = mensagem.get('message_id')
48
+ if (not isinstance(resposta, str) or not resposta.strip() or len(resposta) > 4096
49
+ or '\x00' in resposta or not referencia):
50
+ raise ValueError('resposta ou referência de mensagem inválida')
51
+ return ['gate' if operacao == 'ork_gate_answer' else 'sessions', 'answer', thread, pedido,
52
+ '--resposta-stdin', '--por', f'telegram:{usuario}',
53
+ '--mensagem', f'telegram:{chat}:{referencia}', '--origem', 'telegram'], resposta
54
+
55
+
56
+ def main():
57
+ parser = argparse.ArgumentParser(description=__doc__)
58
+ parser.add_argument('comando', choices=['ork_gate_answer', 'ork_session_answer'])
59
+ parser.add_argument('thread')
60
+ parser.add_argument('pedido')
61
+ args = parser.parse_args()
62
+ try:
63
+ # O gateway fornece o update original por stdin, nunca uma descrição criada por LLM.
64
+ bruto = sys.stdin.read(65537)
65
+ if len(bruto) > 65536:
66
+ raise ValueError('update excede limite')
67
+ argv, resposta = argumentos(json.loads(bruto), args.comando, args.thread, args.pedido)
68
+ result = subprocess.run([os.environ.get('ORK_BIN', 'ork'), *argv],
69
+ input=resposta, text=True, capture_output=True, timeout=55, check=False)
70
+ # O núcleo devolve um recibo sem repetir a resposta nem credenciais.
71
+ if result.returncode != 0:
72
+ print(json.dumps({'ok': False, 'erro': 'núcleo recusou a resposta', 'codigo': result.returncode}))
73
+ return 1
74
+ print(result.stdout.strip())
75
+ return 0
76
+ except (ValueError, TypeError, AttributeError, OSError, subprocess.TimeoutExpired):
77
+ print(json.dumps({'ok': False, 'erro': 'resposta HITL não confirmada'}))
78
+ return 1
79
+
80
+
81
+ if __name__ == '__main__':
82
+ sys.exit(main())
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ # Somente leitura; cwd é o projeto do host. Argumentos continuam dados.
3
+ set -eu
4
+ # I-36 (D6): o adaptador declara o canal de conducao do Hermes; descreve a porta, nao da autoridade.
5
+ export ORK_CANAL="${ORK_CANAL:-hermes}"
6
+ exec "${ORK_BIN:-{{ork_bin}}}" maestro --json "$@"