auroq-os 2.6.7 → 2.6.9

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.
@@ -1,7 +1,7 @@
1
1
  project:
2
2
  name: "Auroq OS"
3
3
  type: greenfield
4
- version: 2.6.7
4
+ version: 2.6.9
5
5
  installedAt: '2026-03-16'
6
6
 
7
7
  ide:
package/.claude/CLAUDE.md CHANGED
@@ -4,6 +4,6 @@ Sistema operacional de IA para o negócio. Você manda e julga; a IA executa.
4
4
 
5
5
  Ative um agente pelo comando (`/companion`, `$companion`, `@companion`). Todo conteúdo Arcane (Companion interno, Consultor, forjas, Pack) vem pelo MCP `arcane` — nunca procurar em `agents/`.
6
6
 
7
- Sua memória e seus documentos ficam na sua máquina e no seu GitHub privado (senhas e `business/vault/` ficam fora). O histórico das sessões com os squads só vai para a Arka se você autorizar na plataforma, e você pode retirar a autorização quando quiser. Além disso, a Arka registra qual conteúdo licenciado foi entregue, quando e pra qual conta — igual a uma nota de entrega.
7
+ Sua memória e seus documentos ficam na sua máquina e no seu GitHub privado (senhas e `business/vault/` ficam fora). O histórico das sessões com os squads está previsto nos Termos de Uso: vem ligado para quem aceita os termos na plataforma (quem já tinha dito "não" continua sem gravar) e você desliga quando quiser em Minha Conta, "Guardar minhas conversas". Se a pasta do seu negócio tem dados de clientes, desligue. Além disso, a Arka registra qual conteúdo licenciado foi entregue, quando e pra qual conta — igual a uma nota de entrega.
8
8
 
9
9
  Rules em `.claude/rules/`. Constitution em `.auroq-core/constitution.md`.
@@ -0,0 +1,9 @@
1
+ # Título da conversa na barra de status
2
+
3
+ A barra de status do Claude Code (embaixo da caixa de mensagem) mostra, em amarelo, o título da conversa. Quem escreve esse título é você.
4
+
5
+ - Na primeira resposta de cada conversa, grave em silêncio, uma única vez, um título de 3 a 5 palavras em português sobre o tema central:
6
+ `node ~/.auroq/barra/barra.cjs titulo "Título em português"`
7
+ - Não avise o expert, não comente o comando e não troque o título por causa de tarefa lateral (o primeiro fica).
8
+ - Se o comando falhar ou o arquivo não existir, ignore e siga a conversa normalmente.
9
+ - Vale só no Claude Code. No Codex, no Grok e em outras IAs, não rode.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ## 2.6.9 — 2026-10-16
2
+
3
+ ### Historico das sessoes: texto no modelo "atualizamos os termos"
4
+
5
+ - O historico passa para o modelo "atualizamos os termos": a gravacao das conversas das sessoes com os squads da Arcane esta prevista nos Termos de Uso e na Politica de Privacidade da plataforma. Ela vem ligada para quem aceita os termos no aviso da plataforma e o aluno desliga quando quiser em Minha Conta (arcane.arka.education/conta), em "Guardar minhas conversas", ou pedindo ao proprio agente para nao guardar. Religar e so pela plataforma.
6
+ - Quem ja tinha dito "nao" continua sem gravar: aceitar os termos nao desfaz essa recusa. Quem tinha dito "sim" continua com o "sim".
7
+ - Os textos do pacote acompanham o modelo novo: `casca/.claude/CLAUDE.md` (o que o aluno le dentro do projeto), a secao "Historico de uso (AHI)" do README e a linha de ajuda e a mensagem do comando `auroq-os historico pausar` (agora diz como desligar em Minha Conta ou pelo agente, sem precisar desligar o MCP). Saiu a frase "so grava quem marcou sim / caixa desmarcada = nao". Entrou o aviso: se a pasta do negocio tem dados de clientes, desligue.
8
+ - Alcance do texto novo de `casca/.claude/CLAUDE.md`: ele vale para instalacoes novas. A manutencao nunca sobrescreve o `.claude/CLAUDE.md` que o aluno ja tem, entao quem ja instalou continua com o paragrafo antigo no arquivo dele (esse comportamento nao mudou). O caminho dessas pessoas e o aviso de termos na plataforma e o que o Arcano explica a elas.
9
+ - Nenhuma mudanca no coletor, nos hooks nem nos dados ja guardados: so textos, versao e teste (`tests/vercelignore-ops.test.mjs` agora fixa o texto novo da casca).
10
+ - Mantem `arcane-mcp@0.7.0`. Instaladores do repositorio preparados para 2.6.9.
11
+
12
+ ## 2.6.8 — 2026-10-16
13
+
14
+ ### Barra de status do Claude Code igual à do Euriler
15
+
16
+ - Pedido do Euriler: a barra que ele usa embaixo da caixa de mensagem do Claude Code vira padrão do aluno, em qualquer terminal (Mac e Windows) e dentro do app Auroq OS. Quatro linhas: modelo, esforço, título da conversa, situação do Claude e tempo da sessão; pasta e branch; contexto usado e cache; uso de 5 h e da semana com o tempo até renovar, e a data.
17
+ - Quem desenha é o `ccstatusline` 2.2.30 (MIT, sem dependências), travado como dependência exata do pacote. `instalar`, `manutencao` e `clone` copiam o motor para `~/.auroq/barra/ccstatusline`, gravam `~/.auroq/barra/barra.cjs` e o layout `~/.auroq/barra/ccstatusline.json`, e ligam `statusLine` no `~/.claude/settings.json` mexendo só nessa chave (permissões, hooks e o resto ficam). Sem rede na hora de desenhar; nada de `npx ccstatusline@latest`.
18
+ - Nunca troca uma barra que o aluno já tinha. Ocupa o lugar só quando está vazio, quando já é a nossa ou quando é o leitor de uso do app Auroq OS/Orca (que não desenha nada). Dentro do app, a barra repassa o mesmo JSON para o leitor do app, então o painel de uso continua ao vivo. Se o aluno tirar a barra, a manutenção não põe de volta; `~/.auroq/sem-barra` desliga de vez. Layout mexido pelo aluno fica.
19
+ - Título da conversa: nova regra `.claude/rules/titulo-da-barra.md` faz o Claude gravar, uma vez por conversa, um título de 3 a 5 palavras (`node ~/.auroq/barra/barra.cjs titulo "..."`), guardado por sessão do Claude Code (`CLAUDE_CODE_SESSION_ID`), sem depender de `ps` (funciona no Windows). Títulos com mais de 7 dias são apagados.
20
+ - Qualquer falha da barra vira aviso na instalação e barra vazia na tela; o resto do sistema segue igual.
21
+ - Testes novos (`tests/barra.test.mjs`): instalação no HOME, preservação do settings, barra do aluno intocada, troca do leitor do app, aluno que tirou a barra, desligamento, settings quebrado, layout do aluno, título por sessão, pintura das 4 linhas pelo ccstatusline e repasse ao app. Prova no Windows pelo cmd, Git Bash e PowerShell em `.github/workflows/barra-windows.yml`. Provado também com o Claude Code de verdade num terminal: a barra aparece e o título gravado pela IA entra nela.
22
+ - Mantem `arcane-mcp@0.7.0`. Instaladores do repositorio preparados para 2.6.8.
23
+
1
24
  ## 2.6.7 — 2026-10-16
2
25
 
3
26
  ### Antivírus Kaspersky não bloqueia mais a atualização no Windows
package/README.md CHANGED
@@ -132,12 +132,17 @@ proprio pacote.
132
132
  ## Historico de uso (AHI)
133
133
 
134
134
  `auroq-os historico status` mostra captura comprovada, fila pendente, ultimo ACK,
135
- exclusoes e problemas. So ha registro para quem marcou "sim" na pergunta unica da
136
- plataforma Arcane (caixa desmarcada = nao), e so quando a sessao usa o MCP Arcane
137
- com conta autenticada e licenca validada pelo servidor. Para nao guardar, basta
138
- deixar a caixa desmarcada; quem ja marcou pode tirar a autorizacao pelo proprio
139
- agente (ele registra o "nao") ou pelo e-mail euriler@arka.education. Nao e preciso
140
- desligar o MCP nem os hooks. Instalar ou apenas abrir o projeto nao prova captura.
135
+ exclusoes e problemas. O registro das sessoes com os squads da Arcane esta previsto
136
+ nos Termos de Uso e na Politica de Privacidade da plataforma: vem ligado para quem
137
+ aceita os termos (aviso na plataforma) e so acontece quando a sessao usa o MCP Arcane
138
+ com conta autenticada e licenca validada pelo servidor. Quem ja tinha dito "nao"
139
+ continua sem gravar: aceitar os termos nao desfaz essa recusa. Para desligar, entre
140
+ em Minha Conta (arcane.arka.education/conta) e desligue "Guardar minhas conversas",
141
+ ou peca ao proprio agente (ele registra o "nao"). Religar so pela plataforma. Se a
142
+ pasta do seu negocio tem dados de clientes, desligue. Para pedir a exclusao do que ja
143
+ foi guardado, use os comandos de exclusao abaixo ou o e-mail euriler@arka.education.
144
+ Nao e preciso desligar o MCP nem os hooks. Instalar ou apenas abrir o projeto nao
145
+ prova captura.
141
146
 
142
147
  O adaptador `ahi-hooks-v2` registra mensagens e entradas/saidas de ferramentas
143
148
  que os hooks visiveis do Claude Code/Codex disponibilizam. A cobertura e parcial:
@@ -188,7 +193,10 @@ as paginas do mesmo recorte e grava um novo arquivo privado em
188
193
  `~/.arcane/ahi-exports/`; uma falha nunca e apresentada como exportacao completa.
189
194
  Direitos de consulta/exclusao continuam disponiveis com autenticacao mesmo sem
190
195
  licenca de captura. Para apagar o historico da conta inteira, o escopo explicito
191
- exigido e `excluir --account --confirm-delete`.
196
+ exigido e `excluir --account --confirm-delete`. Apagar o historico da conta inteira
197
+ (`excluir --account`) tambem encerra a gravacao nessa conta (marca de exclusao
198
+ permanente); para voltar a gravar, escreva para euriler@arka.education. Excluir uma
199
+ sessao nao encerra a gravacao.
192
200
 
193
201
  A atualizacao do coletor exige a manutencao no projeto (peca ao Ops "atualiza o sistema")
194
202
  e reabrir o host. O aviso de nova versao ao iniciar o Claude Code nao instala essa correcao.
@@ -246,13 +254,13 @@ agents/ → Seu exercito (companion, workers, minds, squads)
246
254
 
247
255
  ## Observabilidade e integridade do motor
248
256
 
249
- Apos publicacao, `npx -y auroq-os@2.6.7 doctor` mostra a fila local segura e os comandos pinados de
250
- manutencao/diagnostico. `npx -y auroq-os@2.6.7 manutencao` preserva o caminho existente
257
+ Apos publicacao, `npx -y auroq-os@2.6.9 doctor` mostra a fila local segura e os comandos pinados de
258
+ manutencao/diagnostico. `npx -y auroq-os@2.6.9 manutencao` preserva o caminho existente
251
259
  de consentimento legado, studentFiles, customizacoes e dados do negocio. Nao ha
252
260
  migracao forcada. O registro MCP aponta para `arcane-mcp@0.7.0` — o pin mora no campo
253
261
  `arcaneMcpPin` do package.json (fonte unica; o servidor le o mesmo campo no npm).
254
262
  `npm run release:verify` recusa publicar com um pin que o npm nao resolva.
255
- Os instaladores do repositorio ficam preparados para 2.6.7; as copias publicas so recebem
263
+ Os instaladores do repositorio ficam preparados para 2.6.9; as copias publicas so recebem
256
264
  a versao apos os gates nativos e a verificacao do tarball publicado.
257
265
  O pacote inclui `lib/runtime-integrity.json`: inventario SHA-256 gerado depois da montagem da casca, verificavel com `npm run integrity:verify` dentro do pacote extraido. Ele comprova consistencia do conteudo; nao e uma assinatura de autoria.
258
266
 
package/bin/auroq-os.js CHANGED
@@ -1549,6 +1549,29 @@ function opcoesDeLoginDeTeste() {
1549
1549
  }
1550
1550
 
1551
1551
  // ─── INSTALACAO ──────────────────────────────────────────
1552
+ // Barra de status do Claude Code (2.6.8): a mesma do Euriler, no HOME do aluno. Nunca derruba a
1553
+ // instalacao: sem a barra o sistema funciona igual, entao qualquer falha vira aviso.
1554
+ function ligarBarraDeStatus() {
1555
+ step('Ligando a barra de status do Claude Code...');
1556
+ try {
1557
+ const r = require('../lib/barra').instalarBarra();
1558
+ const textos = {
1559
+ 'ligada': 'Barra de status ligada (vale em todo terminal do Claude Code)',
1560
+ 'atualizada': 'Barra de status em dia',
1561
+ 'em-dia': 'Barra de status em dia',
1562
+ 'barra-do-aluno': 'Voce ja tem uma barra de status propria no Claude Code; ficou como estava',
1563
+ 'tirada-pelo-aluno': 'Barra de status desligada por voce; ficou desligada',
1564
+ 'desligada': 'Barra de status desligada neste computador (~/.auroq/sem-barra)',
1565
+ };
1566
+ if (textos[r.estado]) success(textos[r.estado]);
1567
+ else warn(`Barra de status nao ligada (${r.estado}${r.detalhe ? `: ${r.detalhe}` : ''})`);
1568
+ return r;
1569
+ } catch (e) {
1570
+ warn(`Barra de status nao ligada (${String(e && e.message || e).split(/\r?\n/)[0].slice(0, 200)}). O resto funciona normal.`);
1571
+ return null;
1572
+ }
1573
+ }
1574
+
1552
1575
  async function init({ pasta = null, maintenance = false, modoAgente = false, migrarMcp = false } = {}) {
1553
1576
  if (maintenance && (pasta || !(await fs.pathExists(path.join(process.cwd(), '.auroq-core'))))) {
1554
1577
  throw falhaMarcada('pasta', 'Manutencao exige a raiz de um negocio existente, sem --pasta. Primeira instalacao pela plataforma.');
@@ -1745,6 +1768,7 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
1745
1768
  '.claude/rules/operacao-autonoma.md',
1746
1769
  '.claude/rules/custom-do-aluno.md',
1747
1770
  '.claude/rules/puxar-e-entregar.md',
1771
+ '.claude/rules/titulo-da-barra.md', // 2.6.8 — a IA grava o titulo da barra de status
1748
1772
 
1749
1773
  // Hooks
1750
1774
  '.claude/hooks/synapse-engine.cjs',
@@ -2070,6 +2094,8 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2070
2094
  step('Protegendo segredos...');
2071
2095
  await applySecretProtections(targetDir);
2072
2096
 
2097
+ ligarBarraDeStatus();
2098
+
2073
2099
  // ─── Fase 7: Health check rapido
2074
2100
  step('Verificando integridade...');
2075
2101
  await runHealthChecks(targetDir);
@@ -2253,6 +2279,8 @@ async function clone(repoArg) {
2253
2279
  step('Protegendo segredos...');
2254
2280
  await applySecretProtections(destDir);
2255
2281
 
2282
+ ligarBarraDeStatus();
2283
+
2256
2284
  // ─── Fase 6: Dependencias (nao viajam no git — de proposito)
2257
2285
  step('Instalando dependencias...');
2258
2286
  try {
@@ -2453,7 +2481,7 @@ if (['init', 'install', 'update'].includes(command)) {
2453
2481
  log(` ${CYAN}doctor${RESET} Diagnostico: arquivos, Node, MCP arcane, login e servidor`);
2454
2482
  log(` ${CYAN}register-mcp${RESET} Reescrever o registro do conteudo ao vivo (MCP arcane) no projeto`);
2455
2483
  log(` ${CYAN}sync-codex${RESET} Gerar e verificar as skills locais do Codex CLI ($nome)`);
2456
- log(` ${CYAN}historico${RESET} Estado da captura do trabalho (so com o "sim" dado na plataforma)`);
2484
+ log(` ${CYAN}historico${RESET} Estado da captura do trabalho (prevista nos Termos de Uso; desliga em Minha Conta)`);
2457
2485
  log(` ${CYAN}conectar-1password${RESET} Conectar o 1Password CLI (token lido do Ctrl+C, nunca digitado)`);
2458
2486
  log('');
2459
2487
  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.6.7 check-access
592
+ & (Get-AuroqNpx) -y auroq-os@2.6.9 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.6.7 instalar
680
+ & (Get-AuroqNpx) -y auroq-os@2.6.9 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.6.7 "$@"
222
+ npx -y auroq-os@2.6.9 "$@"
223
223
  else
224
- npx -y auroq-os@2.6.7 "$@" < /dev/tty
224
+ npx -y auroq-os@2.6.9 "$@" < /dev/tty
225
225
  fi
226
226
  }
227
227
 
@@ -5,7 +5,7 @@ const require = createRequire(import.meta.url);
5
5
  const runtime = require('../../.claude/hooks/ahi/runtime.cjs');
6
6
  export function run(argv = [], cwd = process.cwd()) {
7
7
  const host = argv.includes('--codex') ? 'codex' : 'claude-code';
8
- if (['pausar', 'pause'].includes(argv[0])) return { ok: false, code: 'NO_PAUSE', error: 'Historico acompanha o uso do MCP. Desabilitar o MCP encerra novas capturas; direitos de acesso e exclusao continuam disponiveis.' };
8
+ if (['pausar', 'pause'].includes(argv[0])) return { ok: false, code: 'NO_PAUSE', error: 'Nao ha pausa por aqui. Para nao guardar suas conversas, desligue "Guardar minhas conversas" em Minha Conta (arcane.arka.education/conta) ou peca ao agente para registrar "nao". Nao e preciso desligar o MCP nem os hooks; direitos de acesso e exclusao continuam disponiveis.' };
9
9
  if (['sessoes', 'sessions', 'timeline', 'busca', 'search', 'exportar', 'export', 'excluir', 'delete'].includes(argv[0])) return runRemote(argv, cwd);
10
10
  if (argv[0] && !['status', '--codex'].includes(argv[0])) return { ok: false, code: 'UNKNOWN_COMMAND', error: 'Use auroq-os historico status [--codex].' };
11
11
  try { return runtime.status(cwd, host); } catch { return { ok: false, capture: 'error', reason: 'DIAGNOSTIC_UNAVAILABLE' }; }
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Barra de status do Claude Code do aluno (2.6.8). Mora em ~/.auroq/barra/barra.cjs e e o
4
+ // `statusLine.command` do ~/.claude/settings.json: vale em qualquer terminal e no app Auroq OS.
5
+ //
6
+ // node barra.cjs desenha a barra (o Claude Code manda o JSON da sessao na entrada)
7
+ // node barra.cjs titulo "Texto" grava o titulo da conversa (uma vez por sessao; a IA chama)
8
+ // node barra.cjs topico pedaco da barra: o titulo desta sessao
9
+ // node barra.cjs data pedaco da barra: "sex 16/10 11:39"
10
+ //
11
+ // Quem desenha e o ccstatusline (MIT, versao travada, copiado pelo `auroq-os` para ./ccstatusline).
12
+ // Nada aqui usa rede. Qualquer falha sai em silencio: barra vazia, nunca erro na tela do aluno.
13
+ const fs = require('node:fs');
14
+ const os = require('node:os');
15
+ const path = require('node:path');
16
+ const { spawn } = require('node:child_process');
17
+
18
+ const PASTA = __dirname;
19
+ const TITULOS = path.join(PASTA, 'titulos');
20
+ const MOTOR = path.join(PASTA, 'ccstatusline', 'dist', 'ccstatusline.js');
21
+ const LAYOUT = path.join(PASTA, 'ccstatusline.json');
22
+ const SESSAO_VALIDA = /^[A-Za-z0-9._-]{1,128}$/;
23
+ const SETE_DIAS_MS = 7 * 24 * 60 * 60 * 1000;
24
+
25
+ function lerEntrada() {
26
+ return new Promise(resolve => {
27
+ if (process.stdin.isTTY) return resolve('');
28
+ const partes = [];
29
+ process.stdin.on('data', p => partes.push(p));
30
+ process.stdin.on('end', () => resolve(Buffer.concat(partes).toString('utf8')));
31
+ process.stdin.on('error', () => resolve(''));
32
+ });
33
+ }
34
+
35
+ function sessaoDoJson(texto) {
36
+ try {
37
+ const id = JSON.parse(texto).session_id;
38
+ return typeof id === 'string' && SESSAO_VALIDA.test(id) ? id : null;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ function arquivoDoTitulo(sessao) {
45
+ return path.join(TITULOS, `${sessao}.txt`);
46
+ }
47
+
48
+ function gravarTitulo(texto) {
49
+ const sessao = process.env.CLAUDE_CODE_SESSION_ID;
50
+ const titulo = String(texto || '').replace(/[\r\n\t]+/g, ' ').replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, 60);
51
+ if (!titulo || !sessao || !SESSAO_VALIDA.test(sessao)) return;
52
+ fs.mkdirSync(TITULOS, { recursive: true });
53
+ const alvo = arquivoDoTitulo(sessao);
54
+ // Uma vez por sessao: o primeiro titulo fica, como o do Euriler.
55
+ try {
56
+ fs.writeFileSync(alvo, `${titulo}\n`, { flag: 'wx' });
57
+ } catch (e) {
58
+ if (e.code !== 'EEXIST') throw e;
59
+ }
60
+ limparTitulosVelhos();
61
+ }
62
+
63
+ function limparTitulosVelhos() {
64
+ const limite = Date.now() - SETE_DIAS_MS;
65
+ for (const nome of fs.readdirSync(TITULOS)) {
66
+ const arquivo = path.join(TITULOS, nome);
67
+ try {
68
+ if (fs.statSync(arquivo).mtimeMs < limite) fs.unlinkSync(arquivo);
69
+ } catch {}
70
+ }
71
+ }
72
+
73
+ function mostrarTitulo(entrada) {
74
+ const sessao = sessaoDoJson(entrada);
75
+ if (!sessao) return '';
76
+ try {
77
+ const primeira = fs.readFileSync(arquivoDoTitulo(sessao), 'utf8').split(/\r?\n/)[0] || '';
78
+ return [...primeira].slice(0, 40).join('');
79
+ } catch {
80
+ return '';
81
+ }
82
+ }
83
+
84
+ const DIAS = ['dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sáb'];
85
+ function dataCurta(agora = new Date()) {
86
+ const dois = n => String(n).padStart(2, '0');
87
+ return `${DIAS[agora.getDay()]} ${dois(agora.getDate())}/${dois(agora.getMonth() + 1)} ${dois(agora.getHours())}:${dois(agora.getMinutes())}`;
88
+ }
89
+
90
+ // Dentro do app Auroq OS (ou do Orca), o app usa a statusLine para ler o uso da conta ao vivo.
91
+ // A barra ocupou esse lugar, entao repassa o mesmo JSON para o script do app, sem esperar por ele.
92
+ function scriptDoApp() {
93
+ if (!process.env.ORCA_PANE_KEY || (!process.env.ORCA_AGENT_HOOK_PORT && !process.env.ORCA_AGENT_HOOK_ENDPOINT)) return null;
94
+ const nome = process.platform === 'win32' ? 'claude-statusline.cmd' : 'claude-statusline.sh';
95
+ const pastas = [];
96
+ if (process.env.ORCA_AGENT_HOOK_ENDPOINT) pastas.push(path.dirname(process.env.ORCA_AGENT_HOOK_ENDPOINT));
97
+ pastas.push(path.join(os.homedir(), '.auroq-os', 'agent-hooks'), path.join(os.homedir(), '.orca', 'agent-hooks'));
98
+ for (const pasta of pastas) {
99
+ const alvo = path.join(pasta, nome);
100
+ if (fs.existsSync(alvo)) return alvo;
101
+ }
102
+ return null;
103
+ }
104
+
105
+ function repassarAoApp(entrada) {
106
+ const alvo = scriptDoApp();
107
+ if (!alvo || !entrada) return;
108
+ try {
109
+ const filho = process.platform === 'win32'
110
+ ? spawn(process.env.ComSpec || 'cmd.exe', ['/d', '/c', alvo], { stdio: ['pipe', 'ignore', 'ignore'], windowsHide: true, detached: true })
111
+ : spawn('/bin/sh', [alvo], { stdio: ['pipe', 'ignore', 'ignore'], detached: true });
112
+ filho.on('error', () => {});
113
+ filho.stdin.on('error', () => {});
114
+ filho.stdin.end(entrada);
115
+ filho.unref();
116
+ } catch {}
117
+ }
118
+
119
+ function desenhar(entrada) {
120
+ return new Promise(resolve => {
121
+ if (!fs.existsSync(MOTOR)) return resolve();
122
+ let filho;
123
+ try {
124
+ filho = spawn(process.execPath, [MOTOR, '--config', LAYOUT], { stdio: ['pipe', 'inherit', 'ignore'], windowsHide: true });
125
+ } catch {
126
+ return resolve();
127
+ }
128
+ filho.on('error', () => resolve());
129
+ filho.on('close', () => resolve());
130
+ filho.stdin.on('error', () => {});
131
+ filho.stdin.end(entrada);
132
+ });
133
+ }
134
+
135
+ async function principal() {
136
+ const [modo, ...resto] = process.argv.slice(2);
137
+ if (modo === 'titulo') return gravarTitulo(resto.join(' '));
138
+ if (modo === 'data') return process.stdout.write(dataCurta());
139
+ const entrada = await lerEntrada();
140
+ if (modo === 'topico') return process.stdout.write(mostrarTitulo(entrada));
141
+ repassarAoApp(entrada);
142
+ await desenhar(entrada);
143
+ }
144
+
145
+ if (require.main === module) {
146
+ principal().catch(() => {}).finally(() => { process.exitCode = 0; });
147
+ }
148
+
149
+ module.exports = { dataCurta, sessaoDoJson, mostrarTitulo, gravarTitulo, scriptDoApp };
@@ -0,0 +1,198 @@
1
+ {
2
+ "version": 4,
3
+ "lines": [
4
+ [
5
+ {
6
+ "id": "l1-model",
7
+ "type": "model",
8
+ "color": "brightCyan",
9
+ "bold": true,
10
+ "rawValue": true
11
+ },
12
+ {
13
+ "id": "l1-effort",
14
+ "type": "thinking-effort",
15
+ "color": "magenta"
16
+ },
17
+ {
18
+ "id": "l1-skill",
19
+ "type": "skills",
20
+ "color": "brightBlack",
21
+ "metadata": {
22
+ "hide": "empty"
23
+ }
24
+ },
25
+ {
26
+ "id": "l1-topic",
27
+ "type": "custom-command",
28
+ "color": "yellow",
29
+ "commandPath": "{{BARRA}} topico",
30
+ "timeout": 1000
31
+ },
32
+ {
33
+ "id": "l1-flex",
34
+ "type": "flex-separator"
35
+ },
36
+ {
37
+ "id": "l1-status",
38
+ "type": "claude-status",
39
+ "color": "brightBlack"
40
+ },
41
+ {
42
+ "id": "l1-clock-ico",
43
+ "type": "custom-text",
44
+ "customText": "⏱",
45
+ "color": "brightYellow",
46
+ "merge": "no-padding"
47
+ },
48
+ {
49
+ "id": "l1-clock",
50
+ "type": "session-clock",
51
+ "color": "brightYellow",
52
+ "rawValue": true
53
+ }
54
+ ],
55
+ [
56
+ {
57
+ "id": "l2-cwd",
58
+ "type": "current-working-dir",
59
+ "color": "blue",
60
+ "metadata": {
61
+ "abbreviateHome": "true"
62
+ }
63
+ },
64
+ {
65
+ "id": "l2-branch",
66
+ "type": "git-branch",
67
+ "color": "green",
68
+ "metadata": {
69
+ "hide": "no-git"
70
+ }
71
+ },
72
+ {
73
+ "id": "l2-changes",
74
+ "type": "git-changes",
75
+ "color": "yellow",
76
+ "metadata": {
77
+ "hide": "zero"
78
+ }
79
+ }
80
+ ],
81
+ [
82
+ {
83
+ "id": "l3-ctx",
84
+ "type": "context-bar",
85
+ "color": "brightMagenta"
86
+ },
87
+ {
88
+ "id": "l3-flex",
89
+ "type": "flex-separator"
90
+ },
91
+ {
92
+ "id": "l3-cache",
93
+ "type": "cache-timer",
94
+ "color": "brightBlack",
95
+ "metadata": {
96
+ "ttlSeconds": "3600"
97
+ }
98
+ }
99
+ ],
100
+ [
101
+ {
102
+ "id": "l4-5h-lbl",
103
+ "type": "custom-text",
104
+ "customText": "5h ",
105
+ "color": "brightBlack",
106
+ "merge": "no-padding",
107
+ "metadata": {
108
+ "hide": "merge-target-hidden"
109
+ }
110
+ },
111
+ {
112
+ "id": "l4-5h",
113
+ "type": "session-usage",
114
+ "color": "brightGreen",
115
+ "rawValue": true,
116
+ "metadata": {
117
+ "hide": "no-data"
118
+ }
119
+ },
120
+ {
121
+ "id": "l4-5hr-lbl",
122
+ "type": "custom-text",
123
+ "customText": "↻ ",
124
+ "color": "brightBlack",
125
+ "merge": "no-padding",
126
+ "metadata": {
127
+ "hide": "merge-target-hidden"
128
+ }
129
+ },
130
+ {
131
+ "id": "l4-5hr",
132
+ "type": "reset-timer",
133
+ "color": "brightBlack",
134
+ "rawValue": true,
135
+ "metadata": {
136
+ "hide": "no-data"
137
+ }
138
+ },
139
+ {
140
+ "id": "l4-sep1",
141
+ "type": "separator",
142
+ "character": "|"
143
+ },
144
+ {
145
+ "id": "l4-wk-lbl",
146
+ "type": "custom-text",
147
+ "customText": "semana ",
148
+ "color": "brightBlack",
149
+ "merge": "no-padding",
150
+ "metadata": {
151
+ "hide": "merge-target-hidden"
152
+ }
153
+ },
154
+ {
155
+ "id": "l4-wk",
156
+ "type": "weekly-usage",
157
+ "color": "brightRed",
158
+ "rawValue": true,
159
+ "metadata": {
160
+ "hide": "no-data"
161
+ }
162
+ },
163
+ {
164
+ "id": "l4-wkr-lbl",
165
+ "type": "custom-text",
166
+ "customText": "↻ ",
167
+ "color": "brightBlack",
168
+ "merge": "no-padding",
169
+ "metadata": {
170
+ "hide": "merge-target-hidden"
171
+ }
172
+ },
173
+ {
174
+ "id": "l4-wkr",
175
+ "type": "weekly-reset-timer",
176
+ "color": "brightBlack",
177
+ "rawValue": true,
178
+ "metadata": {
179
+ "hide": "no-data"
180
+ }
181
+ },
182
+ {
183
+ "id": "l4-flex",
184
+ "type": "flex-separator"
185
+ },
186
+ {
187
+ "id": "l4-date",
188
+ "type": "custom-command",
189
+ "color": "brightBlack",
190
+ "commandPath": "{{BARRA}} data",
191
+ "timeout": 1000
192
+ }
193
+ ]
194
+ ],
195
+ "flexMode": "full",
196
+ "colorLevel": 3,
197
+ "defaultPadding": " "
198
+ }
@@ -0,0 +1,127 @@
1
+ 'use strict';
2
+ // Barra de status do Claude Code do aluno (2.6.8): a mesma barra do Euriler (modelo, esforco,
3
+ // titulo da conversa, pasta, branch, contexto, cache, uso de 5 h e da semana, data), em qualquer
4
+ // terminal do Mac ou do Windows e dentro do app Auroq OS.
5
+ //
6
+ // O que faz, sempre no HOME do aluno (nunca na pasta do negocio):
7
+ // - copia o ccstatusline travado (MIT, sem dependencias) para ~/.auroq/barra/ccstatusline;
8
+ // - grava ~/.auroq/barra/barra.cjs (quem roda a cada pintura) e o layout ccstatusline.json;
9
+ // - liga `statusLine` no ~/.claude/settings.json, mexendo so nessa chave.
10
+ // Nunca troca uma barra que o aluno ja tinha. Ocupa o lugar so quando ele esta vazio, quando ja e
11
+ // a nossa ou quando e o leitor de uso do app Auroq OS/Orca (que nao desenha nada; a barra repassa
12
+ // o JSON para ele). Se o aluno tirar a barra depois, ela nao volta. `~/.auroq/sem-barra` desliga.
13
+ const fs = require('node:fs');
14
+ const os = require('node:os');
15
+ const path = require('node:path');
16
+ const crypto = require('node:crypto');
17
+
18
+ const VERSAO_CCSTATUSLINE = '2.2.30';
19
+ const AQUI = __dirname;
20
+
21
+ const ehNossa = comando => /[\\/]\.auroq[\\/]barra[\\/]barra\.cjs/.test(comando);
22
+ const ehDoApp = comando => /agent-hooks[\\/]+claude-statusline/.test(comando);
23
+ const sha = texto => crypto.createHash('sha256').update(texto).digest('hex');
24
+
25
+ function gravarAtomico(arquivo, conteudo) {
26
+ const tmp = `${arquivo}.${process.pid}.tmp`;
27
+ fs.writeFileSync(tmp, conteudo);
28
+ fs.renameSync(tmp, arquivo);
29
+ }
30
+
31
+ function lerJson(arquivo) {
32
+ try {
33
+ return JSON.parse(fs.readFileSync(arquivo, 'utf8').replace(/^/, ''));
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ function origemPadrao() {
40
+ return path.dirname(require.resolve('ccstatusline/package.json'));
41
+ }
42
+
43
+ function copiarMotor(origem, destino) {
44
+ const versao = lerJson(path.join(origem, 'package.json'))?.version;
45
+ if (versao !== VERSAO_CCSTATUSLINE) throw new Error(`ccstatusline ${versao || 'ausente'} no pacote; esperado ${VERSAO_CCSTATUSLINE}`);
46
+ const jaTem = lerJson(path.join(destino, 'package.json'))?.version === VERSAO_CCSTATUSLINE
47
+ && fs.existsSync(path.join(destino, 'dist', 'ccstatusline.js'));
48
+ if (jaTem) return false;
49
+ // Monta ao lado e troca de uma vez: uma sessao aberta nunca le o motor pela metade.
50
+ const novo = `${destino}.novo-${process.pid}`;
51
+ fs.rmSync(novo, { recursive: true, force: true });
52
+ fs.mkdirSync(path.join(novo, 'dist'), { recursive: true });
53
+ for (const arquivo of ['package.json', 'LICENSE', path.join('dist', 'ccstatusline.js')]) {
54
+ if (fs.existsSync(path.join(origem, arquivo))) fs.copyFileSync(path.join(origem, arquivo), path.join(novo, arquivo));
55
+ }
56
+ const velho = `${destino}.velho-${process.pid}`;
57
+ try {
58
+ if (fs.existsSync(destino)) fs.renameSync(destino, velho);
59
+ fs.renameSync(novo, destino);
60
+ } catch {
61
+ // Windows com o motor aberto por outra sessao: copia por cima.
62
+ if (fs.existsSync(velho) && !fs.existsSync(destino)) fs.renameSync(velho, destino);
63
+ fs.cpSync(novo, destino, { recursive: true, force: true });
64
+ }
65
+ fs.rmSync(novo, { recursive: true, force: true });
66
+ fs.rmSync(velho, { recursive: true, force: true });
67
+ return true;
68
+ }
69
+
70
+ function instalarBarra({
71
+ home = os.homedir(),
72
+ claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(home, '.claude'),
73
+ origem = null,
74
+ } = {}) {
75
+ if (fs.existsSync(path.join(home, '.auroq', 'sem-barra'))) return { estado: 'desligada' };
76
+
77
+ const pasta = path.join(home, '.auroq', 'barra');
78
+ const script = path.join(pasta, 'barra.cjs').split(path.sep).join('/');
79
+ // Aspas servem ao cmd.exe e aos shells POSIX; caminho com aspas, $, crase ou quebra de linha fica de fora.
80
+ if (/["\r\n`$%]/.test(script)) return { estado: 'caminho-nao-suportado', detalhe: script };
81
+ const comando = `node "${script}"`;
82
+
83
+ fs.mkdirSync(pasta, { recursive: true });
84
+ const motorNovo = copiarMotor(origem || origemPadrao(), path.join(pasta, 'ccstatusline'));
85
+ gravarAtomico(path.join(pasta, 'barra.cjs'), fs.readFileSync(path.join(AQUI, 'barra.cjs')));
86
+
87
+ // Layout: o nosso, a menos que o aluno tenha mexido no que gravamos da ultima vez.
88
+ const registroPath = path.join(pasta, 'instalacao.json');
89
+ const registro = lerJson(registroPath) || {};
90
+ const layoutPath = path.join(pasta, 'ccstatusline.json');
91
+ const layout = fs.readFileSync(path.join(AQUI, 'ccstatusline.json'), 'utf8').split('{{BARRA}}').join(comando.replace(/"/g, '\\"'));
92
+ const layoutAtual = fs.existsSync(layoutPath) ? fs.readFileSync(layoutPath, 'utf8') : null;
93
+ const layoutDoAluno = layoutAtual !== null && registro.layoutSha && sha(layoutAtual) !== registro.layoutSha && sha(layoutAtual) !== sha(layout);
94
+ if (!layoutDoAluno && layoutAtual !== layout) gravarAtomico(layoutPath, layout);
95
+
96
+ const settingsPath = path.join(claudeDir, 'settings.json');
97
+ let settings = {};
98
+ if (fs.existsSync(settingsPath)) {
99
+ settings = lerJson(settingsPath);
100
+ if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
101
+ return { estado: 'settings-ilegivel', detalhe: settingsPath };
102
+ }
103
+ }
104
+ const atual = settings.statusLine && typeof settings.statusLine.command === 'string' ? settings.statusLine.command : '';
105
+ let estado;
106
+ if (!atual) estado = registro.ligadaEm ? 'tirada-pelo-aluno' : 'ligada';
107
+ else if (ehNossa(atual)) estado = 'em-dia';
108
+ else if (ehDoApp(atual)) estado = 'ligada';
109
+ else estado = 'barra-do-aluno';
110
+
111
+ const desejada = { type: 'command', command: comando, padding: 0, refreshInterval: 10 };
112
+ if (estado === 'ligada' || (estado === 'em-dia' && JSON.stringify(settings.statusLine) !== JSON.stringify({ ...settings.statusLine, ...desejada }))) {
113
+ fs.mkdirSync(claudeDir, { recursive: true });
114
+ gravarAtomico(settingsPath, `${JSON.stringify({ ...settings, statusLine: { ...(estado === 'em-dia' ? settings.statusLine : {}), ...desejada } }, null, 2)}\n`);
115
+ if (estado === 'em-dia') estado = 'atualizada';
116
+ }
117
+
118
+ const novoRegistro = {
119
+ versaoCcstatusline: VERSAO_CCSTATUSLINE,
120
+ layoutSha: layoutDoAluno ? registro.layoutSha : sha(layout),
121
+ ligadaEm: registro.ligadaEm || (estado === 'ligada' ? new Date().toISOString() : undefined),
122
+ };
123
+ gravarAtomico(registroPath, `${JSON.stringify(novoRegistro, null, 2)}\n`);
124
+ return { estado, comando, motorNovo, layoutDoAluno: Boolean(layoutDoAluno) };
125
+ }
126
+
127
+ module.exports = { instalarBarra, ehNossa, ehDoApp, VERSAO_CCSTATUSLINE };
@@ -2,7 +2,7 @@
2
2
  "schema": 1,
3
3
  "algorithm": "sha256",
4
4
  "scope": "packaged-runtime-and-cascas",
5
- "version": "2.6.7",
5
+ "version": "2.6.9",
6
6
  "files": [
7
7
  {
8
8
  "path": ".auroq-core/constitution.md",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  {
12
12
  "path": ".auroq-core/core-config.yaml",
13
- "sha256": "59ba6487bbd6defc87ccda7d174503c8d18af089e284b61cb6f202a646778548"
13
+ "sha256": "619e43f8d9e495c48269650e1e96b52f70d455d277fd3251d2c5f17a81ef7a69"
14
14
  },
15
15
  {
16
16
  "path": ".auroq-core/core/synapse/context/context-builder.js",
@@ -210,7 +210,7 @@
210
210
  },
211
211
  {
212
212
  "path": "bin/auroq-os.js",
213
- "sha256": "3ba86acde44b47edfae407e328500855eaa86281b0429da1717d517a0a7e56a3"
213
+ "sha256": "ed26b60a9309f55f5175cc8469c71e28f3bd58bcb60da05fae8dccbe92ac5892"
214
214
  },
215
215
  {
216
216
  "path": "lib/ahi/client.mjs",
@@ -218,7 +218,7 @@
218
218
  },
219
219
  {
220
220
  "path": "lib/ahi/historico.mjs",
221
- "sha256": "cb85e53dae59e793bdb83f59c3f8d14342912953b43dd9408d757a7b7182733a"
221
+ "sha256": "909c0d0b5f6c19a75d1c278b639e107d8f29efb015aac91464b3168d23388556"
222
222
  },
223
223
  {
224
224
  "path": "lib/ahi/install.cjs",
@@ -228,6 +228,18 @@
228
228
  "path": "lib/auth.js",
229
229
  "sha256": "5f1ddefbf2d4b9005e562380b40525e5bf823641e05a7bdb71568e15a5179869"
230
230
  },
231
+ {
232
+ "path": "lib/barra/barra.cjs",
233
+ "sha256": "30fa51fd3561b8da7e17dd9b35fd55739d0a33d358dbbd99583f6b0eec1b576e"
234
+ },
235
+ {
236
+ "path": "lib/barra/ccstatusline.json",
237
+ "sha256": "590573ff67c95cac2294f987789a4646cca6ccf0e85bc558fa6af22d0608296e"
238
+ },
239
+ {
240
+ "path": "lib/barra/index.js",
241
+ "sha256": "a72edfd62af60bfb5b314300a618cbb3fc8e7e30b9092ecb83ff366a776fee90"
242
+ },
231
243
  {
232
244
  "path": "lib/codex-windows.cjs",
233
245
  "sha256": "d6307d0106bad3e69142052d6450cef3f6252544049d3f3340aec55fc99005d1"
@@ -262,7 +274,7 @@
262
274
  },
263
275
  {
264
276
  "path": "package.json",
265
- "sha256": "cce3f831abf590fffbd6af0356a6b0899b17ba7f8a5964dcfced577637e3be19"
277
+ "sha256": "ffc469c06ce3d8b5ac8c1353e3cbf412169dd420b8de3341ee4e648effc96768"
266
278
  },
267
279
  {
268
280
  "path": "scripts/build-pack.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auroq-os",
3
- "version": "2.6.7",
3
+ "version": "2.6.9",
4
4
  "arcaneMcpPin": "0.7.0",
5
5
  "description": "Auroq OS — Sistema Operacional de IA para Experts",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "auroq:sync:codex:check": "npm run sync:codex:check",
20
20
  "auroq:validate": "npm run validate:hybrid",
21
21
  "validate:hybrid": "node scripts/validate-hybrid.mjs",
22
- "lint": "node --check bin/auroq-os.js && node --check lib/auth.js && node --check lib/diagnostico.js && node --check lib/credentials.js && node --check lib/onepassword.js && node --check lib/supabase.js && node --check scripts/sync-codex-skills.mjs && node --check scripts/validate-hybrid.mjs && node --check scripts/prepack-casca.mjs && node --check scripts/postpack-casca.mjs && node --check scripts/assert-mcp-pin.mjs && node --check lib/telemetry.mjs && node --check scripts/synapse-hashes.mjs && node --check lib/ahi/historico.mjs && node --check .claude/hooks/ahi-capture.cjs && node --check .claude/hooks/ahi/security.cjs && node --check .claude/hooks/ahi/runtime.cjs && node --check .claude/hooks/ahi/worker.cjs && node --check lib/ahi/install.cjs && node --check lib/codex-windows.cjs && node --check .claude/hooks/ahi/auth-config.cjs && node --check lib/ahi/client.mjs && node --check scripts/build-pack.mjs && node --check scripts/assert-native-release.mjs && node --check scripts/runtime-integrity.mjs && node --check scripts/pack-state.mjs",
22
+ "lint": "node --check bin/auroq-os.js && node --check lib/barra/index.js && node --check lib/barra/barra.cjs && node --check lib/auth.js && node --check lib/diagnostico.js && node --check lib/credentials.js && node --check lib/onepassword.js && node --check lib/supabase.js && node --check scripts/sync-codex-skills.mjs && node --check scripts/validate-hybrid.mjs && node --check scripts/prepack-casca.mjs && node --check scripts/postpack-casca.mjs && node --check scripts/assert-mcp-pin.mjs && node --check lib/telemetry.mjs && node --check scripts/synapse-hashes.mjs && node --check lib/ahi/historico.mjs && node --check .claude/hooks/ahi-capture.cjs && node --check .claude/hooks/ahi/security.cjs && node --check .claude/hooks/ahi/runtime.cjs && node --check .claude/hooks/ahi/worker.cjs && node --check lib/ahi/install.cjs && node --check lib/codex-windows.cjs && node --check .claude/hooks/ahi/auth-config.cjs && node --check lib/ahi/client.mjs && node --check scripts/build-pack.mjs && node --check scripts/assert-native-release.mjs && node --check scripts/runtime-integrity.mjs && node --check scripts/pack-state.mjs",
23
23
  "typecheck": "npm run validate:hybrid",
24
24
  "test": "node --test tests/*.test.mjs",
25
25
  "release:verify": "node scripts/assert-mcp-pin.mjs && node scripts/assert-native-release.mjs",
@@ -57,6 +57,7 @@
57
57
  ],
58
58
  "dependencies": {
59
59
  "@supabase/supabase-js": "^2.103.0",
60
+ "ccstatusline": "2.2.30",
60
61
  "fs-extra": "^11.3.0",
61
62
  "js-yaml": "^4.3.2",
62
63
  "prompts": "^2.4.2"