auroq-os 2.6.6 → 2.6.8

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.6
4
+ version: 2.6.8
5
5
  installedAt: '2026-03-16'
6
6
 
7
7
  ide:
@@ -53,11 +53,15 @@ function safePath(file) {
53
53
  cursor = path.dirname(cursor);
54
54
  }
55
55
  }
56
- function powershell(script, input) {
56
+ // Windows only. The vault logic lives in win-vault.ps1, shipped as plain readable text next to this file:
57
+ // no encoded command, no script text built here. Data goes through stdin as UTF-8; the answer is hex on stdout.
58
+ // The script is started by relative name from its own folder, so quotes, brackets or apostrophes in the
59
+ // student's folder names never reach the PowerShell command line.
60
+ function powershell(action, input) {
57
61
  // Windows PowerShell 5.1 must build its own module path when launched through Node/pwsh 7.
58
62
  // Keep the caller's environment unchanged, including differently cased Windows names.
59
63
  const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => name.toLowerCase() !== 'psmodulepath'));
60
- const result = spawnSync('powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(`$ErrorActionPreference='Stop'; $PSModuleAutoLoadingPreference='None'; ${script}`, 'utf16le').toString('base64')], { input, env, encoding: 'utf8', timeout: 5000, windowsHide: true, maxBuffer: 65536 });
64
+ const result = spawnSync('powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', '.\\win-vault.ps1', action], { cwd: __dirname, input, env, encoding: 'utf8', timeout: 5000, windowsHide: true, maxBuffer: 65536 });
61
65
  if (result.status !== 0 || result.error) throw new Error('SECURE_STORAGE_UNAVAILABLE');
62
66
  return result.stdout.trim();
63
67
  }
@@ -65,10 +69,10 @@ function protectMany(dirs) {
65
69
  const unique = [...new Set(dirs)]; if (!unique.length) return;
66
70
  for (const dir of unique) { safePath(dir); fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); }
67
71
  if (process.platform === 'win32') {
68
- // Core .NET APIs avoid the variable cold cost of preparing PowerShell cmdlet modules.
72
+ // Core .NET APIs (win-vault.ps1) avoid the variable cold cost of preparing PowerShell cmdlet modules.
69
73
  // Keep the exact same private DACL: current owner + SYSTEM, no inherited external access.
70
- const encoded = unique.map(dir => `'${Buffer.from(dir).toString('base64')}'`).join(',');
71
- powershell(`$sid=[Security.Principal.WindowsIdentity]::GetCurrent().User; foreach($encoded in @(${encoded})){ $p=[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($encoded)); $acl=[Security.AccessControl.DirectorySecurity]::new(); $acl.SetOwner($sid); $acl.SetAccessRuleProtection($true,$false); foreach($s in @($sid,[Security.Principal.SecurityIdentifier]::new('S-1-5-18'))){ $rule=[Security.AccessControl.FileSystemAccessRule]::new($s,[Security.AccessControl.FileSystemRights]::FullControl,[Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit',[Security.AccessControl.PropagationFlags]::None,[Security.AccessControl.AccessControlType]::Allow); [void]$acl.AddAccessRule($rule) }; [void][IO.Directory]::SetAccessControl($p,$acl) }`);
74
+ // The script confirms with "ok <count>": an empty or truncated .ps1 exits 0 without doing anything, and must not pass for success.
75
+ if (powershell('protect', unique.map(dir => path.resolve(dir)).join('\n')) !== `ok ${unique.length}`) throw new Error('SECURE_STORAGE_UNAVAILABLE');
72
76
  } else {
73
77
  for (const dir of unique) {
74
78
  fs.chmodSync(dir, 0o700);
@@ -119,14 +123,19 @@ function keyFor(ctx, create = false) {
119
123
  const file = path.join(ctx.accountDir, 'key.dpapi');
120
124
  if (!fs.existsSync(file)) {
121
125
  if (!create) throw new Error('SECURE_STORAGE_UNAVAILABLE');
122
- const wrapped = powershell("[void][Reflection.Assembly]::Load('System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'); $b=[byte[]]::new(32); $rng=[Security.Cryptography.RandomNumberGenerator]::Create(); try { $rng.GetBytes($b); [Console]::Write([Convert]::ToBase64String([Security.Cryptography.ProtectedData]::Protect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser))) } finally { $rng.Dispose(); [Array]::Clear($b,0,$b.Length) }");
126
+ const created = powershell('create-key');
127
+ if (!/^(?:[a-f0-9]{2})+$/.test(created)) throw new Error('SECURE_STORAGE_UNAVAILABLE');
128
+ const wrapped = Buffer.from(created, 'hex').toString('base64');
123
129
  if (!/^[A-Za-z0-9+/]+={0,2}$/.test(wrapped) || Buffer.from(wrapped, 'base64').length < 32) throw new Error('SECURE_STORAGE_UNAVAILABLE');
124
130
  try { atomic(file, wrapped, true); } catch (e) { if (e.code !== 'EEXIST') throw e; }
125
131
  }
126
132
  safePath(file);
127
- const wrapped = fs.readFileSync(file, 'utf8');
128
- const raw = powershell("[void][Reflection.Assembly]::Load('System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'); $b=[Convert]::FromBase64String([Console]::In.ReadToEnd().Trim()); $plain=[Security.Cryptography.ProtectedData]::Unprotect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser); try { [Console]::Write([Convert]::ToBase64String($plain)) } finally { [Array]::Clear($plain,0,$plain.Length) }", wrapped);
129
- const key = Buffer.from(raw, 'base64'); if (key.length !== 32) throw new Error('SECURE_STORAGE_UNAVAILABLE'); return key;
133
+ // key.dpapi keeps its original format: the DPAPI blob as base64 text. Only hex goes through the PowerShell side.
134
+ const wrapped = fs.readFileSync(file, 'utf8').trim();
135
+ if (wrapped.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(wrapped)) throw new Error('SECURE_STORAGE_UNAVAILABLE');
136
+ const raw = powershell('open-key', Buffer.from(wrapped, 'base64').toString('hex'));
137
+ if (!/^[a-f0-9]{64}$/.test(raw)) throw new Error('SECURE_STORAGE_UNAVAILABLE');
138
+ return Buffer.from(raw, 'hex');
130
139
  }
131
140
  throw new Error('UNSUPPORTED_OS_KEYSTORE');
132
141
  }
@@ -0,0 +1,102 @@
1
+ # win-vault.ps1 - cofre local do Auroq OS no Windows (captura AHI).
2
+ #
3
+ # Faz so isto, no computador do proprio aluno, e nada mais:
4
+ # protect deixa as pastas recebidas privadas: so o dono da conta do Windows e o SISTEMA
5
+ # acessam, sem heranca de permissao de fora.
6
+ # create-key gera uma chave aleatoria de 32 bytes e a protege com o DPAPI do Windows
7
+ # (escopo do usuario atual: so este usuario, neste computador, consegue abrir).
8
+ # open-key abre com o DPAPI uma chave que o create-key protegeu antes.
9
+ #
10
+ # Nao acessa a rede, nao baixa nem executa codigo de fora, nao inicia outros programas e nao grava
11
+ # arquivo nenhum: so troca a permissao das pastas recebidas (protect) ou escreve o resultado na
12
+ # saida padrao. Quem chama e o security.cjs, desta mesma pasta, por -File, passando a acao como
13
+ # argumento. Os dados entram por stdin em UTF-8 (uma pasta por linha em protect; a chave protegida
14
+ # em hex em open-key) e a resposta sai por stdout: "ok N" em protect (N pastas protegidas) e a chave
15
+ # em hex nas outras duas. Qualquer erro, ou resposta fora desse formato, e tratado pelo security.cjs
16
+ # como cofre indisponivel (falha fechada).
17
+ #
18
+ # Usa so a API do .NET, sem cmdlets: preparar os modulos do PowerShell numa maquina fria passava
19
+ # do limite de 5 segundos do security.cjs.
20
+ param([string]$Action)
21
+
22
+ $ErrorActionPreference = 'Stop'
23
+ $PSModuleAutoLoadingPreference = 'None'
24
+
25
+ # stdin em bytes crus, lidos como UTF-8: o console do Windows usa outra codificacao (OEM) e
26
+ # estragaria o acento no nome da pasta do aluno.
27
+ function Get-StdinText {
28
+ $stream = [Console]::OpenStandardInput()
29
+ $buffer = [IO.MemoryStream]::new()
30
+ try { $stream.CopyTo($buffer) } finally { $stream.Dispose() }
31
+ return [Text.UTF8Encoding]::new($false).GetString($buffer.ToArray())
32
+ }
33
+
34
+ function ConvertTo-Hex([byte[]]$Bytes) {
35
+ return [BitConverter]::ToString($Bytes).Replace('-', '').ToLowerInvariant()
36
+ }
37
+
38
+ function ConvertFrom-Hex([string]$Hex) {
39
+ if ($Hex.Length -eq 0 -or ($Hex.Length % 2) -ne 0) { throw 'hex invalido' }
40
+ $bytes = [byte[]]::new([int]($Hex.Length / 2))
41
+ for ($i = 0; $i -lt $bytes.Length; $i++) { $bytes[$i] = [Convert]::ToByte($Hex.Substring(2 * $i, 2), 16) }
42
+ return , $bytes
43
+ }
44
+
45
+ function Protect-Folders([string]$Text) {
46
+ $owner = [Security.Principal.WindowsIdentity]::GetCurrent().User
47
+ $system = [Security.Principal.SecurityIdentifier]::new('S-1-5-18')
48
+ $count = 0
49
+ foreach ($line in $Text.Split([char[]]@([char]10), [StringSplitOptions]::RemoveEmptyEntries)) {
50
+ $folder = $line.TrimEnd([char]13)
51
+ if ($folder.Length -eq 0) { continue }
52
+ # Caminho relativo seria resolvido a partir da pasta do hook, nao da pasta do aluno.
53
+ if (-not [IO.Path]::IsPathRooted($folder)) { throw 'caminho nao absoluto' }
54
+ $acl = [Security.AccessControl.DirectorySecurity]::new()
55
+ $acl.SetOwner($owner)
56
+ $acl.SetAccessRuleProtection($true, $false)
57
+ foreach ($who in @($owner, $system)) {
58
+ $rule = [Security.AccessControl.FileSystemAccessRule]::new($who, [Security.AccessControl.FileSystemRights]::FullControl, [Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit', [Security.AccessControl.PropagationFlags]::None, [Security.AccessControl.AccessControlType]::Allow)
59
+ [void]$acl.AddAccessRule($rule)
60
+ }
61
+ [void][IO.Directory]::SetAccessControl($folder, $acl)
62
+ $count++
63
+ }
64
+ if ($count -eq 0) { throw 'nenhuma pasta recebida' }
65
+ [Console]::Write("ok $count")
66
+ }
67
+
68
+ function Import-DpapiAssembly {
69
+ [void][Reflection.Assembly]::Load('System.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
70
+ }
71
+
72
+ function New-ProtectedKey {
73
+ Import-DpapiAssembly
74
+ $key = [byte[]]::new(32)
75
+ $random = [Security.Cryptography.RandomNumberGenerator]::Create()
76
+ try {
77
+ $random.GetBytes($key)
78
+ $wrapped = [Security.Cryptography.ProtectedData]::Protect($key, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
79
+ [Console]::Write((ConvertTo-Hex $wrapped))
80
+ } finally {
81
+ $random.Dispose()
82
+ [Array]::Clear($key, 0, $key.Length)
83
+ }
84
+ }
85
+
86
+ function Open-ProtectedKey([string]$Text) {
87
+ Import-DpapiAssembly
88
+ $wrapped = ConvertFrom-Hex $Text.Trim()
89
+ $key = [Security.Cryptography.ProtectedData]::Unprotect($wrapped, $null, [Security.Cryptography.DataProtectionScope]::CurrentUser)
90
+ try {
91
+ [Console]::Write((ConvertTo-Hex $key))
92
+ } finally {
93
+ [Array]::Clear($key, 0, $key.Length)
94
+ }
95
+ }
96
+
97
+ switch ($Action) {
98
+ 'protect' { Protect-Folders (Get-StdinText) }
99
+ 'create-key' { New-ProtectedKey }
100
+ 'open-key' { Open-ProtectedKey (Get-StdinText) }
101
+ default { throw 'acao desconhecida' }
102
+ }
@@ -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.8 — 2026-10-16
2
+
3
+ ### Barra de status do Claude Code igual à do Euriler
4
+
5
+ - 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.
6
+ - 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`.
7
+ - 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.
8
+ - 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.
9
+ - Qualquer falha da barra vira aviso na instalação e barra vazia na tela; o resto do sistema segue igual.
10
+ - 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.
11
+ - Mantem `arcane-mcp@0.7.0`. Instaladores do repositorio preparados para 2.6.8.
12
+
13
+ ## 2.6.7 — 2026-10-16
14
+
15
+ ### Antivírus Kaspersky não bloqueia mais a atualização no Windows
16
+
17
+ - Uma aluna com Kaspersky não conseguiu atualizar: o antivírus barrou o arquivo `security.cjs` do cofre local da captura (alerta "Cavalo de Troia", análise heurística) e a instalação parou. Era falso positivo, mas o jeito de chamar o PowerShell lembrava um programa malicioso: o comando ia embaralhado em base64, e o mesmo arquivo trocava permissões de pasta.
18
+ - Agora o PowerShell roda um script legível e versionado, `.claude/hooks/ahi/win-vault.ps1`, chamado por arquivo. Caminhos e dados vão por entrada padrão, nada embaralhado na linha de comando. O arquivo tem comentário dizendo tudo o que faz: deixa as pastas do AHI privadas (dono + SISTEMA, sem herança) e protege a chave local com o DPAPI do Windows. Não usa rede, não baixa nada e não executa texto de fora.
19
+ - Segurança igual à anterior: mesma permissão privada, mesma proteção DPAPI do usuário atual, limite de 5 segundos e falha fechada (sem cofre, nada é gravado). O `key.dpapi` mantém o formato; quem já tinha chave guardada continua abrindo e a chave nova abre nas versões antigas.
20
+ - A manutenção (`atualiza o sistema`) leva o `win-vault.ps1` junto, antes do `security.cjs`, e o inventário de integridade passa a exigi-lo.
21
+ - Testes novos (`tests/ahi-windows-vault.test.mjs`): nenhum arquivo publicado pode voltar a usar comando do PowerShell em base64; o script é ASCII, sem rede e sem base64; o contrato com o PowerShell (argumentos, pasta, entrada, falha fechada); no Windows de verdade, compatibilidade do `key.dpapi` nos dois sentidos e pastas com apóstrofo, colchetes e acento.
22
+ - Mantem `arcane-mcp@0.7.0`. Instaladores do repositorio preparados para 2.6.7.
23
+
1
24
  ## 2.6.6 — 2026-10-03
2
25
 
3
26
  ### Squad Edição Euriliana no Pack
package/README.md CHANGED
@@ -246,13 +246,13 @@ agents/ → Seu exercito (companion, workers, minds, squads)
246
246
 
247
247
  ## Observabilidade e integridade do motor
248
248
 
249
- Apos publicacao, `npx -y auroq-os@2.6.6 doctor` mostra a fila local segura e os comandos pinados de
250
- manutencao/diagnostico. `npx -y auroq-os@2.6.6 manutencao` preserva o caminho existente
249
+ Apos publicacao, `npx -y auroq-os@2.6.8 doctor` mostra a fila local segura e os comandos pinados de
250
+ manutencao/diagnostico. `npx -y auroq-os@2.6.8 manutencao` preserva o caminho existente
251
251
  de consentimento legado, studentFiles, customizacoes e dados do negocio. Nao ha
252
252
  migracao forcada. O registro MCP aponta para `arcane-mcp@0.7.0` — o pin mora no campo
253
253
  `arcaneMcpPin` do package.json (fonte unica; o servidor le o mesmo campo no npm).
254
254
  `npm run release:verify` recusa publicar com um pin que o npm nao resolva.
255
- Os instaladores do repositorio ficam preparados para 2.6.6; as copias publicas so recebem
255
+ Os instaladores do repositorio ficam preparados para 2.6.8; as copias publicas so recebem
256
256
  a versao apos os gates nativos e a verificacao do tarball publicado.
257
257
  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
258
 
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,10 +1768,12 @@ 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',
1751
1775
  '.claude/hooks/ahi-capture.cjs',
1776
+ '.claude/hooks/ahi/win-vault.ps1', // 2.6.7 — antes do security.cjs, que o chama
1752
1777
  '.claude/hooks/ahi/security.cjs',
1753
1778
  '.claude/hooks/ahi/runtime.cjs',
1754
1779
  '.claude/hooks/ahi/worker.cjs',
@@ -2069,6 +2094,8 @@ async function init({ pasta = null, maintenance = false, modoAgente = false, mig
2069
2094
  step('Protegendo segredos...');
2070
2095
  await applySecretProtections(targetDir);
2071
2096
 
2097
+ ligarBarraDeStatus();
2098
+
2072
2099
  // ─── Fase 7: Health check rapido
2073
2100
  step('Verificando integridade...');
2074
2101
  await runHealthChecks(targetDir);
@@ -2252,6 +2279,8 @@ async function clone(repoArg) {
2252
2279
  step('Protegendo segredos...');
2253
2280
  await applySecretProtections(destDir);
2254
2281
 
2282
+ ligarBarraDeStatus();
2283
+
2255
2284
  // ─── Fase 6: Dependencias (nao viajam no git — de proposito)
2256
2285
  step('Instalando dependencias...');
2257
2286
  try {
@@ -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.6 check-access
592
+ & (Get-AuroqNpx) -y auroq-os@2.6.8 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.6 instalar
680
+ & (Get-AuroqNpx) -y auroq-os@2.6.8 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.6 "$@"
222
+ npx -y auroq-os@2.6.8 "$@"
223
223
  else
224
- npx -y auroq-os@2.6.6 "$@" < /dev/tty
224
+ npx -y auroq-os@2.6.8 "$@" < /dev/tty
225
225
  fi
226
226
  }
227
227
 
@@ -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.6",
5
+ "version": "2.6.8",
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": "ebd8a96492b433bd4b37475920233989ec2a69f383d67f4af1e130e6e52cc052"
13
+ "sha256": "1a2d275b50ead64cb01a6befd9b070a545ec957e4738caff8121df7284eb4a4a"
14
14
  },
15
15
  {
16
16
  "path": ".auroq-core/core/synapse/context/context-builder.js",
@@ -178,7 +178,11 @@
178
178
  },
179
179
  {
180
180
  "path": ".claude/hooks/ahi/security.cjs",
181
- "sha256": "dc27db1392acd0abd8102490860bfad6a94276bbc92f63e086dc997dbe6b208c"
181
+ "sha256": "ff8b4f7069a0a17506e4ea75aeb6cc0fd40cebe350e2e59048372380f059a3c6"
182
+ },
183
+ {
184
+ "path": ".claude/hooks/ahi/win-vault.ps1",
185
+ "sha256": "b3332d3387ed2eea0990bd589cdf0213623e7e30b4daa187bb2930948bbdac29"
182
186
  },
183
187
  {
184
188
  "path": ".claude/hooks/ahi/worker.cjs",
@@ -206,7 +210,7 @@
206
210
  },
207
211
  {
208
212
  "path": "bin/auroq-os.js",
209
- "sha256": "793af8782292df5d108944ec1696b46a028455fef9c6d62b800a51e731ace1c6"
213
+ "sha256": "dd043094b3b7999bd96e6de9d62f176530b88b287861c865b498be90469290a5"
210
214
  },
211
215
  {
212
216
  "path": "lib/ahi/client.mjs",
@@ -224,6 +228,18 @@
224
228
  "path": "lib/auth.js",
225
229
  "sha256": "5f1ddefbf2d4b9005e562380b40525e5bf823641e05a7bdb71568e15a5179869"
226
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
+ },
227
243
  {
228
244
  "path": "lib/codex-windows.cjs",
229
245
  "sha256": "d6307d0106bad3e69142052d6450cef3f6252544049d3f3340aec55fc99005d1"
@@ -258,7 +274,7 @@
258
274
  },
259
275
  {
260
276
  "path": "package.json",
261
- "sha256": "e595250e2aec2457f0017693cbe86ec291bc2f764e9da8c7af762c455e67cd4e"
277
+ "sha256": "c1425f8e2aad837ac27f75503c376c19fbb0787d7dcec19bbc1bc5456dcc5a34"
262
278
  },
263
279
  {
264
280
  "path": "scripts/build-pack.mjs",
@@ -278,7 +294,7 @@
278
294
  },
279
295
  {
280
296
  "path": "scripts/runtime-integrity.mjs",
281
- "sha256": "af0cb75622dcf4c049da3fc053817087648a86fc31df3be4762e974279eb87a3"
297
+ "sha256": "d2d6d30fa3a288c019a4f7e6d06ba25742775258e5631466e48a9aeb55d030c5"
282
298
  },
283
299
  {
284
300
  "path": "scripts/sync-codex-skills.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auroq-os",
3
- "version": "2.6.6",
3
+ "version": "2.6.8",
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"
@@ -27,7 +27,7 @@ export const REQUIRED_FILES = [
27
27
  '.claude/commands/AuroqOS/agents/ops.md', '.claude/commands/auroq-companion.md',
28
28
  '.claude/hooks/synapse-engine.cjs', '.claude/hooks/auroq-sync.cjs',
29
29
  '.claude/hooks/ahi-capture.cjs', '.claude/hooks/ahi/runtime.cjs',
30
- '.claude/hooks/ahi/security.cjs', '.claude/hooks/ahi/worker.cjs', '.claude/hooks/ahi/auth-config.cjs',
30
+ '.claude/hooks/ahi/security.cjs', '.claude/hooks/ahi/win-vault.ps1', '.claude/hooks/ahi/worker.cjs', '.claude/hooks/ahi/auth-config.cjs',
31
31
  ];
32
32
  const PROTECTED_TREES = ['lib/', '.auroq-core/core/synapse/', '.claude/hooks/'];
33
33
  const FORBIDDEN_PREFIXES = ['business/', 'docs/knowledge/', 'casca/', '.git/', '.pack-casca-backup/'];