@orkastery/cli 0.5.0 → 0.5.3
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/claude-code/README.md +11 -2
- package/adapters/claude-code/agents/ork-master.md +2 -0
- package/adapters/claude-code/commands/master.md +8 -0
- package/adapters/claude-code/commands/onboarding.md +3 -2
- package/adapters/claude-code/commands/ork.md +9 -0
- package/adapters/codex/skills/ork/SKILL.md +18 -3
- package/adapters/hermes/README.md +1 -0
- package/adapters/hermes/bin/ork-network-status.sh +10 -0
- package/adapters/hermes/hermes.plugin.json +1 -0
- package/adapters/hermes/hitl-ingress/__init__.py +2 -2
- package/adapters/hermes/skills/orkastery-devmaster/SKILL.md +6 -5
- package/adapters/openclaw/README.md +35 -4
- package/adapters/openclaw/dist/hitl-ingress.js +2 -2
- package/adapters/openclaw/dist/index.js +47 -12
- package/adapters/openclaw/openclaw.plugin.json +5 -1
- package/adapters/openclaw/package.json +2 -2
- package/adapters/openclaw/src/hitl-ingress.ts +2 -2
- package/adapters/openclaw/src/index.ts +50 -12
- package/assets/orkmind_bridge.py +117 -9
- package/dist/adapters/claude-bg.js +59 -11
- package/dist/adapters/codex.js +4 -3
- package/dist/agents-md.js +1 -0
- package/dist/auditrun.js +6 -2
- package/dist/board.js +16 -14
- package/dist/branch-de-estado.js +66 -10
- package/dist/busca-semantica.js +52 -12
- package/dist/canarios-rm057.js +149 -0
- package/dist/canarios.js +2 -0
- package/dist/ci.js +8 -1
- package/dist/claim-lint.js +3 -1
- package/dist/claims.js +39 -1
- package/dist/company-brain-context.js +158 -22
- package/dist/docs.js +110 -3
- package/dist/doctor-pulse-cron.js +194 -0
- package/dist/doctor-rede.js +149 -0
- package/dist/doctor.js +294 -37
- package/dist/entrega-pr.js +27 -8
- package/dist/esgotamentos.js +181 -0
- package/dist/experiencia.js +12 -2
- package/dist/fabrica-estado.js +35 -9
- package/dist/fabrica-publicar.js +6 -0
- package/dist/fechamento.js +20 -66
- package/dist/fix.js +3 -3
- package/dist/forja.js +31 -7
- package/dist/gates.js +5 -1
- package/dist/hitl-contract.js +59 -4
- package/dist/hitl-curto.js +11 -6
- package/dist/hitl-gates.js +5 -0
- package/dist/hitl-lote.js +5 -2
- package/dist/hitl-resumo.js +33 -1
- package/dist/hitl-tempo-parado.js +201 -0
- package/dist/hitl-texto-livre.js +5 -5
- package/dist/horario.js +27 -0
- package/dist/hosts.js +59 -13
- package/dist/impedimento.js +205 -0
- package/dist/index.js +433 -88
- package/dist/indice-vetorial.js +87 -10
- package/dist/indice.js +3 -1
- package/dist/init.js +28 -5
- package/dist/integracoes-locais.js +4 -0
- package/dist/intelligence-graph-cli.js +267 -30
- package/dist/intelligence-graph-contexto.js +215 -0
- package/dist/intelligence-graph-contract.js +71 -12
- package/dist/intelligence-graph-extract-md.js +41 -23
- package/dist/intelligence-graph-extract-ts.js +181 -11
- package/dist/intelligence-graph-extract.js +186 -9
- package/dist/intelligence-graph-index.js +205 -24
- package/dist/intelligence-graph-parsers.js +6 -4
- package/dist/intelligence-graph-repo.js +10 -0
- package/dist/leases.js +680 -87
- package/dist/ledger-stats.js +15 -1
- package/dist/ledger.js +12 -0
- package/dist/licoes.js +6 -4
- package/dist/liveness.js +2 -1
- package/dist/maestro-runtime.js +7 -1
- package/dist/manifest.js +44 -1
- package/dist/master-nota.js +14 -5
- package/dist/master.js +129 -12
- package/dist/mcp-artifacts.js +36 -3
- package/dist/mcp-git.js +80 -15
- package/dist/mcp-grafo-worker.js +93 -0
- package/dist/mcp-grafo.js +279 -0
- package/dist/mcp-install.js +2 -1
- package/dist/mcp-server.js +23 -1
- package/dist/mcp-ship.js +2 -0
- package/dist/mcp-verify.js +3 -1
- package/dist/memoria.js +48 -6
- package/dist/network-roadmap.js +195 -20
- package/dist/ocupacao.js +17 -5
- package/dist/onboarding.js +9 -4
- package/dist/orkmind.js +90 -5
- package/dist/orquestracao.js +14 -11
- package/dist/parado-no-condutor.js +1089 -0
- package/dist/phase.js +68 -15
- package/dist/policies.js +79 -3
- package/dist/portfolio.js +4 -1
- package/dist/projeto-alvo.js +5 -1
- package/dist/prompts.js +36 -1
- package/dist/prova-ativacao.js +414 -0
- package/dist/pulse-delivery.js +60 -7
- package/dist/pulse.js +99 -3
- package/dist/ratelimit.js +20 -4
- package/dist/recall.js +3 -1
- package/dist/rede-adesao.js +399 -0
- package/dist/rede-forja.js +289 -0
- package/dist/rede-projetos.js +239 -0
- package/dist/rede-status.js +336 -0
- package/dist/rede.js +980 -0
- package/dist/retry.js +69 -2
- package/dist/roadmap-status.js +162 -7
- package/dist/runtime-context.js +5 -1
- package/dist/runtime-profiles.js +22 -1
- package/dist/saida-segura.js +58 -0
- package/dist/session-watcher-claude.js +113 -23
- package/dist/sessoes-contas.js +187 -0
- package/dist/sessoes-inventario.js +6 -12
- package/dist/sessoes.js +87 -3
- package/dist/ship.js +110 -20
- package/dist/thread.js +212 -14
- package/dist/util.js +71 -4
- package/dist/verify.js +2 -2
- package/dist/worktree.js +34 -8
- package/eval/casos/onboarding.json +1 -1
- package/eval/fixtures/fx-pedido-colado/caso.json +20 -0
- package/package.json +7 -3
- package/references/definition-of-done.md +1 -1
- package/skills/README.md +1 -1
- package/skills/core/onboarding/SKILL.md +3 -2
- package/skills/core/orkastery-bootstrap/SKILL.md +2 -2
- package/skills/phases/master-metrics/SKILL.md +8 -3
- package/skills/phases/ship-release/SKILL.md +6 -3
|
@@ -0,0 +1,149 @@
|
|
|
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.CAUDA_DO_LOG_BYTES = void 0;
|
|
37
|
+
exports.caudaDoLogDaRede = caudaDoLogDaRede;
|
|
38
|
+
exports.correcaoDaFalha = correcaoDaFalha;
|
|
39
|
+
exports.checarRede = checarRede;
|
|
40
|
+
/**
|
|
41
|
+
* RM-053 (fatia 2): o check "rede" do `ork doctor`.
|
|
42
|
+
*
|
|
43
|
+
* A rede pessoal publica sozinha (batida do pulse e eventos de thread) e so deixava rastro em
|
|
44
|
+
* `~/.orkastery/rede/rede.log`: a srvjcp86 ficou de 02/10 em diante como membro herdado da fabrica,
|
|
45
|
+
* com toda publicacao caindo em `rede.sem-repositorio`, e o doctor dizia PRONTO sem uma palavra.
|
|
46
|
+
*
|
|
47
|
+
* O check diz a adesao, a casa, a ultima batida publicada e a ultima falha do log. Ele so le
|
|
48
|
+
* arquivos locais (`rede.json`, `maquina.json`, `rede/publicada.json`, `rede/rede.log`): nao chama
|
|
49
|
+
* a forja, nao cria estado e roda de qualquer diretorio. Nunca reprova: a rede e opcional e o
|
|
50
|
+
* doctor e gate de despacho; o pior nivel e `warn`, com a correcao.
|
|
51
|
+
*/
|
|
52
|
+
const fs = __importStar(require("node:fs"));
|
|
53
|
+
const path = __importStar(require("node:path"));
|
|
54
|
+
const horario_1 = require("./horario");
|
|
55
|
+
const rede_1 = require("./rede");
|
|
56
|
+
const rede_adesao_1 = require("./rede-adesao");
|
|
57
|
+
const rede_status_1 = require("./rede-status");
|
|
58
|
+
const saida_segura_1 = require("./saida-segura");
|
|
59
|
+
/** O fim do `rede.log` que o doctor le: o log so cresce, e o que importa e o mais recente. */
|
|
60
|
+
exports.CAUDA_DO_LOG_BYTES = 64 * 1024;
|
|
61
|
+
/** As linhas legiveis do fim do `rede.log`, da mais antiga para a mais nova. Sem log, lista vazia. */
|
|
62
|
+
function caudaDoLogDaRede(arquivo = path.join((0, rede_adesao_1.pastaDaRede)(), 'rede.log')) {
|
|
63
|
+
let texto;
|
|
64
|
+
try {
|
|
65
|
+
const fd = fs.openSync(arquivo, 'r');
|
|
66
|
+
try {
|
|
67
|
+
const tamanho = fs.fstatSync(fd).size;
|
|
68
|
+
const inicio = Math.max(0, tamanho - exports.CAUDA_DO_LOG_BYTES);
|
|
69
|
+
const buf = Buffer.alloc(tamanho - inicio);
|
|
70
|
+
fs.readSync(fd, buf, 0, buf.length, inicio);
|
|
71
|
+
texto = buf.toString('utf8');
|
|
72
|
+
// A primeira linha de uma cauda cortada vem pela metade.
|
|
73
|
+
if (inicio > 0)
|
|
74
|
+
texto = texto.slice(texto.indexOf('\n') + 1);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
fs.closeSync(fd);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const registros = [];
|
|
84
|
+
for (const linha of texto.split('\n')) {
|
|
85
|
+
if (!linha.trim())
|
|
86
|
+
continue;
|
|
87
|
+
try {
|
|
88
|
+
const r = JSON.parse(linha);
|
|
89
|
+
if (typeof r.ts !== 'string' || !Number.isFinite(Date.parse(r.ts)) || typeof r.acao !== 'string')
|
|
90
|
+
continue;
|
|
91
|
+
registros.push({ ts: r.ts, acao: r.acao, origem: typeof r.origem === 'string' ? r.origem : null,
|
|
92
|
+
erro: typeof r.erro === 'string' ? r.erro : null });
|
|
93
|
+
}
|
|
94
|
+
catch { /* linha ilegivel: o log e informativo */ }
|
|
95
|
+
}
|
|
96
|
+
return registros;
|
|
97
|
+
}
|
|
98
|
+
const curto = (s, teto = 200) => {
|
|
99
|
+
const limpo = (0, saida_segura_1.emUmaLinha)(s).trim();
|
|
100
|
+
return limpo.length > teto ? `${limpo.slice(0, teto - 3)}...` : limpo;
|
|
101
|
+
};
|
|
102
|
+
/** A correcao pela familia do erro da ultima falha (o prefixo tipado, como `rede.sem-repositorio`). */
|
|
103
|
+
function correcaoDaFalha(erro) {
|
|
104
|
+
const codigo = /^([a-z]+\.[a-z-]+):/.exec(erro)?.[1] ?? '';
|
|
105
|
+
if (codigo === 'rede.sem-repositorio' || codigo === 'rede.repositorio-alheio') {
|
|
106
|
+
return 'a casa da rede ainda nao existe: o dono roda ork network entrar, que cria o repositorio privado; ou ork network sair, para tirar esta maquina da rede';
|
|
107
|
+
}
|
|
108
|
+
if (codigo === 'rede.sem-forja')
|
|
109
|
+
return 'faca login na forja (gh auth login ou glab auth login) e rode ork network publicar';
|
|
110
|
+
if (codigo === 'rede.repositorio-publico')
|
|
111
|
+
return 'torne a casa da rede privada na forja; nada e publicado num repositorio publico';
|
|
112
|
+
if (codigo === 'rede.nome-em-uso')
|
|
113
|
+
return 'escolha outro nome com ork network entrar --maquina NOME, ou tome este com --forcar';
|
|
114
|
+
return 'ork network status mostra as lacunas; ork network publicar tenta de novo';
|
|
115
|
+
}
|
|
116
|
+
/** O check "rede". `agoraMs` e o log ficam injetaveis para o teste. */
|
|
117
|
+
function checarRede(opcoes = {}) {
|
|
118
|
+
const nome = 'rede';
|
|
119
|
+
const agora = opcoes.agoraMs ?? Date.now();
|
|
120
|
+
const adesao = (0, rede_adesao_1.adesaoDaRede)();
|
|
121
|
+
if (!adesao.membro) {
|
|
122
|
+
return { nome, nivel: 'ok', detalhe: adesao.config && !adesao.config.membro
|
|
123
|
+
? 'fora da rede (saiu com ork network sair)'
|
|
124
|
+
: 'fora da rede; ork network entrar poe esta maquina na rede da pessoa' };
|
|
125
|
+
}
|
|
126
|
+
const marca = (0, rede_1.lerMarcaDaRede)();
|
|
127
|
+
const config = adesao.config;
|
|
128
|
+
const casa = config?.host && config.dono && config.repositorio ? `${config.host}/${config.dono}/${config.repositorio}`
|
|
129
|
+
: typeof marca?.casa === 'string' ? marca.casa : null;
|
|
130
|
+
const registros = caudaDoLogDaRede(opcoes.log);
|
|
131
|
+
const falha = [...registros].reverse().find((r) => r.acao === 'falhou') ?? null;
|
|
132
|
+
const emBatida = marca && typeof marca.em === 'string' && Number.isFinite(Date.parse(marca.em)) ? marca.em : null;
|
|
133
|
+
const idade = emBatida ? agora - Date.parse(emBatida) : NaN;
|
|
134
|
+
const partes = [
|
|
135
|
+
adesao.adesao === 'fabrica' ? 'membro herdado da fabrica' : 'membro',
|
|
136
|
+
casa ? `casa ${curto(casa, 120)}` : 'casa ainda nao gravada',
|
|
137
|
+
emBatida ? `ultima batida ${(0, horario_1.formatarDataHora)(emBatida)} (ha ${(0, rede_status_1.duracao)(idade)})` : 'nenhuma batida publicada',
|
|
138
|
+
falha ? `ultima falha ${(0, horario_1.formatarDataHora)(falha.ts)}${falha.origem ? ` (${curto(falha.origem, 20)})` : ''}: ${curto(falha.erro ?? 'sem detalhe')}`
|
|
139
|
+
: 'nenhuma falha no rede.log',
|
|
140
|
+
];
|
|
141
|
+
// A falha mais nova que a ultima batida e o estado de agora; a de antes ja passou.
|
|
142
|
+
const falhaAtual = !!falha && (!emBatida || Date.parse(falha.ts) > Date.parse(emBatida));
|
|
143
|
+
const parada = !emBatida || !(idade <= rede_status_1.SEM_BATIDA_MS);
|
|
144
|
+
if (!falhaAtual && !parada)
|
|
145
|
+
return { nome, nivel: 'ok', detalhe: partes.join('; ') };
|
|
146
|
+
const correcao = falhaAtual ? correcaoDaFalha(falha.erro ?? '')
|
|
147
|
+
: 'a batida sai do pulse: confira o cron do pulse e rode ork network publicar';
|
|
148
|
+
return { nome, nivel: 'warn', detalhe: partes.join('; '), correcao };
|
|
149
|
+
}
|
package/dist/doctor.js
CHANGED
|
@@ -39,9 +39,15 @@ 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;
|
|
43
|
+
exports.manifestoForaDoRepositorio = manifestoForaDoRepositorio;
|
|
42
44
|
exports.checarContas = checarContas;
|
|
43
45
|
exports.checarChaveDeEmbedding = checarChaveDeEmbedding;
|
|
46
|
+
exports.checarDonoDoGit = checarDonoDoGit;
|
|
44
47
|
exports.checarOnboarding = checarOnboarding;
|
|
48
|
+
exports.blocosDoRuntime = blocosDoRuntime;
|
|
49
|
+
exports.checarRuntimeClaude = checarRuntimeClaude;
|
|
50
|
+
exports.checarDespachoPeloCodex = checarDespachoPeloCodex;
|
|
45
51
|
exports.checar = checar;
|
|
46
52
|
exports.relatorio = relatorio;
|
|
47
53
|
exports.doctor = doctor;
|
|
@@ -63,6 +69,42 @@ const project_state_1 = require("./project-state");
|
|
|
63
69
|
const runtime_ambiente_1 = require("./runtime-ambiente");
|
|
64
70
|
const runtime_profiles_1 = require("./runtime-profiles");
|
|
65
71
|
const preflight_1 = require("./preflight");
|
|
72
|
+
const setup_1 = require("./setup");
|
|
73
|
+
const doctor_pulse_cron_1 = require("./doctor-pulse-cron");
|
|
74
|
+
const doctor_rede_1 = require("./doctor-rede");
|
|
75
|
+
/**
|
|
76
|
+
* Ensaio de 03/10/2026 (RM-049): o manifesto e achado subindo a partir do diretorio atual. Um
|
|
77
|
+
* `orkastery.yaml` de uma pasta acima do repositorio (um `ork init` rodado por engano no HOME) era
|
|
78
|
+
* lido como o deste projeto, com outro nome e outra abbrev, e o doctor dizia PRONTO. Vale o manifesto
|
|
79
|
+
* dentro do repositorio ou na arvore principal dele (a worktree de thread le o da arvore principal).
|
|
80
|
+
*/
|
|
81
|
+
function manifestoForaDoRepositorio(dirInicial, caminhoDoManifesto) {
|
|
82
|
+
const topo = (0, util_1.exec)('git', ['rev-parse', '--show-toplevel'], dirInicial);
|
|
83
|
+
if (!topo.ok)
|
|
84
|
+
return null;
|
|
85
|
+
const real = (p) => { try {
|
|
86
|
+
return fs.realpathSync(p);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return path.resolve(p);
|
|
90
|
+
} };
|
|
91
|
+
const dirDoManifesto = real(path.dirname(caminhoDoManifesto));
|
|
92
|
+
const dentro = (raiz) => {
|
|
93
|
+
const r = path.relative(real(raiz), dirDoManifesto);
|
|
94
|
+
return r === '' || (!r.startsWith('..') && !path.isAbsolute(r));
|
|
95
|
+
};
|
|
96
|
+
if (dentro(topo.stdout.trim()))
|
|
97
|
+
return null;
|
|
98
|
+
const comum = (0, util_1.exec)('git', ['rev-parse', '--path-format=absolute', '--git-common-dir'], dirInicial);
|
|
99
|
+
if (comum.ok && path.basename(comum.stdout.trim()) === '.git' && dentro(path.dirname(comum.stdout.trim())))
|
|
100
|
+
return null;
|
|
101
|
+
return {
|
|
102
|
+
nome: 'manifesto do repositorio',
|
|
103
|
+
nivel: 'warn',
|
|
104
|
+
detalhe: `o ${manifest_1.NOME_MANIFESTO} lido fica fora deste repositorio (${caminhoDoManifesto}): o ork conduz o projeto daquela pasta, nao o de ${topo.stdout.trim()}`,
|
|
105
|
+
correcao: `rode ork init na raiz deste repositorio (${topo.stdout.trim()}); se o manifesto de fora nasceu por engano, apague-o junto com o AGENTS.md e o .orkastery/ ao lado dele`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
66
108
|
/**
|
|
67
109
|
* I-33 (D7): check "contas por runtime". Cada perfil ativo tem o login conferido pelo proprio
|
|
68
110
|
* CLI com o env dele (`claude auth status`, `codex login status`); o doctor so le e relata, sem
|
|
@@ -148,6 +190,81 @@ function checarChaveDeEmbedding(carregado, env = process.env) {
|
|
|
148
190
|
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`,
|
|
149
191
|
correcao: `exporte ${variavel} com a chave dedicada ao Orkastery (com limite de credito no painel do provider)` };
|
|
150
192
|
}
|
|
193
|
+
/** Acima disso a conferencia do dono do `.git` fica parcial (aviso), para o doctor nao pesar. */
|
|
194
|
+
exports.TETO_DO_DONO_DO_GIT = 200_000;
|
|
195
|
+
/**
|
|
196
|
+
* RM-037 (fatia 3, defeito 7): git rodado como root no repositorio do dono deixa objeto, pasta e
|
|
197
|
+
* `FETCH_HEAD` com outro dono, e o git do dono deixa de gravar neles: o fetch travou em 29/09 e em
|
|
198
|
+
* 01/10. O dono do repositorio e o dono do diretorio comum do git. O check acusa com a contagem, ate
|
|
199
|
+
* tres exemplos e o `chown` exato; o doctor nunca roda nada. Fora de repositorio git, `null`.
|
|
200
|
+
*/
|
|
201
|
+
function checarDonoDoGit(dirInicial, opcoes = {}) {
|
|
202
|
+
const nome = 'dono do .git';
|
|
203
|
+
const comum = (0, util_1.exec)('git', ['rev-parse', '--git-common-dir'], dirInicial);
|
|
204
|
+
if (!comum.ok || !comum.stdout.trim())
|
|
205
|
+
return null;
|
|
206
|
+
const dirComum = path.resolve(dirInicial, comum.stdout.trim());
|
|
207
|
+
const lstat = opcoes.lstat ?? ((p) => fs.lstatSync(p));
|
|
208
|
+
let raiz;
|
|
209
|
+
try {
|
|
210
|
+
raiz = lstat(dirComum);
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const teto = opcoes.teto ?? exports.TETO_DO_DONO_DO_GIT;
|
|
216
|
+
const relativo = (f) => path.relative(path.dirname(dirComum), f);
|
|
217
|
+
// A correcao sai pronta para copiar: caminho com caractere fora do conjunto seguro vai entre aspas simples.
|
|
218
|
+
const noShell = (s) => /^[A-Za-z0-9._/-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
219
|
+
const estranhos = [], uids = new Set();
|
|
220
|
+
let total = 0, vistos = 0, parcial = false;
|
|
221
|
+
const pilha = [dirComum];
|
|
222
|
+
while (pilha.length > 0 && !parcial) {
|
|
223
|
+
const atual = pilha.pop();
|
|
224
|
+
let nomes;
|
|
225
|
+
// Pasta que o dono nao consegue listar ja aparece pelo dono dela, na entrada de cima.
|
|
226
|
+
try {
|
|
227
|
+
nomes = fs.readdirSync(atual);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
for (const n of nomes) {
|
|
233
|
+
if (++vistos > teto) {
|
|
234
|
+
parcial = true;
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
const f = path.join(atual, n);
|
|
238
|
+
let st;
|
|
239
|
+
try {
|
|
240
|
+
st = lstat(f);
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
if (st.uid !== raiz.uid) {
|
|
246
|
+
total++;
|
|
247
|
+
uids.add(st.uid);
|
|
248
|
+
if (estranhos.length < 3)
|
|
249
|
+
estranhos.push(relativo(f));
|
|
250
|
+
}
|
|
251
|
+
if (st.isDirectory())
|
|
252
|
+
pilha.push(f);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
if (total > 0) {
|
|
256
|
+
return { nome, nivel: 'fail',
|
|
257
|
+
detalhe: `${total} entrada(s) de ${relativo(dirComum)} com outro dono (uid ${[...uids].sort((a, b) => a - b).join(', ')}; o do ` +
|
|
258
|
+
`repositorio e ${raiz.uid}): ${estranhos.join(', ')}${total > estranhos.length ? ', ...' : ''}; o git do dono nao grava nelas, ` +
|
|
259
|
+
`e o fetch e o commit falham${parcial ? ` (conferencia parcial: mais de ${teto} entradas)` : ''}`,
|
|
260
|
+
correcao: `sudo chown -R ${raiz.uid}:${raiz.gid} ${noShell(dirComum)} (o ork nao roda isso sozinho)` };
|
|
261
|
+
}
|
|
262
|
+
if (parcial) {
|
|
263
|
+
return { nome, nivel: 'warn', detalhe: `mais de ${teto} entradas em ${relativo(dirComum)}: conferencia parcial, sem outro dono ate aqui`,
|
|
264
|
+
correcao: `confira o resto com: find ${noShell(dirComum)} -not -uid ${raiz.uid}` };
|
|
265
|
+
}
|
|
266
|
+
return { nome, nivel: 'ok', detalhe: `${vistos} entradas de ${relativo(dirComum)} com o dono do repositorio (uid ${raiz.uid})` };
|
|
267
|
+
}
|
|
151
268
|
/** Checks locais; ler a entrevista não abre driver, banco, runtime ou rede. */
|
|
152
269
|
function checarOnboarding(carregado) {
|
|
153
270
|
const estado = (0, onboarding_1.lerOnboarding)(carregado.raiz);
|
|
@@ -163,9 +280,15 @@ function checarOnboarding(carregado) {
|
|
|
163
280
|
checks.push({ nome: 'onboarding memoria', nivel: 'warn', detalhe: `entrevista escolheu ${modo}; manifesto declara ${carregado.manifesto.memory.mode}`,
|
|
164
281
|
correcao: `revise memory.mode: ${modo} em orkastery.yaml; a entrevista não altera o manifesto` });
|
|
165
282
|
}
|
|
166
|
-
// I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto.
|
|
283
|
+
// I-35: o fuso respondido na etapa maestro orienta owner.timezone, sem editar o manifesto. Com
|
|
284
|
+
// `owner.timezone` na mesma resposta (gravado no manifesto pelo `onboarding set`), vale ele: no
|
|
285
|
+
// ensaio da 0.5.0, o `fuso` legado da resposta anterior mandava desfazer a escolha explicita.
|
|
167
286
|
const maestro = estado.etapas.maestro?.conteudo;
|
|
168
|
-
const
|
|
287
|
+
const owner = maestro && typeof maestro === 'object' && !Array.isArray(maestro) ? maestro.owner : undefined;
|
|
288
|
+
const fusoDoOwner = owner && typeof owner === 'object' && !Array.isArray(owner) ? owner.timezone : undefined;
|
|
289
|
+
// Owner invalido (so por edicao a mao: o `onboarding set` recusa) nao cala o fuso legado.
|
|
290
|
+
const fusoDaEntrevista = maestro && typeof maestro === 'object' && !Array.isArray(maestro)
|
|
291
|
+
? (0, horario_1.normalizarFuso)(fusoDoOwner) ?? (0, horario_1.normalizarFuso)(maestro.fuso) : undefined;
|
|
169
292
|
if (fusoDaEntrevista && fusoDaEntrevista !== carregado.manifesto.owner?.timezone) {
|
|
170
293
|
checks.push({ nome: 'onboarding fuso', nivel: 'warn',
|
|
171
294
|
detalhe: `entrevista informou ${fusoDaEntrevista}; manifesto declara ${carregado.manifesto.owner?.timezone ?? `${horario_1.CHAVE_DO_FUSO} ausente`}`,
|
|
@@ -173,8 +296,128 @@ function checarOnboarding(carregado) {
|
|
|
173
296
|
}
|
|
174
297
|
return checks;
|
|
175
298
|
}
|
|
176
|
-
/**
|
|
177
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Fatia 2 do ensaio da 0.5.0 (P1): por qual runtime cada bloco dos modos de
|
|
301
|
+
* `conduction.allowed_modes` despacha, pelo mesmo criterio do despacho sem opcao de CLI
|
|
302
|
+
* (`resolverDespacho`: o bloco do setup vence `runtime.adapter`). Quem passou os blocos para o
|
|
303
|
+
* Codex nao precisa do `claude`. Setup ilegivel devolve `null`: quem chama fica no lado seguro.
|
|
304
|
+
*/
|
|
305
|
+
function blocosDoRuntime(carregado, runtime) {
|
|
306
|
+
const { manifesto } = carregado;
|
|
307
|
+
const r = { principal: [], fallback: [] };
|
|
308
|
+
try {
|
|
309
|
+
const setup = (0, setup_1.lerSetup)(carregado.raiz);
|
|
310
|
+
for (const modo of manifesto.conduction.allowed_modes) {
|
|
311
|
+
modos_1.MODOS[modo].blocos.forEach((b, i) => {
|
|
312
|
+
const doBloco = (0, setup_1.configDoBloco)(setup, modo, b.fases[0]);
|
|
313
|
+
const bloco = { tag: modos_1.MODOS[modo].tag, bloco: i + 1 };
|
|
314
|
+
if ((doBloco?.runtime ?? manifesto.runtime.adapter) === runtime)
|
|
315
|
+
r.principal.push(bloco);
|
|
316
|
+
else if (doBloco?.fallback?.some((f) => f.split(':')[0] === runtime))
|
|
317
|
+
r.fallback.push(bloco);
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
return r;
|
|
325
|
+
}
|
|
326
|
+
/** `#Classic 1, 2; #Auto 1`: os blocos agrupados por modo, na ordem dos modos permitidos. */
|
|
327
|
+
function textoDosBlocos(blocos) {
|
|
328
|
+
const porModo = new Map();
|
|
329
|
+
for (const b of blocos)
|
|
330
|
+
porModo.set(b.tag, [...(porModo.get(b.tag) ?? []), b.bloco]);
|
|
331
|
+
return [...porModo].map(([tag, numeros]) => `${tag} ${numeros.join(', ')}`).join('; ');
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Ensaio de 03/10 (R1): com perfil ativo do runtime, quem confere o login e o check "contas por runtime";
|
|
335
|
+
* sem perfil (ou com o store ilegivel, que aquele check reprova), o despacho usa o login do `claude` do processo.
|
|
336
|
+
*/
|
|
337
|
+
function temPerfilAtivo(carregado, runtime) {
|
|
338
|
+
if (!carregado || carregado.erros.length)
|
|
339
|
+
return false;
|
|
340
|
+
try {
|
|
341
|
+
return (0, runtime_profiles_1.lerPerfisComContas)(carregado.raiz).perfis.some(p => p.runtime === runtime && p.estado !== 'desativado');
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Fatia 2 do ensaio da 0.5.0 (P1): o `claude` so e obrigatorio quando algum bloco de modo permitido
|
|
349
|
+
* despacha por ele. Sem manifesto, com manifesto invalido ou com setup ilegivel vale o padrao (todo
|
|
350
|
+
* bloco no claude-bg), e a falta reprova como antes.
|
|
351
|
+
*/
|
|
352
|
+
function checarRuntimeClaude(carregado, claude, versao, auth = null) {
|
|
353
|
+
const nome = 'runtime claude-bg';
|
|
354
|
+
if (claude) {
|
|
355
|
+
const detalhe = `${claude} (${versao ?? 'versao desconhecida'})`;
|
|
356
|
+
// Ensaio de 03/10 (R1): sem perfil de conta, o despacho usa o login do proprio `claude`; sem ele, o
|
|
357
|
+
// primeiro despacho falha. Conferencia inconclusiva (timeout, JSON ilegivel) nao prova falta de login.
|
|
358
|
+
if (auth && !auth.ok && !auth.transitorio) {
|
|
359
|
+
return { nome, nivel: 'warn', detalhe: `${detalhe}; ${auth.detalhe}: o despacho pelo claude-bg falharia`,
|
|
360
|
+
correcao: auth.pago
|
|
361
|
+
? 'faca o login de assinatura (claude.ai) no `claude`, sem API key nem provider de nuvem'
|
|
362
|
+
: 'rode `claude` uma vez, faca o login de assinatura (/login) e aceite a confianca no diretorio do projeto; ' +
|
|
363
|
+
'ou crie um perfil com ork accounts add <id> --runtime claude-bg --dir <pasta>' };
|
|
364
|
+
}
|
|
365
|
+
return { nome, nivel: 'ok', detalhe };
|
|
366
|
+
}
|
|
367
|
+
const blocos = carregado && carregado.erros.length === 0 ? blocosDoRuntime(carregado, 'claude-bg') : null;
|
|
368
|
+
if (blocos && blocos.principal.length === 0) {
|
|
369
|
+
// CHECK, rodada 1 (S6): as fases nao precisam dele, mas o `ork audit run` despacha sempre pelo claude-bg.
|
|
370
|
+
return { nome, nivel: 'warn',
|
|
371
|
+
detalhe: 'binario `claude` fora do PATH (opcional para as fases: nenhum bloco dos modos permitidos despacha pelo claude-bg' +
|
|
372
|
+
(blocos.fallback.length
|
|
373
|
+
? `; o fallback de ${blocos.fallback.length} bloco(s) cai nele e falharia: ${textoDosBlocos(blocos.fallback)}` : '') +
|
|
374
|
+
'; o ork audit run ainda despacha por ele)',
|
|
375
|
+
correcao: 'para despachar pelo claude-bg (e rodar ork audit run), instale o Claude Code e garanta `claude` no PATH' };
|
|
376
|
+
}
|
|
377
|
+
return { nome, nivel: 'fail',
|
|
378
|
+
detalhe: 'binario `claude` fora do PATH' + (blocos
|
|
379
|
+
? `; ${blocos.principal.length} bloco(s) dos modos permitidos despacham por ele (${textoDosBlocos(blocos.principal)})` : ''),
|
|
380
|
+
correcao: 'instale o Claude Code e garanta `claude` no PATH; so com o Codex, passe cada bloco para ele ' +
|
|
381
|
+
'(ork setup <modo> --bloco N --runtime codex --model <modelo>) ou tire o modo de conduction.allowed_modes ' +
|
|
382
|
+
'(mantenha o conduction.default_mode entre os permitidos)' };
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* O despacho pelo Codex quando o projeto o elege: por `runtime.adapter: codex`, como antes, ou, desde
|
|
386
|
+
* a fatia 2 do ensaio da 0.5.0 (P1), por bloco de modo permitido. A falta do `codex`, ou um sandbox
|
|
387
|
+
* que nao executa, deixa de ser aviso: e exatamente o que bloquearia a fase. Sem nenhum dos dois, o
|
|
388
|
+
* check nao sai.
|
|
389
|
+
*/
|
|
390
|
+
function checarDespachoPeloCodex(carregado, codex, sonda) {
|
|
391
|
+
const pelaAdapter = carregado.manifesto.runtime.adapter === 'codex';
|
|
392
|
+
const blocos = blocosDoRuntime(carregado, 'codex')?.principal ?? [];
|
|
393
|
+
if (!pelaAdapter && blocos.length === 0)
|
|
394
|
+
return null;
|
|
395
|
+
const origem = [pelaAdapter ? 'runtime.adapter: codex' : '',
|
|
396
|
+
blocos.length ? `${blocos.length} bloco(s) dos modos permitidos no codex (${textoDosBlocos(blocos)})` : '']
|
|
397
|
+
.filter(Boolean).join(' e ');
|
|
398
|
+
const sandboxConfigurado = carregado.manifesto.runtime.sandbox;
|
|
399
|
+
const sandboxQuebrado = sonda !== null && !sonda.ok && sandboxConfigurado !== 'danger-full-access';
|
|
400
|
+
return {
|
|
401
|
+
nome: 'despacho pelo codex',
|
|
402
|
+
nivel: !codex ? 'fail' : sandboxQuebrado ? 'fail' : 'ok',
|
|
403
|
+
detalhe: !codex
|
|
404
|
+
? `${origem}, mas o binario \`codex\` esta fora do PATH`
|
|
405
|
+
: sandboxQuebrado
|
|
406
|
+
? `${origem} com sandbox "${sandboxConfigurado}", mas o sandbox nao executa nesta maquina (o agente narraria sucesso sem rodar nada)`
|
|
407
|
+
: `${origem} com sandbox "${sandboxConfigurado}"`,
|
|
408
|
+
correcao: !codex
|
|
409
|
+
? 'instale o Codex CLI e autentique com `codex login` (assinatura, nunca API key)'
|
|
410
|
+
: sandboxQuebrado
|
|
411
|
+
? 'instale o bubblewrap do sistema, ou declare runtime.sandbox: danger-full-access ciente do risco'
|
|
412
|
+
: undefined,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Roda todos os checks a partir do diretorio informado. RM-031: `analisadores` e o check do grafo
|
|
417
|
+
* (`checarAnalisadoresDoGrafo` do CLI do grafo), que o `index.ts` passa: fora da familia do grafo so
|
|
418
|
+
* ele e o worker do MCP a abrem (fronteira do KG1), e o doctor nao a importa.
|
|
419
|
+
*/
|
|
420
|
+
function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)(), lerCrontab = doctor_pulse_cron_1.lerCrontabDoSistema, conferirAuthDoClaude = () => adapter.conferirAuth(null), analisadores) {
|
|
178
421
|
const checks = [];
|
|
179
422
|
const major = versaoNode();
|
|
180
423
|
checks.push({
|
|
@@ -183,6 +426,8 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
183
426
|
detalhe: `v${process.versions.node}`,
|
|
184
427
|
correcao: major >= 20 ? undefined : 'instale Node 20 ou superior',
|
|
185
428
|
});
|
|
429
|
+
if (analisadores)
|
|
430
|
+
checks.push(analisadores());
|
|
186
431
|
const git = (0, util_1.noPath)('git');
|
|
187
432
|
checks.push({
|
|
188
433
|
nome: 'git',
|
|
@@ -192,31 +437,43 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
192
437
|
});
|
|
193
438
|
const repo = (0, util_1.exec)('git', ['rev-parse', '--is-inside-work-tree'], dirInicial);
|
|
194
439
|
const dentroDeRepo = repo.ok && repo.stdout.trim() === 'true';
|
|
195
|
-
|
|
440
|
+
// Ensaio da 0.5.0: sem commit, o `rev-parse --abbrev-ref` respondia "HEAD"; a branch vem do
|
|
441
|
+
// `symbolic-ref`, e a falta de commit fica dita.
|
|
442
|
+
const semCommit = dentroDeRepo && !(0, util_1.exec)('git', ['rev-parse', '--verify', '--quiet', 'HEAD'], dirInicial).ok;
|
|
443
|
+
const branch = dentroDeRepo ? (0, util_1.branchDoHead)(dirInicial) ?? (0, util_1.exec)('git', ['rev-parse', '--abbrev-ref', 'HEAD'], dirInicial).stdout.trim() : '';
|
|
196
444
|
checks.push({
|
|
197
445
|
nome: 'repositorio',
|
|
198
446
|
nivel: dentroDeRepo ? 'ok' : 'fail',
|
|
199
|
-
detalhe: dentroDeRepo ? `branch ${branch
|
|
447
|
+
detalhe: dentroDeRepo ? `branch ${branch}${semCommit ? ' (sem commit)' : ''}` : 'fora de um repositorio git',
|
|
200
448
|
correcao: dentroDeRepo ? undefined : 'rode o ork dentro de um repositorio git',
|
|
201
449
|
});
|
|
450
|
+
if (dentroDeRepo) {
|
|
451
|
+
const dono = checarDonoDoGit(dirInicial);
|
|
452
|
+
if (dono)
|
|
453
|
+
checks.push(dono);
|
|
454
|
+
}
|
|
455
|
+
// Fatia 2 do ensaio da 0.5.0 (P1): o manifesto e lido antes dos runtimes, porque e o setup dos
|
|
456
|
+
// modos permitidos que diz se o `claude` e obrigatorio; a ordem das linhas do relatorio nao muda.
|
|
457
|
+
const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
|
|
202
458
|
const claude = adapter.disponivel();
|
|
203
459
|
const v = claude ? adapter.versao() : null;
|
|
204
|
-
checks.push(
|
|
205
|
-
nome: 'runtime claude-bg',
|
|
206
|
-
nivel: claude ? 'ok' : 'fail',
|
|
207
|
-
detalhe: claude ? `${claude} (${v ?? 'versao desconhecida'})` : 'binario `claude` fora do PATH',
|
|
208
|
-
correcao: claude ? undefined : 'instale o Claude Code e garanta `claude` no PATH',
|
|
209
|
-
});
|
|
460
|
+
checks.push(checarRuntimeClaude(carregado, claude, v, claude && !temPerfilAtivo(carregado, 'claude-bg') ? conferirAuthDoClaude() : null));
|
|
210
461
|
// Segundo runtime homologado. Ausente e `warn`, nao `fail`: o claude-bg segue sendo o
|
|
211
462
|
// padrao, e um projeto que nunca pediu codex nao pode ficar bloqueado por ele.
|
|
212
463
|
const codex = codexAdapter.disponivel();
|
|
213
464
|
const codexVersao = codex ? codexAdapter.versao() : null;
|
|
465
|
+
// CHECK, rodada 1 (S6): com o projeto despachando pelo codex, a falta dele nao e "opcional"; quem
|
|
466
|
+
// reprova e o check `despacho pelo codex`, mais abaixo.
|
|
467
|
+
const usaCodex = !!carregado && carregado.erros.length === 0 && (carregado.manifesto.runtime.adapter === 'codex' ||
|
|
468
|
+
(blocosDoRuntime(carregado, 'codex')?.principal.length ?? 0) > 0);
|
|
214
469
|
checks.push({
|
|
215
470
|
nome: 'runtime codex',
|
|
216
471
|
nivel: codex ? 'ok' : 'warn',
|
|
217
472
|
detalhe: codex
|
|
218
473
|
? `${codex} (${codexVersao ?? 'versao desconhecida'})`
|
|
219
|
-
:
|
|
474
|
+
: usaCodex
|
|
475
|
+
? 'binario `codex` fora do PATH (o projeto despacha por ele: veja despacho pelo codex)'
|
|
476
|
+
: 'binario `codex` fora do PATH (opcional: claude-bg e o runtime padrao)',
|
|
220
477
|
correcao: codex
|
|
221
478
|
? undefined
|
|
222
479
|
: 'para despachar pelo codex, instale o Codex CLI e autentique com `codex login`',
|
|
@@ -238,13 +495,13 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
238
495
|
'nesta maquina) ou declare runtime.sandbox: danger-full-access ciente do risco',
|
|
239
496
|
});
|
|
240
497
|
}
|
|
241
|
-
const carregado = (0, manifest_1.carregarManifesto)(dirInicial);
|
|
242
498
|
if (!carregado) {
|
|
243
499
|
checks.push({
|
|
244
500
|
nome: 'manifesto',
|
|
245
501
|
nivel: 'fail',
|
|
246
502
|
detalhe: `${manifest_1.NOME_MANIFESTO} nao encontrado a partir de ${dirInicial}`,
|
|
247
|
-
|
|
503
|
+
// Ensaio de 03/10/2026 (RM-049): fora de repositorio, o `ork init` recusa; a correcao diz onde roda-lo.
|
|
504
|
+
correcao: dentroDeRepo ? 'ork init' : 'entre no repositorio do projeto (ou crie um com git init e o primeiro commit) e rode ork init',
|
|
248
505
|
});
|
|
249
506
|
}
|
|
250
507
|
else {
|
|
@@ -257,6 +514,11 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
257
514
|
(carregado.avisos.length > 0 ? `; ${carregado.avisos.join('; ')}` : ''),
|
|
258
515
|
correcao: carregado.erros.length > 0 ? 'corrija o manifesto e rode ork doctor de novo' : undefined,
|
|
259
516
|
});
|
|
517
|
+
if (dentroDeRepo) {
|
|
518
|
+
const fora = manifestoForaDoRepositorio(dirInicial, carregado.caminho);
|
|
519
|
+
if (fora)
|
|
520
|
+
checks.push(fora);
|
|
521
|
+
}
|
|
260
522
|
checks.push(...checarOnboarding(carregado));
|
|
261
523
|
const abbrev = carregado.manifesto.project.abbrev;
|
|
262
524
|
const checkAbbrev = (0, slug_1.validarAbbrev)(abbrev);
|
|
@@ -285,26 +547,11 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
285
547
|
: `${fuso.fuso} (fuso do sistema; ${horario_1.CHAVE_DO_FUSO} nao configurado)`),
|
|
286
548
|
correcao: fuso.aviso ? `corrija ${horario_1.CHAVE_DO_FUSO} com um nome IANA` : undefined,
|
|
287
549
|
});
|
|
288
|
-
// Quando o manifesto
|
|
550
|
+
// Quando o manifesto ou um bloco de modo permitido ELEGE o codex, a ausencia dele (ou um
|
|
289
551
|
// sandbox que nao executa) deixa de ser aviso: e exatamente o que bloquearia a fase.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
checks.push({
|
|
294
|
-
nome: 'despacho pelo codex',
|
|
295
|
-
nivel: !codex ? 'fail' : sandboxQuebrado ? 'fail' : 'ok',
|
|
296
|
-
detalhe: !codex
|
|
297
|
-
? 'runtime.adapter: codex, mas o binario `codex` esta fora do PATH'
|
|
298
|
-
: sandboxQuebrado
|
|
299
|
-
? `runtime.adapter: codex com sandbox "${sandboxConfigurado}", mas o sandbox nao executa nesta maquina (o agente narraria sucesso sem rodar nada)`
|
|
300
|
-
: `runtime.adapter: codex com sandbox "${sandboxConfigurado}"`,
|
|
301
|
-
correcao: !codex
|
|
302
|
-
? 'instale o Codex CLI e autentique com `codex login` (assinatura, nunca API key)'
|
|
303
|
-
: sandboxQuebrado
|
|
304
|
-
? 'instale o bubblewrap do sistema, ou declare runtime.sandbox: danger-full-access ciente do risco'
|
|
305
|
-
: undefined,
|
|
306
|
-
});
|
|
307
|
-
}
|
|
552
|
+
const despachoPeloCodex = checarDespachoPeloCodex(carregado, codex, sondaDoCodex);
|
|
553
|
+
if (despachoPeloCodex)
|
|
554
|
+
checks.push(despachoPeloCodex);
|
|
308
555
|
const politica = carregado.manifesto.runtime.provider_policy;
|
|
309
556
|
const soAssinatura = politica === 'subscription-only';
|
|
310
557
|
const redirecionam = ENVS_QUE_REDIRECIONAM.filter(e => nomesHerdados.includes(e));
|
|
@@ -380,22 +627,32 @@ function checar(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente
|
|
|
380
627
|
: `${dirEstadoProjeto} ausente`,
|
|
381
628
|
correcao: fs.existsSync(dirEstadoProjeto) ? undefined : 'ork init cria o diretorio de estado',
|
|
382
629
|
});
|
|
630
|
+
// RM-039 (B6): com o transporte do pulse configurado, a varredura tem de bater de 15 em 15
|
|
631
|
+
// minutos; a instalacao antiga em `0 * * * *` vira aviso com a linha nova. Nunca edita o crontab.
|
|
632
|
+
const cronDoPulse = (0, doctor_pulse_cron_1.checarCronDoPulse)(path.join(dirEstadoProjeto, 'monitor'), (0, estado_thread_1.raizDoEstado)(carregado.raiz), lerCrontab);
|
|
633
|
+
if (cronDoPulse)
|
|
634
|
+
checks.push(cronDoPulse);
|
|
383
635
|
checks.push(checarContas(carregado.raiz));
|
|
384
636
|
// I-33 (D7): umask e permissoes do estado, na mesma regra do sensor (sem bits 0o022).
|
|
385
637
|
checks.push(...(0, preflight_1.sondasDeAmbiente)(carregado.raiz));
|
|
386
638
|
{
|
|
387
639
|
const inventario = (0, sessoes_inventario_1.inventariarSessoes)(carregado.raiz, { global: true, todas: true });
|
|
640
|
+
// Fatia 2 do ensaio da 0.5.0 (P1): binario ausente e fonte ausente, dita no detalhe.
|
|
641
|
+
const ausentes = inventario.fontes.filter((f) => f.ausente).map((f) => f.origem);
|
|
388
642
|
checks.push({
|
|
389
643
|
nome: 'governanca de sessoes',
|
|
390
644
|
nivel: inventario.ok && inventario.semThread === 0 ? 'ok' : 'warn',
|
|
391
645
|
detalhe: `${inventario.escopo.usuario}, Claude e Codex, global com histórico: ${inventario.total} sessões; ` +
|
|
392
646
|
`${inventario.semThread} sem thread; ${inventario.ambiguas} ambíguas; ` +
|
|
393
|
-
`inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}
|
|
647
|
+
`inventário ${inventario.ok ? 'válido' : 'INCOMPLETO (zero não comprovado)'}` +
|
|
648
|
+
(ausentes.length ? `; fonte ausente: ${ausentes.join(', ')}` : ''),
|
|
394
649
|
correcao: inventario.ok && inventario.semThread === 0 ? undefined :
|
|
395
650
|
'ork sessions --global --all --json; adote identidades sem vínculo com ork sessions adopt <id>',
|
|
396
651
|
});
|
|
397
652
|
}
|
|
398
653
|
}
|
|
654
|
+
// RM-053 (fatia 2): a rede da pessoa e da maquina, nao do projeto; vale de qualquer diretorio.
|
|
655
|
+
checks.push((0, doctor_rede_1.checarRede)());
|
|
399
656
|
return checks;
|
|
400
657
|
}
|
|
401
658
|
/** Texto do relatorio, com o resumo "o que vale nesta maquina agora". */
|
|
@@ -431,8 +688,8 @@ function relatorio(checks) {
|
|
|
431
688
|
return linhas.join('\n');
|
|
432
689
|
}
|
|
433
690
|
/** Executa o doctor e devolve o codigo de saida (0 = pronto). */
|
|
434
|
-
function doctor(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)()) {
|
|
435
|
-
const checks = checar(dirInicial, nomesHerdados);
|
|
691
|
+
function doctor(dirInicial = process.cwd(), nomesHerdados = (0, runtime_ambiente_1.nomesDeProviderAtivos)(), analisadores) {
|
|
692
|
+
const checks = checar(dirInicial, nomesHerdados, undefined, undefined, analisadores);
|
|
436
693
|
const falhas = checks.filter((c) => c.nivel === 'fail').length;
|
|
437
694
|
return { texto: relatorio(checks), codigo: falhas > 0 ? 1 : 0 };
|
|
438
695
|
}
|