@orkastery/cli 0.5.6 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/README.md +18 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +1 -0
- package/adapters/claude-code/README.md +37 -5
- package/adapters/claude-code/agents/ork-check.md +1 -0
- package/adapters/claude-code/agents/ork-go.md +1 -0
- package/adapters/claude-code/agents/ork-goal.md +1 -0
- package/adapters/claude-code/agents/ork-master.md +1 -0
- package/adapters/claude-code/agents/ork-plan.md +1 -0
- package/adapters/claude-code/agents/ork-ship.md +1 -0
- package/adapters/claude-code/hooks/hooks.json +2 -1
- package/adapters/claude-code/hooks/ork-guard.js +15 -1
- package/adapters/claude-code/hooks/ork-resposta.js +91 -0
- package/adapters/claude-code/hooks/ork-sensor.js +18 -2
- package/adapters/claude-code/hooks/quota-signal.js +14 -0
- package/adapters/claude-code/mods/ork-mensageiro/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/caixa.ts +215 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/painel.tsx +165 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/recepcao.ts +256 -0
- package/adapters/claude-code/mods/ork-mensageiro/hooks/register.tsx +481 -0
- package/adapters/claude-code/mods/ork-mensageiro/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mensageiro/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +9 -5
- package/adapters/claude-code/mods/ork-ritual/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/nota.ts +88 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/register.tsx +494 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/replay.tsx +271 -0
- package/adapters/claude-code/mods/ork-ritual/hooks/ritual.ts +218 -0
- package/adapters/claude-code/mods/ork-ritual/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ritual/types/index.d.ts +106 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +1 -1
- package/adapters/codex/skills/ork/SKILL.md +2 -0
- package/adapters/hermes/README.md +64 -1
- package/adapters/hermes/bin/ork-conhecimento-colecoes.sh +14 -0
- package/adapters/hermes/bin/ork-conhecimento-listar.sh +15 -0
- package/adapters/hermes/bin/ork-conhecimento-mostrar.sh +16 -0
- package/adapters/hermes/bin/ork-conhecimento-verificar.sh +15 -0
- package/adapters/hermes/bin/ork-vigia-batida.py +127 -0
- package/adapters/hermes/hermes.plugin.json +4 -0
- package/adapters/hermes/hitl-ingress/__init__.py +101 -8
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +2 -2
- package/adapters/openclaw/README.md +81 -9
- package/adapters/openclaw/bin/ork-vigia-batida.js +86 -0
- package/adapters/openclaw/dist/hitl-ingress.js +106 -9
- package/adapters/openclaw/dist/index.js +86 -0
- package/adapters/openclaw/openclaw.plugin.json +34 -4
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +103 -9
- package/adapters/openclaw/src/index.ts +94 -0
- package/assets/adapters-en/claude-code/README.md +403 -0
- package/assets/adapters-en/claude-code/agents/ork-check.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-go.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-goal.md +34 -0
- package/assets/adapters-en/claude-code/agents/ork-master.md +35 -0
- package/assets/adapters-en/claude-code/agents/ork-plan.md +33 -0
- package/assets/adapters-en/claude-code/agents/ork-ship.md +33 -0
- package/assets/adapters-en/claude-code/commands/check.md +46 -0
- package/assets/adapters-en/claude-code/commands/go.md +46 -0
- package/assets/adapters-en/claude-code/commands/goal.md +55 -0
- package/assets/adapters-en/claude-code/commands/master.md +54 -0
- package/assets/adapters-en/claude-code/commands/onboarding.md +22 -0
- package/assets/adapters-en/claude-code/commands/ork.md +126 -0
- package/assets/adapters-en/claude-code/commands/plan.md +47 -0
- package/assets/adapters-en/claude-code/commands/ship.md +45 -0
- package/assets/adapters-en/codex/skills/ork/SKILL.md +85 -0
- package/assets/adapters-en/hermes/README.md +273 -0
- package/assets/adapters-en/hermes/skills/orkastery-devmaster/SKILL.md +169 -0
- package/assets/references-en/README.md +25 -0
- package/assets/references-en/code-review-axes.md +82 -0
- package/assets/references-en/definition-of-done.md +74 -0
- package/assets/references-en/performance-checklist.md +53 -0
- package/assets/references-en/security-checklist.md +101 -0
- package/assets/references-en/testing-patterns.md +51 -0
- package/assets/security-scan/defaults/.golangci.yml +2 -0
- package/assets/security-scan/defaults/eslint.config.mjs +11 -0
- package/assets/security-scan/defaults/gitleaks.toml +3 -0
- package/assets/security-scan/defaults/ruff.toml +1 -0
- package/assets/security-scan/tools-agil.json +87 -0
- package/assets/security-scan/tools.json +625 -0
- package/assets/skills-en/core/onboarding/SKILL.md +58 -0
- package/assets/skills-en/core/orkastery-bootstrap/SKILL.md +119 -0
- package/assets/skills-en/core/thread-state/SKILL.md +88 -0
- package/assets/skills-en/governance/decision-triage/SKILL.md +65 -0
- package/assets/skills-en/governance/narrative-guardian/SKILL.md +66 -0
- package/assets/skills-en/governance/roadmap-keeper/SKILL.md +60 -0
- package/assets/skills-en/governance/scope-check-capability-map/SKILL.md +71 -0
- package/assets/skills-en/observability/thread-tracing/SKILL.md +63 -0
- package/assets/skills-en/phases/check-quality/SKILL.md +103 -0
- package/assets/skills-en/phases/go-implementation/SKILL.md +78 -0
- package/assets/skills-en/phases/goal-definition/SKILL.md +69 -0
- package/assets/skills-en/phases/master-metrics/SKILL.md +72 -0
- package/assets/skills-en/phases/plan-specification/SKILL.md +67 -0
- package/assets/skills-en/phases/security-remediation/SKILL.md +70 -0
- package/assets/skills-en/phases/ship-release/SKILL.md +71 -0
- package/assets/skills-en/reviewers/code-reviewer/SKILL.md +61 -0
- package/assets/skills-en/reviewers/security-auditor/SKILL.md +93 -0
- package/assets/skills-en/reviewers/test-engineer/SKILL.md +66 -0
- package/assets/skills-en/reviewers/web-performance-auditor/SKILL.md +63 -0
- package/dist/adapters/claude-bg.js +118 -4
- package/dist/adapters/codex-controller-worker.js +12 -5
- package/dist/adapters/codex-events.js +16 -4
- package/dist/adapters/codex.js +3 -1
- package/dist/atualizar-branch.js +245 -0
- package/dist/auditoria.js +13 -11
- package/dist/auditrun.js +51 -46
- package/dist/autorizacao-duravel.js +327 -0
- package/dist/board.js +94 -40
- package/dist/branch-de-estado.js +16 -8
- package/dist/busca-semantica.js +7 -5
- package/dist/catalogo.js +2 -1
- package/dist/changelog-reconciliacao.js +290 -0
- package/dist/check-agil.js +500 -0
- package/dist/check-modo.js +41 -0
- package/dist/check-paralelo.js +183 -0
- package/dist/ci.js +248 -45
- package/dist/ciclos.js +8 -6
- package/dist/claim-lint.js +12 -8
- package/dist/claims-conferir.js +47 -39
- package/dist/claims.js +10 -9
- package/dist/company-brain-client.js +10 -3
- package/dist/company-brain-migration.js +11 -5
- package/dist/conducao-batida.js +759 -0
- package/dist/conducao-sentinela.js +25 -8
- package/dist/conducao.js +84 -29
- package/dist/conhecimento-consulta.js +270 -0
- package/dist/conhecimento.js +111 -87
- package/dist/conta-esgotada.js +127 -0
- package/dist/dado-privado.js +816 -0
- package/dist/decisao-autonoma.js +5 -4
- package/dist/demo.js +14 -12
- package/dist/dependencias-da-worktree.js +25 -0
- package/dist/divida.js +38 -36
- package/dist/docs.js +81 -74
- package/dist/doctor-forja.js +345 -0
- package/dist/doctor-pulse-cron.js +113 -1
- package/dist/doctor.js +164 -6
- package/dist/dsn-da-memoria.js +417 -0
- package/dist/entrega-por-mod.js +503 -0
- package/dist/entrega-pr.js +143 -43
- package/dist/esgotamentos.js +13 -11
- package/dist/estado-thread.js +21 -18
- package/dist/evalrunner.js +35 -32
- package/dist/fabrica-batida.js +34 -21
- package/dist/fabrica-estado.js +13 -10
- package/dist/fix.js +21 -19
- package/dist/forja/adaptador.js +6 -0
- package/dist/forja/ambiente-de-ci.js +27 -0
- package/dist/forja/api.js +256 -0
- package/dist/forja/cache.js +89 -0
- package/dist/forja/cli.js +60 -0
- package/dist/forja/contrato.js +9 -0
- package/dist/forja/endereco.js +43 -0
- package/dist/forja/estado.js +22 -0
- package/dist/forja/executor.js +73 -0
- package/dist/forja/github/ci.js +95 -0
- package/dist/forja/github/dono-da-rede.js +18 -0
- package/dist/forja/github/metadados.js +15 -0
- package/dist/forja/github/pedidos.js +200 -0
- package/dist/forja/gitlab/ci.js +141 -0
- package/dist/forja/gitlab/consultas.js +59 -0
- package/dist/forja/gitlab/dono-da-rede.js +43 -0
- package/dist/forja/gitlab/metadados.js +15 -0
- package/dist/forja/gitlab/pedidos-abertos.js +158 -0
- package/dist/forja/gitlab/pedidos.js +141 -0
- package/dist/forja/produtor.js +32 -0
- package/dist/forja/registro.js +31 -0
- package/dist/forja/resolver.js +121 -0
- package/dist/forja/texto.js +13 -0
- package/dist/forja/versao.js +71 -0
- package/dist/forja.js +123 -80
- package/dist/handoff.js +23 -13
- package/dist/hitl-contract.js +46 -43
- package/dist/hitl-curto.js +37 -25
- package/dist/hitl-gates.js +13 -11
- package/dist/hitl-local-receipt.js +51 -0
- package/dist/hitl-local.js +11 -2
- package/dist/hitl-lock.js +5 -11
- package/dist/hitl-public-receipt.js +11 -0
- package/dist/hitl-resumo.js +44 -1
- package/dist/hitl-sessions.js +62 -9
- package/dist/hitl-texto-livre.js +7 -4
- package/dist/hitl.js +34 -31
- package/dist/horario.js +16 -0
- package/dist/hosts.js +104 -134
- package/dist/index.js +848 -548
- package/dist/indice-vetorial.js +14 -12
- package/dist/init.js +11 -2
- package/dist/integracoes-locais.js +2 -0
- package/dist/intelligence-graph-cli.js +123 -69
- package/dist/intelligence-graph-query.js +37 -22
- package/dist/leases.js +19 -18
- package/dist/ledger-stats.js +17 -16
- package/dist/ledger.js +31 -1
- package/dist/licoes.js +12 -11
- package/dist/locale-accounts.js +220 -0
- package/dist/locale-adapter.js +291 -0
- package/dist/locale-ajuda.js +76 -4
- package/dist/locale-audit.js +199 -0
- package/dist/locale-claims.js +213 -0
- package/dist/locale-conducao.js +138 -0
- package/dist/locale-conhecimento.js +181 -0
- package/dist/locale-decisao.js +205 -0
- package/dist/locale-docs.js +230 -0
- package/dist/locale-estado.js +101 -0
- package/dist/locale-forja.js +290 -0
- package/dist/locale-gerados.js +5 -0
- package/dist/locale-grafo.js +129 -0
- package/dist/locale-master.js +83 -0
- package/dist/locale-network.js +524 -0
- package/dist/locale-operacao-restante.js +931 -0
- package/dist/locale-projetos.js +100 -0
- package/dist/locale-prompts.js +194 -0
- package/dist/locale-pulse.js +140 -2
- package/dist/locale-reservas.js +87 -0
- package/dist/locale-retry.js +145 -6
- package/dist/locale-security-scan.js +69 -0
- package/dist/locale-setup.js +192 -0
- package/dist/locale-ship.js +169 -66
- package/dist/locale-thread.js +149 -5
- package/dist/locale-verify.js +80 -4
- package/dist/locale-worktree.js +246 -0
- package/dist/locale.js +553 -9
- package/dist/maestro-runtime.js +22 -3
- package/dist/manifest.js +287 -11
- package/dist/maquina-ociosa.js +211 -0
- package/dist/maquina.js +10 -5
- package/dist/master-nota-local.js +200 -0
- package/dist/master-nota.js +10 -2
- package/dist/master.js +118 -41
- package/dist/mcp-conhecimento.js +52 -0
- package/dist/mcp-experiencia.js +26 -5
- package/dist/mcp-install.js +73 -8
- package/dist/mcp-noctum.js +101 -0
- package/dist/mcp-server.js +82 -14
- package/dist/mcp-ship-transporte.js +977 -0
- package/dist/mcp-ship.js +68 -24
- package/dist/mcp-transportes.js +17 -0
- package/dist/memoria.js +63 -58
- package/dist/modos-migracao.js +8 -6
- package/dist/modos.js +17 -18
- package/dist/network-roadmap.js +85 -49
- package/dist/noctum-aceite.js +789 -0
- package/dist/noctum-arco.js +540 -33
- package/dist/noctum-capacidade.js +3 -3
- package/dist/noctum-changelog.js +399 -0
- package/dist/noctum-cli.js +482 -0
- package/dist/noctum-coordenacao.js +1225 -0
- package/dist/noctum-entrega.js +1169 -0
- package/dist/noctum-envelope.js +252 -16
- package/dist/noctum-execucao.js +95 -23
- package/dist/noctum-fechamento.js +405 -0
- package/dist/noctum-fila.js +43 -9
- package/dist/noctum-guarda.js +256 -0
- package/dist/noctum-integracao.js +507 -0
- package/dist/noctum-maquinas.js +383 -0
- package/dist/noctum-medicao.js +450 -0
- package/dist/noctum-modo.js +362 -0
- package/dist/noctum-pergunta-canal.js +96 -0
- package/dist/noctum-pergunta.js +115 -0
- package/dist/noctum-provas.js +838 -0
- package/dist/noctum-reconciliacao.js +591 -0
- package/dist/noctum-registro.js +215 -0
- package/dist/noctum-relatorio.js +827 -0
- package/dist/noctum-resposta.js +207 -0
- package/dist/noctum-sessoes-em-voo.js +93 -0
- package/dist/noctum-supervisao.js +649 -0
- package/dist/noctum-terminal.js +459 -0
- package/dist/noctum-transporte.js +655 -0
- package/dist/noctum-vigia.js +639 -0
- package/dist/ocupacao.js +3 -1
- package/dist/onboarding.js +16 -5
- package/dist/orkmind.js +39 -23
- package/dist/orquestracao.js +31 -35
- package/dist/parado-no-condutor.js +146 -124
- package/dist/phase.js +53 -27
- package/dist/policies.js +33 -0
- package/dist/postura-local.js +4 -3
- package/dist/procedencia.js +9 -14
- package/dist/projeto-alvo.js +59 -20
- package/dist/prompts.js +136 -42
- package/dist/prova-minima.js +5 -6
- package/dist/pulse-cadencia.js +5 -4
- package/dist/pulse-consentimento.js +53 -1
- package/dist/pulse-delivery.js +143 -27
- package/dist/pulse-resposta.js +368 -4
- package/dist/pulse.js +136 -3
- package/dist/ratelimit.js +12 -4
- package/dist/recall.js +14 -13
- package/dist/rede-adesao.js +13 -8
- package/dist/rede-forja.js +108 -24
- package/dist/rede-status.js +63 -45
- package/dist/rede.js +86 -46
- package/dist/retomada-checkpoint.js +101 -0
- package/dist/retry.js +228 -73
- package/dist/roadmap-reservas.js +32 -32
- package/dist/runtime-ambiente.js +5 -0
- package/dist/runtime-context.js +117 -43
- package/dist/runtime-escada.js +423 -0
- package/dist/runtime-profiles.js +103 -46
- package/dist/saida-segura.js +3 -2
- package/dist/security-scan/agil.js +355 -0
- package/dist/security-scan/cli.js +76 -0
- package/dist/security-scan/compare.js +149 -0
- package/dist/security-scan/config.js +93 -0
- package/dist/security-scan/detect.js +97 -0
- package/dist/security-scan/executor.js +188 -0
- package/dist/security-scan/guard.js +180 -0
- package/dist/security-scan/imagem-de-lint.js +96 -0
- package/dist/security-scan/normalize/actionlint.js +12 -0
- package/dist/security-scan/normalize/eslint.js +12 -0
- package/dist/security-scan/normalize/gitleaks.js +13 -0
- package/dist/security-scan/normalize/golangci-lint.js +13 -0
- package/dist/security-scan/normalize/govulncheck.js +36 -0
- package/dist/security-scan/normalize/index.js +25 -0
- package/dist/security-scan/normalize/npm-audit.js +30 -0
- package/dist/security-scan/normalize/osv-scanner.js +32 -0
- package/dist/security-scan/normalize/oxlint.js +51 -0
- package/dist/security-scan/normalize/pip-audit.js +16 -0
- package/dist/security-scan/normalize/ruff.js +12 -0
- package/dist/security-scan/normalize/semgrep.js +20 -0
- package/dist/security-scan/normalize/trivy.js +33 -0
- package/dist/security-scan/normalize/util.js +204 -0
- package/dist/security-scan/normalize/zizmor.js +19 -0
- package/dist/security-scan/report.js +156 -0
- package/dist/security-scan/run.js +448 -0
- package/dist/security-scan/tools.js +62 -0
- package/dist/security-scan/trabalhador.js +74 -0
- package/dist/security-scan/types.js +15 -0
- package/dist/session-events.js +19 -2
- package/dist/session-watcher-claude.js +74 -19
- package/dist/session-watcher.js +156 -10
- package/dist/sessoes-contas.js +9 -0
- package/dist/sessoes-inventario.js +1 -1
- package/dist/sessoes.js +25 -23
- package/dist/setup.js +59 -58
- package/dist/ship-publicar.js +263 -92
- package/dist/ship.js +160 -17
- package/dist/superficie.js +14 -11
- package/dist/thread-close.js +9 -9
- package/dist/thread.js +121 -18
- package/dist/tokens.js +15 -11
- package/dist/trabalho-thread.js +297 -0
- package/dist/transporte-do-canal.js +189 -0
- package/dist/types.js +12 -1
- package/dist/util.js +5 -2
- package/dist/varredura-acoes.js +507 -0
- package/dist/verify.js +472 -29
- package/dist/worktree-local.js +12 -10
- package/dist/worktree.js +81 -85
- package/eval/casos/check-quality.json +77 -0
- package/eval/casos/security-auditor.json +148 -0
- package/eval/casos/security-remediation.json +161 -0
- package/eval/fixtures/security-scan/README.md +8 -0
- package/eval/fixtures/security-scan/go/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/go/Dockerfile +4 -0
- package/eval/fixtures/security-scan/go/README.md +4 -0
- package/eval/fixtures/security-scan/go/config.go +4 -0
- package/eval/fixtures/security-scan/go/go.mod +5 -0
- package/eval/fixtures/security-scan/go/go.sum +2 -0
- package/eval/fixtures/security-scan/go/main.go +31 -0
- package/eval/fixtures/security-scan/js/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/js/Dockerfile +3 -0
- package/eval/fixtures/security-scan/js/README.md +4 -0
- package/eval/fixtures/security-scan/js/package-lock.json +844 -0
- package/eval/fixtures/security-scan/js/package.json +10 -0
- package/eval/fixtures/security-scan/js/src/config.js +4 -0
- package/eval/fixtures/security-scan/js/src/server.js +17 -0
- package/eval/fixtures/security-scan/js/src/util.ts +4 -0
- package/eval/fixtures/security-scan/js/tsconfig.json +4 -0
- package/eval/fixtures/security-scan/python/.github/workflows/ci.yml +12 -0
- package/eval/fixtures/security-scan/python/Dockerfile +3 -0
- package/eval/fixtures/security-scan/python/README.md +4 -0
- package/eval/fixtures/security-scan/python/app/__init__.py +0 -0
- package/eval/fixtures/security-scan/python/app/config.py +2 -0
- package/eval/fixtures/security-scan/python/app/main.py +19 -0
- package/eval/fixtures/security-scan/python/requirements.txt +1 -0
- package/package.json +9 -4
- package/references/security-checklist.md +3 -3
- package/skills/README.md +1 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/check-quality/SKILL.md +16 -0
- package/skills/phases/go-implementation/SKILL.md +6 -0
- package/skills/phases/security-remediation/SKILL.md +70 -0
- package/skills/reviewers/security-auditor/SKILL.md +25 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.TERMINAL_LIGADO = exports.CONTRATO_DO_TERMINAL = void 0;
|
|
37
|
+
exports.ancestraisPeloProc = ancestraisPeloProc;
|
|
38
|
+
exports.fimDaTranscricao = fimDaTranscricao;
|
|
39
|
+
exports.codigosMostradosPorUltimo = codigosMostradosPorUltimo;
|
|
40
|
+
exports.origemDoDono = origemDoDono;
|
|
41
|
+
exports.lerEntradaDoHook = lerEntradaDoHook;
|
|
42
|
+
exports.responderPeloTerminal = responderPeloTerminal;
|
|
43
|
+
/**
|
|
44
|
+
* RM-057 (resposta curta, D5 e D6 da ork-rm057respost): o ingresso do terminal do Claude Code.
|
|
45
|
+
*
|
|
46
|
+
* DESLIGADO (GO-FIX 2, R2 e R3 do CHECK, decisão D22): o núcleo não grava nada pelo terminal. Quando o dono digita uma
|
|
47
|
+
* resposta curta a uma pergunta que espera por ele, o hook leva o evento ao núcleo, e o núcleo só devolve o aviso de
|
|
48
|
+
* responder pelo Telegram (em reply à mensagem da pergunta, ou com o código) ou pela janela de confirmação do Claude Code
|
|
49
|
+
* (o diálogo nativo). Por quê: o Claude Code instalado (2.1.306) não manda a origem humana do evento (`source`), então
|
|
50
|
+
* nada do dono gravaria; e o agente da própria sessão do dono forja o evento e passa a cadeia de processos, com `exec` e
|
|
51
|
+
* sem a marca `AI_AGENT` (S15 do CHECK). Hoje o ingresso não serviria ao dono e serviria a quem forja.
|
|
52
|
+
*
|
|
53
|
+
* O que falta para religar, numa fatia própria: o Claude Code mandar o `source` do evento, e uma prova de que o evento
|
|
54
|
+
* veio do hook do harness e não de um processo do mesmo usuário (a cadeia e o guard são lombadas, não prova); a pergunta
|
|
55
|
+
* mostrada exigida como a linha que o núcleo monta para ela, ou só o código (R3). Até lá, o código abaixo fica atrás da
|
|
56
|
+
* chave `TERMINAL_LIGADO`, desligada; só os testes a ligam, por `AmbienteDoTerminal.ligado`, e o CLI e o hook nunca.
|
|
57
|
+
*
|
|
58
|
+
* Com a chave ligada, o dono decidiu que aprova onde estiver. No terminal do Claude Code, o hook `UserPromptSubmit` do
|
|
59
|
+
* plugin do `ork` leva ao núcleo o que ele digitou numa sessão interativa; quando o texto é uma resposta curta a uma
|
|
60
|
+
* pergunta do arco #Noctum, o núcleo confere a ORIGEM do prompt e da sessão, nunca o texto, e grava o ato com o recibo.
|
|
61
|
+
*
|
|
62
|
+
* A origem (D5; GO-FIX 1, achados 1 e 5), conferida nesta ordem, cada passo com o motivo tipado de quando falha:
|
|
63
|
+
* - prompt digitado: o evento diz quem escreveu o prompt (`source`), e só `user`, o compositor interativo, vale. A tarefa
|
|
64
|
+
* agendada, a volta do `/loop`, a mensagem de canal ou de outra sessão, o SDK e o evento de sondagem são recusados, e o
|
|
65
|
+
* evento sem o campo também: sem como provar que o dono digitou, nada é gravado;
|
|
66
|
+
* - presença: o Claude Code marca os filhos de uma sessão com `CLAUDE_CODE_SESSION_ATTENDED=1` só quando há alguém
|
|
67
|
+
* nela; em segundo plano, em `daemon` e na execução por `-p` aninhada, vale `0`;
|
|
68
|
+
* - id: o `CLAUDE_CODE_SESSION_ID` do ambiente é o `session_id` do evento;
|
|
69
|
+
* - sem despacho: nem a identidade de despacho do `ork` (`ORK_DISPATCH_ID`, `ORK_DISPATCH_THREAD`) nem a pasta de job
|
|
70
|
+
* de segundo plano (`CLAUDE_JOB_DIR`) no ambiente;
|
|
71
|
+
* - ponto de entrada: não é o do SDK (`sdk-*`);
|
|
72
|
+
* - registro: o id não é de sessão que o `ork` despachou ou adotou em thread nenhuma deste projeto;
|
|
73
|
+
* - worktree: o `cwd` não está em worktree de thread;
|
|
74
|
+
* - ancestralidade (Linux, pelo `/proc`): a sessão do Claude Code (`CLAUDE_PID`) é ancestral deste processo, e TODO
|
|
75
|
+
* processo entre este e ela nasceu com o ambiente que o Claude Code dá ao hook dela: o mesmo id de sessão, o mesmo
|
|
76
|
+
* `CLAUDE_PID`, a presença e nenhuma marca `AI_AGENT`, que o Claude Code põe no shell das ferramentas do agente e não
|
|
77
|
+
* no hook. O ambiente de quando cada ancestral nasceu não se reescreve de baixo. O ambiente da sessão não é de segundo
|
|
78
|
+
* plano (`CLAUDE_CODE_SESSION_KIND`) e nenhuma outra sessão do Claude Code está acima dela. Sem `/proc`, nada é gravado.
|
|
79
|
+
*
|
|
80
|
+
* O limite que sobra, dito como o do diálogo nativo (A21 e NP14): a fronteira é a conta do sistema. Um processo do mesmo
|
|
81
|
+
* usuário que abra uma sessão interativa nova do Claude Code fora da árvore de processos do agente (com `setsid` e um
|
|
82
|
+
* terminal virtual, por exemplo) e digite nela passa, porque o núcleo e os agentes dividem a conta; o agente pela
|
|
83
|
+
* ferramenta Bash da própria sessão também passa, se trocar o shell pelo núcleo com `exec`, tirar a marca `AI_AGENT` e
|
|
84
|
+
* forjar o evento com `source` igual a `user` (S15 do CHECK; o guard do plugin não vê o subcomando entre aspas). Separar
|
|
85
|
+
* de verdade é rodar os agentes em outra conta ou sandbox.
|
|
86
|
+
*
|
|
87
|
+
* A pergunta (D6; GO-FIX 1, achado 3): o código digitado ("K7QX a") vale sempre que a origem prova o dono. A palavra
|
|
88
|
+
* solta, a letra e o número com a letra só valem logo depois da pergunta mostrada: a última linha da última mensagem do
|
|
89
|
+
* assistente, que é a última coisa da transcrição, traz o código dela (saída de ferramenta não conta). Só a alternativa
|
|
90
|
+
* "a" age por esse caminho: "b", "c", "não" e o resto seguem ao modelo, sem efeito, e nunca são engolidos. A pergunta já
|
|
91
|
+
* respondida, a que já ouviu "b" ou "c" e a que mudou (a proposta trocada) não aceitam a palavra solta: a primeira e a
|
|
92
|
+
* segunda deixam o prompt seguir ao modelo, e a terceira volta dizendo a pergunta de agora. A resposta a um gate não é
|
|
93
|
+
* gravada aqui (D1): ela vai ao condutor como contexto, para ele abrir o diálogo nativo, só com a origem provada.
|
|
94
|
+
*/
|
|
95
|
+
const fs = __importStar(require("node:fs"));
|
|
96
|
+
const path = __importStar(require("node:path"));
|
|
97
|
+
const node_crypto_1 = require("node:crypto");
|
|
98
|
+
const estado_thread_1 = require("./estado-thread");
|
|
99
|
+
const hitl_texto_livre_1 = require("./hitl-texto-livre");
|
|
100
|
+
const manifest_1 = require("./manifest");
|
|
101
|
+
const noctum_resposta_1 = require("./noctum-resposta");
|
|
102
|
+
const pulse_resposta_1 = require("./pulse-resposta");
|
|
103
|
+
const thread_1 = require("./thread");
|
|
104
|
+
exports.CONTRATO_DO_TERMINAL = 'ork.noctum-terminal/v1';
|
|
105
|
+
/**
|
|
106
|
+
* GO-FIX 2 (R2 e R3 do CHECK, D22): a chave do ingresso do terminal, DESLIGADA. Desligada, a resposta curta a uma pergunta
|
|
107
|
+
* que espera o dono volta como recusa (`noctum.terminal.desligado`) com o aviso de por onde responder, antes de conferir a
|
|
108
|
+
* origem, e nada é gravado. Só um teste (ou a fatia que religar, com o que falta dito no topo deste arquivo) a liga.
|
|
109
|
+
*/
|
|
110
|
+
exports.TERMINAL_LIGADO = false;
|
|
111
|
+
const TETO_DO_PROMPT = 300;
|
|
112
|
+
const TETO_DA_TRANSCRICAO = 512 * 1024;
|
|
113
|
+
const ID_DE_SESSAO = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/;
|
|
114
|
+
const KINDS_DE_FUNDO = ['bg', 'daemon', 'daemon-worker'];
|
|
115
|
+
/** O código curto como palavra inteira, em maiúsculas: hash e identificador em minúsculas nunca casam. */
|
|
116
|
+
const CODIGO_NA_LINHA = /(?<![A-Za-z0-9])(?=[A-HJKMNP-TV-Z][2-9A-HJKMNP-TV-Z]{0,2}[2-9])[A-HJKMNP-TV-Z][2-9A-HJKMNP-TV-Z]{3}(?![A-Za-z0-9])/g;
|
|
117
|
+
const sha = (s) => (0, node_crypto_1.createHash)('sha256').update(s).digest('hex');
|
|
118
|
+
const decisao = (d) => ({ contrato: exports.CONTRATO_DO_TERMINAL, ...d });
|
|
119
|
+
/** A cadeia de processos pelo `/proc`, do atual até o topo (Linux). Fora do Linux, `null`. */
|
|
120
|
+
function ancestraisPeloProc() {
|
|
121
|
+
if (!fs.existsSync('/proc/self/stat'))
|
|
122
|
+
return null;
|
|
123
|
+
const cadeia = [];
|
|
124
|
+
let pid = process.pid;
|
|
125
|
+
for (let i = 0; i < 64 && pid > 0; i++) {
|
|
126
|
+
let stat;
|
|
127
|
+
try {
|
|
128
|
+
stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
const ppid = Number(stat.slice(stat.lastIndexOf(')') + 2).split(' ')[1]);
|
|
134
|
+
let ambiente = null;
|
|
135
|
+
try {
|
|
136
|
+
ambiente = Object.fromEntries(fs.readFileSync(`/proc/${pid}/environ`).toString('utf8').split('\0').filter(Boolean)
|
|
137
|
+
.map(l => { const k = l.indexOf('='); return [l.slice(0, k), l.slice(k + 1)]; }));
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
ambiente = null;
|
|
141
|
+
}
|
|
142
|
+
cadeia.push({ pid, ppid, ambiente });
|
|
143
|
+
if (!Number.isInteger(ppid) || ppid <= 1)
|
|
144
|
+
break;
|
|
145
|
+
pid = ppid;
|
|
146
|
+
}
|
|
147
|
+
return cadeia;
|
|
148
|
+
}
|
|
149
|
+
/** O fim da transcrição da sessão: um `.jsonl` comum do próprio usuário, lido só nos últimos 512 KB. */
|
|
150
|
+
function fimDaTranscricao(arquivo) {
|
|
151
|
+
try {
|
|
152
|
+
if (!path.isAbsolute(arquivo) || !arquivo.endsWith('.jsonl'))
|
|
153
|
+
return null;
|
|
154
|
+
const fd = fs.openSync(arquivo, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
155
|
+
try {
|
|
156
|
+
const st = fs.fstatSync(fd);
|
|
157
|
+
if (!st.isFile() || st.uid !== process.getuid?.())
|
|
158
|
+
return null;
|
|
159
|
+
const tamanho = Math.min(st.size, TETO_DA_TRANSCRICAO), buf = Buffer.alloc(tamanho);
|
|
160
|
+
fs.readSync(fd, buf, 0, tamanho, st.size - tamanho);
|
|
161
|
+
return buf.toString('utf8');
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
fs.closeSync(fd);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* GO-FIX 1 (achado 3): os códigos que o dono viu por último. A última entrada da conversa principal na transcrição (sem a
|
|
173
|
+
* de subagente e sem os registros que não são mensagem) tem de ser uma mensagem do assistente com texto, e os códigos são
|
|
174
|
+
* os da última linha desse texto (cerca de código não conta como linha). Se a última entrada é o resultado de uma
|
|
175
|
+
* ferramenta, um prompt (do dono ou injetado) ou uma mensagem sem texto, nada foi mostrado por último: a lista vem vazia.
|
|
176
|
+
*/
|
|
177
|
+
function codigosMostradosPorUltimo(fim) {
|
|
178
|
+
if (fim === null)
|
|
179
|
+
return [];
|
|
180
|
+
const linhas = fim.split('\n');
|
|
181
|
+
for (let i = linhas.length - 1; i >= 0; i--) {
|
|
182
|
+
let e;
|
|
183
|
+
try {
|
|
184
|
+
e = JSON.parse(linhas[i]);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (!e || typeof e !== 'object' || Array.isArray(e))
|
|
190
|
+
continue;
|
|
191
|
+
const entrada = e;
|
|
192
|
+
if ((entrada.type !== 'assistant' && entrada.type !== 'user') || entrada.isSidechain === true)
|
|
193
|
+
continue;
|
|
194
|
+
if (entrada.type === 'user')
|
|
195
|
+
return [];
|
|
196
|
+
const blocos = Array.isArray(entrada.message?.content) ? entrada.message.content : [];
|
|
197
|
+
const texto = blocos.filter((b) => !!b && typeof b === 'object' &&
|
|
198
|
+
b.type === 'text' && typeof b.text === 'string').map(b => b.text).join('\n');
|
|
199
|
+
const ultima = texto.split('\n').map(l => l.trim()).filter(l => l && !/^(```|~~~)/.test(l)).at(-1) ?? '';
|
|
200
|
+
return [...new Set(ultima.match(CODIGO_NA_LINHA) ?? [])];
|
|
201
|
+
}
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
/** As sessões que o `ork` despachou ou adotou em alguma thread deste projeto, e as worktrees das threads. */
|
|
205
|
+
function registroDoOrk(raiz) {
|
|
206
|
+
const sessoes = new Set(), worktrees = [];
|
|
207
|
+
for (const id of (0, thread_1.listarIds)(raiz)) {
|
|
208
|
+
try {
|
|
209
|
+
const t = (0, thread_1.lerThread)(raiz, id);
|
|
210
|
+
for (const s of t.sessoes ?? [])
|
|
211
|
+
if (typeof s.sessionId === 'string')
|
|
212
|
+
sessoes.add(s.sessionId);
|
|
213
|
+
if (typeof t.worktree === 'string' && t.worktree)
|
|
214
|
+
worktrees.push(t.worktree);
|
|
215
|
+
}
|
|
216
|
+
catch { /* thread ilegível não tira nem põe ninguém no registro */ }
|
|
217
|
+
}
|
|
218
|
+
return { sessoes, worktrees };
|
|
219
|
+
}
|
|
220
|
+
const real = (p) => { try {
|
|
221
|
+
return fs.realpathSync(p);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return path.resolve(p);
|
|
225
|
+
} };
|
|
226
|
+
const dentro = (pai, filho) => {
|
|
227
|
+
const rel = path.relative(real(pai), real(filho));
|
|
228
|
+
return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel));
|
|
229
|
+
};
|
|
230
|
+
const MOTIVOS = Object.freeze({
|
|
231
|
+
'noctum.terminal.desligado': 'o ingresso do terminal está desligado até o Claude Code mandar a origem humana do evento',
|
|
232
|
+
'noctum.terminal.origem-do-prompt-desconhecida': 'o evento do Claude Code não diz que foi você quem digitou (sem o campo source, o terminal não grava)',
|
|
233
|
+
'noctum.terminal.prompt-injetado': 'o prompt não foi digitado por você (veio de tarefa agendada, /loop, canal, outra sessão ou programa)',
|
|
234
|
+
'noctum.terminal.sem-presenca': 'a sessão não tem alguém presente (segundo plano ou execução por programa)',
|
|
235
|
+
'noctum.terminal.sessao-divergente': 'o id da sessão do evento não é o do ambiente',
|
|
236
|
+
'noctum.terminal.sessao-despachada': 'a sessão foi despachada pelo ork ou roda como job de segundo plano',
|
|
237
|
+
'noctum.terminal.sessao-programatica': 'a sessão é do SDK, não do terminal',
|
|
238
|
+
'noctum.terminal.sessao-do-ork': 'a sessão foi despachada ou adotada pelo ork numa thread',
|
|
239
|
+
'noctum.terminal.worktree-de-thread': 'a sessão roda numa worktree de thread',
|
|
240
|
+
'noctum.terminal.sem-cadeia': 'a cadeia de processos não se lê nesta plataforma',
|
|
241
|
+
'noctum.terminal.ancestral-divergente': 'a sessão do Claude Code não é ancestral deste processo',
|
|
242
|
+
'noctum.terminal.ancestral-ilegivel': 'o ambiente de um processo da cadeia não se lê',
|
|
243
|
+
'noctum.terminal.cadeia-fora-do-hook': 'um processo entre este e a sessão não nasceu do hook dela',
|
|
244
|
+
'noctum.terminal.cadeia-do-agente': 'a chamada saiu de uma ferramenta do agente, não do hook',
|
|
245
|
+
'noctum.terminal.sessao-em-segundo-plano': 'a sessão do Claude Code roda em segundo plano',
|
|
246
|
+
'noctum.terminal.sessao-aninhada': 'a sessão está aninhada em outra sessão do Claude Code',
|
|
247
|
+
});
|
|
248
|
+
/**
|
|
249
|
+
* D5: a origem do prompt e da sessão, nesta ordem. Devolve as conferências que passaram, para o recibo, ou o primeiro
|
|
250
|
+
* motivo que falhou. Nada aqui lê o texto do dono.
|
|
251
|
+
*/
|
|
252
|
+
function origemDoDono(raiz, entrada, amb) {
|
|
253
|
+
const env = amb.env, conferencias = [];
|
|
254
|
+
const falha = (motivo) => ({ ok: false, motivo });
|
|
255
|
+
// GO-FIX 1 (achado 1): o prompt que a máquina injeta na sessão do dono não é o dono, e sem o campo não há como provar.
|
|
256
|
+
if (entrada.source === undefined)
|
|
257
|
+
return falha('noctum.terminal.origem-do-prompt-desconhecida');
|
|
258
|
+
if (entrada.source !== 'user')
|
|
259
|
+
return falha('noctum.terminal.prompt-injetado');
|
|
260
|
+
conferencias.push('prompt-digitado');
|
|
261
|
+
if (env.CLAUDE_CODE_SESSION_ATTENDED !== '1')
|
|
262
|
+
return falha('noctum.terminal.sem-presenca');
|
|
263
|
+
conferencias.push('presenca');
|
|
264
|
+
if (env.CLAUDE_CODE_SESSION_ID !== entrada.session_id)
|
|
265
|
+
return falha('noctum.terminal.sessao-divergente');
|
|
266
|
+
conferencias.push('id-da-sessao');
|
|
267
|
+
if (env.ORK_DISPATCH_ID || env.ORK_DISPATCH_THREAD || env.CLAUDE_JOB_DIR)
|
|
268
|
+
return falha('noctum.terminal.sessao-despachada');
|
|
269
|
+
conferencias.push('sem-despacho');
|
|
270
|
+
if (/^sdk/i.test(env.CLAUDE_CODE_ENTRYPOINT ?? ''))
|
|
271
|
+
return falha('noctum.terminal.sessao-programatica');
|
|
272
|
+
conferencias.push('ponto-de-entrada');
|
|
273
|
+
const registro = registroDoOrk(raiz);
|
|
274
|
+
if (registro.sessoes.has(entrada.session_id))
|
|
275
|
+
return falha('noctum.terminal.sessao-do-ork');
|
|
276
|
+
conferencias.push('fora-do-registro');
|
|
277
|
+
let dirDasWorktrees = '.claude/worktrees';
|
|
278
|
+
try {
|
|
279
|
+
dirDasWorktrees = (0, manifest_1.exigirManifesto)((0, estado_thread_1.raizDoEstado)(raiz)).manifesto.worktree.dir || dirDasWorktrees;
|
|
280
|
+
}
|
|
281
|
+
catch { /* o padrão do manifesto */ }
|
|
282
|
+
const raizes = [...registro.worktrees, path.join((0, estado_thread_1.raizDoEstado)(raiz), dirDasWorktrees)];
|
|
283
|
+
if (raizes.some(w => dentro(w, entrada.cwd)))
|
|
284
|
+
return falha('noctum.terminal.worktree-de-thread');
|
|
285
|
+
conferencias.push('fora-de-worktree');
|
|
286
|
+
// GO-FIX 1 (achado 5): `CLAUDE_PID` não vale de qualquer ancestral. Cada processo entre este e a sessão tem de ter nascido
|
|
287
|
+
// do hook dela, e o agente não reescreve o ambiente de um ancestral que já está de pé.
|
|
288
|
+
const cadeia = (amb.ancestrais ?? ancestraisPeloProc)();
|
|
289
|
+
if (cadeia === null)
|
|
290
|
+
return falha('noctum.terminal.sem-cadeia');
|
|
291
|
+
const claudePid = Number(env.CLAUDE_PID);
|
|
292
|
+
const i = Number.isInteger(claudePid) && claudePid > 1 ? cadeia.findIndex(a => a.pid === claudePid) : -1;
|
|
293
|
+
if (i < 1)
|
|
294
|
+
return falha('noctum.terminal.ancestral-divergente');
|
|
295
|
+
for (const a of cadeia.slice(0, i)) {
|
|
296
|
+
if (!a.ambiente)
|
|
297
|
+
return falha('noctum.terminal.ancestral-ilegivel');
|
|
298
|
+
if (a.ambiente.CLAUDE_CODE_SESSION_ID !== entrada.session_id || a.ambiente.CLAUDE_PID !== String(claudePid) ||
|
|
299
|
+
a.ambiente.CLAUDE_CODE_SESSION_ATTENDED !== '1')
|
|
300
|
+
return falha('noctum.terminal.cadeia-fora-do-hook');
|
|
301
|
+
if (Object.prototype.hasOwnProperty.call(a.ambiente, 'AI_AGENT'))
|
|
302
|
+
return falha('noctum.terminal.cadeia-do-agente');
|
|
303
|
+
}
|
|
304
|
+
const sessao = cadeia[i];
|
|
305
|
+
if (!sessao.ambiente)
|
|
306
|
+
return falha('noctum.terminal.ancestral-ilegivel');
|
|
307
|
+
if (KINDS_DE_FUNDO.includes(sessao.ambiente.CLAUDE_CODE_SESSION_KIND ?? ''))
|
|
308
|
+
return falha('noctum.terminal.sessao-em-segundo-plano');
|
|
309
|
+
if (cadeia.slice(i + 1).some(a => a.ambiente?.CLAUDECODE === '1'))
|
|
310
|
+
return falha('noctum.terminal.sessao-aninhada');
|
|
311
|
+
conferencias.push('ancestralidade');
|
|
312
|
+
const entrypoint = typeof env.CLAUDE_CODE_ENTRYPOINT === 'string' && env.CLAUDE_CODE_ENTRYPOINT ? env.CLAUDE_CODE_ENTRYPOINT.slice(0, 64) : null;
|
|
313
|
+
return { ok: true, atestado: { host: 'claude-code', sessao: entrada.session_id, entrypoint, conferencias } };
|
|
314
|
+
}
|
|
315
|
+
/** A entrada do hook, ou `null` quando ela não tem a forma do `UserPromptSubmit`. */
|
|
316
|
+
function lerEntradaDoHook(v) {
|
|
317
|
+
if (!v || typeof v !== 'object')
|
|
318
|
+
return null;
|
|
319
|
+
const e = v;
|
|
320
|
+
if (e.hook_event_name !== 'UserPromptSubmit' || typeof e.session_id !== 'string' || !ID_DE_SESSAO.test(e.session_id) ||
|
|
321
|
+
typeof e.cwd !== 'string' || !path.isAbsolute(e.cwd) || typeof e.prompt !== 'string' ||
|
|
322
|
+
(e.transcript_path !== undefined && typeof e.transcript_path !== 'string') ||
|
|
323
|
+
(e.source !== undefined && (typeof e.source !== 'string' || !/^[a-z_]{1,40}$/.test(e.source))))
|
|
324
|
+
return null;
|
|
325
|
+
return { session_id: e.session_id, cwd: e.cwd, hook_event_name: e.hook_event_name, prompt: e.prompt,
|
|
326
|
+
...(typeof e.transcript_path === 'string' ? { transcript_path: e.transcript_path } : {}),
|
|
327
|
+
...(typeof e.source === 'string' ? { source: e.source } : {}) };
|
|
328
|
+
}
|
|
329
|
+
/** A decisão para o desfecho da resposta à pergunta do arco. */
|
|
330
|
+
function decisaoDoDesfecho(p, d) {
|
|
331
|
+
if (d.tipo === 'registrada') {
|
|
332
|
+
return decisao({ acao: 'registrada', mensagem: d.mensagem, arco: p.arco, ato: d.ato, codigo: p.codigo, repetida: d.repetida });
|
|
333
|
+
}
|
|
334
|
+
if (d.tipo === 'sem-efeito' || d.tipo === 'detalhe')
|
|
335
|
+
return decisao({ acao: d.tipo, mensagem: d.mensagem });
|
|
336
|
+
return decisao({ acao: 'pergunta', mensagem: d.mensagem });
|
|
337
|
+
}
|
|
338
|
+
/** O contexto ao condutor quando o dono respondeu a um gate no terminal (D1): o que abrir, sem resposta nos argumentos. */
|
|
339
|
+
function contextoDoGate(codigo, thread, pedidoId, texto) {
|
|
340
|
+
return `Orkastery: o dono digitou "${texto.slice(0, 40)}" e isso parece a resposta à pergunta ${codigo} (gate da thread ${thread}). ` +
|
|
341
|
+
'O terminal não grava resposta de gate: abra o diálogo nativo com ork_request_decision ' +
|
|
342
|
+
`(threadId ${thread}, pedidoId ${pedidoId}) para o dono escolher lá; nunca passe a resposta nos argumentos.`;
|
|
343
|
+
}
|
|
344
|
+
/** A palavra solta, a letra ou o número com a letra que diz "a": só ela age sem o código (GO-FIX 1, achado 3). */
|
|
345
|
+
function dizA(trecho) {
|
|
346
|
+
return (trecho.tipo === 'letra' && trecho.letra === 'a') || (trecho.tipo === 'intencao' && trecho.intencao === 'afirmar');
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* GO-FIX 2 (D22): a resposta do terminal desligado. Nada é gravado nem encaminhado; com alguém presente, o dono vê por onde
|
|
350
|
+
* responder, e o prompt segue ao modelo.
|
|
351
|
+
*/
|
|
352
|
+
function desligado(texto, alvo, env) {
|
|
353
|
+
const codigo = alvo.tipo === 'arco' ? alvo.pergunta.codigo : alvo.tipo === 'gate' ? alvo.codigo : null;
|
|
354
|
+
return decisao({ acao: 'recusada', motivo: 'noctum.terminal.desligado', presenca: env.CLAUDE_CODE_SESSION_ATTENDED === '1',
|
|
355
|
+
mensagem: `O Orkastery não registrou "${texto.slice(0, 40)}"${codigo ? ` para a pergunta ${codigo}` : ''}: ` +
|
|
356
|
+
`${MOTIVOS['noctum.terminal.desligado']}. Responda pelo Telegram, em reply à mensagem da pergunta` +
|
|
357
|
+
`${codigo ? ` ou com ${codigo} e a letra` : ''}, ou pela janela de confirmação do Claude Code (o diálogo nativo).` });
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* GO-FIX 1 (achado 3): a palavra solta e o número com a letra só valem para a pergunta que o dono viu por último, e só
|
|
361
|
+
* para dizer "a". Respondida, já com "b" ou "c", ou sem estar na última linha mostrada: o prompt segue ao modelo.
|
|
362
|
+
*/
|
|
363
|
+
function alvoMostradoPorUltimo(raiz, entrada, amb, quando, trecho, numero) {
|
|
364
|
+
const fim = entrada.transcript_path ? (amb.transcricao ?? fimDaTranscricao)(entrada.transcript_path) : null;
|
|
365
|
+
const doArco = codigosMostradosPorUltimo(fim).flatMap(c => (0, noctum_resposta_1.perguntasPorCodigo)(raiz, c, quando));
|
|
366
|
+
if (!doArco.length)
|
|
367
|
+
return { tipo: 'nada', motivo: 'nenhuma-pergunta-mostrada-por-ultimo' };
|
|
368
|
+
if (doArco.length > 1) {
|
|
369
|
+
return { tipo: 'pergunta-de-volta', mensagem: `A última mensagem mostra ${doArco.length} perguntas do arco, e "${entrada.prompt.trim().slice(0, 40)}" ` +
|
|
370
|
+
`não diz qual; nada foi registrado. Responda pelo código: ${doArco.map(noctum_resposta_1.rotuloDaPergunta).join('; ')}.` };
|
|
371
|
+
}
|
|
372
|
+
const [p] = doArco;
|
|
373
|
+
if (numero !== null) {
|
|
374
|
+
let servida;
|
|
375
|
+
try {
|
|
376
|
+
servida = (0, pulse_resposta_1.lerLoteServido)(raiz, amb.estadoDir).perguntas.find(q => q.numero === numero);
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
servida = undefined;
|
|
380
|
+
}
|
|
381
|
+
if (servida?.arco?.codigo !== p.codigo)
|
|
382
|
+
return { tipo: 'nada', motivo: 'numero-de-outra-pergunta' };
|
|
383
|
+
}
|
|
384
|
+
if (!dizA(trecho))
|
|
385
|
+
return { tipo: 'nada', motivo: 'nao-diz-a' };
|
|
386
|
+
if (p.situacao === 'respondida')
|
|
387
|
+
return { tipo: 'nada', motivo: 'pergunta-ja-respondida' };
|
|
388
|
+
const semEfeito = (0, noctum_resposta_1.perguntasComRespostaSemEfeito)(raiz);
|
|
389
|
+
if (semEfeito === null || semEfeito.has(p.codigo))
|
|
390
|
+
return { tipo: 'nada', motivo: 'pergunta-ja-ouviu-b-ou-c' };
|
|
391
|
+
return { tipo: 'arco', pergunta: p, trecho };
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* O ingresso do terminal: lê o evento do hook, reconhece só a resposta curta, acha a pergunta (o código, ou a mostrada por
|
|
395
|
+
* último para a palavra solta e o número), confere a origem (D5) e responde pela via do terminal. Nunca adivinha.
|
|
396
|
+
* Desligado (D22), devolve o aviso logo depois de achar a pergunta, sem conferir a origem e sem gravar nem encaminhar.
|
|
397
|
+
*/
|
|
398
|
+
function responderPeloTerminal(raiz, bruto, amb) {
|
|
399
|
+
const quando = amb.quando ?? new Date().toISOString();
|
|
400
|
+
const entrada = lerEntradaDoHook(bruto);
|
|
401
|
+
if (!entrada)
|
|
402
|
+
return decisao({ acao: 'ignorar', motivo: 'entrada' });
|
|
403
|
+
const texto = entrada.prompt.trim();
|
|
404
|
+
// Uma linha só, conferida no prompt cru: a mensagem que a máquina embrulha (outra sessão, canal) vem em várias linhas, e
|
|
405
|
+
// nem a quebra no fim passa.
|
|
406
|
+
if (!texto || texto.length > TETO_DO_PROMPT || /[\r\n]/.test(entrada.prompt))
|
|
407
|
+
return decisao({ acao: 'ignorar', motivo: 'nao-e-resposta-curta' });
|
|
408
|
+
const lido = (0, pulse_resposta_1.interpretarRespostaDoPulse)(texto);
|
|
409
|
+
if (!['consentimento', 'lote', 'livre'].includes(lido.forma) || (lido.forma === 'lote' && lido.escolhas.length !== 1)) {
|
|
410
|
+
return decisao({ acao: 'ignorar', motivo: 'nao-e-resposta-curta' });
|
|
411
|
+
}
|
|
412
|
+
if (raiz === null)
|
|
413
|
+
return decisao({ acao: 'ignorar', motivo: 'sem-projeto' });
|
|
414
|
+
// O alvo: pelo código digitado, ou pela pergunta mostrada por último (a palavra solta e o número com a letra).
|
|
415
|
+
let alvo;
|
|
416
|
+
if (lido.forma === 'consentimento') {
|
|
417
|
+
const doArco = (0, noctum_resposta_1.perguntasPorCodigo)(raiz, lido.codigo, quando);
|
|
418
|
+
const gates = (0, pulse_resposta_1.pedidosComCodigo)(raiz, lido.codigo);
|
|
419
|
+
const resto = (0, pulse_resposta_1.restoDoCodigo)(texto, lido.codigo);
|
|
420
|
+
const trecho = (0, hitl_texto_livre_1.lerTrecho)(resto) ?? (resto === '?' ? (0, hitl_texto_livre_1.lerTrecho)('detalhes') : null);
|
|
421
|
+
alvo = doArco.length + gates.length > 1
|
|
422
|
+
? { tipo: 'pergunta-de-volta', mensagem: `O código ${lido.codigo} está em mais de uma pergunta; nada foi registrado. Responda pelo número da pergunta.` }
|
|
423
|
+
: gates.length === 1 ? { tipo: 'gate', contexto: contextoDoGate(lido.codigo, gates[0].thread, gates[0].pedido.id, texto), codigo: lido.codigo }
|
|
424
|
+
: !doArco.length ? { tipo: 'nada', motivo: 'codigo-desconhecido' }
|
|
425
|
+
: !trecho ? { tipo: 'pergunta-de-volta', mensagem: `Não entendi "${resto.slice(0, 40)}" para ${doArco[0].codigo}; nada foi registrado. Responda a, b ou c.` }
|
|
426
|
+
: { tipo: 'arco', pergunta: doArco[0], trecho };
|
|
427
|
+
}
|
|
428
|
+
else if (lido.forma === 'lote') {
|
|
429
|
+
const { numero, letra } = lido.escolhas[0];
|
|
430
|
+
alvo = alvoMostradoPorUltimo(raiz, entrada, amb, quando, { tipo: 'letra', letra }, numero);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
alvo = lido.forma === 'livre' ? alvoMostradoPorUltimo(raiz, entrada, amb, quando, lido.trecho, null)
|
|
434
|
+
: { tipo: 'nada', motivo: 'nao-e-resposta-curta' };
|
|
435
|
+
}
|
|
436
|
+
if (alvo.tipo === 'nada')
|
|
437
|
+
return decisao({ acao: 'ignorar', motivo: alvo.motivo });
|
|
438
|
+
// GO-FIX 2 (D22): desligado, nada é gravado nem encaminhado, e o dono ouve por onde responder.
|
|
439
|
+
if (!(amb.ligado ?? exports.TERMINAL_LIGADO))
|
|
440
|
+
return desligado(texto, alvo, amb.env);
|
|
441
|
+
// D5: a origem do prompt e da sessão, antes de qualquer gravação ou encaminhamento. A palavra do dono não prova nada.
|
|
442
|
+
const origem = origemDoDono(raiz, entrada, amb);
|
|
443
|
+
if (!origem.ok) {
|
|
444
|
+
const presenca = amb.env.CLAUDE_CODE_SESSION_ATTENDED === '1';
|
|
445
|
+
const sobre = alvo.tipo === 'arco' ? ` para a pergunta ${alvo.pergunta.codigo}` : '';
|
|
446
|
+
return decisao({ acao: 'recusada', motivo: origem.motivo, presenca,
|
|
447
|
+
mensagem: `O Orkastery não registrou "${texto.slice(0, 40)}"${sobre}: ${MOTIVOS[origem.motivo] ?? origem.motivo}. ` +
|
|
448
|
+
'Responda pelo Telegram ou pelo diálogo do host.' });
|
|
449
|
+
}
|
|
450
|
+
if (alvo.tipo === 'pergunta-de-volta')
|
|
451
|
+
return decisao({ acao: 'pergunta', mensagem: alvo.mensagem });
|
|
452
|
+
if (alvo.tipo === 'gate')
|
|
453
|
+
return decisao({ acao: 'encaminhar', contexto: alvo.contexto });
|
|
454
|
+
const atestado = { ...origem.atestado, recebidoEm: quando };
|
|
455
|
+
const pergunta = alvo.pergunta;
|
|
456
|
+
const d = (0, noctum_resposta_1.responderPerguntaDoArco)(raiz, pergunta, alvo.trecho, { quando, canal: 'terminal',
|
|
457
|
+
provar: r => ({ via: 'terminal', atestado, pergunta: { ...r, respostaSha256: sha(entrada.prompt) } }) });
|
|
458
|
+
return decisaoDoDesfecho(pergunta, d);
|
|
459
|
+
}
|