auroq-os 2.8.2 → 2.8.5

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
@@ -236,7 +236,7 @@ function mudouAlgoDeAbertura(antes, depois) {
236
236
  // permissions (modo sem pedir permissao), statusLine, env e hooks proprios. Agora: o que o modelo
237
237
  // controla vem do modelo; permissions/statusLine/env do aluno ficam; chave que o modelo nao tem
238
238
  // fica; hooks do aluno ficam e os do framework sao trocados pelos do modelo, sem duplicar.
239
- const HOOK_DO_FRAMEWORK = /(?:^|[\s"'\\/])(?:auroq-sync|synapse-engine|ahi-capture|precompact-session-digest)\.cjs\b/;
239
+ const HOOK_DO_FRAMEWORK = /(?:^|[\s"'\\/])(?:auroq-sync|auroq-ate-o-fim|synapse-engine|ahi-capture|precompact-session-digest)\.cjs\b/;
240
240
  // Gancho de IA do sistema (type "prompt", sem `command`): o texto comeca com uma marca `[auroq-...]`.
241
241
  // Sem ela, a manutencao o tomava por gancho do aluno e o duplicava a cada versao.
242
242
  const MARCA_DO_FRAMEWORK = /^\s*\[auroq-[a-z-]+\]/;
@@ -405,7 +405,7 @@ async function applySecretProtections(targetDir) {
405
405
  try { hasRemote = execFileSync('git', ['remote'], { cwd: targetDir, encoding: 'utf8' }).trim().length > 0; } catch { /* sem git */ }
406
406
  if (hasRemote) {
407
407
  warn(`${GOLD}IMPORTANTE: esses arquivos podem ja ter subido pro GitHub em commits antigos.${RESET}`);
408
- warn(`${GOLD}Troque as chaves que estavam neles — peca ajuda ao Ops: "minhas chaves do vault${RESET}`);
408
+ warn(`${GOLD}Troque as chaves que estavam neles — peca ajuda ao Companion: "minhas chaves do vault${RESET}`);
409
409
  warn(`${GOLD}podem ter vazado no git, me ajuda a trocar e limpar".${RESET}`);
410
410
  }
411
411
  }
@@ -565,7 +565,7 @@ async function runHealthChecks(targetDir) {
565
565
  if (await synapseDesatualizado(targetDir)) {
566
566
  // Aviso, nao trava: um clone de negocio antigo traz o arquivo velho pelo git e so a
567
567
  // manutencao nesta maquina (ou na outra, depois entregue) troca.
568
- warn('Synapse antigo nesta pasta (erro "hookEventName" a cada mensagem). Peca ao Ops: "atualiza o sistema".');
568
+ warn('Synapse antigo nesta pasta (erro "hookEventName" a cada mensagem). Peca ao Companion: "atualiza o sistema".');
569
569
  }
570
570
  if (passed === HEALTH_CHECKS.length) {
571
571
  success(`${passed}/${HEALTH_CHECKS.length} verificacoes OK`);
@@ -603,7 +603,7 @@ async function runDoctor(targetDir, { leve = false } = {}) {
603
603
  success(`Arquivos do sistema: ${HEALTH_CHECKS.length}/${HEALTH_CHECKS.length} no lugar`);
604
604
  } else {
605
605
  error(`Arquivos do sistema: faltam ${faltando}`);
606
- problemas.push('Peca ao Ops, no Claude Code ou no Codex: "atualiza o sistema" (a manutencao vai repor o que falta).');
606
+ problemas.push('Peca ao Companion, no Claude Code ou no Codex: "atualiza o sistema" (a manutencao vai repor o que falta).');
607
607
  }
608
608
  if (!(await synapseRegistrado(targetDir))) {
609
609
  error('O hook do Synapse nao esta registrado: as regras do sistema nao chegam ao modelo');
@@ -611,7 +611,7 @@ async function runDoctor(targetDir, { leve = false } = {}) {
611
611
  }
612
612
  if (await synapseDesatualizado(targetDir)) {
613
613
  error('Synapse antigo: o Claude Code recusa as regras a cada mensagem ("hookEventName")');
614
- problemas.push('Peca ao Ops, no Claude Code ou no Codex: "atualiza o sistema" (a manutencao troca o Synapse antigo). Reserva, so se o Ops nao abrir: npx -y auroq-os@latest manutencao na pasta.');
614
+ problemas.push('Peca ao Companion, no Claude Code ou no Codex: "atualiza o sistema" (a manutencao troca o Synapse antigo). Reserva, so se o Companion nao abrir: npx -y auroq-os@latest manutencao na pasta.');
615
615
  }
616
616
 
617
617
  // 2. O motor — e, principalmente, se quem abre pelo icone vai enxergar ele.
@@ -1694,7 +1694,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1694
1694
  log('');
1695
1695
  log(`${BOLD}Entao o caminho certo NAO e instalar do zero — e clonar o que ja existe.${RESET}`);
1696
1696
  log('');
1697
- log('O seu negocio ja vive no GitHub (o Ops fez isso no Bootstrap 1).');
1697
+ log('O seu negocio ja vive no GitHub.');
1698
1698
  log('Instalar do zero aqui criaria um segundo Auroq desconectado do primeiro.');
1699
1699
  log('');
1700
1700
  log(`Rode: ${CYAN}npx auroq-os clone${RESET}`);
@@ -1846,6 +1846,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1846
1846
  '.claude/hooks/ahi/auth-config.cjs',
1847
1847
  '.claude/hooks/precompact-session-digest.cjs',
1848
1848
  '.claude/hooks/auroq-sync.cjs',
1849
+ '.claude/hooks/auroq-ate-o-fim.cjs', // 2.8.4 — freio de comando no lugar do gancho de IA
1849
1850
 
1850
1851
  // Synapse domain files
1851
1852
  '.synapse/manifest',
@@ -2118,7 +2119,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2118
2119
  try {
2119
2120
  execSync('node scripts/sync-codex-skills.mjs --clean', { cwd: targetDir, stdio: 'pipe' });
2120
2121
  execSync('node scripts/sync-codex-skills.mjs --check', { cwd: targetDir, stdio: 'pipe' });
2121
- success('Codex CLI pronto — skills locais verificadas ($companion, $ops, etc.)');
2122
+ success('Codex CLI pronto — skills locais verificadas ($companion, $consultor, etc.)');
2122
2123
  } catch (e) {
2123
2124
  warn('Sync de skills do Codex falhou — rode "npx auroq-os sync-codex" para diagnosticar');
2124
2125
  // Sem o motivo, o suporte so via o efeito ("Codex Companion faltando") e nunca a causa.
@@ -2219,8 +2220,7 @@ ${DIM} Suas customizacoes (sobrevivem a todo update):${RESET}
2219
2220
  ${CYAN}.claude/settings.local.json${RESET} ${DIM}— suas configuracoes locais${RESET}
2220
2221
 
2221
2222
  ${DIM} Agentes core disponiveis:${RESET}
2222
- ${PURPLE}/auroq-companion${RESET} ${DIM}— Chefe da sua equipe: fale com ele, ele aciona o resto${RESET}
2223
- ${PURPLE}/AuroqOS:agents:ops${RESET} ${DIM}— O tecnico: instala, atualiza, conserta e conecta${RESET}
2223
+ ${PURPLE}/auroq-companion${RESET} ${DIM}— Chefe da sua equipe: fale com ele, ele aciona o resto e cuida do tecnico${RESET}
2224
2224
  ${PURPLE}/auroq-organizer${RESET} ${DIM}— Organizacao e backup${RESET}
2225
2225
 
2226
2226
  ${DIM} Meta Squads (criadores de agentes; o Companion chama quando precisa):${RESET}
@@ -2391,7 +2391,7 @@ ${DIM} Uma vez so, nesta maquina:${RESET}
2391
2391
 
2392
2392
  ${CYAN}cd ${destName}${RESET}
2393
2393
  ${CYAN}claude${RESET} ${DIM}ou${RESET} ${CYAN}codex${RESET}
2394
- ${CYAN}/AuroqOS:agents:ops${RESET}
2394
+ ${CYAN}/auroq-companion${RESET}
2395
2395
  ${CYAN}*conectar-cofre${RESET} ${DIM}— reconectar o cofre de senhas (1Password ou Infisical gratis; ele pergunta qual)${RESET}
2396
2396
  ${DIM}(dono do negocio: se o sistema pedir login em algum momento, ${RESET}${CYAN}npx auroq-os login${RESET}${DIM})${RESET}
2397
2397
 
@@ -2417,7 +2417,7 @@ const command = process.argv[2];
2417
2417
  if (['init', 'install', 'update'].includes(command)) {
2418
2418
  error('Comando aposentado. Nada foi instalado ou alterado.');
2419
2419
  error('Primeira instalacao: https://arcane.arka.education/auroq');
2420
- error('No negocio existente, peca ao Ops, no Claude Code ou no Codex: "atualiza o sistema". Conteudo chega pelo MCP.');
2420
+ error('No negocio existente, peca ao Companion, no Claude Code ou no Codex: "atualiza o sistema". Conteudo chega pelo MCP.');
2421
2421
  error(`Diagnostico: npx -y auroq-os@${PKG_VERSION} doctor. Reserva no terminal: npx -y auroq-os@${PKG_VERSION} manutencao.`);
2422
2422
  process.exitCode = 1;
2423
2423
  } else if (command === 'instalar' || command === 'manutencao') {
@@ -2552,7 +2552,7 @@ if (['init', 'install', 'update'].includes(command)) {
2552
2552
  try {
2553
2553
  execSync('node scripts/sync-codex-skills.mjs --clean', { cwd: process.cwd(), stdio: 'inherit' });
2554
2554
  execSync('node scripts/sync-codex-skills.mjs --check', { cwd: process.cwd(), stdio: 'inherit' });
2555
- success('Skills locais do Codex atualizadas e verificadas. Use $companion, $ops, $consultor, ...');
2555
+ success('Skills locais do Codex atualizadas e verificadas. Use $companion, $consultor, ...');
2556
2556
  } catch (err) {
2557
2557
  error(`Falha ao sincronizar skills do Codex: ${err.message}`);
2558
2558
  process.exit(1);
@@ -2567,13 +2567,13 @@ if (['init', 'install', 'update'].includes(command)) {
2567
2567
  log(` ${CYAN}logout${RESET} Encerrar sessao local`);
2568
2568
  log(` ${CYAN}whoami${RESET} Mostrar usuario autenticado`);
2569
2569
  log(` ${CYAN}check-access${RESET} Validar acesso ativo (online; exit 0=ativo, 1=bloqueado)`);
2570
- log(` ${CYAN}manutencao${RESET} Atualizar o motor e a conexao MCP (caminho normal: peca ao Ops "atualiza o sistema")`);
2570
+ log(` ${CYAN}manutencao${RESET} Atualizar o motor e a conexao MCP (caminho normal: peca ao Companion "atualiza o sistema")`);
2571
2571
  log(` ${CYAN}doctor${RESET} Diagnostico: arquivos, Node, MCP arcane, login e servidor`);
2572
2572
  log(` ${CYAN}register-mcp${RESET} Reescrever o registro do conteudo ao vivo (MCP arcane) no projeto`);
2573
2573
  log(` ${CYAN}sync-codex${RESET} Gerar e verificar as skills locais do Codex CLI ($nome)`);
2574
2574
  log(` ${CYAN}historico${RESET} Estado da captura do trabalho (prevista nos Termos de Uso; desliga em Minha Conta)`);
2575
2575
  log(` ${CYAN}conectar-cofre${RESET} Escolher e conectar o cofre de senhas: 1Password (pago, recomendado) ou Infisical (gratis)`);
2576
- log(` ${CYAN}conectar-1password${RESET} Conectar o 1Password (cria o cofre e a chave sozinho; voce so aprova uma vez no app)`);
2576
+ log(` ${CYAN}conectar-1password${RESET} Conectar o 1Password (cria o cofre e a chave sozinho; voce so aprova uma vez no app; --instalar-app instala o app)`);
2577
2577
  log(` ${CYAN}segredo${RESET} Ler, gravar, listar ou apagar uma credencial no cofre do aluno (vale para 1Password e Infisical)`);
2578
2578
  log('');
2579
2579
  log(`${DIM}Primeira instalacao: https://arcane.arka.education/auroq${RESET}`);
@@ -589,7 +589,7 @@ function Invoke-AuroqLogin {
589
589
  # sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
590
590
  # pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
591
591
  # a criacao da pasta.
592
- & (Get-AuroqNpx) -y auroq-os@2.8.2 check-access
592
+ & (Get-AuroqNpx) -y auroq-os@2.8.5 check-access
593
593
  if ($LASTEXITCODE -ne 0) {
594
594
  Write-AuroqLog 'login' 'recusado'
595
595
  Write-Host ''
@@ -677,7 +677,7 @@ function Invoke-AuroqInit {
677
677
  if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Sistema - seria montado aqui'; return }
678
678
 
679
679
  Set-Location $script:AuroqPastaAlvo
680
- & (Get-AuroqNpx) -y auroq-os@2.8.2 instalar
680
+ & (Get-AuroqNpx) -y auroq-os@2.8.5 instalar
681
681
  if ($LASTEXITCODE -ne 0) {
682
682
  Write-AuroqLog 'init' 'falhou'
683
683
  Write-AuroqErro 'A montagem do sistema parou no meio.' 'Rode o mesmo comando de novo. Se repetir, mande pro suporte o arquivo install.log da pasta .auroq.'
@@ -219,9 +219,9 @@ auroq_tem_terminal() {
219
219
  # recebem pedaco do script no lugar da resposta dele.
220
220
  auroq_npx_aluno() {
221
221
  if [ -t 0 ]; then
222
- npx -y auroq-os@2.8.2 "$@"
222
+ npx -y auroq-os@2.8.5 "$@"
223
223
  else
224
- npx -y auroq-os@2.8.2 "$@" < /dev/tty
224
+ npx -y auroq-os@2.8.5 "$@" < /dev/tty
225
225
  fi
226
226
  }
227
227
 
package/lib/cofre.js CHANGED
@@ -50,9 +50,11 @@ const ESCOLHA_MSG = 'Quer o 1Password (uns 3 dolares por mes, confira o preco na
50
50
 
51
51
  // Codigos do comando `segredo` (stderr: AUROQ_ERRO codigo=<c> mensagem="...").
52
52
  // `uso` = uso errado da linha de comando (ref faltando, valor em argumento, opcao desconhecida).
53
+ // `op-nao-achado` = Windows: o programa `op` do 1Password nao foi achado nesta janela nem depois de recompor o PATH.
54
+ // Sai 1 (erro geral, como `credencial-indisponivel`), NAO 4: com 4 o agente roda a rota A de novo e cai no laco.
53
55
  const SEGREDO_CODIGOS = ['nome-invalido', 'cofre-nao-configurado', 'nao-encontrado', 'sem-valor', 'ja-existe-confirmar',
54
- 'credencial-invalida', 'credencial-indisponivel', 'sem-permissao', 'rede', 'limite', 'bloqueada', 'falha', 'uso'];
55
- // Saida: 0 ok, 1 erro geral, 2 uso errado, 3 nao encontrado, 4 cofre nao configurado.
56
+ 'credencial-invalida', 'credencial-indisponivel', 'op-nao-achado', 'sem-permissao', 'rede', 'limite', 'bloqueada', 'falha', 'uso'];
57
+ // Saida: 0 ok, 1 erro geral (inclui op-nao-achado), 2 uso errado, 3 nao encontrado, 4 cofre nao configurado.
56
58
  const SEGREDO_EXIT = Object.freeze({ ok: 0, erro: 1, uso: 2, 'nao-encontrado': 3, 'cofre-nao-configurado': 4 });
57
59
  const CODIGOS_DE_USO = new Set(['uso', 'nome-invalido', 'sem-valor', 'ja-existe-confirmar']);
58
60
 
@@ -81,6 +83,11 @@ function envOf(d) {
81
83
  return (d && d.env) || process.env;
82
84
  }
83
85
 
86
+ /** Windows? (`d.platform` troca nos testes.) */
87
+ function ehWindows(d) {
88
+ return ((d && d.platform) || process.platform) === 'win32';
89
+ }
90
+
84
91
  function nowOf(d) {
85
92
  return d && typeof d.now === 'function' ? d.now() : Date.now();
86
93
  }
@@ -387,6 +394,10 @@ function opReference(ref) {
387
394
 
388
395
  // ─── Mensagens por codigo ────────────────────────────────
389
396
 
397
+ // Windows, `op` fora do PATH desta janela: primeiro fechar e abrir o programa (o PATH novo so chega a processos novos);
398
+ // a rota A so se isso nao resolver (rodar a rota A de novo logo de cara e o laco que o teste real viveu).
399
+ const MSG_OP_NAO_ACHADO = 'O programa do 1Password (op) nao foi achado nesta janela. Se ele foi instalado agora ha pouco, feche e abra o programa (Claude Code, Codex ou o app) e tente de novo. Se continuar, rode UMA vez: npx auroq-os conectar-cofre --cofre 1password --agente (ele confere o programa e instala se faltar); se ele disser ja-conectado e isto voltar, peca ajuda ao Arcano com este codigo: op-nao-achado.';
400
+
390
401
  function messageFor(codigo, tipo, detalhe = '') {
391
402
  const nome = NOME_TIPO[tipo] || 'cofre';
392
403
  switch (codigo) {
@@ -402,6 +413,8 @@ function messageFor(codigo, tipo, detalhe = '') {
402
413
  }
403
414
  case 'credencial-indisponivel':
404
415
  return `Nao consegui usar a chave deste computador no ${nome} agora. Tente de novo em alguns minutos.`;
416
+ case 'op-nao-achado':
417
+ return MSG_OP_NAO_ACHADO;
405
418
  case 'sem-permissao':
406
419
  return `A chave do agente nao tem permissao para isso no ${nome}.`;
407
420
  case 'rede':
@@ -430,7 +443,9 @@ const OP_PERMISSION_RE = /(forbidden|permission|not allowed|insufficient|denied|
430
443
  function classifyOp(d, r, secrets = []) {
431
444
  const o = mod(d, 'onepassword');
432
445
  const stderr = String((r && r.stderr) || '');
433
- if (r && r.missing) return { codigo: 'cofre-nao-configurado', detalhe: '' };
446
+ // sem o `op`: no Windows (ja tentou recompor o PATH) e "nao achei o programa", que rodar a rota A de novo NAO resolve;
447
+ // fora dele segue como sempre foi
448
+ if (r && r.missing) return { codigo: ehWindows(d) ? 'op-nao-achado' : 'cofre-nao-configurado', detalhe: '' };
434
449
  if (OP_NOT_VAULT_RE.test(stderr)) return { codigo: 'cofre-nao-configurado', detalhe: '' };
435
450
  if (OP_AMBIGUOUS_RE.test(stderr)) return { codigo: 'falha', detalhe: `Tem mais de um item com esse nome no cofre ${VAULT_NAME}; apague ou renomeie o repetido.` };
436
451
  if (OP_NOT_FOUND_RE.test(stderr)) return { codigo: 'nao-encontrado', detalhe: '' };
@@ -472,24 +487,52 @@ function findField(fields, campo) {
472
487
  function makeOpBackend(d) {
473
488
  const tipo = '1password';
474
489
 
475
- async function token() {
490
+ const validToken = (t) => {
491
+ const o = mod(d, 'onepassword');
492
+ return t && o.isValidToken(String(t).trim()) ? String(t).trim() : null;
493
+ };
494
+ const fromEnv = () => validToken(envOf(d)[mod(d, 'onepassword').TOKEN_VAR]);
495
+ async function fromDisk() {
476
496
  const o = mod(d, 'onepassword');
477
- const valid = (t) => (t && o.isValidToken(String(t).trim()) ? String(t).trim() : null);
478
- const fromEnv = valid(envOf(d)[o.TOKEN_VAR]);
479
- if (fromEnv) return fromEnv;
480
- try { return valid(await (d.readOpToken ? d.readOpToken() : o.readPersistedToken())); } catch { return null; }
497
+ try { return validToken(await (d.readOpToken ? d.readOpToken() : o.readPersistedToken())); } catch { return null; }
498
+ }
499
+ async function token() {
500
+ return fromEnv() || fromDisk();
501
+ }
502
+
503
+ // Windows: o `op` instalado DEPOIS de o programa-pai abrir (winget so muda o PATH no registro) nao esta no PATH deste
504
+ // processo: o spawn da ENOENT. Recompoe o PATH UMA vez por backend (cada recomposicao abre o PowerShell) e tenta o
505
+ // comando de novo; chamadas em paralelo esperam a mesma recomposicao. Devolve false se nao ha como recompor.
506
+ let recomposicao = null;
507
+ function recomporPathUmaVez() {
508
+ if (!recomposicao) {
509
+ recomposicao = (async () => {
510
+ const o = mod(d, 'onepassword');
511
+ const recompor = typeof d.refreshPath === 'function' ? d.refreshPath : o.refreshWindowsPath;
512
+ if (typeof recompor !== 'function') return false;
513
+ try { await recompor(); } catch { /* melhor esforco: o comando decide se achou */ }
514
+ return true;
515
+ })();
516
+ }
517
+ return recomposicao;
481
518
  }
482
519
 
483
520
  async function call(tk, args, input = '') {
484
521
  const o = mod(d, 'onepassword');
485
522
  const run = d.op || o.runOp;
486
- // `isolate`: o agente nunca pode cair na janela da digital do app; vale so a chave
487
- const env = o.opEnv(String(tk).trim(), { isolate: true });
488
- // a chave do Infisical (ID e segredo) nao tem nada a ver com o `op`: nao vai para o ambiente dele
489
- for (const k of Object.keys(env)) {
490
- if (/^AUROQ_INFISICAL_/i.test(k)) delete env[k];
491
- }
492
- return run(args, { env, input, timeoutMs: OP_TIMEOUT_MS });
523
+ // o ambiente e montado a cada tentativa: o PATH recomposto vale so para quem copia process.env DEPOIS
524
+ const tentar = () => {
525
+ // `isolate`: o agente nunca pode cair na janela da digital do app; vale so a chave
526
+ const env = o.opEnv(String(tk).trim(), { isolate: true });
527
+ // a chave do Infisical (ID e segredo) nao tem nada a ver com o `op`: nao vai para o ambiente dele
528
+ for (const k of Object.keys(env)) {
529
+ if (/^AUROQ_INFISICAL_/i.test(k)) delete env[k];
530
+ }
531
+ return run(args, { env, input, timeoutMs: OP_TIMEOUT_MS });
532
+ };
533
+ let r = await tentar();
534
+ if (r && r.missing && ehWindows(d) && (await recomporPathUmaVez())) r = await tentar();
535
+ return r;
493
536
  }
494
537
 
495
538
  const semChave = () => failure('cofre-nao-configurado', tipo);
@@ -501,12 +544,34 @@ function makeOpBackend(d) {
501
544
  });
502
545
 
503
546
  async function run(args, input, secrets) {
504
- const tk = await token();
547
+ let tk = await token();
505
548
  if (!tk) return { erro: semChave() };
506
- const r = await call(tk, args, input);
549
+ let r = await call(tk, args, input);
550
+ let c = r.ok ? null : classifyOp(d, r, secrets);
551
+ // A variavel do programa pode estar velha: janela aberta com uma chave que depois foi revogada e trocada (a
552
+ // nova esta gravada no computador). Chave RECUSADA vinda da variavel => tenta a gravada, se for outra. So esta
553
+ // recusa clara conta; rede, limite ou o que for nao muda de chave.
554
+ if (c && c.codigo === 'credencial-invalida' && tk === fromEnv()) {
555
+ const gravada = await fromDisk();
556
+ if (gravada && gravada !== tk) {
557
+ const r2 = await call(gravada, args, input);
558
+ tk = gravada;
559
+ r = r2;
560
+ c = r.ok ? null : classifyOp(d, r, secrets);
561
+ }
562
+ }
507
563
  if (r.ok) return { r, tk };
508
- const c = classifyOp(d, r, secrets);
509
- return { erro: failure(c.codigo, tipo, c.detalhe) };
564
+ const erro = failure(c.codigo, tipo, c.detalhe);
565
+ // Campos extras so para quem precisa saber a causa (a migracao); nenhum entra na mensagem do `segredo`.
566
+ // `semOp`: o programa nem rodou. `diag`: o que o `op` disse (stderr, uma linha, sem a chave nem o valor gravado:
567
+ // oneLine tira ops_..., o token e os segredos que esta execucao conhece). Nunca o stdout.
568
+ if (r.missing) {
569
+ erro.semOp = true;
570
+ } else {
571
+ const diag = oneLine(r.stderr, 160, [...(secrets || []), tk, tk.replace(/^ops_/, '')]);
572
+ if (diag) erro.diag = diag;
573
+ }
574
+ return { erro };
510
575
  }
511
576
 
512
577
  const backend = {
@@ -1281,6 +1346,24 @@ function migracao(status, codigo, mensagem, n = {}) {
1281
1346
  return { status, codigo, movidos: n.movidos || 0, iguais: n.iguais || 0, falhas: n.falhas || 0, mensagem };
1282
1347
  }
1283
1348
 
1349
+ // Mensagens do 'conectar-1password-primeiro': cada uma diz o que de fato aconteceu. Com o complemento do `op` (diagDoOp)
1350
+ // ainda cabem nos 400 caracteres da linha AUROQ_RESULTADO (o texto corta ali).
1351
+ const ROTA_A = 'npx auroq-os conectar-cofre --cofre 1password --agente';
1352
+ // A chave NAO foi achada (nem na variavel do programa nem gravada no computador).
1353
+ const MSG_MIGRAR_SEM_CHAVE = `Nao achei a chave do 1Password nesta janela (nem na variavel do programa nem no que o computador tem gravado). Rode: ${ROTA_A} (se a chave ja estiver gravada ele responde ja-conectado na hora). Se responder ja-conectado e esta mensagem voltar, feche e abra o programa e rode a migracao de novo.`;
1354
+ // A chave foi achada e o 1Password disse que ela nao vale.
1355
+ const MSG_MIGRAR_CHAVE_RECUSADA = `O 1Password recusou a chave gravada neste computador (revogada ou invalida). Rode: ${ROTA_A} (ele cria outra) e depois a migracao de novo.`;
1356
+ // A chave foi achada e o `op` rodou, mas o cofre Claude nao aparece para ela (ou ela nao tem permissao nele).
1357
+ const MSG_MIGRAR_COFRE_INVISIVEL = `A chave do 1Password foi achada, mas nao enxerga o cofre ${VAULT_NAME}. Rode: ${ROTA_A}. Depois rode a migracao de novo.`;
1358
+ // A chave foi achada, mas o programa `op` nao existe aqui (fora do Windows; no Windows e o codigo op-nao-achado).
1359
+ const MSG_MIGRAR_SEM_OP = `A chave do 1Password foi achada, mas o programa do 1Password (op) nao foi achado neste computador. Rode: ${ROTA_A}. Depois rode a migracao de novo.`;
1360
+
1361
+ /** " (O 1Password disse: ...)" com a linha que o `op` devolveu (guardada na falha); '' se nao ha. Nunca traz a chave nem o valor. */
1362
+ function diagDoOp(falha) {
1363
+ const linha = falha && typeof falha.diag === 'string' ? falha.diag.trim() : '';
1364
+ return linha ? ` (O 1Password disse: ${linha})` : '';
1365
+ }
1366
+
1284
1367
  /**
1285
1368
  * Leva as chaves do Infisical para o cofre Claude do 1Password e, so se TUDO foi, troca o cofre ativo (e a UNICA
1286
1369
  * coisa que troca para o 1Password quem ja usa o Infisical: conectar o 1Password sozinho nao troca). Nao apaga
@@ -1304,13 +1387,19 @@ async function migrar(options = {}, d = {}) {
1304
1387
  return migracao('erro', 'origem-indisponivel', 'O Infisical nao esta conectado neste computador, entao nao tenho de onde levar as chaves.');
1305
1388
  }
1306
1389
  if (!(await destino.pronto())) {
1307
- return migracao('aguardando', 'conectar-1password-primeiro', 'Falta conectar o 1Password neste computador. Rode: npx auroq-os conectar-cofre --cofre 1password --agente. Depois rode a migracao de novo.');
1390
+ return migracao('aguardando', 'conectar-1password-primeiro', MSG_MIGRAR_SEM_CHAVE);
1308
1391
  }
1309
1392
  // o cofre Claude precisa estar visivel para a chave do 1Password
1310
1393
  const vis = await destino.listar();
1311
1394
  if (!vis.ok) {
1312
- if (['cofre-nao-configurado', 'credencial-invalida', 'sem-permissao'].includes(vis.codigo)) {
1313
- return migracao('aguardando', 'conectar-1password-primeiro', `A chave do 1Password deste computador nao enxerga o cofre ${VAULT_NAME}. Rode: npx auroq-os conectar-cofre --cofre 1password --agente. Depois rode a migracao de novo.`);
1395
+ // programa `op` nao achado (Windows): rodar a rota A de novo nao resolve (e foi o laco de "conectar primeiro")
1396
+ if (vis.codigo === 'op-nao-achado') return migracao('aguardando', 'op-nao-achado', vis.mensagem);
1397
+ if (vis.codigo === 'credencial-invalida') {
1398
+ return migracao('aguardando', 'conectar-1password-primeiro', `${MSG_MIGRAR_CHAVE_RECUSADA}${diagDoOp(vis)}`);
1399
+ }
1400
+ if (vis.semOp) return migracao('aguardando', 'conectar-1password-primeiro', MSG_MIGRAR_SEM_OP); // fora do Windows: a rota A confere o programa
1401
+ if (['cofre-nao-configurado', 'sem-permissao'].includes(vis.codigo)) {
1402
+ return migracao('aguardando', 'conectar-1password-primeiro', `${MSG_MIGRAR_COFRE_INVISIVEL}${diagDoOp(vis)}`);
1314
1403
  }
1315
1404
  return migracao('erro', 'falha', `Nao consegui olhar o cofre ${VAULT_NAME} do 1Password agora (${vis.codigo}). Tente de novo em alguns minutos.`);
1316
1405
  }