@orkastery/cli 0.5.3 → 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 +195 -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/autoridade.json +56 -0
- package/adapters/claude-code/mods/ork-clima/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-clima/hooks/contas.ts +283 -0
- package/adapters/claude-code/mods/ork-clima/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-clima/hooks/previsao.ts +393 -0
- package/adapters/claude-code/mods/ork-clima/hooks/register.ts +205 -0
- package/adapters/claude-code/mods/ork-clima/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-clima/types/index.d.ts +80 -0
- package/adapters/claude-code/mods/ork-freio/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-freio/hooks/carga.ts +160 -0
- package/adapters/claude-code/mods/ork-freio/hooks/conferencia.ts +309 -0
- package/adapters/claude-code/mods/ork-freio/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-freio/hooks/lote.ts +270 -0
- package/adapters/claude-code/mods/ork-freio/hooks/register.ts +285 -0
- package/adapters/claude-code/mods/ork-freio/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-freio/types/index.d.ts +127 -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-mesa/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/cartoes.tsx +246 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/decidir.ts +110 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/fila.ts +253 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/obvia.ts +98 -0
- package/adapters/claude-code/mods/ork-mesa/hooks/register.tsx +493 -0
- package/adapters/claude-code/mods/ork-mesa/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-mesa/types/index.d.ts +131 -0
- package/adapters/claude-code/mods/ork-pista/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-pista/hooks/acoes.ts +71 -0
- package/adapters/claude-code/mods/ork-pista/hooks/ci.ts +121 -0
- package/adapters/claude-code/mods/ork-pista/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-pista/hooks/pista.tsx +356 -0
- package/adapters/claude-code/mods/ork-pista/hooks/register.tsx +439 -0
- package/adapters/claude-code/mods/ork-pista/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-pista/types/index.d.ts +85 -0
- package/adapters/claude-code/mods/ork-ponte/.claude-plugin/plugin.json +13 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/faixa.tsx +57 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/guarda.ts +410 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/mostrado.ts +55 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/nucleo.ts +157 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/papel.ts +42 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/register.ts +331 -0
- package/adapters/claude-code/mods/ork-ponte/hooks/vigia.ts +76 -0
- package/adapters/claude-code/mods/ork-ponte/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-ponte/types/index.d.ts +178 -0
- package/adapters/claude-code/mods/ork-portao/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-portao/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-portao/hooks/lease.ts +201 -0
- package/adapters/claude-code/mods/ork-portao/hooks/plano.ts +304 -0
- package/adapters/claude-code/mods/ork-portao/hooks/register.ts +339 -0
- package/adapters/claude-code/mods/ork-portao/hooks/verify.ts +152 -0
- package/adapters/claude-code/mods/ork-portao/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-portao/types/index.d.ts +60 -0
- package/adapters/claude-code/mods/ork-radar/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-radar/hooks/colisao.ts +420 -0
- package/adapters/claude-code/mods/ork-radar/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-radar/hooks/mapa.tsx +322 -0
- package/adapters/claude-code/mods/ork-radar/hooks/register.tsx +470 -0
- package/adapters/claude-code/mods/ork-radar/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-radar/types/index.d.ts +72 -0
- 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/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/alertas.ts +85 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/despacho.ts +156 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/register.ts +511 -0
- package/adapters/claude-code/mods/ork-sentinela/hooks/vigia.ts +186 -0
- package/adapters/claude-code/mods/ork-sentinela/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-sentinela/types/index.d.ts +65 -0
- package/adapters/claude-code/mods/ork-torre/.claude-plugin/plugin.json +14 -0
- package/adapters/claude-code/mods/ork-torre/hooks/agenda.ts +60 -0
- package/adapters/claude-code/mods/ork-torre/hooks/detalhe.tsx +236 -0
- package/adapters/claude-code/mods/ork-torre/hooks/frases.ts +42 -0
- package/adapters/claude-code/mods/ork-torre/hooks/hooks.json +3 -0
- package/adapters/claude-code/mods/ork-torre/hooks/painel.tsx +344 -0
- package/adapters/claude-code/mods/ork-torre/hooks/rede.ts +97 -0
- package/adapters/claude-code/mods/ork-torre/hooks/register.tsx +437 -0
- package/adapters/claude-code/mods/ork-torre/orkastery-mod.json +5 -0
- package/adapters/claude-code/mods/ork-torre/types/index.d.ts +108 -0
- 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 +3 -3
- package/adapters/openclaw/README.md +83 -10
- 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/docs-en/markdownlint-cli2.jsonc +22 -0
- package/assets/docs-en/padroes/documentacao-de-produto.md +135 -0
- package/assets/docs-en/padroes/roadmap-de-produto.md +100 -0
- package/assets/docs-en/produto/README.md +14 -0
- package/assets/docs-en/produto/_modelo-feature.md +62 -0
- package/assets/docs-en/roadmap/README.md +14 -0
- package/assets/docs-en/roadmap/_modelo-item.md +75 -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 +193 -15
- package/dist/adapters/codex-controller-worker.js +12 -5
- package/dist/adapters/codex-events.js +16 -4
- package/dist/adapters/codex.js +13 -2
- package/dist/agents-md.js +24 -15
- package/dist/atualizar-branch.js +245 -0
- package/dist/auditoria.js +13 -11
- package/dist/auditrun.js +68 -48
- package/dist/autorizacao-duravel.js +327 -0
- package/dist/board.js +98 -43
- package/dist/branch-de-estado.js +39 -9
- package/dist/busca-semantica.js +7 -5
- package/dist/catalogo.js +35 -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 +255 -46
- package/dist/ciclos.js +8 -6
- package/dist/claim-lint.js +12 -8
- package/dist/claims-conferir.js +350 -0
- package/dist/claims.js +13 -10
- package/dist/company-brain-client.js +45 -3
- package/dist/company-brain-journal.js +2 -1
- package/dist/company-brain-migration.js +47 -6
- package/dist/conducao-batida.js +759 -0
- package/dist/conducao-sentinela.js +405 -0
- package/dist/conducao-texto.js +12 -18
- package/dist/conducao.js +206 -59
- package/dist/conhecimento-consulta.js +270 -0
- package/dist/conhecimento.js +514 -0
- 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 +103 -82
- package/dist/doctor-forja.js +345 -0
- package/dist/doctor-pulse-cron.js +294 -27
- package/dist/doctor-rede.js +18 -17
- package/dist/doctor.js +278 -116
- package/dist/dsn-da-memoria.js +417 -0
- package/dist/entrega-por-mod.js +503 -0
- package/dist/entrega-pr.js +158 -57
- package/dist/escopo-escrita.js +10 -1
- package/dist/esgotamentos.js +13 -11
- package/dist/estado-thread.js +42 -17
- package/dist/evalrunner.js +35 -32
- package/dist/experiencia-instalacao.js +45 -25
- package/dist/fabrica-batida.js +323 -0
- package/dist/fabrica-estado.js +49 -16
- package/dist/fabrica-publicar.js +3 -1
- package/dist/fila-pesada.js +444 -0
- package/dist/fix.js +24 -21
- 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 +124 -81
- package/dist/gates.js +3 -28
- package/dist/handoff.js +33 -19
- 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 +53 -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 +72 -3
- package/dist/hitl-sessions.js +62 -9
- package/dist/hitl-tempo-parado.js +4 -4
- package/dist/hitl-texto-livre.js +7 -4
- package/dist/hitl.js +63 -64
- package/dist/horario.js +30 -7
- package/dist/hosts.js +155 -134
- package/dist/impedimento.js +108 -14
- package/dist/index.js +1421 -1019
- package/dist/indice-vetorial.js +14 -12
- package/dist/indice.js +7 -1
- package/dist/init.js +54 -49
- package/dist/instabilidade.js +144 -0
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +213 -88
- package/dist/intelligence-graph-contexto.js +56 -17
- package/dist/intelligence-graph-contract.js +2 -1
- package/dist/intelligence-graph-extract-md.js +56 -4
- package/dist/intelligence-graph-extract-ts.js +71 -3
- package/dist/intelligence-graph-query.js +96 -34
- package/dist/leases.js +19 -18
- package/dist/ledger-stats.js +17 -16
- package/dist/ledger.js +46 -2
- package/dist/licoes.js +12 -11
- package/dist/liveness.js +6 -3
- package/dist/locale-accounts.js +220 -0
- package/dist/locale-adapter.js +291 -0
- package/dist/locale-ajuda.js +833 -0
- 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 +165 -0
- package/dist/locale-grafo.js +129 -0
- package/dist/locale-master.js +182 -0
- package/dist/locale-network.js +524 -0
- package/dist/locale-onboarding.js +92 -0
- package/dist/locale-operacao-restante.js +931 -0
- package/dist/locale-phase.js +151 -0
- package/dist/locale-projetos.js +100 -0
- package/dist/locale-prompts.js +194 -0
- package/dist/locale-pulse.js +349 -0
- package/dist/locale-reservas.js +87 -0
- package/dist/locale-retry.js +524 -0
- package/dist/locale-roadmap.js +102 -0
- package/dist/locale-security-scan.js +69 -0
- package/dist/locale-setup.js +192 -0
- package/dist/locale-ship.js +597 -0
- package/dist/locale-thread.js +421 -0
- package/dist/locale-verify.js +201 -0
- package/dist/locale-worktree.js +246 -0
- package/dist/locale.js +1258 -0
- package/dist/maestro-runtime.js +22 -3
- package/dist/manifest.js +415 -13
- package/dist/maquina-ociosa.js +211 -0
- package/dist/maquina.js +31 -7
- package/dist/master-digest.js +6 -1
- package/dist/master-nota-local.js +200 -0
- package/dist/master-nota.js +14 -8
- package/dist/master.js +139 -65
- package/dist/mcp-artifacts.js +11 -2
- package/dist/mcp-conhecimento.js +52 -0
- package/dist/mcp-experiencia.js +26 -5
- package/dist/mcp-git.js +23 -6
- package/dist/mcp-grafo.js +7 -4
- package/dist/mcp-install.js +73 -8
- package/dist/mcp-noctum.js +101 -0
- package/dist/mcp-server.js +90 -16
- package/dist/mcp-ship-transporte.js +977 -0
- package/dist/mcp-ship.js +71 -25
- package/dist/mcp-transportes.js +17 -0
- package/dist/mcp-verify.js +6 -1
- package/dist/memoria.js +63 -58
- package/dist/modos-migracao.js +8 -6
- package/dist/modos.js +20 -24
- package/dist/network-roadmap.js +90 -51
- package/dist/noctum-aceite.js +789 -0
- package/dist/noctum-arco.js +1418 -0
- package/dist/noctum-capacidade.js +141 -0
- 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 +1046 -0
- package/dist/noctum-execucao.js +376 -0
- package/dist/noctum-fechamento.js +405 -0
- package/dist/noctum-fila.js +314 -0
- 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 +32 -3
- package/dist/onboarding.js +56 -26
- package/dist/orkmind.js +48 -25
- package/dist/orquestracao.js +44 -47
- package/dist/parado-no-condutor.js +174 -127
- package/dist/phase.js +144 -63
- package/dist/policies.js +37 -4
- package/dist/portfolio.js +4 -2
- package/dist/postura-local.js +235 -0
- package/dist/preflight.js +11 -10
- package/dist/procedencia.js +220 -0
- package/dist/projeto-alvo.js +186 -24
- package/dist/prompts.js +140 -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 +151 -24
- package/dist/pulse-resposta.js +368 -4
- package/dist/pulse.js +188 -22
- package/dist/ratelimit.js +16 -6
- package/dist/recall.js +14 -13
- package/dist/redacao-saida.js +63 -0
- package/dist/rede-adesao.js +13 -8
- package/dist/rede-forja.js +108 -24
- package/dist/rede-status.js +66 -47
- package/dist/rede.js +86 -46
- package/dist/retomada-checkpoint.js +101 -0
- package/dist/retry.js +451 -212
- package/dist/roadmap-reservas.js +45 -28
- package/dist/roadmap-status.js +129 -33
- package/dist/runtime-ambiente.js +5 -0
- package/dist/runtime-context.js +284 -32
- package/dist/runtime-escada.js +423 -0
- package/dist/runtime-profiles.js +103 -46
- package/dist/runtimes.js +2 -1
- 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 +26 -5
- package/dist/session-watcher-claude.js +81 -20
- package/dist/session-watcher.js +340 -42
- package/dist/sessoes-contas.js +10 -1
- package/dist/sessoes-inventario.js +1 -1
- package/dist/sessoes.js +25 -23
- package/dist/setup.js +59 -58
- package/dist/ship-publicar.js +971 -0
- package/dist/ship.js +243 -97
- package/dist/steal.js +77 -0
- package/dist/superficie.js +14 -11
- package/dist/thread-close.js +12 -11
- package/dist/thread.js +274 -100
- 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 +13 -3
- package/dist/varredura-acoes.js +507 -0
- package/dist/verify.js +608 -76
- package/dist/vida-da-thread.js +254 -0
- package/dist/worktree-local.js +167 -0
- package/dist/worktree.js +99 -83
- package/dist/yaml.js +27 -8
- 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/schemas/code-artifact-graph.v1.schema.json +2 -1
- 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
package/dist/tokens.js
CHANGED
|
@@ -63,6 +63,7 @@ const modos_1 = require("./modos");
|
|
|
63
63
|
const phase_1 = require("./phase");
|
|
64
64
|
const thread_1 = require("./thread");
|
|
65
65
|
const util_1 = require("./util");
|
|
66
|
+
const locale_1 = require("./locale");
|
|
66
67
|
/**
|
|
67
68
|
* Janela nominal usada na estimativa por transcript.
|
|
68
69
|
* Declarada, nao escondida: quem le a medida sabe contra o que ela foi calculada.
|
|
@@ -208,21 +209,24 @@ function gateDeTokens(carregado, threadId, opcoes = {}) {
|
|
|
208
209
|
}
|
|
209
210
|
/** Texto de `ork gate next`. */
|
|
210
211
|
function textoDoGateDeTokens(v) {
|
|
212
|
+
const m = (0, locale_1.msg)().operacao.restante.gate.tokens;
|
|
213
|
+
const detalhe = m.localizarDetalhe(v.medida.fonte, v.medida.detalhe);
|
|
214
|
+
const razao = m.localizarRazao(v.medida.ocupacao, v.limiares.rotate_above, v.limiares.force_rotate_above, v.passoPesado, v.razao.includes('refazer fase reprovada'), v.proximoPasso, v.razao);
|
|
211
215
|
const linhas = [];
|
|
212
|
-
linhas.push(
|
|
213
|
-
linhas.push(
|
|
214
|
-
linhas.push(
|
|
215
|
-
linhas.push(
|
|
216
|
-
linhas.push(
|
|
217
|
-
linhas.push(
|
|
216
|
+
linhas.push(m.titulo(v.thread));
|
|
217
|
+
linhas.push(m.ocupacao(v.medida.ocupacao === null ? m.naoMedivel : `${(v.medida.ocupacao * 100).toFixed(1)}%`));
|
|
218
|
+
linhas.push(m.fonte(v.medida.fonte));
|
|
219
|
+
linhas.push(m.detalhe(detalhe));
|
|
220
|
+
linhas.push(m.limiares(v.limiares.rotate_above, v.limiares.force_rotate_above));
|
|
221
|
+
linhas.push(m.proximo(v.proximoPasso, v.passoPesado ? m.pesado : m.leve));
|
|
218
222
|
linhas.push('');
|
|
219
|
-
linhas.push(
|
|
220
|
-
linhas.push(
|
|
223
|
+
linhas.push(m.veredito(v.veredito, v.decididoPor));
|
|
224
|
+
linhas.push(m.razao(razao));
|
|
221
225
|
if (v.slugSugerido) {
|
|
222
|
-
linhas.push(
|
|
223
|
-
linhas.push(
|
|
226
|
+
linhas.push(m.slug(v.slugSugerido));
|
|
227
|
+
linhas.push(m.handoff(v.thread, v.proximoPasso));
|
|
224
228
|
}
|
|
225
229
|
linhas.push('');
|
|
226
|
-
linhas.push(
|
|
230
|
+
linhas.push(m.ledger(v.thread));
|
|
227
231
|
return linhas.join('\n');
|
|
228
232
|
}
|
|
@@ -0,0 +1,297 @@
|
|
|
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.LIMITE_DE_ARQUIVOS_DO_TRABALHO = exports.LIMITE_TOTAL_DO_TRABALHO = exports.LIMITE_DE_ARQUIVO_DO_TRABALHO = void 0;
|
|
37
|
+
exports.diretorioDoTrabalho = diretorioDoTrabalho;
|
|
38
|
+
exports.caminhoDoTrabalho = caminhoDoTrabalho;
|
|
39
|
+
exports.garantirDiretorioDoTrabalho = garantirDiretorioDoTrabalho;
|
|
40
|
+
exports.gravarRespostaFinalDaSessao = gravarRespostaFinalDaSessao;
|
|
41
|
+
exports.resumirTrabalhoDaThread = resumirTrabalhoDaThread;
|
|
42
|
+
exports.formatarResumoDoTrabalho = formatarResumoDoTrabalho;
|
|
43
|
+
/** RM-064 T4: o trabalho pequeno da sessão acompanha a thread entre contas. */
|
|
44
|
+
const node_crypto_1 = require("node:crypto");
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const thread_1 = require("./thread");
|
|
48
|
+
exports.LIMITE_DE_ARQUIVO_DO_TRABALHO = 256 * 1024;
|
|
49
|
+
exports.LIMITE_TOTAL_DO_TRABALHO = 512 * 1024;
|
|
50
|
+
exports.LIMITE_DE_ARQUIVOS_DO_TRABALHO = 24;
|
|
51
|
+
const LIMITE_DE_ENTRADAS = 256;
|
|
52
|
+
const PROFUNDIDADE_MAXIMA = 4;
|
|
53
|
+
/** Caminho real no estado canônico. O prompt usa a forma relativa e portátil de `caminhoDoTrabalho`. */
|
|
54
|
+
function diretorioDoTrabalho(raiz, threadId) {
|
|
55
|
+
return path.join((0, thread_1.dirThread)(raiz, threadId), 'trabalho');
|
|
56
|
+
}
|
|
57
|
+
function caminhoDoTrabalho(threadId) {
|
|
58
|
+
return `.orkastery/threads/${threadId}/trabalho/`;
|
|
59
|
+
}
|
|
60
|
+
function abrirDiretorioDoTrabalho(raiz, threadId) {
|
|
61
|
+
const diretorio = diretorioDoTrabalho(raiz, threadId);
|
|
62
|
+
fs.mkdirSync(diretorio, { recursive: true, mode: 0o700 });
|
|
63
|
+
let fd;
|
|
64
|
+
try {
|
|
65
|
+
fd = fs.openSync(diretorio, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_DIRECTORY);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new Error('trabalho da thread precisa ser diretorio real, nunca link');
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const aberto = fs.fstatSync(fd);
|
|
72
|
+
if (!aberto.isDirectory())
|
|
73
|
+
throw new Error('trabalho da thread precisa ser diretorio real, nunca link');
|
|
74
|
+
// `mode` de mkdir só vale na criação. Pelo descritor, uma troca de caminho não aplica modo em outro alvo.
|
|
75
|
+
fs.fchmodSync(fd, 0o700);
|
|
76
|
+
const real = fs.realpathSync(diretorio), peloCaminho = fs.statSync(real);
|
|
77
|
+
if (aberto.dev !== peloCaminho.dev || aberto.ino !== peloCaminho.ino)
|
|
78
|
+
throw new Error('trabalho da thread mudou durante a abertura');
|
|
79
|
+
return { diretorio, real, fd };
|
|
80
|
+
}
|
|
81
|
+
catch (erro) {
|
|
82
|
+
fs.closeSync(fd);
|
|
83
|
+
throw erro;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function garantirDiretorioDoTrabalho(raiz, threadId) {
|
|
87
|
+
const aberto = abrirDiretorioDoTrabalho(raiz, threadId);
|
|
88
|
+
fs.closeSync(aberto.fd);
|
|
89
|
+
const { diretorio } = aberto;
|
|
90
|
+
return diretorio;
|
|
91
|
+
}
|
|
92
|
+
function nomeSeguro(nome) {
|
|
93
|
+
return nome.replace(/[\u0000-\u001f\u007f]/g, '?');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Persiste a resposta do runtime na pasta privada da thread. O ledger recebe somente este recibo:
|
|
97
|
+
* conteúdo de agente pode conter detalhes grandes ou sensíveis e nunca é copiado para o evento.
|
|
98
|
+
*/
|
|
99
|
+
function gravarRespostaFinalDaSessao(raiz, threadId, sessionId, texto) {
|
|
100
|
+
if (!/^[a-zA-Z0-9-]{1,128}$/.test(sessionId))
|
|
101
|
+
throw new Error('id de sessão inválido para resposta final');
|
|
102
|
+
const aberto = abrirDiretorioDoTrabalho(raiz, threadId);
|
|
103
|
+
const bruto = Buffer.from(texto, 'utf8');
|
|
104
|
+
const truncada = bruto.byteLength > exports.LIMITE_DE_ARQUIVO_DO_TRABALHO;
|
|
105
|
+
const conteudo = truncada
|
|
106
|
+
? Buffer.from(bruto.subarray(0, exports.LIMITE_DE_ARQUIVO_DO_TRABALHO).toString('utf8').replace(/\uFFFD$/, ''), 'utf8')
|
|
107
|
+
: bruto;
|
|
108
|
+
const arquivo = `resposta-final-${sessionId}.md`;
|
|
109
|
+
const alvo = path.join(aberto.diretorio, arquivo);
|
|
110
|
+
const temporario = path.join(aberto.diretorio, `.${arquivo}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`);
|
|
111
|
+
try {
|
|
112
|
+
fs.writeFileSync(temporario, conteudo, { mode: 0o600, flag: 'wx' });
|
|
113
|
+
fs.chmodSync(temporario, 0o600);
|
|
114
|
+
try {
|
|
115
|
+
fs.linkSync(temporario, alvo);
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
if (e.code !== 'EEXIST')
|
|
119
|
+
throw e;
|
|
120
|
+
const existente = lerArquivoSeguro(aberto.real, alvo, {});
|
|
121
|
+
if (existente.estado !== 'ok' || !existente.conteudo.equals(conteudo))
|
|
122
|
+
throw new Error('resposta final já existe com conteúdo divergente');
|
|
123
|
+
}
|
|
124
|
+
const persistido = lerArquivoSeguro(aberto.real, alvo, {});
|
|
125
|
+
if (persistido.estado !== 'ok')
|
|
126
|
+
throw new Error('resposta final não pôde ser reconferida');
|
|
127
|
+
fs.chmodSync(alvo, 0o600);
|
|
128
|
+
return { arquivo, bytes: persistido.conteudo.byteLength,
|
|
129
|
+
sha256: (0, node_crypto_1.createHash)('sha256').update(persistido.conteudo).digest('hex'), truncada };
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
try {
|
|
133
|
+
fs.rmSync(temporario, { force: true });
|
|
134
|
+
}
|
|
135
|
+
catch { /* temporário já ausente */ }
|
|
136
|
+
fs.closeSync(aberto.fd);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const contido = (base, alvo) => alvo === base || alvo.startsWith(base + path.sep);
|
|
140
|
+
/** Abre a entrada sem seguir o componente final e nunca lê mais que o teto mais um byte. */
|
|
141
|
+
function lerArquivoSeguro(baseReal, absoluto, opcoes) {
|
|
142
|
+
try {
|
|
143
|
+
const antes = fs.realpathSync(absoluto);
|
|
144
|
+
if (!contido(baseReal, antes))
|
|
145
|
+
return { estado: 'link' };
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { estado: 'outro' };
|
|
149
|
+
}
|
|
150
|
+
opcoes.antesDeAbrir?.(absoluto);
|
|
151
|
+
let fd;
|
|
152
|
+
try {
|
|
153
|
+
fd = fs.openSync(absoluto, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
154
|
+
}
|
|
155
|
+
catch (erro) {
|
|
156
|
+
return { estado: erro.code === 'ELOOP' ? 'link' : 'outro' };
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const inicial = fs.fstatSync(fd);
|
|
160
|
+
if (!inicial.isFile())
|
|
161
|
+
return { estado: 'outro' };
|
|
162
|
+
if (inicial.size > exports.LIMITE_DE_ARQUIVO_DO_TRABALHO)
|
|
163
|
+
return { estado: 'grande' };
|
|
164
|
+
const buffer = Buffer.alloc(exports.LIMITE_DE_ARQUIVO_DO_TRABALHO + 1);
|
|
165
|
+
let lidos = 0;
|
|
166
|
+
while (lidos < buffer.length) {
|
|
167
|
+
const n = fs.readSync(fd, buffer, lidos, buffer.length - lidos, null);
|
|
168
|
+
if (n === 0)
|
|
169
|
+
break;
|
|
170
|
+
lidos += n;
|
|
171
|
+
}
|
|
172
|
+
const final = fs.fstatSync(fd);
|
|
173
|
+
if (lidos > exports.LIMITE_DE_ARQUIVO_DO_TRABALHO || final.size > exports.LIMITE_DE_ARQUIVO_DO_TRABALHO)
|
|
174
|
+
return { estado: 'grande' };
|
|
175
|
+
// Confere que o caminho ainda aponta para o mesmo inode aberto e continua dentro da pasta.
|
|
176
|
+
let peloCaminho, realDepois;
|
|
177
|
+
try {
|
|
178
|
+
realDepois = fs.realpathSync(absoluto);
|
|
179
|
+
peloCaminho = fs.statSync(realDepois);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { estado: 'outro' };
|
|
183
|
+
}
|
|
184
|
+
if (!contido(baseReal, realDepois) || peloCaminho.dev !== final.dev || peloCaminho.ino !== final.ino)
|
|
185
|
+
return { estado: 'link' };
|
|
186
|
+
// Mudança durante a leitura não produz hash de estado híbrido.
|
|
187
|
+
if (lidos !== final.size || inicial.size !== final.size || inicial.mtimeMs !== final.mtimeMs || inicial.ctimeMs !== final.ctimeMs)
|
|
188
|
+
return { estado: 'outro' };
|
|
189
|
+
return { estado: 'ok', conteudo: buffer.subarray(0, lidos) };
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
fs.closeSync(fd);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Inventário deliberadamente limitado: não segue links, lê cada arquivo por descritor limitado e não deixa uma árvore
|
|
197
|
+
* de job dominar o prompt. A sessão sucessora recebe nomes, tamanhos e hashes; lê o arquivo pelo caminho se precisar.
|
|
198
|
+
*/
|
|
199
|
+
function resumirTrabalhoDaThread(raiz, threadId, opcoes = {}) {
|
|
200
|
+
const aberto = abrirDiretorioDoTrabalho(raiz, threadId);
|
|
201
|
+
const base = aberto.diretorio, baseReal = aberto.real;
|
|
202
|
+
const arquivos = [];
|
|
203
|
+
const ignorados = { grandes: 0, links: 0, excedentes: 0, outros: 0 };
|
|
204
|
+
let bytes = 0;
|
|
205
|
+
let entradas = 0;
|
|
206
|
+
const visitar = (diretorio, relativo, profundidade) => {
|
|
207
|
+
if (profundidade > PROFUNDIDADE_MAXIMA || entradas >= LIMITE_DE_ENTRADAS) {
|
|
208
|
+
ignorados.excedentes += 1;
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
let dir;
|
|
212
|
+
try {
|
|
213
|
+
const real = fs.realpathSync(diretorio);
|
|
214
|
+
if (!contido(baseReal, real) || !fs.lstatSync(diretorio).isDirectory()) {
|
|
215
|
+
ignorados.links += 1;
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
dir = fs.opendirSync(diretorio);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
ignorados.outros += 1;
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const itens = [];
|
|
225
|
+
try {
|
|
226
|
+
while (entradas + itens.length < LIMITE_DE_ENTRADAS) {
|
|
227
|
+
const item = dir.readSync();
|
|
228
|
+
if (!item)
|
|
229
|
+
break;
|
|
230
|
+
itens.push(item);
|
|
231
|
+
}
|
|
232
|
+
if (entradas + itens.length >= LIMITE_DE_ENTRADAS && dir.readSync())
|
|
233
|
+
ignorados.excedentes += 1;
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
dir.closeSync();
|
|
237
|
+
}
|
|
238
|
+
entradas += itens.length;
|
|
239
|
+
itens.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
240
|
+
for (const item of itens) {
|
|
241
|
+
const absoluto = path.join(diretorio, item.name);
|
|
242
|
+
const nome = path.posix.join(relativo, nomeSeguro(item.name));
|
|
243
|
+
if (item.isSymbolicLink()) {
|
|
244
|
+
ignorados.links += 1;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (item.isDirectory()) {
|
|
248
|
+
visitar(absoluto, nome, profundidade + 1);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (!item.isFile()) {
|
|
252
|
+
ignorados.outros += 1;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// Lista ou orçamento já cheios: o arquivo só conta como excedente, sem ser aberto nem lido.
|
|
256
|
+
if (arquivos.length >= exports.LIMITE_DE_ARQUIVOS_DO_TRABALHO || bytes >= exports.LIMITE_TOTAL_DO_TRABALHO) {
|
|
257
|
+
ignorados.excedentes += 1;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const leitura = lerArquivoSeguro(baseReal, absoluto, opcoes);
|
|
261
|
+
if (leitura.estado !== 'ok') {
|
|
262
|
+
if (leitura.estado === 'grande')
|
|
263
|
+
ignorados.grandes += 1;
|
|
264
|
+
else if (leitura.estado === 'link')
|
|
265
|
+
ignorados.links += 1;
|
|
266
|
+
else
|
|
267
|
+
ignorados.outros += 1;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
if (arquivos.length >= exports.LIMITE_DE_ARQUIVOS_DO_TRABALHO || bytes + leitura.conteudo.byteLength > exports.LIMITE_TOTAL_DO_TRABALHO) {
|
|
271
|
+
ignorados.excedentes += 1;
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
arquivos.push({ arquivo: nome, bytes: leitura.conteudo.byteLength,
|
|
275
|
+
sha256: (0, node_crypto_1.createHash)('sha256').update(leitura.conteudo).digest('hex') });
|
|
276
|
+
bytes += leitura.conteudo.byteLength;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
try {
|
|
280
|
+
visitar(base, '', 0);
|
|
281
|
+
return { caminho: caminhoDoTrabalho(threadId), arquivos, ignorados };
|
|
282
|
+
}
|
|
283
|
+
finally {
|
|
284
|
+
fs.closeSync(aberto.fd);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function formatarResumoDoTrabalho(resumo) {
|
|
288
|
+
const linhas = resumo.arquivos.length
|
|
289
|
+
? resumo.arquivos.map((a) => ` - \`${a.arquivo.replace(/`/g, '\\`')}\` (${a.bytes} bytes, sha256 \`${a.sha256}\`)`)
|
|
290
|
+
: [' - (nenhum arquivo pequeno)'];
|
|
291
|
+
const totalIgnorado = Object.values(resumo.ignorados).reduce((soma, n) => soma + n, 0);
|
|
292
|
+
if (totalIgnorado > 0) {
|
|
293
|
+
linhas.push(` - Ignorados pelos limites: ${resumo.ignorados.grandes} grandes, ${resumo.ignorados.links} links, ` +
|
|
294
|
+
`${resumo.ignorados.excedentes} excedentes, ${resumo.ignorados.outros} outros.`);
|
|
295
|
+
}
|
|
296
|
+
return linhas.join('\n');
|
|
297
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
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.DESTINO_DO_CANAL = exports.HOSTS_DO_CANAL = void 0;
|
|
37
|
+
exports.canalValido = canalValido;
|
|
38
|
+
exports.transporteValido = transporteValido;
|
|
39
|
+
exports.hostDoTransporte = hostDoTransporte;
|
|
40
|
+
exports.transporteDoCanal = transporteDoCanal;
|
|
41
|
+
exports.caminhoDoPulseHost = caminhoDoPulseHost;
|
|
42
|
+
exports.gravarTransporteDoCanal = gravarTransporteDoCanal;
|
|
43
|
+
/**
|
|
44
|
+
* RM-063 (fatia 3, H3 e H4): o transporte do pulse pronto de cada host, gravado pelo onboarding junto com o canal do dono.
|
|
45
|
+
*
|
|
46
|
+
* Incidente de 03 a 12/10/2026 (P1 da pagina da RM-063): sem `pulse-host.json`, o `ork doctor` calava e a maquina ficou
|
|
47
|
+
* nove dias sem batida e sem aviso. O transporte era um JSON que o dono escrevia a mao, com o executavel e os argumentos
|
|
48
|
+
* de cada host, e so o do OpenClaw estava pronto num guia. Agora a etapa `maestro` do onboarding aceita o canal do dono
|
|
49
|
+
* (`canal: { host, destino }`) e grava o `.orkastery/monitor/pulse-host.json` desta maquina com o modelo pronto do host:
|
|
50
|
+
*
|
|
51
|
+
* - `openclaw`: `openclaw message send --channel telegram --target <chat> --message {{mensagem}} --json`;
|
|
52
|
+
* - `hermes`: o Python do venv do Hermes com o `ork-pulse-enviar.py` do adaptador e `--target telegram:<chat>[:<topico>]`.
|
|
53
|
+
*
|
|
54
|
+
* O canal de um host novo vira o principal, e o do outro host que ja estava fica como alternativo (H4): a entrega tenta o
|
|
55
|
+
* outro quando o primeiro falha. O arquivo e desta maquina e nunca vai ao git (RM-047).
|
|
56
|
+
*/
|
|
57
|
+
const fs = __importStar(require("node:fs"));
|
|
58
|
+
const os = __importStar(require("node:os"));
|
|
59
|
+
const path = __importStar(require("node:path"));
|
|
60
|
+
const node_crypto_1 = require("node:crypto");
|
|
61
|
+
const estado_thread_1 = require("./estado-thread");
|
|
62
|
+
const procedencia_1 = require("./procedencia");
|
|
63
|
+
const util_1 = require("./util");
|
|
64
|
+
exports.HOSTS_DO_CANAL = ['openclaw', 'hermes'];
|
|
65
|
+
exports.DESTINO_DO_CANAL = /^telegram:(-?\d{1,20})(?::(\d{1,12}))?$/;
|
|
66
|
+
const MARCA = '{' + '{mensagem}}';
|
|
67
|
+
const CHAVES_DO_CANAL = ['host', 'destino', 'executavel', 'script'];
|
|
68
|
+
const caminhoAceito = (v) => typeof v === 'string' && v.length <= 4096 && path.isAbsolute(v) && !/\p{Cc}/u.test(v);
|
|
69
|
+
/** A forma do canal, sem tocar o disco: host conhecido, destino Telegram explicito e caminhos absolutos. */
|
|
70
|
+
function canalValido(v) {
|
|
71
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
72
|
+
return false;
|
|
73
|
+
const c = v;
|
|
74
|
+
if (Object.keys(c).some((k) => !CHAVES_DO_CANAL.includes(k)))
|
|
75
|
+
return false;
|
|
76
|
+
if (!exports.HOSTS_DO_CANAL.includes(c.host))
|
|
77
|
+
return false;
|
|
78
|
+
if (typeof c.destino !== 'string' || !exports.DESTINO_DO_CANAL.test(c.destino))
|
|
79
|
+
return false;
|
|
80
|
+
if (c.executavel !== undefined && !caminhoAceito(c.executavel))
|
|
81
|
+
return false;
|
|
82
|
+
if (c.script !== undefined && (c.host !== 'hermes' || !caminhoAceito(c.script)))
|
|
83
|
+
return false;
|
|
84
|
+
// O `message send` do OpenClaw recebe o chat; o topico e do transporte do Hermes.
|
|
85
|
+
if (c.host === 'openclaw' && exports.DESTINO_DO_CANAL.exec(c.destino)?.[2] !== undefined)
|
|
86
|
+
return false;
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
/** Um transporte valido: executavel e argumentos de texto, com `{{mensagem}}` em algum. */
|
|
90
|
+
function transporteValido(t) {
|
|
91
|
+
const c = t;
|
|
92
|
+
return !!c && typeof c.executavel === 'string' && !!c.executavel && Array.isArray(c.argumentos) &&
|
|
93
|
+
c.argumentos.every((a) => typeof a === 'string') && c.argumentos.some((a) => a.includes(MARCA));
|
|
94
|
+
}
|
|
95
|
+
/** O nome do host de um transporte: o declarado, ou o que o executavel e os argumentos dizem. */
|
|
96
|
+
function hostDoTransporte(t) {
|
|
97
|
+
if (typeof t.host === 'string' && /^[a-z0-9][a-z0-9._-]{0,39}$/i.test(t.host))
|
|
98
|
+
return t.host;
|
|
99
|
+
const nomes = [t.executavel, ...t.argumentos].map((a) => path.basename(a)).join(' ');
|
|
100
|
+
return /openclaw/i.test(nomes) ? 'openclaw' : /hermes|ork-pulse-enviar/i.test(nomes) ? 'hermes' : path.basename(t.executavel).slice(0, 40);
|
|
101
|
+
}
|
|
102
|
+
const executavel = (arquivo) => {
|
|
103
|
+
try {
|
|
104
|
+
fs.accessSync(arquivo, fs.constants.X_OK);
|
|
105
|
+
return fs.statSync(arquivo).isFile();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* O transporte pronto do host do canal, com os caminhos desta maquina. Lanca `onboarding.canal.transporte` com a
|
|
113
|
+
* correcao quando o executavel do host nao esta aqui: o onboarding nao grava um transporte que nunca entrega.
|
|
114
|
+
*/
|
|
115
|
+
function transporteDoCanal(raiz, canal, env = process.env) {
|
|
116
|
+
const falta = (detalhe) => { throw new Error(`onboarding.canal.transporte: ${detalhe}`); };
|
|
117
|
+
if (canal.host === 'openclaw') {
|
|
118
|
+
const bin = canal.executavel ?? (0, util_1.noPath)('openclaw', env);
|
|
119
|
+
if (!bin || !path.isAbsolute(bin) || !executavel(bin)) {
|
|
120
|
+
return falta('o openclaw não está no PATH desta máquina; informe canal.executavel com o caminho absoluto dele');
|
|
121
|
+
}
|
|
122
|
+
if ((0, procedencia_1.rastreadoPeloGit)(raiz, bin))
|
|
123
|
+
return falta(`${bin} está versionado no git: o transporte só vale de um arquivo local desta máquina`);
|
|
124
|
+
const chat = exports.DESTINO_DO_CANAL.exec(canal.destino)[1];
|
|
125
|
+
return { host: 'openclaw', destino: canal.destino, executavel: bin,
|
|
126
|
+
argumentos: ['message', 'send', '--channel', 'telegram', '--target', chat, '--message', MARCA, '--json'] };
|
|
127
|
+
}
|
|
128
|
+
const casa = (env.HERMES_HOME ?? '').trim() || path.join(os.homedir(), '.hermes');
|
|
129
|
+
const agente = (env.HERMES_AGENT_DIR ?? '').trim() || path.join(casa, 'hermes-agent');
|
|
130
|
+
const python = canal.executavel ?? path.join(agente, 'venv', 'bin', 'python3');
|
|
131
|
+
if (!executavel(python))
|
|
132
|
+
return falta(`o Python do venv do Hermes não está em ${python}; informe canal.executavel`);
|
|
133
|
+
const script = canal.script ?? [path.join(casa, 'bin', 'ork-pulse-enviar.py'), path.join((0, estado_thread_1.raizDoEstado)(raiz), '.hermes', 'bin', 'ork-pulse-enviar.py')]
|
|
134
|
+
.find((s) => fs.existsSync(s));
|
|
135
|
+
if (!script || !fs.existsSync(script)) {
|
|
136
|
+
return falta('o ork-pulse-enviar.py do adaptador Hermes não foi achado (ork adapter install hermes); informe canal.script');
|
|
137
|
+
}
|
|
138
|
+
// RM-047: o que a entrega executa so vale do arquivo local desta maquina; versionado no git, veio com o repositorio.
|
|
139
|
+
for (const arquivo of [python, script]) {
|
|
140
|
+
if ((0, procedencia_1.rastreadoPeloGit)(raiz, arquivo))
|
|
141
|
+
return falta(`${arquivo} está versionado no git: o transporte só vale de um arquivo local desta máquina`);
|
|
142
|
+
}
|
|
143
|
+
return { host: 'hermes', destino: canal.destino, executavel: python, argumentos: [script, '--target', canal.destino, '--message', MARCA] };
|
|
144
|
+
}
|
|
145
|
+
function caminhoDoPulseHost(raiz) {
|
|
146
|
+
return path.join((0, estado_thread_1.raizDoEstado)(raiz), '.orkastery', 'monitor', 'pulse-host.json');
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Grava o transporte do canal como o principal do `pulse-host.json` desta maquina. O principal de outro host que ja
|
|
150
|
+
* estava vira alternativo, na frente dos outros; o do mesmo host e trocado. Devolve o arquivo e os hosts alternativos.
|
|
151
|
+
*/
|
|
152
|
+
function gravarTransporteDoCanal(raiz, novo) {
|
|
153
|
+
const arquivo = caminhoDoPulseHost(raiz);
|
|
154
|
+
(0, procedencia_1.exigirHostLocal)(raiz, arquivo);
|
|
155
|
+
let atual = null;
|
|
156
|
+
try {
|
|
157
|
+
const lido = JSON.parse(fs.readFileSync(arquivo, 'utf8'));
|
|
158
|
+
if (transporteValido(lido))
|
|
159
|
+
atual = lido;
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
atual = null;
|
|
163
|
+
}
|
|
164
|
+
const host = hostDoTransporte(novo);
|
|
165
|
+
const alternativos = [];
|
|
166
|
+
const somar = (t) => {
|
|
167
|
+
const h = hostDoTransporte(t);
|
|
168
|
+
if (h !== host && !alternativos.some((a) => hostDoTransporte(a) === h)) {
|
|
169
|
+
alternativos.push({ ...(t.host ? { host: t.host } : { host: h }), ...(t.destino ? { destino: t.destino } : {}),
|
|
170
|
+
executavel: t.executavel, argumentos: t.argumentos });
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
if (atual) {
|
|
174
|
+
somar(atual);
|
|
175
|
+
for (const a of Array.isArray(atual.alternativos) ? atual.alternativos.filter(transporteValido) : [])
|
|
176
|
+
somar(a);
|
|
177
|
+
}
|
|
178
|
+
const conteudo = { ...novo, ...(alternativos.length ? { alternativos } : {}) };
|
|
179
|
+
fs.mkdirSync(path.dirname(arquivo), { recursive: true });
|
|
180
|
+
const temporario = `${arquivo}.${process.pid}.${(0, node_crypto_1.randomUUID)().slice(0, 8)}.tmp`;
|
|
181
|
+
try {
|
|
182
|
+
fs.writeFileSync(temporario, JSON.stringify(conteudo, null, 2) + '\n', { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
183
|
+
fs.renameSync(temporario, arquivo);
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
fs.rmSync(temporario, { force: true });
|
|
187
|
+
}
|
|
188
|
+
return { arquivo, alternativos: alternativos.map(hostDoTransporte) };
|
|
189
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Nada aqui depende de LLM; tudo e deterministico e testavel.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.DIGITO_DA_FASE = exports.FASES = void 0;
|
|
9
|
+
exports.ESTADOS_DE_TRABALHO = exports.DIGITO_DA_FASE = exports.FASES = void 0;
|
|
10
|
+
exports.estadoDeTrabalho = estadoDeTrabalho;
|
|
10
11
|
/** Ordem canonica das fases. */
|
|
11
12
|
exports.FASES = ['GOAL', 'PLAN', 'GO', 'CHECK', 'SHIP', 'MASTER'];
|
|
12
13
|
/** Alias numerico herdado do Devmaster (F1..F6), usado na parte 3 do slug. */
|
|
@@ -18,3 +19,13 @@ exports.DIGITO_DA_FASE = {
|
|
|
18
19
|
SHIP: '5',
|
|
19
20
|
MASTER: '6',
|
|
20
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* RM-063 (fatia 3, achado a): os estados crus do runtime que sao trabalho em curso. O `claude agents --json` diz
|
|
24
|
+
* `working` para a sessao de fundo, e `busy` ou `running` para a interativa que executa um turno: nenhum dos tres e
|
|
25
|
+
* parada, com ou sem thread.
|
|
26
|
+
*/
|
|
27
|
+
exports.ESTADOS_DE_TRABALHO = ['working', 'busy', 'running'];
|
|
28
|
+
/** O estado cru e trabalho em curso? */
|
|
29
|
+
function estadoDeTrabalho(estado) {
|
|
30
|
+
return typeof estado === 'string' && exports.ESTADOS_DE_TRABALHO.includes(estado.trim().toLowerCase());
|
|
31
|
+
}
|
package/dist/util.js
CHANGED
|
@@ -53,6 +53,8 @@ exports.tabela = tabela;
|
|
|
53
53
|
const node_child_process_1 = require("node:child_process");
|
|
54
54
|
const fs = __importStar(require("node:fs"));
|
|
55
55
|
const path = __importStar(require("node:path"));
|
|
56
|
+
/** Saidas de build e teste podem passar do teto padrao de 1 MiB do `spawnSync`. */
|
|
57
|
+
const MAX_BUFFER_EXEC = 64 * 1024 * 1024;
|
|
56
58
|
/** Executa um comando capturando saida, sem shell (argumentos vao como array). */
|
|
57
59
|
function exec(cmd, args, cwd, timeoutMs = 120000, env = process.env) {
|
|
58
60
|
const r = (0, node_child_process_1.spawnSync)(cmd, args, {
|
|
@@ -60,6 +62,7 @@ function exec(cmd, args, cwd, timeoutMs = 120000, env = process.env) {
|
|
|
60
62
|
encoding: 'utf8',
|
|
61
63
|
timeout: timeoutMs,
|
|
62
64
|
env,
|
|
65
|
+
maxBuffer: MAX_BUFFER_EXEC,
|
|
63
66
|
});
|
|
64
67
|
return {
|
|
65
68
|
ok: r.status === 0,
|
|
@@ -119,7 +122,7 @@ exports.GITIGNORE_DA_MAQUINA = '# Criado pelo ork: esta pasta é da máquina, n
|
|
|
119
122
|
* nao cria quando o repositorio ja rastreia algo nela: o projeto que versiona o proprio estado segue
|
|
120
123
|
* versionando. Devolve se criou.
|
|
121
124
|
*/
|
|
122
|
-
function ignorarPastaNoGit(dir, raizDoRepo) {
|
|
125
|
+
function ignorarPastaNoGit(dir, raizDoRepo, conteudo = exports.GITIGNORE_DA_MAQUINA) {
|
|
123
126
|
const relativo = path.relative(raizDoRepo, dir);
|
|
124
127
|
if (!relativo || relativo.startsWith('..') || path.isAbsolute(relativo))
|
|
125
128
|
return false;
|
|
@@ -131,7 +134,7 @@ function ignorarPastaNoGit(dir, raizDoRepo) {
|
|
|
131
134
|
return false;
|
|
132
135
|
fs.mkdirSync(dir, { recursive: true });
|
|
133
136
|
try {
|
|
134
|
-
fs.writeFileSync(arquivo,
|
|
137
|
+
fs.writeFileSync(arquivo, conteudo, { flag: 'wx' });
|
|
135
138
|
}
|
|
136
139
|
catch {
|
|
137
140
|
return false;
|
|
@@ -197,7 +200,14 @@ function lerJsonl(caminho) {
|
|
|
197
200
|
/** Anexa um registro ao armazem JSONL, criando o diretorio que faltar. */
|
|
198
201
|
function anexarJsonl(caminho, valor) {
|
|
199
202
|
fs.mkdirSync(path.dirname(caminho), { recursive: true });
|
|
200
|
-
|
|
203
|
+
// RM-047: O_NOFOLLOW; um armazém versionado como link (claims, board) não leva o append para fora da raiz.
|
|
204
|
+
const fd = fs.openSync(caminho, fs.constants.O_WRONLY | fs.constants.O_APPEND | fs.constants.O_CREAT | fs.constants.O_NOFOLLOW, 0o644);
|
|
205
|
+
try {
|
|
206
|
+
fs.writeFileSync(fd, JSON.stringify(valor) + '\n', 'utf8');
|
|
207
|
+
}
|
|
208
|
+
finally {
|
|
209
|
+
fs.closeSync(fd);
|
|
210
|
+
}
|
|
201
211
|
}
|
|
202
212
|
/** Proximo id sequencial de um armazem (`C1`, `C2`, ... / `F1`, `F2`, ...). */
|
|
203
213
|
function proximoIdSequencial(ids, prefixo) {
|