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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auroq-os",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
4
4
  "description": "Auroq OS — Sistema Operacional de IA para Experts",
5
5
  "bin": {
6
6
  "auroq-os": "bin/auroq-os.js"
@@ -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
- - Resolva referencias relativas a partir de \`${root.replaceAll('\\', '/')}\`; agentes e squads ficam em \`${agentsRef}\`.
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