@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.
- package/LICENSE +1 -1
- package/README.md +86 -65
- package/adapters/README.md +30 -15
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
- package/adapters/claude-code/README.md +110 -8
- package/adapters/claude-code/commands/check.md +4 -3
- package/adapters/claude-code/commands/goal.md +3 -2
- package/adapters/claude-code/commands/master.md +3 -2
- package/adapters/claude-code/commands/onboarding.md +21 -0
- package/adapters/claude-code/commands/ork.md +99 -27
- package/adapters/claude-code/hooks/hooks.json +6 -1
- package/adapters/claude-code/hooks/ork-guard.js +1 -1
- package/adapters/claude-code/hooks/ork-sensor.js +66 -0
- package/adapters/codex/skills/ork/SKILL.md +57 -0
- package/adapters/hermes/README.md +161 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
- package/adapters/hermes/bin/ork-brain.sh +4 -0
- package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
- package/adapters/hermes/bin/ork-maestro.sh +6 -0
- package/adapters/hermes/bin/ork-master-enviar.py +84 -0
- package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +24 -4
- package/adapters/hermes/hitl-ingress/__init__.py +356 -0
- package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
- package/adapters/openclaw/README.md +136 -27
- package/adapters/openclaw/bin/ork-brain.sh +4 -0
- package/adapters/openclaw/construir.sh +19 -0
- package/adapters/openclaw/dist/hitl-ingress.js +199 -0
- package/adapters/openclaw/dist/index.js +437 -0
- package/adapters/openclaw/openclaw.plugin.json +39 -134
- package/adapters/openclaw/package.json +26 -0
- package/adapters/openclaw/src/hitl-ingress.ts +180 -0
- package/adapters/openclaw/src/index.ts +460 -0
- package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
- package/adapters/openclaw/tsconfig.json +15 -0
- package/assets/docs/markdownlint-cli2.jsonc +22 -0
- package/assets/docs/padroes/documentacao-de-produto.md +133 -0
- package/assets/docs/padroes/roadmap-de-produto.md +98 -0
- package/assets/docs/produto/README.md +14 -0
- package/assets/docs/produto/_modelo-feature.md +59 -0
- package/assets/docs/roadmap/README.md +14 -0
- package/assets/docs/roadmap/_modelo-item.md +73 -0
- package/assets/orkmind-native-schema.json +32 -0
- package/assets/orkmind_bridge.py +357 -0
- package/assets/orkmind_fixture.py +67 -0
- package/assets/orkmind_prospective.py +138 -0
- package/assets/reference-tariffs-i07.json +23 -0
- package/dist/adapters/claude-bg.js +488 -39
- package/dist/adapters/codex-controller-sensor.js +449 -0
- package/dist/adapters/codex-controller-worker.js +361 -0
- package/dist/adapters/codex-controller.js +252 -0
- package/dist/adapters/codex-events.js +205 -0
- package/dist/adapters/codex-question.js +26 -0
- package/dist/adapters/codex-runner.js +133 -0
- package/dist/adapters/codex.js +394 -0
- package/dist/agents-md.js +84 -0
- package/dist/auditoria.js +12 -9
- package/dist/auditrun.js +5 -4
- package/dist/board.js +174 -23
- package/dist/branch-de-estado.js +136 -0
- package/dist/canarios-hitl.js +177 -0
- package/dist/canarios-i43.js +543 -0
- package/dist/canarios-pulse.js +147 -0
- package/dist/canarios-sensores.js +129 -0
- package/dist/canarios.js +111 -2
- package/dist/catalogo.js +9 -0
- package/dist/ci.js +223 -0
- package/dist/ciclos.js +2 -1
- package/dist/claim-lint.js +64 -0
- package/dist/claims.js +60 -0
- package/dist/company-brain-capture.js +195 -0
- package/dist/company-brain-cli.js +123 -0
- package/dist/company-brain-client.js +61 -0
- package/dist/company-brain-contract.js +166 -0
- package/dist/company-brain-journal.js +192 -0
- package/dist/company-brain-mcp.js +33 -0
- package/dist/company-brain-migration.js +60 -0
- package/dist/company-brain-source.js +177 -0
- package/dist/company-brain-worker.js +18 -0
- package/dist/conducao-texto.js +61 -0
- package/dist/conducao.js +876 -0
- package/dist/contrato-publico.js +39 -0
- package/dist/creation-operation-store.js +251 -0
- package/dist/creation-operation.js +148 -0
- package/dist/decisao-autonoma.js +183 -0
- package/dist/delegation.js +79 -0
- package/dist/demo.js +120 -0
- package/dist/docs.js +828 -0
- package/dist/doctor.js +184 -25
- package/dist/entrega-pr.js +117 -0
- package/dist/escopo-escrita.js +71 -0
- package/dist/estado-thread.js +222 -0
- package/dist/evalrunner.js +12 -0
- package/dist/fabrica-estado.js +329 -0
- package/dist/fabrica-publicar.js +76 -0
- package/dist/fix.js +22 -1
- package/dist/gates.js +59 -11
- package/dist/handoff.js +39 -23
- package/dist/hitl-canais.js +333 -0
- package/dist/hitl-classificacao.js +131 -0
- package/dist/hitl-contract.js +465 -0
- package/dist/hitl-estado.js +136 -0
- package/dist/hitl-gates.js +554 -0
- package/dist/hitl-ingress-receipt.js +382 -0
- package/dist/hitl-local-atestado.js +57 -0
- package/dist/hitl-local-receipt.js +328 -0
- package/dist/hitl-local.js +143 -0
- package/dist/hitl-lock.js +139 -0
- package/dist/hitl-lote.js +223 -0
- package/dist/hitl-native-offer.js +97 -0
- package/dist/hitl-native.js +65 -0
- package/dist/hitl-presentation.js +209 -0
- package/dist/hitl-public-receipt.js +176 -0
- package/dist/hitl-resumo.js +209 -0
- package/dist/hitl-sessions.js +475 -0
- package/dist/hitl.js +711 -0
- package/dist/horario.js +269 -0
- package/dist/hosts.js +198 -22
- package/dist/index.js +1741 -94
- package/dist/indice.js +99 -0
- package/dist/init.js +28 -3
- package/dist/integracoes-locais.js +17 -0
- package/dist/leases.js +65 -21
- package/dist/ledger-stats.js +272 -0
- package/dist/ledger.js +109 -2
- package/dist/licoes.js +221 -0
- package/dist/liveness.js +218 -0
- package/dist/maestro-actions.js +51 -0
- package/dist/maestro-authority.js +152 -0
- package/dist/maestro-cli.js +97 -0
- package/dist/maestro-contract.js +55 -0
- package/dist/maestro-discovery.js +132 -0
- package/dist/maestro-runtime.js +268 -0
- package/dist/maestro-snapshot.js +86 -0
- package/dist/maestro-sources.js +224 -0
- package/dist/manifest.js +165 -6
- package/dist/maquina.js +102 -0
- package/dist/master-audit.js +101 -0
- package/dist/master-batch.js +43 -0
- package/dist/master-digest.js +149 -0
- package/dist/master-migracao.js +155 -0
- package/dist/master.js +361 -77
- package/dist/mcp-artifacts.js +234 -0
- package/dist/mcp-git.js +433 -0
- package/dist/mcp-install.js +310 -0
- package/dist/mcp-maestro.js +25 -0
- package/dist/mcp-server.js +469 -0
- package/dist/mcp-ship.js +436 -0
- package/dist/mcp-verify.js +173 -0
- package/dist/memoria-humana.js +207 -0
- package/dist/memoria.js +314 -78
- package/dist/memory-migration.js +279 -0
- package/dist/memory-prospective.js +148 -0
- package/dist/modos-migracao.js +191 -0
- package/dist/modos.js +151 -15
- package/dist/monitor-lock.js +110 -0
- package/dist/objective.js +449 -0
- package/dist/ocupacao.js +267 -0
- package/dist/onboarding.js +303 -0
- package/dist/orkmind.js +389 -90
- package/dist/orquestracao.js +96 -69
- package/dist/phase.js +612 -151
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/policies.js +72 -0
- package/dist/portfolio-context.js +61 -0
- package/dist/portfolio.js +180 -0
- package/dist/preflight.js +207 -0
- package/dist/process-audit.js +112 -0
- package/dist/project-state.js +93 -0
- package/dist/prompts.js +25 -5
- package/dist/prova-minima.js +112 -0
- package/dist/pulse-cadencia.js +163 -0
- package/dist/pulse-consentimento.js +260 -0
- package/dist/pulse-delivery.js +323 -0
- package/dist/pulse-resposta.js +542 -0
- package/dist/pulse.js +262 -0
- package/dist/ratelimit.js +35 -2
- package/dist/recall.js +80 -3
- package/dist/redacao-saida.js +45 -0
- package/dist/redacao-url.js +66 -0
- package/dist/retry.js +640 -118
- package/dist/roadmap-reservas.js +243 -0
- package/dist/runtime-ambiente.js +38 -0
- package/dist/runtime-context.js +215 -0
- package/dist/runtime-profiles.js +869 -0
- package/dist/runtimes.js +103 -0
- package/dist/sandbox.js +9 -0
- package/dist/session-events.js +203 -0
- package/dist/session-watcher-claude.js +637 -0
- package/dist/session-watcher.js +700 -0
- package/dist/sessoes-adopt.js +154 -0
- package/dist/sessoes-inventario.js +159 -0
- package/dist/sessoes.js +16 -35
- package/dist/setup.js +691 -0
- package/dist/ship.js +168 -19
- package/dist/slug.js +1 -1
- package/dist/thread-close.js +115 -0
- package/dist/thread.js +142 -28
- package/dist/tokens.js +1 -1
- package/dist/util.js +4 -2
- package/dist/verify-sandbox.js +265 -0
- package/dist/verify.js +270 -25
- package/dist/versao.js +60 -0
- package/dist/worktree.js +31 -2
- package/dist/write-activation.js +291 -0
- package/dist/yaml.js +5 -1
- package/eval/casos/master-metrics.json +1 -1
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +37 -3
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +3 -3
- package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
- package/eval/fixtures/b2-master-log/caso.json +1 -1
- package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
- package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
- package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
- package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
- package/eval/fixtures/fx-codex-dry/caso.json +18 -0
- package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
- package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
- package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
- package/eval/fixtures/fx-happy/caso.json +6 -4
- package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
- package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
- package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
- package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
- package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
- package/eval/fixtures/fx-omnicanal/caso.json +17 -0
- package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
- package/monitor/company-brain.cjs +17 -0
- package/monitor/pulse-scope.cjs +45 -0
- package/monitor/pulse.cron +18 -0
- package/monitor/varredura-pulse.sh +27 -0
- package/package.json +28 -7
- package/references/definition-of-done.md +2 -2
- package/schemas/claims.schema.json +25 -0
- package/schemas/company-brain.schema.json +1158 -0
- package/schemas/creation-operation.schema.json +365 -0
- package/schemas/maestro-snapshot.schema.json +2716 -0
- package/skills/README.md +3 -3
- package/skills/core/onboarding/SKILL.md +50 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
- package/skills/core/thread-state/SKILL.md +3 -1
- package/skills/governance/decision-triage/SKILL.md +4 -4
- package/skills/governance/narrative-guardian/SKILL.md +1 -1
- package/skills/governance/roadmap-keeper/SKILL.md +1 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
- package/skills/observability/thread-tracing/SKILL.md +1 -1
- package/skills/phases/check-quality/SKILL.md +2 -2
- package/skills/phases/goal-definition/SKILL.md +1 -1
- package/skills/phases/master-metrics/SKILL.md +9 -7
- package/skills/phases/plan-specification/SKILL.md +1 -1
- package/skills/phases/ship-release/SKILL.md +1 -1
|
@@ -1,37 +1,109 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
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
|
|
10
|
-
|
|
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
|
-
|
|
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
|
|
16
|
-
ork
|
|
17
|
-
ork
|
|
18
|
-
ork
|
|
19
|
-
ork
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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,
|
|
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,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 "$@"
|