@orkastery/cli 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +86 -65
- package/adapters/README.md +30 -15
- package/adapters/claude-code/.claude-plugin/plugin.json +11 -5
- package/adapters/claude-code/README.md +110 -8
- package/adapters/claude-code/commands/check.md +4 -3
- package/adapters/claude-code/commands/goal.md +3 -2
- package/adapters/claude-code/commands/master.md +3 -2
- package/adapters/claude-code/commands/onboarding.md +21 -0
- package/adapters/claude-code/commands/ork.md +99 -27
- package/adapters/claude-code/hooks/hooks.json +6 -1
- package/adapters/claude-code/hooks/ork-guard.js +1 -1
- package/adapters/claude-code/hooks/ork-sensor.js +66 -0
- package/adapters/codex/skills/ork/SKILL.md +57 -0
- package/adapters/hermes/README.md +161 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +2 -0
- package/adapters/hermes/bin/ork-brain.sh +4 -0
- package/adapters/hermes/bin/ork-hitl-answer.py +82 -0
- package/adapters/hermes/bin/ork-maestro.sh +6 -0
- package/adapters/hermes/bin/ork-master-enviar.py +84 -0
- package/adapters/hermes/bin/ork-pulse-enviar.py +47 -0
- package/adapters/hermes/hermes.plugin.json +24 -4
- package/adapters/hermes/hitl-ingress/__init__.py +356 -0
- package/adapters/hermes/hitl-ingress/plugin.yaml +4 -0
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +75 -22
- package/adapters/openclaw/README.md +136 -27
- package/adapters/openclaw/bin/ork-brain.sh +4 -0
- package/adapters/openclaw/construir.sh +19 -0
- package/adapters/openclaw/dist/hitl-ingress.js +199 -0
- package/adapters/openclaw/dist/index.js +437 -0
- package/adapters/openclaw/openclaw.plugin.json +39 -134
- package/adapters/openclaw/package.json +26 -0
- package/adapters/openclaw/src/hitl-ingress.ts +180 -0
- package/adapters/openclaw/src/index.ts +460 -0
- package/adapters/openclaw/src/tipos-openclaw.d.ts +58 -0
- package/adapters/openclaw/tsconfig.json +15 -0
- package/assets/docs/markdownlint-cli2.jsonc +22 -0
- package/assets/docs/padroes/documentacao-de-produto.md +133 -0
- package/assets/docs/padroes/roadmap-de-produto.md +98 -0
- package/assets/docs/produto/README.md +14 -0
- package/assets/docs/produto/_modelo-feature.md +59 -0
- package/assets/docs/roadmap/README.md +14 -0
- package/assets/docs/roadmap/_modelo-item.md +73 -0
- package/assets/orkmind-native-schema.json +32 -0
- package/assets/orkmind_bridge.py +357 -0
- package/assets/orkmind_fixture.py +67 -0
- package/assets/orkmind_prospective.py +138 -0
- package/assets/reference-tariffs-i07.json +23 -0
- package/dist/adapters/claude-bg.js +488 -39
- package/dist/adapters/codex-controller-sensor.js +449 -0
- package/dist/adapters/codex-controller-worker.js +361 -0
- package/dist/adapters/codex-controller.js +252 -0
- package/dist/adapters/codex-events.js +205 -0
- package/dist/adapters/codex-question.js +26 -0
- package/dist/adapters/codex-runner.js +133 -0
- package/dist/adapters/codex.js +394 -0
- package/dist/agents-md.js +84 -0
- package/dist/auditoria.js +12 -9
- package/dist/auditrun.js +5 -4
- package/dist/board.js +174 -23
- package/dist/branch-de-estado.js +136 -0
- package/dist/canarios-hitl.js +177 -0
- package/dist/canarios-i43.js +543 -0
- package/dist/canarios-pulse.js +147 -0
- package/dist/canarios-sensores.js +129 -0
- package/dist/canarios.js +111 -2
- package/dist/catalogo.js +9 -0
- package/dist/ci.js +223 -0
- package/dist/ciclos.js +2 -1
- package/dist/claim-lint.js +64 -0
- package/dist/claims.js +60 -0
- package/dist/company-brain-capture.js +195 -0
- package/dist/company-brain-cli.js +123 -0
- package/dist/company-brain-client.js +61 -0
- package/dist/company-brain-contract.js +166 -0
- package/dist/company-brain-journal.js +192 -0
- package/dist/company-brain-mcp.js +33 -0
- package/dist/company-brain-migration.js +60 -0
- package/dist/company-brain-source.js +177 -0
- package/dist/company-brain-worker.js +18 -0
- package/dist/conducao-texto.js +61 -0
- package/dist/conducao.js +876 -0
- package/dist/contrato-publico.js +39 -0
- package/dist/creation-operation-store.js +251 -0
- package/dist/creation-operation.js +148 -0
- package/dist/decisao-autonoma.js +183 -0
- package/dist/delegation.js +79 -0
- package/dist/demo.js +120 -0
- package/dist/docs.js +828 -0
- package/dist/doctor.js +184 -25
- package/dist/entrega-pr.js +117 -0
- package/dist/escopo-escrita.js +71 -0
- package/dist/estado-thread.js +222 -0
- package/dist/evalrunner.js +12 -0
- package/dist/fabrica-estado.js +329 -0
- package/dist/fabrica-publicar.js +76 -0
- package/dist/fix.js +22 -1
- package/dist/gates.js +59 -11
- package/dist/handoff.js +39 -23
- package/dist/hitl-canais.js +333 -0
- package/dist/hitl-classificacao.js +131 -0
- package/dist/hitl-contract.js +465 -0
- package/dist/hitl-estado.js +136 -0
- package/dist/hitl-gates.js +554 -0
- package/dist/hitl-ingress-receipt.js +382 -0
- package/dist/hitl-local-atestado.js +57 -0
- package/dist/hitl-local-receipt.js +328 -0
- package/dist/hitl-local.js +143 -0
- package/dist/hitl-lock.js +139 -0
- package/dist/hitl-lote.js +223 -0
- package/dist/hitl-native-offer.js +97 -0
- package/dist/hitl-native.js +65 -0
- package/dist/hitl-presentation.js +209 -0
- package/dist/hitl-public-receipt.js +176 -0
- package/dist/hitl-resumo.js +209 -0
- package/dist/hitl-sessions.js +475 -0
- package/dist/hitl.js +711 -0
- package/dist/horario.js +269 -0
- package/dist/hosts.js +198 -22
- package/dist/index.js +1741 -94
- package/dist/indice.js +99 -0
- package/dist/init.js +28 -3
- package/dist/integracoes-locais.js +17 -0
- package/dist/leases.js +65 -21
- package/dist/ledger-stats.js +272 -0
- package/dist/ledger.js +109 -2
- package/dist/licoes.js +221 -0
- package/dist/liveness.js +218 -0
- package/dist/maestro-actions.js +51 -0
- package/dist/maestro-authority.js +152 -0
- package/dist/maestro-cli.js +97 -0
- package/dist/maestro-contract.js +55 -0
- package/dist/maestro-discovery.js +132 -0
- package/dist/maestro-runtime.js +268 -0
- package/dist/maestro-snapshot.js +86 -0
- package/dist/maestro-sources.js +224 -0
- package/dist/manifest.js +165 -6
- package/dist/maquina.js +102 -0
- package/dist/master-audit.js +101 -0
- package/dist/master-batch.js +43 -0
- package/dist/master-digest.js +149 -0
- package/dist/master-migracao.js +155 -0
- package/dist/master.js +361 -77
- package/dist/mcp-artifacts.js +234 -0
- package/dist/mcp-git.js +433 -0
- package/dist/mcp-install.js +310 -0
- package/dist/mcp-maestro.js +25 -0
- package/dist/mcp-server.js +469 -0
- package/dist/mcp-ship.js +436 -0
- package/dist/mcp-verify.js +173 -0
- package/dist/memoria-humana.js +207 -0
- package/dist/memoria.js +314 -78
- package/dist/memory-migration.js +279 -0
- package/dist/memory-prospective.js +148 -0
- package/dist/modos-migracao.js +191 -0
- package/dist/modos.js +151 -15
- package/dist/monitor-lock.js +110 -0
- package/dist/objective.js +449 -0
- package/dist/ocupacao.js +267 -0
- package/dist/onboarding.js +303 -0
- package/dist/orkmind.js +389 -90
- package/dist/orquestracao.js +96 -69
- package/dist/phase.js +612 -151
- package/dist/playbook-capabilities.js +150 -0
- package/dist/playbook-contracts.js +188 -0
- package/dist/policies.js +72 -0
- package/dist/portfolio-context.js +61 -0
- package/dist/portfolio.js +180 -0
- package/dist/preflight.js +207 -0
- package/dist/process-audit.js +112 -0
- package/dist/project-state.js +93 -0
- package/dist/prompts.js +25 -5
- package/dist/prova-minima.js +112 -0
- package/dist/pulse-cadencia.js +163 -0
- package/dist/pulse-consentimento.js +260 -0
- package/dist/pulse-delivery.js +323 -0
- package/dist/pulse-resposta.js +542 -0
- package/dist/pulse.js +262 -0
- package/dist/ratelimit.js +35 -2
- package/dist/recall.js +80 -3
- package/dist/redacao-saida.js +45 -0
- package/dist/redacao-url.js +66 -0
- package/dist/retry.js +640 -118
- package/dist/roadmap-reservas.js +243 -0
- package/dist/runtime-ambiente.js +38 -0
- package/dist/runtime-context.js +215 -0
- package/dist/runtime-profiles.js +869 -0
- package/dist/runtimes.js +103 -0
- package/dist/sandbox.js +9 -0
- package/dist/session-events.js +203 -0
- package/dist/session-watcher-claude.js +637 -0
- package/dist/session-watcher.js +700 -0
- package/dist/sessoes-adopt.js +154 -0
- package/dist/sessoes-inventario.js +159 -0
- package/dist/sessoes.js +16 -35
- package/dist/setup.js +691 -0
- package/dist/ship.js +168 -19
- package/dist/slug.js +1 -1
- package/dist/thread-close.js +115 -0
- package/dist/thread.js +142 -28
- package/dist/tokens.js +1 -1
- package/dist/util.js +4 -2
- package/dist/verify-sandbox.js +265 -0
- package/dist/verify.js +270 -25
- package/dist/versao.js +60 -0
- package/dist/worktree.js +31 -2
- package/dist/write-activation.js +291 -0
- package/dist/yaml.js +5 -1
- package/eval/casos/master-metrics.json +1 -1
- package/eval/casos/onboarding.json +102 -0
- package/eval/casos/orkastery-bootstrap.json +37 -3
- package/eval/casos/scope-check-capability-map.json +45 -7
- package/eval/casos/ship-release.json +3 -3
- package/eval/fixtures/b0-slug-e-modos/caso.json +35 -22
- package/eval/fixtures/b2-master-log/caso.json +1 -1
- package/eval/fixtures/fx-adapter-editado-detectado/caso.json +19 -0
- package/eval/fixtures/fx-auto-quiet/caso.json +11 -0
- package/eval/fixtures/fx-blanket-approve/caso.json +10 -0
- package/eval/fixtures/fx-check-runtime-cruzado/caso.json +20 -0
- package/eval/fixtures/fx-codex-dry/caso.json +18 -0
- package/eval/fixtures/fx-donewhen-executavel/caso.json +15 -0
- package/eval/fixtures/fx-estado-dividido/caso.json +15 -0
- package/eval/fixtures/fx-fase-orfa/caso.json +116 -0
- package/eval/fixtures/fx-happy/caso.json +6 -4
- package/eval/fixtures/fx-hitl-latency/caso.json +20 -0
- package/eval/fixtures/fx-indice-reversao/caso.json +25 -0
- package/eval/fixtures/fx-listagem-abertas/caso.json +16 -0
- package/eval/fixtures/fx-maestro-bootstrap/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-escritor/caso.json +21 -0
- package/eval/fixtures/fx-modo-aposentado-leitor/caso.json +16 -0
- package/eval/fixtures/fx-objective-oscillation/caso.json +14 -0
- package/eval/fixtures/fx-omnicanal/caso.json +17 -0
- package/eval/fixtures/fx-sensores-runtime/caso.json +17 -0
- package/monitor/company-brain.cjs +17 -0
- package/monitor/pulse-scope.cjs +45 -0
- package/monitor/pulse.cron +18 -0
- package/monitor/varredura-pulse.sh +27 -0
- package/package.json +28 -7
- package/references/definition-of-done.md +2 -2
- package/schemas/claims.schema.json +25 -0
- package/schemas/company-brain.schema.json +1158 -0
- package/schemas/creation-operation.schema.json +365 -0
- package/schemas/maestro-snapshot.schema.json +2716 -0
- package/skills/README.md +3 -3
- package/skills/core/onboarding/SKILL.md +50 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +95 -65
- package/skills/core/thread-state/SKILL.md +3 -1
- package/skills/governance/decision-triage/SKILL.md +4 -4
- package/skills/governance/narrative-guardian/SKILL.md +1 -1
- package/skills/governance/roadmap-keeper/SKILL.md +1 -1
- package/skills/governance/scope-check-capability-map/SKILL.md +17 -7
- package/skills/observability/thread-tracing/SKILL.md +1 -1
- package/skills/phases/check-quality/SKILL.md +2 -2
- package/skills/phases/goal-definition/SKILL.md +1 -1
- package/skills/phases/master-metrics/SKILL.md +9 -7
- package/skills/phases/plan-specification/SKILL.md +1 -1
- package/skills/phases/ship-release/SKILL.md +1 -1
package/dist/doctor.js
CHANGED
|
@@ -39,21 +39,72 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.checarContas = checarContas;
|
|
43
|
+
exports.checarOnboarding = checarOnboarding;
|
|
42
44
|
exports.checar = checar;
|
|
43
45
|
exports.relatorio = relatorio;
|
|
44
46
|
exports.doctor = doctor;
|
|
45
47
|
const fs = __importStar(require("node:fs"));
|
|
46
48
|
const path = __importStar(require("node:path"));
|
|
47
49
|
const adapter = __importStar(require("./adapters/claude-bg"));
|
|
50
|
+
const codexAdapter = __importStar(require("./adapters/codex"));
|
|
48
51
|
const manifest_1 = require("./manifest");
|
|
49
52
|
const modos_1 = require("./modos");
|
|
50
53
|
const orkmind_1 = require("./orkmind");
|
|
54
|
+
const onboarding_1 = require("./onboarding");
|
|
51
55
|
const ratelimit_1 = require("./ratelimit");
|
|
52
56
|
const slug_1 = require("./slug");
|
|
57
|
+
const horario_1 = require("./horario");
|
|
53
58
|
const util_1 = require("./util");
|
|
59
|
+
const sessoes_inventario_1 = require("./sessoes-inventario");
|
|
60
|
+
const estado_thread_1 = require("./estado-thread");
|
|
61
|
+
const project_state_1 = require("./project-state");
|
|
62
|
+
const runtime_ambiente_1 = require("./runtime-ambiente");
|
|
63
|
+
const runtime_profiles_1 = require("./runtime-profiles");
|
|
64
|
+
const preflight_1 = require("./preflight");
|
|
65
|
+
/**
|
|
66
|
+
* I-33 (D7): check "contas por runtime". Cada perfil ativo tem o login conferido pelo proprio
|
|
67
|
+
* CLI com o env dele (`claude auth status`, `codex login status`); o doctor so le e relata, sem
|
|
68
|
+
* marcar o store. Runtime com perfis e nenhum pronto reprova: o despacho dele nao sairia.
|
|
69
|
+
*/
|
|
70
|
+
function checarContas(raiz, auth = (p) => p.runtime === 'claude-bg' ? adapter.conferirAuth(p) : codexAdapter.conferirAuth(p)) {
|
|
71
|
+
let perfis;
|
|
72
|
+
try {
|
|
73
|
+
perfis = (0, runtime_profiles_1.lerPerfisComContas)(raiz).perfis.filter(p => p.estado !== 'desativado');
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
return { nome: 'contas por runtime', nivel: 'fail', detalhe: `store de perfis invalido: ${e.message}`,
|
|
77
|
+
correcao: 'o store fica em .orkastery/private/runtime-profiles.json (arquivo 0600, pasta 0700)' };
|
|
78
|
+
}
|
|
79
|
+
if (perfis.length === 0)
|
|
80
|
+
return { nome: 'contas por runtime', nivel: 'ok',
|
|
81
|
+
detalhe: 'nenhum perfil configurado: cada runtime despacha pelo ambiente do processo' };
|
|
82
|
+
const partes = [];
|
|
83
|
+
let nivel = 'ok';
|
|
84
|
+
for (const runtime of runtime_profiles_1.RUNTIMES_COM_PERFIL) {
|
|
85
|
+
const doRuntime = perfis.filter(p => p.runtime === runtime);
|
|
86
|
+
if (doRuntime.length === 0)
|
|
87
|
+
continue;
|
|
88
|
+
const estados = doRuntime.map(p => {
|
|
89
|
+
const a = auth((0, runtime_profiles_1.perfilDeDespacho)(p));
|
|
90
|
+
return { id: p.id, pronto: a.ok && (0, runtime_profiles_1.perfilDisponivel)(p),
|
|
91
|
+
texto: !a.ok ? (a.pago ? 'provider pago (nunca despacha)' : a.transitorio ? 'conferencia de login inconclusiva' : 'sem login')
|
|
92
|
+
: (0, runtime_profiles_1.perfilDisponivel)(p) ? 'pronto' : `${p.estado}${p.esgotadoAte ? ` ate ${p.esgotadoAte}` : ''}` };
|
|
93
|
+
});
|
|
94
|
+
const prontos = estados.filter(e => e.pronto).length;
|
|
95
|
+
if (prontos === 0)
|
|
96
|
+
nivel = 'fail';
|
|
97
|
+
else if (prontos < estados.length && nivel === 'ok')
|
|
98
|
+
nivel = 'warn';
|
|
99
|
+
partes.push(`${runtime}: ${estados.map(e => `${e.id} ${e.texto}`).join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
return { nome: 'contas por runtime', nivel, detalhe: partes.join('; '),
|
|
102
|
+
...(nivel !== 'ok' ? { correcao: 'ork accounts check marca os perfis (sem-auth, provider-pago); ork accounts add refaz o login de assinatura pelo proprio CLI, nunca copiando credencial' } : {}) };
|
|
103
|
+
}
|
|
54
104
|
/**
|
|
55
105
|
* Variaveis que REDIRECIONAM o despacho do `claude` para um provider pago.
|
|
56
|
-
* Presenca delas com politica `subscription-only` e bloqueante
|
|
106
|
+
* Presenca delas com politica `subscription-only` e bloqueante: o despacho passaria a cobrar
|
|
107
|
+
* por token, fora da assinatura, sem ninguem pedir.
|
|
57
108
|
*/
|
|
58
109
|
const ENVS_QUE_REDIRECIONAM = [
|
|
59
110
|
'ANTHROPIC_API_KEY',
|
|
@@ -62,16 +113,36 @@ const ENVS_QUE_REDIRECIONAM = [
|
|
|
62
113
|
'CLAUDE_CODE_USE_BEDROCK',
|
|
63
114
|
'CLAUDE_CODE_USE_VERTEX',
|
|
64
115
|
];
|
|
65
|
-
/**
|
|
66
|
-
* Variaveis de provider pago que nao mudam o despacho do `claude`, mas indicam
|
|
67
|
-
* credencial cobrada por token no ambiente. Viram aviso, nao bloqueio.
|
|
68
|
-
*/
|
|
69
|
-
const ENVS_DE_PROVIDER_PAGO = ['OPENROUTER_API_KEY', 'OPENAI_API_KEY', 'GEMINI_API_KEY'];
|
|
70
116
|
function versaoNode() {
|
|
71
117
|
return Number(process.versions.node.split('.')[0]);
|
|
72
118
|
}
|
|
119
|
+
/** Checks locais; ler a entrevista não abre driver, banco, runtime ou rede. */
|
|
120
|
+
function checarOnboarding(carregado) {
|
|
121
|
+
const estado = (0, onboarding_1.lerOnboarding)(carregado.raiz);
|
|
122
|
+
const pendentes = onboarding_1.ETAPAS_ONBOARDING.filter(e => estado.etapas[e] === null);
|
|
123
|
+
const checks = [{ nome: 'onboarding', nivel: pendentes.length ? 'warn' : 'ok',
|
|
124
|
+
detalhe: pendentes.length ? `${pendentes.length} etapa(s) pendente(s): ${pendentes.join(', ')}` : '9 etapas respondidas',
|
|
125
|
+
...(pendentes.length ? { correcao: 'ork onboarding' } : {}) }];
|
|
126
|
+
const escolha = estado.etapas.memoria?.conteudo;
|
|
127
|
+
const modo = escolha === 'sim' || escolha === true ? 'orkmind' :
|
|
128
|
+
escolha === 'orkmind' || escolha === 'files' ? escolha :
|
|
129
|
+
escolha && typeof escolha === 'object' && !Array.isArray(escolha) ? escolha.modo : null;
|
|
130
|
+
if ((modo === 'orkmind' || modo === 'files') && modo !== carregado.manifesto.memory.mode) {
|
|
131
|
+
checks.push({ nome: 'onboarding memoria', nivel: 'warn', detalhe: `entrevista escolheu ${modo}; manifesto declara ${carregado.manifesto.memory.mode}`,
|
|
132
|
+
correcao: `revise memory.mode: ${modo} em orkastery.yaml; a entrevista não altera o manifesto` });
|
|
133
|
+
}
|
|
134
|
+
// I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto.
|
|
135
|
+
const maestro = estado.etapas.maestro?.conteudo;
|
|
136
|
+
const fusoDaEntrevista = maestro && typeof maestro === 'object' && !Array.isArray(maestro) ? (0, horario_1.normalizarFuso)(maestro.fuso) : undefined;
|
|
137
|
+
if (fusoDaEntrevista && fusoDaEntrevista !== carregado.manifesto.owner?.timezone) {
|
|
138
|
+
checks.push({ nome: 'onboarding fuso', nivel: 'warn',
|
|
139
|
+
detalhe: `entrevista informou ${fusoDaEntrevista}; manifesto declara ${carregado.manifesto.owner?.timezone ?? `${horario_1.CHAVE_DO_FUSO} ausente`}`,
|
|
140
|
+
correcao: `revise ${horario_1.CHAVE_DO_FUSO}: "${fusoDaEntrevista}" em orkastery.yaml; a entrevista não altera o manifesto` });
|
|
141
|
+
}
|
|
142
|
+
return checks;
|
|
143
|
+
}
|
|
73
144
|
/** Roda todos os checks a partir do diretorio informado. */
|
|
74
|
-
function checar(dirInicial = process.cwd()) {
|
|
145
|
+
function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
|
|
75
146
|
const checks = [];
|
|
76
147
|
const major = versaoNode();
|
|
77
148
|
checks.push({
|
|
@@ -104,6 +175,37 @@ function checar(dirInicial = process.cwd()) {
|
|
|
104
175
|
detalhe: claude ? `${claude} (${v ?? 'versao desconhecida'})` : 'binario `claude` fora do PATH',
|
|
105
176
|
correcao: claude ? undefined : 'instale o Claude Code e garanta `claude` no PATH',
|
|
106
177
|
});
|
|
178
|
+
// Segundo runtime homologado. Ausente e `warn`, nao `fail`: o claude-bg segue sendo o
|
|
179
|
+
// padrao, e um projeto que nunca pediu codex nao pode ficar bloqueado por ele.
|
|
180
|
+
const codex = codexAdapter.disponivel();
|
|
181
|
+
const codexVersao = codex ? codexAdapter.versao() : null;
|
|
182
|
+
checks.push({
|
|
183
|
+
nome: 'runtime codex',
|
|
184
|
+
nivel: codex ? 'ok' : 'warn',
|
|
185
|
+
detalhe: codex
|
|
186
|
+
? `${codex} (${codexVersao ?? 'versao desconhecida'})`
|
|
187
|
+
: 'binario `codex` fora do PATH (opcional: claude-bg e o runtime padrao)',
|
|
188
|
+
correcao: codex
|
|
189
|
+
? undefined
|
|
190
|
+
: 'para despachar pelo codex, instale o Codex CLI e autentique com `codex login`',
|
|
191
|
+
});
|
|
192
|
+
// Pitfall MEDIDO em 06/09/2026: com o sandbox quebrado, o `codex exec` sai 0 e o agente
|
|
193
|
+
// NARRA sucesso sem executar nada. A sonda e deterministica (roda `true`, sem LLM).
|
|
194
|
+
let sondaDoCodex = null;
|
|
195
|
+
if (codex) {
|
|
196
|
+
sondaDoCodex = codexAdapter.sondarSandbox();
|
|
197
|
+
checks.push({
|
|
198
|
+
nome: 'sandbox do codex',
|
|
199
|
+
nivel: sondaDoCodex.ok ? 'ok' : 'warn',
|
|
200
|
+
detalhe: sondaDoCodex.ok
|
|
201
|
+
? '`codex sandbox true` executa nesta maquina'
|
|
202
|
+
: `sonda \`codex sandbox true\` falhou: ${sondaDoCodex.detalhe}`,
|
|
203
|
+
correcao: sondaDoCodex.ok
|
|
204
|
+
? undefined
|
|
205
|
+
: 'instale o pacote bubblewrap do sistema (o bwrap embutido nao cria user namespace ' +
|
|
206
|
+
'nesta maquina) ou declare runtime.sandbox: danger-full-access ciente do risco',
|
|
207
|
+
});
|
|
208
|
+
}
|
|
107
209
|
const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
|
|
108
210
|
if (!carregado) {
|
|
109
211
|
checks.push({
|
|
@@ -123,6 +225,7 @@ function checar(dirInicial = process.cwd()) {
|
|
|
123
225
|
(carregado.avisos.length > 0 ? `; ${carregado.avisos.join('; ')}` : ''),
|
|
124
226
|
correcao: carregado.erros.length > 0 ? 'corrija o manifesto e rode ork doctor de novo' : undefined,
|
|
125
227
|
});
|
|
228
|
+
checks.push(...checarOnboarding(carregado));
|
|
126
229
|
const abbrev = carregado.manifesto.project.abbrev;
|
|
127
230
|
const checkAbbrev = (0, slug_1.validarAbbrev)(abbrev);
|
|
128
231
|
checks.push({
|
|
@@ -140,13 +243,43 @@ function checar(dirInicial = process.cwd()) {
|
|
|
140
243
|
detalhe: `padrao ${modos_1.MODOS[cond.default_mode].tag}; ` +
|
|
141
244
|
`permitidos ${cond.allowed_modes.map((m) => modos_1.MODOS[m].tag).join(', ')}`,
|
|
142
245
|
});
|
|
246
|
+
// I-35: o fuso em que todo horario chega ao dono; valor invalido avisa e nao para nada.
|
|
247
|
+
const fuso = (0, horario_1.fusoDoManifesto)(carregado);
|
|
248
|
+
checks.push({
|
|
249
|
+
nome: 'fuso do dono',
|
|
250
|
+
nivel: fuso.aviso ? 'warn' : 'ok',
|
|
251
|
+
detalhe: fuso.aviso ?? (fuso.origem === 'manifesto'
|
|
252
|
+
? `${fuso.fuso} (${horario_1.CHAVE_DO_FUSO}); horarios para pessoas em ${(0, horario_1.rotuloDoFuso)(fuso.fuso)}`
|
|
253
|
+
: `${fuso.fuso} (fuso do sistema; ${horario_1.CHAVE_DO_FUSO} nao configurado)`),
|
|
254
|
+
correcao: fuso.aviso ? `corrija ${horario_1.CHAVE_DO_FUSO} com um nome IANA` : undefined,
|
|
255
|
+
});
|
|
256
|
+
// Quando o manifesto ELEGE o codex como runtime de despacho, a ausencia dele (ou um
|
|
257
|
+
// sandbox que nao executa) deixa de ser aviso: e exatamente o que bloquearia a fase.
|
|
258
|
+
if (carregado.manifesto.runtime.adapter === 'codex') {
|
|
259
|
+
const sandboxConfigurado = carregado.manifesto.runtime.sandbox;
|
|
260
|
+
const sandboxQuebrado = sondaDoCodex !== null && !sondaDoCodex.ok && sandboxConfigurado !== 'danger-full-access';
|
|
261
|
+
checks.push({
|
|
262
|
+
nome: 'despacho pelo codex',
|
|
263
|
+
nivel: !codex ? 'fail' : sandboxQuebrado ? 'fail' : 'ok',
|
|
264
|
+
detalhe: !codex
|
|
265
|
+
? 'runtime.adapter: codex, mas o binario `codex` esta fora do PATH'
|
|
266
|
+
: sandboxQuebrado
|
|
267
|
+
? `runtime.adapter: codex com sandbox "${sandboxConfigurado}", mas o sandbox nao executa nesta maquina (o agente narraria sucesso sem rodar nada)`
|
|
268
|
+
: `runtime.adapter: codex com sandbox "${sandboxConfigurado}"`,
|
|
269
|
+
correcao: !codex
|
|
270
|
+
? 'instale o Codex CLI e autentique com `codex login` (assinatura, nunca API key)'
|
|
271
|
+
: sandboxQuebrado
|
|
272
|
+
? 'instale o bubblewrap do sistema, ou declare runtime.sandbox: danger-full-access ciente do risco'
|
|
273
|
+
: undefined,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
143
276
|
const politica = carregado.manifesto.runtime.provider_policy;
|
|
144
277
|
const soAssinatura = politica === 'subscription-only';
|
|
145
|
-
const redirecionam = ENVS_QUE_REDIRECIONAM.filter(
|
|
146
|
-
const pagas =
|
|
278
|
+
const redirecionam = ENVS_QUE_REDIRECIONAM.filter(e => nomesHerdados.includes(e));
|
|
279
|
+
const pagas = nomesHerdados;
|
|
147
280
|
const bloqueia = soAssinatura && redirecionam.length > 0;
|
|
148
281
|
checks.push({
|
|
149
|
-
nome: 'custo e provider',
|
|
282
|
+
nome: 'custo e provider herdado',
|
|
150
283
|
nivel: bloqueia ? 'fail' : soAssinatura && pagas.length > 0 ? 'warn' : 'ok',
|
|
151
284
|
detalhe: bloqueia
|
|
152
285
|
? `politica ${politica} violada: ${redirecionam.join(', ')} redireciona o despacho do claude`
|
|
@@ -159,10 +292,19 @@ function checar(dirInicial = process.cwd()) {
|
|
|
159
292
|
? `nenhuma acao obrigatoria; nunca despache fase por ${pagas.join(', ')}`
|
|
160
293
|
: undefined,
|
|
161
294
|
});
|
|
295
|
+
const efetivas = (0, runtime_ambiente_1.nomesDeProviderAtivos)();
|
|
296
|
+
checks.push({
|
|
297
|
+
nome: 'provider efetivo da fabrica',
|
|
298
|
+
nivel: soAssinatura && efetivas.length ? 'warn' : 'ok',
|
|
299
|
+
detalhe: efetivas.length ? `nomes ativos: ${efetivas.join(', ')}` : 'nenhum nome da lista de provider ativo',
|
|
300
|
+
});
|
|
162
301
|
// Bloco B6: o regime de memoria e um CHECK, nao um detalhe do manifesto. Manifesto
|
|
163
302
|
// que pede `orkmind` e nao consegue liga-lo vira `warn` com a correcao, nunca `fail`:
|
|
164
303
|
// memoria semantica melhora o produto, e nao e requisito dele.
|
|
165
|
-
const
|
|
304
|
+
const context = (0, project_state_1.memoryState)(carregado);
|
|
305
|
+
const { estado } = (0, orkmind_1.resolverRegime)(context.loaded.manifesto, null);
|
|
306
|
+
checks.push({ nome: 'fonte da memoria', nivel: context.divergent ? 'warn' : 'ok',
|
|
307
|
+
detalhe: `${context.source}${context.divergent ? ' (cópia da worktree divergente preservada)' : ''}` });
|
|
166
308
|
checks.push({
|
|
167
309
|
nome: 'regime de memoria',
|
|
168
310
|
nivel: estado.efetivo === 'orkmind' ? 'ok' : estado.pedido === 'orkmind' ? 'warn' : 'ok',
|
|
@@ -185,14 +327,14 @@ function checar(dirInicial = process.cwd()) {
|
|
|
185
327
|
detalhe: fila.length === 0
|
|
186
328
|
? 'vazia: nenhuma fase morreu por limite de uso neste projeto'
|
|
187
329
|
: `${esperando.length} aguardando janela, ${escalados.length} escalado(s) para humano` +
|
|
188
|
-
(esperando.length > 0 ? `; proxima janela em ${esperando[0].liberaEm}` : ''),
|
|
330
|
+
(esperando.length > 0 ? `; proxima janela em ${(0, horario_1.formatarDataHoraRotulada)(esperando[0].liberaEm)}` : ''),
|
|
189
331
|
correcao: escalados.length > 0
|
|
190
|
-
? `pedido escalado alem do limite de retry.max_tentativas: ork retry list e ork gate
|
|
332
|
+
? `pedido escalado alem do limite de retry.max_tentativas: ork retry list e ork gate request <thread>`
|
|
191
333
|
: esperando.length > 0
|
|
192
334
|
? 'ork retry resume retoma o que ja liberou'
|
|
193
335
|
: undefined,
|
|
194
336
|
});
|
|
195
|
-
const dirEstadoProjeto = path.join(carregado.raiz, manifest_1.DIR_ESTADO);
|
|
337
|
+
const dirEstadoProjeto = path.join((0, estado_thread_1.raizDoEstado)(carregado.raiz), manifest_1.DIR_ESTADO);
|
|
196
338
|
const threads = path.join(dirEstadoProjeto, 'threads');
|
|
197
339
|
const qtd = fs.existsSync(threads)
|
|
198
340
|
? fs.readdirSync(threads, { withFileTypes: true }).filter((e) => e.isDirectory()).length
|
|
@@ -205,14 +347,19 @@ function checar(dirInicial = process.cwd()) {
|
|
|
205
347
|
: `${dirEstadoProjeto} ausente`,
|
|
206
348
|
correcao: fs.existsSync(dirEstadoProjeto) ? undefined : 'ork init cria o diretorio de estado',
|
|
207
349
|
});
|
|
208
|
-
|
|
209
|
-
|
|
350
|
+
checks.push(checarContas(carregado.raiz));
|
|
351
|
+
// I-33 (D7): umask e permissoes do estado, na mesma regra do sensor (sem bits 0o022).
|
|
352
|
+
checks.push(...(0, preflight_1.sondasDeAmbiente)(carregado.raiz));
|
|
353
|
+
{
|
|
354
|
+
const inventario = (0, sessoes_inventario_1.inventariarSessoes)(carregado.raiz, { global: true, todas: true });
|
|
210
355
|
checks.push({
|
|
211
|
-
nome: '
|
|
212
|
-
nivel: 'ok',
|
|
213
|
-
detalhe:
|
|
214
|
-
|
|
215
|
-
|
|
356
|
+
nome: 'governanca de sessoes',
|
|
357
|
+
nivel: inventario.ok && inventario.semThread === 0 ? 'ok' : 'warn',
|
|
358
|
+
detalhe: `${inventario.escopo.usuario}, Claude e Codex, global com histórico: ${inventario.total} sessões; ` +
|
|
359
|
+
`${inventario.semThread} sem thread; ${inventario.ambiguas} ambíguas; ` +
|
|
360
|
+
`inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}`,
|
|
361
|
+
correcao: inventario.ok && inventario.semThread === 0 ? undefined :
|
|
362
|
+
'ork sessions --global --all --json; adote identidades sem vínculo com ork sessions adopt <id>',
|
|
216
363
|
});
|
|
217
364
|
}
|
|
218
365
|
}
|
|
@@ -224,12 +371,24 @@ function relatorio(checks) {
|
|
|
224
371
|
linhas.push('ork doctor: o que vale nesta maquina agora');
|
|
225
372
|
linhas.push('');
|
|
226
373
|
const largura = Math.max(...checks.map((c) => c.nome.length));
|
|
374
|
+
// I-35: o Check guarda o ISO (dado de maquina, tambem lido por teste); quem imprime para o dono
|
|
375
|
+
// localiza. Vale para todo check, nao so o de contas: nenhum horario chega cru ao relatorio.
|
|
376
|
+
let localizou = false;
|
|
377
|
+
const local = (t) => {
|
|
378
|
+
const l = (0, horario_1.localizarTexto)(t);
|
|
379
|
+
if (l !== t)
|
|
380
|
+
localizou = true;
|
|
381
|
+
return l;
|
|
382
|
+
};
|
|
227
383
|
for (const c of checks) {
|
|
228
|
-
linhas.push(` ${(0, util_1.simbolo)(c.nivel)} ${c.nome.padEnd(largura)} ${c.detalhe}`);
|
|
384
|
+
linhas.push(` ${(0, util_1.simbolo)(c.nivel)} ${c.nome.padEnd(largura)} ${local(c.detalhe)}`);
|
|
229
385
|
if (c.nivel !== 'ok' && c.correcao) {
|
|
230
|
-
linhas.push(` ${' '.repeat(largura)} correcao: ${c.correcao}`);
|
|
386
|
+
linhas.push(` ${' '.repeat(largura)} correcao: ${local(c.correcao)}`);
|
|
231
387
|
}
|
|
232
388
|
}
|
|
389
|
+
// O fuso sai uma vez por mensagem, antes do veredito, que segue sendo a ultima linha.
|
|
390
|
+
if (localizou && !linhas.some((l) => l.includes((0, horario_1.legendaDoFuso)())))
|
|
391
|
+
linhas.push((0, horario_1.legendaDoFuso)());
|
|
233
392
|
const falhas = checks.filter((c) => c.nivel === 'fail').length;
|
|
234
393
|
const avisos = checks.filter((c) => c.nivel === 'warn').length;
|
|
235
394
|
linhas.push('');
|
|
@@ -239,8 +398,8 @@ function relatorio(checks) {
|
|
|
239
398
|
return linhas.join('\n');
|
|
240
399
|
}
|
|
241
400
|
/** Executa o doctor e devolve o codigo de saida (0 = pronto). */
|
|
242
|
-
function doctor(dirInicial = process.cwd()) {
|
|
243
|
-
const checks = checar(dirInicial);
|
|
401
|
+
function doctor(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
|
|
402
|
+
const checks = checar(dirInicial, nomesHerdados);
|
|
244
403
|
const falhas = checks.filter((c) => c.nivel === 'fail').length;
|
|
245
404
|
return { texto: relatorio(checks), codigo: falhas > 0 ? 1 : 0 };
|
|
246
405
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeDaEntrega = mergeDaEntrega;
|
|
4
|
+
exports.registrarEntregaPorPr = registrarEntregaPorPr;
|
|
5
|
+
exports.registrarEntregasPorPr = registrarEntregasPorPr;
|
|
6
|
+
/**
|
|
7
|
+
* I-57 (RM-008, fatia 2): a entrega feita por PR tambem prova entrega para o MASTER.
|
|
8
|
+
*
|
|
9
|
+
* O fluxo de entrega desta fabrica e o PR: CI independente verde no SHA exato, merge com
|
|
10
|
+
* `--match-head-commit` e o assunto `ship(<thread>): ...`. So que o MASTER exigia o `ship_done`
|
|
11
|
+
* do `ork ship`, e a thread entregue por PR ficava aberta para sempre: nao fechava, nao virava
|
|
12
|
+
* licao para o loop de aprendizado, e o board a mostrava como trabalho em curso.
|
|
13
|
+
*
|
|
14
|
+
* Aqui a mesma prova vira `ship_done`, com o que a sustenta de verdade: o merge dentro da base
|
|
15
|
+
* remota (ancestralidade conferida contra a ponta que o `ls-remote` devolve) e o check do CI no
|
|
16
|
+
* head do PR. Sem CI verde, nao registra: merge sem prova independente nao e entrega.
|
|
17
|
+
*/
|
|
18
|
+
const ci_1 = require("./ci");
|
|
19
|
+
const fabrica_publicar_1 = require("./fabrica-publicar");
|
|
20
|
+
const ledger_1 = require("./ledger");
|
|
21
|
+
const modos_1 = require("./modos");
|
|
22
|
+
const thread_1 = require("./thread");
|
|
23
|
+
const util_1 = require("./util");
|
|
24
|
+
/** O merge `ship(<thread>)` mais recente na base remota, com o head do PR (segundo pai). */
|
|
25
|
+
function mergeDaEntrega(raiz, thread, remoto, base) {
|
|
26
|
+
const r = (0, util_1.exec)('git', ['log', `refs/remotes/${remoto}/${base}`, '--first-parent', '--format=%H%x09%P%x09%s', `--grep=^ship(${thread})`], raiz);
|
|
27
|
+
if (!r.ok)
|
|
28
|
+
return null;
|
|
29
|
+
for (const linha of r.stdout.split('\n')) {
|
|
30
|
+
const [sha, pais, assunto] = linha.split('\t');
|
|
31
|
+
if (!sha || !assunto || !assunto.startsWith(`ship(${thread})`))
|
|
32
|
+
continue;
|
|
33
|
+
const segundo = (pais ?? '').split(' ')[1] ?? null;
|
|
34
|
+
return { mergeSha: sha, headSha: segundo };
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function resultado(thread, acao, motivo, extra = {}) {
|
|
39
|
+
return { thread, acao, motivo, mergeSha: null, headSha: null, ci: null, ...extra };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* `ork ship registrar-pr <thread>`: grava o `ship_done` da entrega feita por PR. Idempotente:
|
|
43
|
+
* a mesma entrega nao e registrada duas vezes.
|
|
44
|
+
*/
|
|
45
|
+
function registrarEntregaPorPr(carregado, threadId, opcoes = {}) {
|
|
46
|
+
const raiz = carregado.raiz;
|
|
47
|
+
const remoto = opcoes.remoto ?? 'origin';
|
|
48
|
+
const base = carregado.manifesto.worktree.base_branch;
|
|
49
|
+
const thread = (0, thread_1.lerThread)(raiz, threadId);
|
|
50
|
+
if (thread.status === 'fechada')
|
|
51
|
+
return resultado(threadId, 'ja-registrada', 'thread ja fechada');
|
|
52
|
+
if (opcoes.buscar !== false)
|
|
53
|
+
(0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], raiz);
|
|
54
|
+
const merge = mergeDaEntrega(raiz, threadId, remoto, base);
|
|
55
|
+
if (!merge)
|
|
56
|
+
return resultado(threadId, 'sem-merge', `nenhum merge ship(${threadId}) em ${remoto}/${base}`);
|
|
57
|
+
const dir = (0, thread_1.dirThread)(raiz, threadId);
|
|
58
|
+
const jaTem = (0, ledger_1.lerLedger)(dir).some((e) => e.tipo === ledger_1.TIPOS_DE_EVENTO.shipConcluido && e.mergeSha === merge.mergeSha);
|
|
59
|
+
if (jaTem)
|
|
60
|
+
return resultado(threadId, 'ja-registrada', 'esta entrega ja tem ship_done', merge);
|
|
61
|
+
// A ponta do remoto AGORA, e o merge dentro dela: e o que torna o push provado, nao presumido.
|
|
62
|
+
const remotoAgora = (0, util_1.exec)('git', ['ls-remote', remoto, `refs/heads/${base}`], raiz);
|
|
63
|
+
const ponta = remotoAgora.ok ? remotoAgora.stdout.split('\t')[0].trim() : '';
|
|
64
|
+
if (!ponta || !(0, util_1.exec)('git', ['merge-base', '--is-ancestor', merge.mergeSha, ponta], raiz).ok) {
|
|
65
|
+
return resultado(threadId, 'recusada', `o merge ${merge.mergeSha.slice(0, 7)} nao esta na ponta de ${remoto}/${base}`, merge);
|
|
66
|
+
}
|
|
67
|
+
const ci = (0, ci_1.consultarCi)(carregado, merge.headSha ?? merge.mergeSha, remoto, opcoes.executorCi);
|
|
68
|
+
if (ci.required && !ci.ok) {
|
|
69
|
+
return resultado(threadId, 'recusada', `sem CI verde no head do PR: ${ci.detail}`, { ...merge, ci });
|
|
70
|
+
}
|
|
71
|
+
(0, ledger_1.registrar)(dir, threadId, ledger_1.TIPOS_DE_EVENTO.shipConcluido, {
|
|
72
|
+
de: thread.base?.branch ?? null,
|
|
73
|
+
para: base,
|
|
74
|
+
shaDe: merge.headSha,
|
|
75
|
+
mergeSha: merge.mergeSha,
|
|
76
|
+
jaIncorporado: true,
|
|
77
|
+
remoto,
|
|
78
|
+
shaRemoto: ponta,
|
|
79
|
+
pushVerificado: true,
|
|
80
|
+
fonteDaProva: `git merge-base --is-ancestor ${merge.mergeSha} ${ponta} (ls-remote ${remoto} refs/heads/${base})`,
|
|
81
|
+
autorizadoPor: 'merge de PR com o CI independente verde no SHA exato',
|
|
82
|
+
tipoDeAutorizacao: 'pr',
|
|
83
|
+
modo: thread.modo,
|
|
84
|
+
tag: (0, modos_1.tagDoModo)(thread.modo),
|
|
85
|
+
evidencia: { viaPr: true, ci: { state: ci.state, context: ci.context, url: ci.url, sha: ci.sha } },
|
|
86
|
+
});
|
|
87
|
+
// Como no `ork ship`: a thread chega ao SHIP quando o ciclo dela tem SHIP.
|
|
88
|
+
const atualizada = (0, thread_1.lerThread)(raiz, threadId);
|
|
89
|
+
if (atualizada.fases?.includes('SHIP')) {
|
|
90
|
+
atualizada.faseAtual = 'SHIP';
|
|
91
|
+
(0, thread_1.gravarThread)(raiz, atualizada);
|
|
92
|
+
}
|
|
93
|
+
if (opcoes.publicar !== false)
|
|
94
|
+
(0, fabrica_publicar_1.publicarEmSegundoPlano)(raiz);
|
|
95
|
+
return resultado(threadId, 'registrou', `ship_done pelo merge ${merge.mergeSha.slice(0, 7)} do PR`, { ...merge, ci });
|
|
96
|
+
}
|
|
97
|
+
/** `ork ship registrar-pr --todas`: toda thread aberta que ja tem merge `ship(<thread>)` na base. */
|
|
98
|
+
function registrarEntregasPorPr(carregado, opcoes = {}) {
|
|
99
|
+
const remoto = opcoes.remoto ?? 'origin';
|
|
100
|
+
const base = carregado.manifesto.worktree.base_branch;
|
|
101
|
+
(0, util_1.exec)('git', ['fetch', '-q', remoto, `+refs/heads/${base}:refs/remotes/${remoto}/${base}`], carregado.raiz);
|
|
102
|
+
const r = (0, thread_1.listarIds)(carregado.raiz)
|
|
103
|
+
.filter((id) => (0, thread_1.lerThread)(carregado.raiz, id).status !== 'fechada')
|
|
104
|
+
.filter((id) => mergeDaEntrega(carregado.raiz, id, remoto, base) !== null)
|
|
105
|
+
.map((id) => {
|
|
106
|
+
try {
|
|
107
|
+
return registrarEntregaPorPr(carregado, id, { ...opcoes, buscar: false, publicar: false });
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
return resultado(id, 'recusada', e.message);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
// Uma publicacao so para o lote inteiro, nao uma por thread.
|
|
114
|
+
if (r.some((x) => x.acao === 'registrou'))
|
|
115
|
+
(0, fabrica_publicar_1.publicarEmSegundoPlano)(carregado.raiz);
|
|
116
|
+
return r;
|
|
117
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
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.THREADS_PROTEGIDAS = void 0;
|
|
37
|
+
exports.validarThreadDeEscrita = validarThreadDeEscrita;
|
|
38
|
+
exports.exigirEscopoDeEscrita = exigirEscopoDeEscrita;
|
|
39
|
+
exports.validarDiretorioDeThread = validarDiretorioDeThread;
|
|
40
|
+
const fs = __importStar(require("node:fs"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const estado_thread_1 = require("./estado-thread");
|
|
43
|
+
/** Autorizar leitura de um tenant nao autoriza escrever em suas threads. */
|
|
44
|
+
exports.THREADS_PROTEGIDAS = new Set([
|
|
45
|
+
'ork-grandeevoluc', 'ork-jornadasdpa', 'ork-renarrativac',
|
|
46
|
+
]);
|
|
47
|
+
function validarThreadDeEscrita(id) {
|
|
48
|
+
if (typeof id !== 'string' || !/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(id)) {
|
|
49
|
+
throw new Error('scope.thread.invalid');
|
|
50
|
+
}
|
|
51
|
+
if (exports.THREADS_PROTEGIDAS.has(id.toLowerCase()))
|
|
52
|
+
throw new Error('scope.thread.protected');
|
|
53
|
+
}
|
|
54
|
+
function exigirEscopoDeEscrita(threads) {
|
|
55
|
+
if (!Array.isArray(threads) || threads.length === 0)
|
|
56
|
+
throw new Error('scope.write.required');
|
|
57
|
+
threads.forEach(validarThreadDeEscrita);
|
|
58
|
+
return new Set(threads);
|
|
59
|
+
}
|
|
60
|
+
/** Um nome autorizado nao pode ser alias de outra thread ou de estado externo. */
|
|
61
|
+
function validarDiretorioDeThread(raiz, id) {
|
|
62
|
+
validarThreadDeEscrita(id);
|
|
63
|
+
const dir = (0, estado_thread_1.estadoCanonico)(raiz, id);
|
|
64
|
+
for (const candidato of [path.dirname(path.dirname(dir)), path.dirname(dir), dir]) {
|
|
65
|
+
const stat = fs.lstatSync(candidato, { throwIfNoEntry: false });
|
|
66
|
+
if (!stat)
|
|
67
|
+
throw new Error('scope.thread.missing');
|
|
68
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
69
|
+
throw new Error('scope.thread.alias');
|
|
70
|
+
}
|
|
71
|
+
}
|