@nectarcrm/ccx 0.5.1 → 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.
Files changed (2) hide show
  1. package/bin/ccx.js +32 -6
  2. package/package.json +1 -1
package/bin/ccx.js CHANGED
@@ -511,13 +511,21 @@ async function autoUpdate() {
511
511
  const prefix = globalPrefix()
512
512
  if (!prefix) return save({ error: 'ccx não foi instalado com npm install -g' })
513
513
  try {
514
- const npm = join(dirname(process.execPath), WIN ? 'npm.cmd' : 'npm')
515
- execFileSync(existsSync(npm) ? npm : 'npm', ['install', '-g', '--prefix', prefix, `${PKG}@${latest}`], { stdio: 'ignore', timeout: 180_000, shell: WIN })
514
+ const args = ['install', '-g', '--prefix', prefix, `${PKG}@${latest}`]
515
+ const opts = { stdio: ['ignore', 'ignore', 'pipe'], timeout: 180_000 }
516
+ // O npm que vem com o Node, rodado pelo próprio Node: sem cmd.exe, então espaço no caminho
517
+ // (C:\Program Files\nodejs, C:\Users\Nome Sobrenome) não quebra o comando
518
+ const cli = [join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js'), join(dirname(dirname(process.execPath)), 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js')].find(existsSync)
519
+ if (cli) execFileSync(process.execPath, [cli, ...args], opts)
520
+ else if (WIN) execFileSync('npm.cmd', args.map(a => `"${a}"`), { ...opts, shell: true })
521
+ else execFileSync('npm', args, opts)
516
522
  log(`ccx atualizado: ${mine} → ${latest}`)
517
523
  save({})
518
524
  }
519
525
  catch (e) {
520
- const msg = e.message.split('\n')[0]
526
+ // O motivo de verdade vem no fim do stderr do npm (ex.: EACCES, EPERM, ENOTFOUND)
527
+ const why = String(e.stderr ?? '').split(/\r?\n/).map(l => l.replace(/^npm (error|ERR!) ?/, '').trim()).filter(Boolean)
528
+ const msg = why.find(l => /^(code )?E[A-Z]+/.test(l)) ?? why.at(-1) ?? e.message.split('\n')[0]
521
529
  log(`não consegui atualizar o ccx pra ${latest}: ${msg}`)
522
530
  save({ error: msg })
523
531
  }
@@ -669,9 +677,22 @@ function when(d) {
669
677
  const dd = Math.floor(mins / 1440), hh = Math.floor((mins % 1440) / 60), mm = mins % 60
670
678
  return dd ? `${dd}d ${hh}h` : hh ? `${hh}h${String(mm).padStart(2, '0')}` : `${mm}min`
671
679
  }
680
+ // O servidor diz quem dá pra usar (available); app antigo não manda: vale como disponível
681
+ const usableNow = a => a.available !== false
682
+ // Conta no limite (97% ou mais, a regra do painel): vale o limite que estiver mais alto
683
+ function limitText(a) {
684
+ const week = (a.weekly_pct ?? 0) >= (a.five_hour_pct ?? 0)
685
+ const at = week ? a.weekly_resets_at : a.five_hour_resets_at
686
+ const d = at && new Date(at)
687
+ const back = !d ? '' : d.toDateString() === new Date().toDateString()
688
+ ? ` · volta ${d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}`
689
+ : ` · volta ${d.toLocaleDateString('pt-BR', { weekday: 'short' }).replace('.', '')} ${d.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' })}`
690
+ return `no limite ${week ? 'da semana' : 'da sessão de 5h'} (${week ? a.weekly_pct : a.five_hour_pct}%)${back}`
691
+ }
672
692
  function line(a) {
673
693
  const name = a.slug.padEnd(14)
674
694
  if (a.five_hour_pct === null && a.weekly_pct === null) return `${name} ${c(90, a.status === 'ok' ? 'sem leitura ainda' : 'desconectada — avise um admin')}`
695
+ if (!usableNow(a) && (a.status === 'ok' || a.status === 'erro_leitura')) return `${name} ${c(31, limitText(a))}`
675
696
  const at = s => s && new Date(s)
676
697
  return `${name} 5h ${colorPct(a.five_hour_pct ?? 0).padEnd(isTTY ? 13 : 4)} (reinicia em ${when(at(a.five_hour_resets_at))}) semana ${colorPct(a.weekly_pct ?? 0).padEnd(isTTY ? 13 : 4)} (reinicia em ${when(at(a.weekly_resets_at))})`
677
698
  }
@@ -734,15 +755,20 @@ async function chooseAccount(app, key) {
734
755
  if (!list.length) die('Nenhuma conta liberada pra você. Peça a um admin.')
735
756
  if (list.length === 1) return list[0].slug
736
757
  if (!process.stdin.isTTY) return recommended ?? die('Nenhuma conta disponível agora.')
737
- console.error('Qual conta este computador deve usar?\n')
738
- list.forEach((a, i) => console.error(` ${c(1, String(i + 1))} ${line(a)}${a.slug === recommended ? c(36, ' ← recomendada') : ''}${a.id === app.account?.id ? c(90, ' (atual)') : ''}`))
758
+ // Só as que dá pra usar ganham número; as no limite aparecem embaixo, sem número
759
+ const options = list.filter(usableNow)
760
+ const current = a => (a.id === app.account?.id ? c(90, ' (atual)') : '')
761
+ console.error(options.length ? 'Qual conta este computador deve usar?\n' : 'Nenhuma conta com folga agora.\n')
762
+ options.forEach((a, i) => console.error(` ${c(1, String(i + 1))} ${line(a)}${a.slug === recommended ? c(36, ' ← recomendada') : ''}${current(a)}`))
763
+ for (const a of list.filter(a => !usableNow(a))) console.error(` ${c(90, '–')} ${line(a)}${current(a)}`)
764
+ if (!options.length) die('\nPra usar uma delas mesmo assim: ccx <conta>')
739
765
  const { createInterface } = await import('node:readline/promises')
740
766
  const rl = createInterface({ input: process.stdin, output: process.stderr })
741
767
  for (;;) {
742
768
  const ans = (await rl.question(`\nNúmero${recommended ? ' (Enter = recomendada)' : ''}: `).catch(() => die('\nCancelado.'))).trim()
743
769
  if (!ans && recommended) { rl.close(); return recommended }
744
770
  const n = Number(ans)
745
- if (Number.isInteger(n) && n >= 1 && n <= list.length) { rl.close(); return list[n - 1].slug }
771
+ if (Number.isInteger(n) && n >= 1 && n <= options.length) { rl.close(); return options[n - 1].slug }
746
772
  console.error('Digite um dos números da lista.')
747
773
  }
748
774
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nectarcrm/ccx",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Escolhe qual conta Claude este computador usa, conectado ao app Contas Claude da Nectar.",
5
5
  "type": "module",
6
6
  "bin": { "ccx": "bin/ccx.js" },