@orkastery/cli 0.4.3 → 0.5.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/adapters/README.md +11 -0
- package/adapters/claude-code/.claude-plugin/plugin.json +3 -1
- package/adapters/claude-code/README.md +11 -2
- package/adapters/claude-code/agents/ork-check.md +1 -1
- package/adapters/claude-code/agents/ork-go.md +2 -2
- package/adapters/claude-code/agents/ork-goal.md +1 -1
- package/adapters/claude-code/agents/ork-master.md +1 -1
- package/adapters/claude-code/agents/ork-plan.md +1 -1
- package/adapters/claude-code/agents/ork-ship.md +1 -1
- package/adapters/claude-code/commands/master.md +11 -8
- package/adapters/claude-code/commands/onboarding.md +3 -2
- package/adapters/claude-code/commands/ork.md +8 -0
- package/adapters/claude-code/commands/ship.md +2 -2
- package/adapters/codex/skills/ork/SKILL.md +12 -1
- package/adapters/hermes/README.md +3 -0
- package/adapters/hermes/bin/ork-abrir-thread.sh +17 -2
- package/adapters/hermes/bin/ork-brain.sh +3 -0
- package/adapters/hermes/bin/ork-maestro.sh +4 -1
- package/adapters/hermes/bin/ork-network-roadmap.sh +11 -0
- package/adapters/hermes/bin/ork-roadmap-status.sh +9 -0
- package/adapters/hermes/hermes.plugin.json +2 -0
- package/adapters/hermes/hitl-ingress/__init__.py +36 -3
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +19 -20
- package/adapters/openclaw/README.md +45 -2
- package/adapters/openclaw/dist/hitl-ingress.js +37 -3
- package/adapters/openclaw/dist/index.js +93 -21
- package/adapters/openclaw/openclaw.plugin.json +10 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +32 -3
- package/adapters/openclaw/src/index.ts +109 -21
- package/assets/docs/padroes/documentacao-de-produto.md +2 -2
- package/assets/docs/padroes/roadmap-de-produto.md +1 -1
- package/assets/docs/produto/_modelo-feature.md +2 -0
- package/assets/orkmind_bridge.py +214 -1
- package/dist/adapters/claude-bg.js +24 -7
- package/dist/auditrun.js +1 -1
- package/dist/board.js +74 -0
- package/dist/branch-de-estado.js +5 -4
- package/dist/busca-semantica.js +161 -0
- package/dist/ci.js +141 -10
- package/dist/claim-lint.js +3 -1
- package/dist/company-brain-cli.js +27 -2
- package/dist/company-brain-context.js +132 -0
- package/dist/company-brain-dossie.js +376 -0
- package/dist/company-brain-mcp.js +4 -1
- package/dist/conducao.js +71 -18
- package/dist/decisao-autonoma.js +42 -0
- package/dist/docs.js +135 -25
- package/dist/doctor.js +242 -32
- package/dist/entrega-pr.js +116 -5
- package/dist/experiencia-instalacao.js +256 -0
- package/dist/experiencia.js +72 -0
- package/dist/fabrica-estado.js +63 -12
- package/dist/fechamento.js +105 -0
- package/dist/fix.js +3 -3
- package/dist/forja.js +435 -0
- package/dist/gates.js +9 -1
- package/dist/hitl-classificacao.js +11 -1
- package/dist/hitl-contract.js +50 -7
- package/dist/hitl-curto.js +158 -0
- package/dist/hitl-gates.js +67 -1
- package/dist/hitl-lote.js +30 -15
- package/dist/hitl-presentation.js +10 -7
- package/dist/hitl-resumo.js +57 -13
- package/dist/hitl-texto-livre.js +150 -0
- package/dist/hosts.js +92 -3
- package/dist/index.js +637 -45
- package/dist/indice-vetorial.js +317 -0
- package/dist/init.js +24 -5
- package/dist/integracoes-locais.js +3 -1
- package/dist/intelligence-benchmark-contract.js +570 -0
- package/dist/intelligence-graph-cli.js +584 -0
- package/dist/intelligence-graph-contract.js +636 -0
- package/dist/intelligence-graph-extract-md.js +487 -0
- package/dist/intelligence-graph-extract-ts.js +980 -0
- package/dist/intelligence-graph-extract.js +546 -0
- package/dist/intelligence-graph-index.js +693 -0
- package/dist/intelligence-graph-parsers.js +327 -0
- package/dist/intelligence-graph-query.js +344 -0
- package/dist/intelligence-graph-repo.js +197 -0
- package/dist/leases.js +100 -0
- package/dist/ledger.js +23 -0
- package/dist/licoes.js +5 -4
- package/dist/liveness.js +2 -1
- package/dist/maestro-cli.js +10 -1
- package/dist/maestro-contract.js +5 -1
- package/dist/maestro-discovery.js +16 -2
- package/dist/maestro-runtime.js +3 -0
- package/dist/maestro-snapshot.js +6 -2
- package/dist/manifest.js +166 -5
- package/dist/master-batch.js +3 -2
- package/dist/master-digest.js +2 -2
- package/dist/master-nota.js +203 -0
- package/dist/master.js +4 -0
- package/dist/mcp-artifacts.js +2 -0
- package/dist/mcp-experiencia.js +164 -0
- package/dist/mcp-git.js +64 -12
- package/dist/mcp-grafo-worker.js +91 -0
- package/dist/mcp-grafo.js +233 -0
- package/dist/mcp-install.js +5 -2
- package/dist/mcp-maestro.js +3 -2
- package/dist/mcp-server.js +93 -5
- package/dist/mcp-ship.js +2 -0
- package/dist/mcp-verify.js +3 -1
- package/dist/memoria.js +147 -1
- package/dist/network-roadmap.js +907 -0
- package/dist/ocupacao.js +43 -3
- package/dist/onboarding.js +122 -11
- package/dist/orkmind.js +165 -9
- package/dist/orquestracao.js +2 -1
- package/dist/parado-no-condutor.js +933 -0
- package/dist/phase.js +166 -13
- package/dist/policies.js +29 -2
- package/dist/projeto-alvo.js +551 -0
- package/dist/prompts.js +1 -1
- package/dist/prova-ativacao.js +345 -0
- package/dist/pulse-consentimento.js +4 -2
- package/dist/pulse-delivery.js +32 -6
- package/dist/pulse-resposta.js +674 -49
- package/dist/pulse.js +74 -3
- package/dist/retry.js +51 -8
- package/dist/roadmap-reservas.js +262 -20
- package/dist/roadmap-status.js +348 -0
- package/dist/runtime-context.js +5 -1
- package/dist/sessoes-inventario.js +7 -1
- package/dist/sessoes.js +4 -1
- package/dist/ship.js +25 -1
- package/dist/thread-close.js +3 -0
- package/dist/thread.js +21 -2
- package/dist/util.js +71 -4
- package/dist/verify.js +6 -5
- package/dist/worktree.js +29 -6
- package/eval/casos/onboarding.json +1 -1
- package/eval/casos/orchestration-experience-pt-br.json +48 -0
- package/eval/casos/orchestration-experience.json +48 -0
- package/package.json +1 -1
- package/schemas/code-artifact-graph.v1.schema.json +581 -0
- package/schemas/graph-benchmark.v1.schema.json +2240 -0
- package/schemas/maestro-snapshot.schema.json +23 -0
- package/skills/README.md +7 -5
- package/skills/core/onboarding/SKILL.md +10 -2
- package/skills/core/orchestration-experience/SKILL.md +113 -0
- package/skills/core/orchestration-experience-pt-br/SKILL.md +112 -0
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/go-implementation/SKILL.md +2 -0
- package/skills/phases/ship-release/SKILL.md +6 -3
package/dist/docs.js
CHANGED
|
@@ -35,6 +35,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.LIMITE_DO_PARAGRAFO = exports.LIMITE_DA_FRASE = exports.CATEGORIAS = exports.DIMENSOES = exports.ESTADOS_DA_ESPECIFICACAO = exports.DIR_PADROES = exports.DIR_ROADMAP = exports.DIR_PRODUTO = void 0;
|
|
37
37
|
exports.separarFrontmatter = separarFrontmatter;
|
|
38
|
+
exports.ehPaginaDeDocs = ehPaginaDeDocs;
|
|
39
|
+
exports.documentoDeTexto = documentoDeTexto;
|
|
38
40
|
exports.carregarDocs = carregarDocs;
|
|
39
41
|
exports.resolverBase = resolverBase;
|
|
40
42
|
exports.comandosDaAjuda = comandosDaAjuda;
|
|
@@ -44,6 +46,8 @@ exports.renderizarEstado = renderizarEstado;
|
|
|
44
46
|
exports.textoDaVerificacao = textoDaVerificacao;
|
|
45
47
|
exports.escreverYaml = escreverYaml;
|
|
46
48
|
exports.mergeDaThread = mergeDaThread;
|
|
49
|
+
exports.mergesDaThreadNoGit = mergesDaThreadNoGit;
|
|
50
|
+
exports.escopoPadraoDoSync = escopoPadraoDoSync;
|
|
47
51
|
exports.sincronizarDocs = sincronizarDocs;
|
|
48
52
|
exports.tabelaDoRoadmap = tabelaDoRoadmap;
|
|
49
53
|
exports.tabelaDoProduto = tabelaDoProduto;
|
|
@@ -136,38 +140,49 @@ function separarFrontmatter(texto) {
|
|
|
136
140
|
return { bruto: null, corpo: t };
|
|
137
141
|
return { bruto: t.slice(4, fim + 1), corpo: t.slice(fim + 5) };
|
|
138
142
|
}
|
|
143
|
+
/** `_modelo-*.md` e `README.md` sao modelo e indice, nao paginas de entidade. */
|
|
144
|
+
function ehPaginaDeDocs(nome) {
|
|
145
|
+
return nome.endsWith('.md') && !nome.startsWith('_') && nome !== 'README.md';
|
|
146
|
+
}
|
|
139
147
|
function paginas(raiz, dir) {
|
|
140
148
|
const abs = path.join(raiz, dir);
|
|
141
149
|
if (!fs.existsSync(abs))
|
|
142
150
|
return [];
|
|
143
|
-
// `_modelo-*.md` e `README.md` sao modelo e indice, nao paginas de entidade.
|
|
144
151
|
return fs.readdirSync(abs)
|
|
145
|
-
.filter(
|
|
152
|
+
.filter(ehPaginaDeDocs)
|
|
146
153
|
.sort()
|
|
147
154
|
.map((n) => `${dir}/${n}`);
|
|
148
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* RM-054: uma pagina a partir do texto, venha ele do disco, de um blob do git ou da forja. O
|
|
158
|
+
* achado e o mesmo que a leitura do disco daria.
|
|
159
|
+
*/
|
|
160
|
+
function documentoDeTexto(arquivo, texto) {
|
|
161
|
+
const { bruto, corpo } = separarFrontmatter(texto);
|
|
162
|
+
if (bruto === null) {
|
|
163
|
+
return { achado: erro(arquivo, undefined, 'docs.frontmatter.ausente', 'página sem frontmatter YAML', 'comece o arquivo com as chaves do modelo entre duas linhas ---') };
|
|
164
|
+
}
|
|
165
|
+
let dados;
|
|
166
|
+
try {
|
|
167
|
+
dados = (0, yaml_1.lerYaml)(bruto);
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', `frontmatter inválido: ${e.message}`) };
|
|
171
|
+
}
|
|
172
|
+
if (!ehMapa(dados)) {
|
|
173
|
+
return { achado: erro(arquivo, undefined, 'docs.frontmatter.invalido', 'o frontmatter precisa ser um mapa de chaves') };
|
|
174
|
+
}
|
|
175
|
+
return { doc: { arquivo, tipo: dados.tipo, id: String(dados.id ?? ''), dados, corpo } };
|
|
176
|
+
}
|
|
149
177
|
function carregarDocs(raiz) {
|
|
150
178
|
const docs = [];
|
|
151
179
|
const achados = [];
|
|
152
180
|
for (const arquivo of [...paginas(raiz, exports.DIR_PRODUTO), ...paginas(raiz, exports.DIR_ROADMAP)]) {
|
|
153
|
-
const
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
let dados;
|
|
159
|
-
try {
|
|
160
|
-
dados = (0, yaml_1.lerYaml)(bruto);
|
|
161
|
-
}
|
|
162
|
-
catch (e) {
|
|
163
|
-
achados.push(erro(arquivo, undefined, 'docs.frontmatter.invalido', `frontmatter inválido: ${e.message}`));
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (!ehMapa(dados)) {
|
|
167
|
-
achados.push(erro(arquivo, undefined, 'docs.frontmatter.invalido', 'o frontmatter precisa ser um mapa de chaves'));
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
docs.push({ arquivo, tipo: dados.tipo, id: String(dados.id ?? ''), dados, corpo });
|
|
181
|
+
const lido = documentoDeTexto(arquivo, fs.readFileSync(path.join(raiz, arquivo), 'utf8'));
|
|
182
|
+
if ('doc' in lido)
|
|
183
|
+
docs.push(lido.doc);
|
|
184
|
+
else
|
|
185
|
+
achados.push(lido.achado);
|
|
171
186
|
}
|
|
172
187
|
return { docs, achados };
|
|
173
188
|
}
|
|
@@ -248,9 +263,12 @@ function verificarDocs(raiz, opcoes = {}) {
|
|
|
248
263
|
verificarFontes(raiz, d, comandos, achados);
|
|
249
264
|
if (d.tipo === 'roadmap') {
|
|
250
265
|
verificarEstadoDoRoadmap(raiz, d, base, achados);
|
|
266
|
+
if (base)
|
|
267
|
+
verificarMergeDaThread(raiz, d, base, achados, opcoes.pr === true);
|
|
251
268
|
verificarTabelasDeEstado(d, achados);
|
|
252
269
|
}
|
|
253
270
|
}
|
|
271
|
+
verificarIndices(raiz, docs, achados, opcoes.pr === true);
|
|
254
272
|
return { docs, achados };
|
|
255
273
|
}
|
|
256
274
|
function verificarChaves(d, achados) {
|
|
@@ -550,6 +568,57 @@ function verificarEstadoDoRoadmap(raiz, d, base, achados) {
|
|
|
550
568
|
}
|
|
551
569
|
}
|
|
552
570
|
}
|
|
571
|
+
/**
|
|
572
|
+
* RM-037 (fatia 3, defeito 1): o outro sentido da paridade com o git. Depois do merge do PR, o
|
|
573
|
+
* frontmatter da RM-049 (#26) e da RM-051 (#33) seguiu em "Branch criada", e o verificador dizia OK:
|
|
574
|
+
* ele so conferia que `Mesclado` tem o commit na base. O merge desta fabrica e pelo GitHub, sem o
|
|
575
|
+
* `ork ship` no caminho, entao a prova mora aqui, no job que o CI obrigatorio roda. A regra usa o
|
|
576
|
+
* mesmo `ship(<thread>)` do `sincronizarDocs`: tudo o que ela acusa o `sincronizar` corrige.
|
|
577
|
+
*/
|
|
578
|
+
function verificarMergeDaThread(raiz, d, base, achados, pr = false) {
|
|
579
|
+
const sdlc = ehMapa(d.dados.sdlc) ? d.dados.sdlc : null;
|
|
580
|
+
const thread = sdlc && typeof sdlc.thread === 'string' ? sdlc.thread.trim() : '';
|
|
581
|
+
if (!thread)
|
|
582
|
+
return;
|
|
583
|
+
const merges = mergesDaThreadNoGit(raiz, thread, base);
|
|
584
|
+
if (merges.length === 0)
|
|
585
|
+
return;
|
|
586
|
+
const codigo = String((ehMapa(d.dados.estado) ? d.dados.estado.codigo : null) ?? '');
|
|
587
|
+
if (codigo === 'Mesclado')
|
|
588
|
+
return;
|
|
589
|
+
achados.push((pr ? aviso : erro)(d.arquivo, d.id, 'docs.paridade.merge', `a thread ${thread} entrou na ${base} pelo merge ${merges[0].slice(0, 7)} (ship(${thread})), e o estado.codigo diz "${codigo || 'vazio'}"` +
|
|
590
|
+
(pr ? ' (no PR, aviso: o push da main reprova)' : ''), `abra um PR de docs sobre a ${base} atualizada com ork docs sincronizar --escrever --so ${d.id} (o item e os índices); ` +
|
|
591
|
+
`se o item tem outra fatia em curso, aponte sdlc.thread para a thread dela`));
|
|
592
|
+
}
|
|
593
|
+
/** Os indices gerados (`docs/roadmap/README.md`, `docs/produto/README.md`) e o que o frontmatter diz. */
|
|
594
|
+
const INDICES_GERADOS = [
|
|
595
|
+
[`${exports.DIR_ROADMAP}/README.md`, (docs) => tabelaDoRoadmap(docs)],
|
|
596
|
+
[`${exports.DIR_PRODUTO}/README.md`, (docs) => tabelaDoProduto(docs)],
|
|
597
|
+
];
|
|
598
|
+
/**
|
|
599
|
+
* RM-037 (fatia 3, defeito 1): o indice e uma vista do frontmatter, como as tabelas do corpo, e mentia
|
|
600
|
+
* do mesmo jeito: sem a RM-051 e com a RM-031 de antes. Divergente reprova; vazio (o modelo recem-copiado
|
|
601
|
+
* pelo `ork docs init`) so avisa; sem os marcadores, nao ha indice gerado para conferir.
|
|
602
|
+
*/
|
|
603
|
+
function verificarIndices(raiz, docs, achados, pr = false) {
|
|
604
|
+
for (const [arquivo, gerar] of INDICES_GERADOS) {
|
|
605
|
+
const abs = path.join(raiz, arquivo);
|
|
606
|
+
if (!fs.existsSync(abs))
|
|
607
|
+
continue;
|
|
608
|
+
// Checkout com CRLF (Windows com core.autocrlf) nao e divergencia: as paginas tambem normalizam.
|
|
609
|
+
const atual = blocoEntre(fs.readFileSync(abs, 'utf8').replace(/\r\n/g, '\n'), INICIO, FIM);
|
|
610
|
+
if (atual === null)
|
|
611
|
+
continue;
|
|
612
|
+
if (atual === '') {
|
|
613
|
+
if (docs.length > 0) {
|
|
614
|
+
achados.push(aviso(arquivo, undefined, 'docs.paridade.indice', 'o índice ainda não foi gerado', 'rode ork docs sincronizar --escrever'));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
else if (atual !== gerar(docs)) {
|
|
618
|
+
achados.push((pr ? aviso : erro)(arquivo, undefined, 'docs.paridade.indice', `o índice diverge do frontmatter das páginas${pr ? ' (no PR, aviso: o push da main reprova)' : ''}`, 'o índice é gerado do frontmatter: rode ork docs sincronizar --escrever e commite o índice'));
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
553
622
|
// --------------------------------------------------------------------------------------------
|
|
554
623
|
// Saida para humano (TDAH) e para agente
|
|
555
624
|
function textoDaVerificacao(docs, achados) {
|
|
@@ -652,24 +721,65 @@ function mergeDaThread(raiz, thread, base) {
|
|
|
652
721
|
return { sha: String(ship.mergeSha).slice(0, 7), fonte: 'ledger ship_done' };
|
|
653
722
|
}
|
|
654
723
|
catch { /* thread sem estado nesta maquina: cai para o git */ }
|
|
655
|
-
|
|
656
|
-
const log = git(raiz, ['log', base, '--reverse', '--format=%H', '--fixed-strings', `--grep=ship(${thread})`]);
|
|
657
|
-
const primeiro = log.ok ? log.saida.split('\n')[0] : '';
|
|
724
|
+
const primeiro = mergesDaThreadNoGit(raiz, thread, base)[0];
|
|
658
725
|
if (primeiro)
|
|
659
726
|
return { sha: primeiro.slice(0, 7), fonte: `git log ${base}` };
|
|
660
727
|
return null;
|
|
661
728
|
}
|
|
729
|
+
/**
|
|
730
|
+
* Os commits `ship(<thread>)` da base, do mais velho ao mais novo, so pelo git (o CI nao tem ledger).
|
|
731
|
+
* RM-037 (fatia 3): um lugar so para o `sincronizarDocs` e o `verificarDocs` acharem o mesmo merge.
|
|
732
|
+
*/
|
|
733
|
+
function mergesDaThreadNoGit(raiz, thread, base) {
|
|
734
|
+
// Sem `-n 1`: o git corta antes de inverter, e `--reverse -n 1` devolveria o mais recente.
|
|
735
|
+
// GO-FIX 2 (achado 4 do CHECK): so a linha de primeiro pai da base e o assunto que COMECA com
|
|
736
|
+
// `ship(<thread>)`, como no `mergeDaEntrega`. Commit que cita o merge no corpo, ou o Revert dele, nao e merge.
|
|
737
|
+
const log = git(raiz, ['log', base, '--first-parent', '--reverse', '--format=%H%x09%s', '--fixed-strings', `--grep=ship(${thread})`]);
|
|
738
|
+
if (!log.ok)
|
|
739
|
+
return [];
|
|
740
|
+
return log.saida.split('\n').map((l) => l.split('\t'))
|
|
741
|
+
.filter(([sha, assunto]) => !!sha && typeof assunto === 'string' && assunto.startsWith(`ship(${thread})`))
|
|
742
|
+
.map(([sha]) => sha);
|
|
743
|
+
}
|
|
662
744
|
function temBranch(raiz, thread) {
|
|
663
745
|
const r = git(raiz, ['for-each-ref', '--format=%(refname:short)', `refs/heads/ork/${thread}-*`, `refs/remotes/origin/ork/${thread}-*`]);
|
|
664
746
|
return r.ok && r.saida.length > 0;
|
|
665
747
|
}
|
|
666
748
|
const ORDEM_DO_CODIGO = exports.DIMENSOES.codigo;
|
|
749
|
+
/**
|
|
750
|
+
* RM-037 (rm037noite, defeito 5): o escopo padrao do `ork docs sincronizar`. Na worktree de uma thread
|
|
751
|
+
* com item do roadmap, so o item dela: da worktree da ork-rm037noite, o sincronizar gravava RM-025,
|
|
752
|
+
* 026, 031, 038, 048, 049, 050 e 054, e cada PR conflitava com as outras. Fora de worktree de thread
|
|
753
|
+
* (a raiz, onde o condutor sincroniza depois do merge), todo item, como antes.
|
|
754
|
+
*/
|
|
755
|
+
function escopoPadraoDoSync(raiz) {
|
|
756
|
+
const real = (p) => { try {
|
|
757
|
+
return fs.realpathSync(p);
|
|
758
|
+
}
|
|
759
|
+
catch {
|
|
760
|
+
return path.resolve(p);
|
|
761
|
+
} };
|
|
762
|
+
const aqui = real(raiz);
|
|
763
|
+
for (const id of (0, thread_1.listarIds)(raiz)) {
|
|
764
|
+
let t;
|
|
765
|
+
try {
|
|
766
|
+
t = (0, thread_1.lerThread)(raiz, id);
|
|
767
|
+
}
|
|
768
|
+
catch {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
if (t.worktree && real(t.worktree) === aqui)
|
|
772
|
+
return { itens: t.roadmap ? [t.roadmap] : null, thread: t.id };
|
|
773
|
+
}
|
|
774
|
+
return { itens: null, thread: null };
|
|
775
|
+
}
|
|
667
776
|
function sincronizarDocs(raiz, opcoes = {}) {
|
|
668
777
|
const base = resolverBase(raiz, opcoes.baseBranch) ?? (opcoes.baseBranch ?? 'main');
|
|
669
778
|
const agora = opcoes.agora ?? (() => isoComFusoLocal(new Date()));
|
|
670
779
|
const { docs } = carregarDocs(raiz);
|
|
671
780
|
const mudancas = [];
|
|
672
|
-
|
|
781
|
+
const noEscopo = (d) => !opcoes.itens || opcoes.itens.includes(d.id);
|
|
782
|
+
for (const d of docs.filter((x) => x.tipo === 'roadmap' && noEscopo(x))) {
|
|
673
783
|
const sdlc = ehMapa(d.dados.sdlc) ? d.dados.sdlc : null;
|
|
674
784
|
const thread = sdlc && typeof sdlc.thread === 'string' ? sdlc.thread : null;
|
|
675
785
|
if (!thread)
|
|
@@ -715,7 +825,7 @@ function sincronizarDocs(raiz, opcoes = {}) {
|
|
|
715
825
|
}
|
|
716
826
|
// As tabelas de estado do corpo sao vistas do frontmatter: regeradas em todo item de roadmap,
|
|
717
827
|
// inclusive quando a pessoa mudou o frontmatter a mao (ciclo, deploy, exposicao...).
|
|
718
|
-
for (const d of docs.filter((x) => x.tipo === 'roadmap')) {
|
|
828
|
+
for (const d of docs.filter((x) => x.tipo === 'roadmap' && noEscopo(x))) {
|
|
719
829
|
const novo = substituirBloco(substituirBloco(d.corpo, RELANCE_INI, RELANCE_FIM, renderizarRelance(d)), ESTADO_INI, ESTADO_FIM, renderizarEstado(d));
|
|
720
830
|
if (novo !== d.corpo) {
|
|
721
831
|
if (!mudancas.some((m) => m.id === d.id)) {
|
package/dist/doctor.js
CHANGED
|
@@ -39,8 +39,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.TETO_DO_DONO_DO_GIT = void 0;
|
|
42
43
|
exports.checarContas = checarContas;
|
|
44
|
+
exports.checarChaveDeEmbedding = checarChaveDeEmbedding;
|
|
45
|
+
exports.checarDonoDoGit = checarDonoDoGit;
|
|
43
46
|
exports.checarOnboarding = checarOnboarding;
|
|
47
|
+
exports.blocosDoRuntime = blocosDoRuntime;
|
|
48
|
+
exports.checarRuntimeClaude = checarRuntimeClaude;
|
|
49
|
+
exports.checarDespachoPeloCodex = checarDespachoPeloCodex;
|
|
44
50
|
exports.checar = checar;
|
|
45
51
|
exports.relatorio = relatorio;
|
|
46
52
|
exports.doctor = doctor;
|
|
@@ -62,6 +68,7 @@ const project_state_1 = require("./project-state");
|
|
|
62
68
|
const runtime_ambiente_1 = require("./runtime-ambiente");
|
|
63
69
|
const runtime_profiles_1 = require("./runtime-profiles");
|
|
64
70
|
const preflight_1 = require("./preflight");
|
|
71
|
+
const setup_1 = require("./setup");
|
|
65
72
|
/**
|
|
66
73
|
* I-33 (D7): check "contas por runtime". Cada perfil ativo tem o login conferido pelo proprio
|
|
67
74
|
* CLI com o env dele (`claude auth status`, `codex login status`); o doctor so le e relata, sem
|
|
@@ -116,6 +123,112 @@ const ENVS_QUE_REDIRECIONAM = [
|
|
|
116
123
|
function versaoNode() {
|
|
117
124
|
return Number(process.versions.node.split('.')[0]);
|
|
118
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* I-38 (T7): a chave de embedding aparece pelo NOME, nunca pelo valor. Ausente e aviso (a busca
|
|
128
|
+
* cai para o fallback local ou para FTS e o regime segue); nome de provider pago e falha, porque a
|
|
129
|
+
* entrada do `ork` apagaria a variavel sob `subscription-only` e o preflight reprovaria o codex.
|
|
130
|
+
*/
|
|
131
|
+
function checarChaveDeEmbedding(carregado, env = process.env) {
|
|
132
|
+
const nome = 'chave de embedding';
|
|
133
|
+
const config = (0, manifest_1.configDeEmbedding)(carregado.manifesto);
|
|
134
|
+
if (config.provider === 'none')
|
|
135
|
+
return { nome, nivel: 'ok', detalhe: 'memory.embedding com provider none: busca por significado desligada' };
|
|
136
|
+
const variavel = config.api_key_env;
|
|
137
|
+
if (runtime_ambiente_1.ENVS_DE_PROVIDER_PAGO.includes(variavel)) {
|
|
138
|
+
return { nome, nivel: 'fail', detalhe: `memory.embedding.api_key_env declara ${variavel}, nome da lista de provider pago`,
|
|
139
|
+
correcao: 'use uma chave dedicada ao Orkastery com nome proprio, por exemplo ORKASTERY_EMBEDDING_API_KEY' };
|
|
140
|
+
}
|
|
141
|
+
if (!variavel) {
|
|
142
|
+
return { nome, nivel: 'fail', detalhe: `memory.embedding com provider ${config.provider} sem api_key_env`,
|
|
143
|
+
correcao: 'declare em memory.embedding.api_key_env o NOME da variavel com a chave dedicada' };
|
|
144
|
+
}
|
|
145
|
+
const valor = (env[variavel] ?? '').trim();
|
|
146
|
+
const dsn = carregado.manifesto.memory.database_url_env ? (env[carregado.manifesto.memory.database_url_env] ?? '') : '';
|
|
147
|
+
if (valor !== '' && !(0, orkmind_1.chaveDeEmbeddingAceita)(valor, dsn)) {
|
|
148
|
+
return { nome, nivel: 'fail', detalhe: `${variavel} tem valor recusado: parece URL, DSN ou texto com espaco (valor nunca impresso)`,
|
|
149
|
+
correcao: `confira se ${variavel} guarda a chave dedicada, e nao outra credencial` };
|
|
150
|
+
}
|
|
151
|
+
if (valor !== '') {
|
|
152
|
+
return { nome, nivel: 'ok', detalhe: `${variavel} presente no ambiente (valor nunca impresso); ${config.provider} ${config.model}` };
|
|
153
|
+
}
|
|
154
|
+
return { nome, nivel: 'warn', detalhe: `${variavel} ausente do ambiente: a busca por significado usa o fallback local ou cai para FTS; o regime nao muda`,
|
|
155
|
+
correcao: `exporte ${variavel} com a chave dedicada ao Orkastery (com limite de credito no painel do provider)` };
|
|
156
|
+
}
|
|
157
|
+
/** Acima disso a conferencia do dono do `.git` fica parcial (aviso), para o doctor nao pesar. */
|
|
158
|
+
exports.TETO_DO_DONO_DO_GIT = 200_000;
|
|
159
|
+
/**
|
|
160
|
+
* RM-037 (fatia 3, defeito 7): git rodado como root no repositorio do dono deixa objeto, pasta e
|
|
161
|
+
* `FETCH_HEAD` com outro dono, e o git do dono deixa de gravar neles: o fetch travou em 29/09 e em
|
|
162
|
+
* 01/10. O dono do repositorio e o dono do diretorio comum do git. O check acusa com a contagem, ate
|
|
163
|
+
* tres exemplos e o `chown` exato; o doctor nunca roda nada. Fora de repositorio git, `null`.
|
|
164
|
+
*/
|
|
165
|
+
function checarDonoDoGit(dirInicial, opcoes = {}) {
|
|
166
|
+
const nome = 'dono do .git';
|
|
167
|
+
const comum = (0, util_1.exec)('git', ['rev-parse', '--git-common-dir'], dirInicial);
|
|
168
|
+
if (!comum.ok || !comum.stdout.trim())
|
|
169
|
+
return null;
|
|
170
|
+
const dirComum = path.resolve(dirInicial, comum.stdout.trim());
|
|
171
|
+
const lstat = opcoes.lstat ?? ((p) => fs.lstatSync(p));
|
|
172
|
+
let raiz;
|
|
173
|
+
try {
|
|
174
|
+
raiz = lstat(dirComum);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const teto = opcoes.teto ?? exports.TETO_DO_DONO_DO_GIT;
|
|
180
|
+
const relativo = (f) => path.relative(path.dirname(dirComum), f);
|
|
181
|
+
// A correcao sai pronta para copiar: caminho com caractere fora do conjunto seguro vai entre aspas simples.
|
|
182
|
+
const noShell = (s) => /^[A-Za-z0-9._/-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
183
|
+
const estranhos = [], uids = new Set();
|
|
184
|
+
let total = 0, vistos = 0, parcial = false;
|
|
185
|
+
const pilha = [dirComum];
|
|
186
|
+
while (pilha.length > 0 && !parcial) {
|
|
187
|
+
const atual = pilha.pop();
|
|
188
|
+
let nomes;
|
|
189
|
+
// Pasta que o dono nao consegue listar ja aparece pelo dono dela, na entrada de cima.
|
|
190
|
+
try {
|
|
191
|
+
nomes = fs.readdirSync(atual);
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
for (const n of nomes) {
|
|
197
|
+
if (++vistos > teto) {
|
|
198
|
+
parcial = true;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
const f = path.join(atual, n);
|
|
202
|
+
let st;
|
|
203
|
+
try {
|
|
204
|
+
st = lstat(f);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (st.uid !== raiz.uid) {
|
|
210
|
+
total++;
|
|
211
|
+
uids.add(st.uid);
|
|
212
|
+
if (estranhos.length < 3)
|
|
213
|
+
estranhos.push(relativo(f));
|
|
214
|
+
}
|
|
215
|
+
if (st.isDirectory())
|
|
216
|
+
pilha.push(f);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (total > 0) {
|
|
220
|
+
return { nome, nivel: 'fail',
|
|
221
|
+
detalhe: `${total} entrada(s) de ${relativo(dirComum)} com outro dono (uid ${[...uids].sort((a, b) => a - b).join(', ')}; o do ` +
|
|
222
|
+
`repositorio e ${raiz.uid}): ${estranhos.join(', ')}${total > estranhos.length ? ', ...' : ''}; o git do dono nao grava nelas, ` +
|
|
223
|
+
`e o fetch e o commit falham${parcial ? ` (conferencia parcial: mais de ${teto} entradas)` : ''}`,
|
|
224
|
+
correcao: `sudo chown -R ${raiz.uid}:${raiz.gid} ${noShell(dirComum)} (o ork nao roda isso sozinho)` };
|
|
225
|
+
}
|
|
226
|
+
if (parcial) {
|
|
227
|
+
return { nome, nivel: 'warn', detalhe: `mais de ${teto} entradas em ${relativo(dirComum)}: conferencia parcial, sem outro dono ate aqui`,
|
|
228
|
+
correcao: `confira o resto com: find ${noShell(dirComum)} -not -uid ${raiz.uid}` };
|
|
229
|
+
}
|
|
230
|
+
return { nome, nivel: 'ok', detalhe: `${vistos} entradas de ${relativo(dirComum)} com o dono do repositorio (uid ${raiz.uid})` };
|
|
231
|
+
}
|
|
119
232
|
/** Checks locais; ler a entrevista não abre driver, banco, runtime ou rede. */
|
|
120
233
|
function checarOnboarding(carregado) {
|
|
121
234
|
const estado = (0, onboarding_1.lerOnboarding)(carregado.raiz);
|
|
@@ -131,9 +244,15 @@ function checarOnboarding(carregado) {
|
|
|
131
244
|
checks.push({ nome: 'onboarding memoria', nivel: 'warn', detalhe: `entrevista escolheu ${modo}; manifesto declara ${carregado.manifesto.memory.mode}`,
|
|
132
245
|
correcao: `revise memory.mode: ${modo} em orkastery.yaml; a entrevista não altera o manifesto` });
|
|
133
246
|
}
|
|
134
|
-
// I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto.
|
|
247
|
+
// I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto. Com
|
|
248
|
+
// `owner.timezone` na mesma resposta (gravado no manifesto pelo `onboarding set`), vale ele: no
|
|
249
|
+
// ensaio da 0.5.0, o `fuso` legado da resposta anterior mandava desfazer a escolha explicita.
|
|
135
250
|
const maestro = estado.etapas.maestro?.conteudo;
|
|
136
|
-
const
|
|
251
|
+
const owner = maestro && typeof maestro === 'object' && !Array.isArray(maestro) ? maestro.owner : undefined;
|
|
252
|
+
const fusoDoOwner = owner && typeof owner === 'object' && !Array.isArray(owner) ? owner.timezone : undefined;
|
|
253
|
+
// Owner invalido (so por edicao a mao: o `onboarding set` recusa) nao cala o fuso legado.
|
|
254
|
+
const fusoDaEntrevista = maestro && typeof maestro === 'object' && !Array.isArray(maestro)
|
|
255
|
+
? (0, horario_1.normalizarFuso)(fusoDoOwner) ?? (0, horario_1.normalizarFuso)(maestro.fuso) : undefined;
|
|
137
256
|
if (fusoDaEntrevista && fusoDaEntrevista !== carregado.manifesto.owner?.timezone) {
|
|
138
257
|
checks.push({ nome: 'onboarding fuso', nivel: 'warn',
|
|
139
258
|
detalhe: `entrevista informou ${fusoDaEntrevista}; manifesto declara ${carregado.manifesto.owner?.timezone ?? `${horario_1.CHAVE_DO_FUSO} ausente`}`,
|
|
@@ -141,6 +260,97 @@ function checarOnboarding(carregado) {
|
|
|
141
260
|
}
|
|
142
261
|
return checks;
|
|
143
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Fatia 2 do ensaio da 0.5.0 (P1): por qual runtime cada bloco dos modos de
|
|
265
|
+
* `conduction.allowed_modes` despacha, pelo mesmo criterio do despacho sem opcao de CLI
|
|
266
|
+
* (`resolverDespacho`: o bloco do setup vence `runtime.adapter`). Quem passou os blocos para o
|
|
267
|
+
* Codex nao precisa do `claude`. Setup ilegivel devolve `null`: quem chama fica no lado seguro.
|
|
268
|
+
*/
|
|
269
|
+
function blocosDoRuntime(carregado, runtime) {
|
|
270
|
+
const { manifesto } = carregado;
|
|
271
|
+
const r = { principal: [], fallback: [] };
|
|
272
|
+
try {
|
|
273
|
+
const setup = (0, setup_1.lerSetup)(carregado.raiz);
|
|
274
|
+
for (const modo of manifesto.conduction.allowed_modes) {
|
|
275
|
+
modos_1.MODOS[modo].blocos.forEach((b, i) => {
|
|
276
|
+
const doBloco = (0, setup_1.configDoBloco)(setup, modo, b.fases[0]);
|
|
277
|
+
const bloco = { tag: modos_1.MODOS[modo].tag, bloco: i + 1 };
|
|
278
|
+
if ((doBloco?.runtime ?? manifesto.runtime.adapter) === runtime)
|
|
279
|
+
r.principal.push(bloco);
|
|
280
|
+
else if (doBloco?.fallback?.some((f) => f.split(':')[0] === runtime))
|
|
281
|
+
r.fallback.push(bloco);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
return r;
|
|
289
|
+
}
|
|
290
|
+
/** `#Classic 1, 2; #Auto 1`: os blocos agrupados por modo, na ordem dos modos permitidos. */
|
|
291
|
+
function textoDosBlocos(blocos) {
|
|
292
|
+
const porModo = new Map();
|
|
293
|
+
for (const b of blocos)
|
|
294
|
+
porModo.set(b.tag, [...(porModo.get(b.tag) ?? []), b.bloco]);
|
|
295
|
+
return [...porModo].map(([tag, numeros]) => `${tag} ${numeros.join(', ')}`).join('; ');
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Fatia 2 do ensaio da 0.5.0 (P1): o `claude` so e obrigatorio quando algum bloco de modo permitido
|
|
299
|
+
* despacha por ele. Sem manifesto, com manifesto invalido ou com setup ilegivel vale o padrao (todo
|
|
300
|
+
* bloco no claude-bg), e a falta reprova como antes.
|
|
301
|
+
*/
|
|
302
|
+
function checarRuntimeClaude(carregado, claude, versao) {
|
|
303
|
+
const nome = 'runtime claude-bg';
|
|
304
|
+
if (claude)
|
|
305
|
+
return { nome, nivel: 'ok', detalhe: `${claude} (${versao ?? 'versao desconhecida'})` };
|
|
306
|
+
const blocos = carregado && carregado.erros.length === 0 ? blocosDoRuntime(carregado, 'claude-bg') : null;
|
|
307
|
+
if (blocos && blocos.principal.length === 0) {
|
|
308
|
+
// CHECK, rodada 1 (S6): as fases nao precisam dele, mas o `ork audit run` despacha sempre pelo claude-bg.
|
|
309
|
+
return { nome, nivel: 'warn',
|
|
310
|
+
detalhe: 'binario `claude` fora do PATH (opcional para as fases: nenhum bloco dos modos permitidos despacha pelo claude-bg' +
|
|
311
|
+
(blocos.fallback.length
|
|
312
|
+
? `; o fallback de ${blocos.fallback.length} bloco(s) cai nele e falharia: ${textoDosBlocos(blocos.fallback)}` : '') +
|
|
313
|
+
'; o ork audit run ainda despacha por ele)',
|
|
314
|
+
correcao: 'para despachar pelo claude-bg (e rodar ork audit run), instale o Claude Code e garanta `claude` no PATH' };
|
|
315
|
+
}
|
|
316
|
+
return { nome, nivel: 'fail',
|
|
317
|
+
detalhe: 'binario `claude` fora do PATH' + (blocos
|
|
318
|
+
? `; ${blocos.principal.length} bloco(s) dos modos permitidos despacham por ele (${textoDosBlocos(blocos.principal)})` : ''),
|
|
319
|
+
correcao: 'instale o Claude Code e garanta `claude` no PATH; so com o Codex, passe cada bloco para ele ' +
|
|
320
|
+
'(ork setup <modo> --bloco N --runtime codex --model <modelo>) ou tire o modo de conduction.allowed_modes ' +
|
|
321
|
+
'(mantenha o conduction.default_mode entre os permitidos)' };
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* O despacho pelo Codex quando o projeto o elege: por `runtime.adapter: codex`, como antes, ou, desde
|
|
325
|
+
* a fatia 2 do ensaio da 0.5.0 (P1), por bloco de modo permitido. A falta do `codex`, ou um sandbox
|
|
326
|
+
* que nao executa, deixa de ser aviso: e exatamente o que bloquearia a fase. Sem nenhum dos dois, o
|
|
327
|
+
* check nao sai.
|
|
328
|
+
*/
|
|
329
|
+
function checarDespachoPeloCodex(carregado, codex, sonda) {
|
|
330
|
+
const pelaAdapter = carregado.manifesto.runtime.adapter === 'codex';
|
|
331
|
+
const blocos = blocosDoRuntime(carregado, 'codex')?.principal ?? [];
|
|
332
|
+
if (!pelaAdapter && blocos.length === 0)
|
|
333
|
+
return null;
|
|
334
|
+
const origem = [pelaAdapter ? 'runtime.adapter: codex' : '',
|
|
335
|
+
blocos.length ? `${blocos.length} bloco(s) dos modos permitidos no codex (${textoDosBlocos(blocos)})` : '']
|
|
336
|
+
.filter(Boolean).join(' e ');
|
|
337
|
+
const sandboxConfigurado = carregado.manifesto.runtime.sandbox;
|
|
338
|
+
const sandboxQuebrado = sonda !== null && !sonda.ok && sandboxConfigurado !== 'danger-full-access';
|
|
339
|
+
return {
|
|
340
|
+
nome: 'despacho pelo codex',
|
|
341
|
+
nivel: !codex ? 'fail' : sandboxQuebrado ? 'fail' : 'ok',
|
|
342
|
+
detalhe: !codex
|
|
343
|
+
? `${origem}, mas o binario \`codex\` esta fora do PATH`
|
|
344
|
+
: sandboxQuebrado
|
|
345
|
+
? `${origem} com sandbox "${sandboxConfigurado}", mas o sandbox nao executa nesta maquina (o agente narraria sucesso sem rodar nada)`
|
|
346
|
+
: `${origem} com sandbox "${sandboxConfigurado}"`,
|
|
347
|
+
correcao: !codex
|
|
348
|
+
? 'instale o Codex CLI e autentique com `codex login` (assinatura, nunca API key)'
|
|
349
|
+
: sandboxQuebrado
|
|
350
|
+
? 'instale o bubblewrap do sistema, ou declare runtime.sandbox: danger-full-access ciente do risco'
|
|
351
|
+
: undefined,
|
|
352
|
+
};
|
|
353
|
+
}
|
|
144
354
|
/** Roda todos os checks a partir do diretorio informado. */
|
|
145
355
|
function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
|
|
146
356
|
const checks = [];
|
|
@@ -160,31 +370,43 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
160
370
|
});
|
|
161
371
|
const repo = (0, util_1.exec)('git', ['rev-parse', '--is-inside-work-tree'], dirInicial);
|
|
162
372
|
const dentroDeRepo = repo.ok && repo.stdout.trim() === 'true';
|
|
163
|
-
|
|
373
|
+
// Ensaio da 0.5.0: sem commit, o `rev-parse --abbrev-ref` respondia "HEAD"; a branch vem do
|
|
374
|
+
// `symbolic-ref`, e a falta de commit fica dita.
|
|
375
|
+
const semCommit = dentroDeRepo && !(0, util_1.exec)('git', ['rev-parse', '--verify', '--quiet', 'HEAD'], dirInicial).ok;
|
|
376
|
+
const branch = dentroDeRepo ? (0, util_1.branchDoHead)(dirInicial) ?? (0, util_1.exec)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], dirInicial).stdout.trim() : '';
|
|
164
377
|
checks.push({
|
|
165
378
|
nome: 'repositorio',
|
|
166
379
|
nivel: dentroDeRepo ? 'ok' : 'fail',
|
|
167
|
-
detalhe: dentroDeRepo ? `branch ${branch
|
|
380
|
+
detalhe: dentroDeRepo ? `branch ${branch}${semCommit ? ' (sem commit)' : ''}` : 'fora de um repositorio git',
|
|
168
381
|
correcao: dentroDeRepo ? undefined : 'rode o ork dentro de um repositorio git',
|
|
169
382
|
});
|
|
383
|
+
if (dentroDeRepo) {
|
|
384
|
+
const dono = checarDonoDoGit(dirInicial);
|
|
385
|
+
if (dono)
|
|
386
|
+
checks.push(dono);
|
|
387
|
+
}
|
|
388
|
+
// Fatia 2 do ensaio da 0.5.0 (P1): o manifesto e lido antes dos runtimes, porque e o setup dos
|
|
389
|
+
// modos permitidos que diz se o `claude` e obrigatorio; a ordem das linhas do relatorio nao muda.
|
|
390
|
+
const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
|
|
170
391
|
const claude = adapter.disponivel();
|
|
171
392
|
const v = claude ? adapter.versao() : null;
|
|
172
|
-
checks.push(
|
|
173
|
-
nome: 'runtime claude-bg',
|
|
174
|
-
nivel: claude ? 'ok' : 'fail',
|
|
175
|
-
detalhe: claude ? `${claude} (${v ?? 'versao desconhecida'})` : 'binario `claude` fora do PATH',
|
|
176
|
-
correcao: claude ? undefined : 'instale o Claude Code e garanta `claude` no PATH',
|
|
177
|
-
});
|
|
393
|
+
checks.push(checarRuntimeClaude(carregado, claude, v));
|
|
178
394
|
// Segundo runtime homologado. Ausente e `warn`, nao `fail`: o claude-bg segue sendo o
|
|
179
395
|
// padrao, e um projeto que nunca pediu codex nao pode ficar bloqueado por ele.
|
|
180
396
|
const codex = codexAdapter.disponivel();
|
|
181
397
|
const codexVersao = codex ? codexAdapter.versao() : null;
|
|
398
|
+
// CHECK, rodada 1 (S6): com o projeto despachando pelo codex, a falta dele nao e "opcional"; quem
|
|
399
|
+
// reprova e o check `despacho pelo codex`, mais abaixo.
|
|
400
|
+
const usaCodex = !!carregado && carregado.erros.length === 0 && (carregado.manifesto.runtime.adapter === 'codex' ||
|
|
401
|
+
(blocosDoRuntime(carregado, 'codex')?.principal.length ?? 0) > 0);
|
|
182
402
|
checks.push({
|
|
183
403
|
nome: 'runtime codex',
|
|
184
404
|
nivel: codex ? 'ok' : 'warn',
|
|
185
405
|
detalhe: codex
|
|
186
406
|
? `${codex} (${codexVersao ?? 'versao desconhecida'})`
|
|
187
|
-
:
|
|
407
|
+
: usaCodex
|
|
408
|
+
? 'binario `codex` fora do PATH (o projeto despacha por ele: veja despacho pelo codex)'
|
|
409
|
+
: 'binario `codex` fora do PATH (opcional: claude-bg e o runtime padrao)',
|
|
188
410
|
correcao: codex
|
|
189
411
|
? undefined
|
|
190
412
|
: 'para despachar pelo codex, instale o Codex CLI e autentique com `codex login`',
|
|
@@ -206,7 +428,6 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
206
428
|
'nesta maquina) ou declare runtime.sandbox: danger-full-access ciente do risco',
|
|
207
429
|
});
|
|
208
430
|
}
|
|
209
|
-
const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
|
|
210
431
|
if (!carregado) {
|
|
211
432
|
checks.push({
|
|
212
433
|
nome: 'manifesto',
|
|
@@ -253,26 +474,11 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
253
474
|
: `${fuso.fuso} (fuso do sistema; ${horario_1.CHAVE_DO_FUSO} nao configurado)`),
|
|
254
475
|
correcao: fuso.aviso ? `corrija ${horario_1.CHAVE_DO_FUSO} com um nome IANA` : undefined,
|
|
255
476
|
});
|
|
256
|
-
// Quando o manifesto
|
|
477
|
+
// Quando o manifesto ou um bloco de modo permitido ELEGE o codex, a ausencia dele (ou um
|
|
257
478
|
// sandbox que nao executa) deixa de ser aviso: e exatamente o que bloquearia a fase.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
}
|
|
479
|
+
const despachoPeloCodex = checarDespachoPeloCodex(carregado, codex, sondaDoCodex);
|
|
480
|
+
if (despachoPeloCodex)
|
|
481
|
+
checks.push(despachoPeloCodex);
|
|
276
482
|
const politica = carregado.manifesto.runtime.provider_policy;
|
|
277
483
|
const soAssinatura = politica === 'subscription-only';
|
|
278
484
|
const redirecionam = ENVS_QUE_REDIRECIONAM.filter(e => nomesHerdados.includes(e));
|
|
@@ -315,6 +521,7 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
315
521
|
: 'files (fallback honesto: handoff por arquivos, ponteiro path#ancora)',
|
|
316
522
|
correcao: estado.pedido === 'orkmind' && estado.efetivo === 'files' ? estado.correcao : undefined,
|
|
317
523
|
});
|
|
524
|
+
checks.push(checarChaveDeEmbedding(context.loaded));
|
|
318
525
|
// Bloco B3: a fila de rate limit e estado do mundo, nao detalhe interno. Uma fase
|
|
319
526
|
// esperando janela e uma fase que NAO esta rodando, e quem olha o doctor precisa
|
|
320
527
|
// saber disso antes de concluir que a thread travou.
|
|
@@ -352,12 +559,15 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
352
559
|
checks.push(...(0, preflight_1.sondasDeAmbiente)(carregado.raiz));
|
|
353
560
|
{
|
|
354
561
|
const inventario = (0, sessoes_inventario_1.inventariarSessoes)(carregado.raiz, { global: true, todas: true });
|
|
562
|
+
// Fatia 2 do ensaio da 0.5.0 (P1): binario ausente e fonte ausente, dita no detalhe.
|
|
563
|
+
const ausentes = inventario.fontes.filter((f) => f.ausente).map((f) => f.origem);
|
|
355
564
|
checks.push({
|
|
356
565
|
nome: 'governanca de sessoes',
|
|
357
566
|
nivel: inventario.ok && inventario.semThread === 0 ? 'ok' : 'warn',
|
|
358
567
|
detalhe: `${inventario.escopo.usuario}, Claude e Codex, global com histórico: ${inventario.total} sessões; ` +
|
|
359
568
|
`${inventario.semThread} sem thread; ${inventario.ambiguas} ambíguas; ` +
|
|
360
|
-
`inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}
|
|
569
|
+
`inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}` +
|
|
570
|
+
(ausentes.length ? `; fonte ausente: ${ausentes.join(', ')}` : ''),
|
|
361
571
|
correcao: inventario.ok && inventario.semThread === 0 ? undefined :
|
|
362
572
|
'ork sessions --global --all --json; adote identidades sem vínculo com ork sessions adopt <id>',
|
|
363
573
|
});
|