auroq-os 2.6.7 → 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.
- package/.auroq-core/core-config.yaml +1 -1
- package/.claude/rules/titulo-da-barra.md +9 -0
- package/CHANGELOG.md +12 -0
- package/README.md +3 -3
- package/bin/auroq-os.js +28 -0
- package/installer/install.ps1 +2 -2
- package/installer/install.sh +2 -2
- package/lib/barra/barra.cjs +149 -0
- package/lib/barra/ccstatusline.json +198 -0
- package/lib/barra/index.js +127 -0
- package/lib/runtime-integrity.json +16 -4
- package/package.json +3 -2
|
@@ -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,15 @@
|
|
|
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
|
+
|
|
1
13
|
## 2.6.7 — 2026-10-16
|
|
2
14
|
|
|
3
15
|
### Antivírus Kaspersky não bloqueia mais a atualização no Windows
|
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.
|
|
250
|
-
manutencao/diagnostico. `npx -y auroq-os@2.6.
|
|
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.
|
|
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,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 {
|
package/installer/install.ps1
CHANGED
|
@@ -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.
|
|
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.
|
|
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.'
|
package/installer/install.sh
CHANGED
|
@@ -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.
|
|
222
|
+
npx -y auroq-os@2.6.8 "$@"
|
|
223
223
|
else
|
|
224
|
-
npx -y auroq-os@2.6.
|
|
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.
|
|
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": "
|
|
13
|
+
"sha256": "1a2d275b50ead64cb01a6befd9b070a545ec957e4738caff8121df7284eb4a4a"
|
|
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": "
|
|
213
|
+
"sha256": "dd043094b3b7999bd96e6de9d62f176530b88b287861c865b498be90469290a5"
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
"path": "lib/ahi/client.mjs",
|
|
@@ -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": "
|
|
277
|
+
"sha256": "c1425f8e2aad837ac27f75503c376c19fbb0787d7dcec19bbc1bc5456dcc5a34"
|
|
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.
|
|
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"
|