auroq-os 2.3.1 → 2.3.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/bin/auroq-os.js +101 -0
- package/package.json +1 -1
- package/scripts/sync-codex-skills.mjs +9 -1
package/bin/auroq-os.js
CHANGED
|
@@ -183,6 +183,101 @@ async function runHealthChecks(targetDir) {
|
|
|
183
183
|
return { passed, total: HEALTH_CHECKS.length };
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/**
|
|
187
|
+
* `doctor` — o diagnostico que o suporte pede primeiro. Existe por causa do NFR-06:
|
|
188
|
+
* a falha do MCP e silenciosa (conteudo simplesmente nao aparece), entao alguem
|
|
189
|
+
* precisa perguntar em voz alta se o caminho inteiro esta de pe.
|
|
190
|
+
*/
|
|
191
|
+
async function runDoctor(targetDir) {
|
|
192
|
+
showBanner();
|
|
193
|
+
log(`${BOLD}Diagnostico do Auroq${RESET}`);
|
|
194
|
+
log('');
|
|
195
|
+
|
|
196
|
+
const problemas = [];
|
|
197
|
+
|
|
198
|
+
// 1. arquivos de autoload
|
|
199
|
+
let faltando = 0;
|
|
200
|
+
for (const [file] of HEALTH_CHECKS) {
|
|
201
|
+
if (!(await fs.pathExists(path.join(targetDir, file)))) faltando++;
|
|
202
|
+
}
|
|
203
|
+
if (faltando === 0) {
|
|
204
|
+
success(`Arquivos do sistema: ${HEALTH_CHECKS.length}/${HEALTH_CHECKS.length} no lugar`);
|
|
205
|
+
} else {
|
|
206
|
+
error(`Arquivos do sistema: faltam ${faltando}`);
|
|
207
|
+
problemas.push('Rode *update-auroq dentro do Claude Code pra repor o que falta.');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 2. Node visivel pra quem abre pelo icone (NFR-06 — o caso real de falha)
|
|
211
|
+
try {
|
|
212
|
+
const v = execSync('npx --version', { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
213
|
+
success(`Node/npx no caminho: npx ${v}`);
|
|
214
|
+
} catch {
|
|
215
|
+
error('Node/npx nao encontrado no caminho deste programa');
|
|
216
|
+
problemas.push('O app do Claude aberto pelo icone nao enxerga o Node. Abra o Ops e peca o *bootstrap, ou abra o Claude pelo Terminal.');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 3. registro do MCP nos dois runtimes
|
|
220
|
+
const mcpPath = path.join(targetDir, '.mcp.json');
|
|
221
|
+
let pin = null;
|
|
222
|
+
if (await fs.pathExists(mcpPath)) {
|
|
223
|
+
try {
|
|
224
|
+
const json = await fs.readJSON(mcpPath);
|
|
225
|
+
pin = json?.mcpServers?.arcane?.args?.find(a => String(a).startsWith('arcane-mcp@')) || null;
|
|
226
|
+
} catch { /* arquivo corrompido cai no erro abaixo */ }
|
|
227
|
+
}
|
|
228
|
+
if (pin) {
|
|
229
|
+
success(`MCP arcane registrado no Claude Code (${pin})`);
|
|
230
|
+
} else {
|
|
231
|
+
error('MCP arcane nao registrado em .mcp.json');
|
|
232
|
+
problemas.push('Rode *update-auroq — ele reescreve o registro do MCP.');
|
|
233
|
+
}
|
|
234
|
+
const tomlPath = path.join(targetDir, '.codex', 'config.toml');
|
|
235
|
+
const temToml = (await fs.pathExists(tomlPath)) &&
|
|
236
|
+
(await fs.readFile(tomlPath, 'utf8')).includes('[mcp_servers.arcane]');
|
|
237
|
+
if (temToml) success('MCP arcane registrado no Codex');
|
|
238
|
+
else log(` ${DIM}MCP arcane ainda nao registrado no Codex (so importa se voce usa o Codex)${RESET}`);
|
|
239
|
+
|
|
240
|
+
// 4. login e licenca — o unico jeito de saber se o conteudo vai chegar
|
|
241
|
+
const credPath = path.join(require('os').homedir(), '.arcane', 'credentials.json');
|
|
242
|
+
let cred = null;
|
|
243
|
+
try {
|
|
244
|
+
if (await fs.pathExists(credPath)) cred = await fs.readJSON(credPath);
|
|
245
|
+
} catch { /* arquivo ilegivel = tratado como sem login */ }
|
|
246
|
+
if (cred?.user?.email) {
|
|
247
|
+
success(`Logado como ${cred.user.email}`);
|
|
248
|
+
} else {
|
|
249
|
+
error('Voce nao esta logado');
|
|
250
|
+
problemas.push('Rode: npx arcane-mcp login (mesmo email e senha da plataforma).');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 5. o servidor do conteudo responde?
|
|
254
|
+
try {
|
|
255
|
+
const r = await fetch('https://arcane.arka.education/api/mcp/verify', { method: 'POST' });
|
|
256
|
+
if (r.status === 401) {
|
|
257
|
+
success('Servidor do conteudo respondendo (pediu login, como esperado)');
|
|
258
|
+
} else if (r.ok) {
|
|
259
|
+
success('Servidor do conteudo respondendo');
|
|
260
|
+
} else {
|
|
261
|
+
error(`Servidor do conteudo respondeu ${r.status}`);
|
|
262
|
+
problemas.push('O conteudo ao vivo pode estar fora do ar. Seus arquivos locais continuam funcionando.');
|
|
263
|
+
}
|
|
264
|
+
} catch {
|
|
265
|
+
error('Sem resposta do servidor do conteudo');
|
|
266
|
+
problemas.push('Confira sua internet. Sem servidor, o conteudo ao vivo nao chega — o resto do Auroq continua.');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
log('');
|
|
270
|
+
if (problemas.length === 0) {
|
|
271
|
+
success('Tudo certo. Pode chamar o Companion.');
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
error(`${problemas.length} coisa(s) pra resolver:`);
|
|
275
|
+
for (const p of problemas) log(` ${DIM}- ${p}${RESET}`);
|
|
276
|
+
log('');
|
|
277
|
+
log(`${DIM}Se travar, chame o suporte: 11 97312-2273${RESET}`);
|
|
278
|
+
return 1;
|
|
279
|
+
}
|
|
280
|
+
|
|
186
281
|
async function writeArcaneMcpConfig(targetDir) {
|
|
187
282
|
const pin = 'arcane-mcp@0.2.0';
|
|
188
283
|
const mcpPath = path.join(targetDir, '.mcp.json');
|
|
@@ -927,6 +1022,11 @@ if (command === 'init' || command === 'install') {
|
|
|
927
1022
|
error(`Falha ao conectar 1Password: ${e.message}`);
|
|
928
1023
|
process.exit(1);
|
|
929
1024
|
});
|
|
1025
|
+
} else if (command === 'doctor' || command === 'diagnostico') {
|
|
1026
|
+
runDoctor(process.cwd()).then(code => process.exit(code)).catch(e => {
|
|
1027
|
+
error(`Falha no diagnostico: ${e.message}`);
|
|
1028
|
+
process.exit(1);
|
|
1029
|
+
});
|
|
930
1030
|
} else if (command === 'sync-codex') {
|
|
931
1031
|
// Regenera as skills do Codex CLI a partir dos comandos atuais do projeto.
|
|
932
1032
|
try {
|
|
@@ -948,6 +1048,7 @@ if (command === 'init' || command === 'install') {
|
|
|
948
1048
|
log(` ${CYAN}whoami${RESET} Mostrar usuario autenticado`);
|
|
949
1049
|
log(` ${CYAN}check-access${RESET} Validar acesso ativo (online; exit 0=ativo, 1=bloqueado)`);
|
|
950
1050
|
log(` ${CYAN}update${RESET} Atualizar (via Ops dentro do Claude Code)`);
|
|
1051
|
+
log(` ${CYAN}doctor${RESET} Diagnostico: arquivos, Node, MCP arcane, login e servidor`);
|
|
951
1052
|
log(` ${CYAN}sync-codex${RESET} Gerar e verificar as skills locais do Codex CLI ($nome)`);
|
|
952
1053
|
log(` ${CYAN}conectar-1password${RESET} Conectar o 1Password CLI (token lido do Ctrl+C, nunca digitado)`);
|
|
953
1054
|
log('');
|
package/package.json
CHANGED
|
@@ -88,6 +88,12 @@ function collectSkills() {
|
|
|
88
88
|
|
|
89
89
|
function skillContent(name, commandFile, outRoot) {
|
|
90
90
|
const commandRef = sourceRef(commandFile, outRoot);
|
|
91
|
+
// Casca de MCP: mandar o Codex "resolver em agents/" faz ele varrer pasta vazia
|
|
92
|
+
// e improvisar. Quando o comando ja aponta pro MCP, a skill tem que dizer o mesmo.
|
|
93
|
+
let viaMcp = false;
|
|
94
|
+
try {
|
|
95
|
+
viaMcp = /MCP `arcane`/.test(fs.readFileSync(commandFile, 'utf8'));
|
|
96
|
+
} catch { /* comando ilegivel = trata como local */ }
|
|
91
97
|
const agentsRef = sourceRef(path.join(root, 'agents'), outRoot);
|
|
92
98
|
const agentsMdRef = sourceRef(path.join(root, 'AGENTS.md'), outRoot);
|
|
93
99
|
const description = `Ativa o agente Auroq '${name}' no Codex CLI. Use quando o usuario digitar $${name}, /${name}, /auroq-${name}, @${name}, pedir o agente '${name}', ou solicitar seu fluxo de trabalho. Fonte de verdade: ${commandRef}.`;
|
|
@@ -105,7 +111,9 @@ ${summaryFromMarkdown(commandFile)}
|
|
|
105
111
|
|
|
106
112
|
- Leia \`${commandRef}\` por completo.
|
|
107
113
|
- Siga as instrucoes CRITICAL exatamente como escritas, incluindo persona, task, dependencias e exit behavior.
|
|
108
|
-
|
|
114
|
+
${viaMcp
|
|
115
|
+
? '- O conteudo deste agente vem pelo MCP `arcane`. Nao procurar em `' + agentsRef + '` — la nao ha nada deste agente.'
|
|
116
|
+
: '- Resolva referencias relativas a partir de `' + root.replaceAll('\\', '/') + '`; agentes e squads ficam em `' + agentsRef + '`.'}
|
|
109
117
|
- Carregue KBs, tasks e assets apenas quando o comando ou pedido exigir.
|
|
110
118
|
- Mantenha a persona ativa ate \`*exit\` ou troca explicita.
|
|
111
119
|
|