auroq-os 2.5.1 → 2.5.2

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.5.1
4
+ version: 2.5.2
5
5
  installedAt: '2026-03-16'
6
6
 
7
7
  ide:
@@ -3,6 +3,9 @@
3
3
  "allow": [],
4
4
  "deny": []
5
5
  },
6
+ "env": {
7
+ "MCP_TIMEOUT": "120000"
8
+ },
6
9
  "hooks": {
7
10
  "UserPromptSubmit": [
8
11
  {
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 2.5.2 — 2026-09-11
2
+
3
+ - **"UserPromptSubmit hook error ... hookEventName" a cada mensagem (EMB-040).** Quem instalou ate a 2.4.9 ficou com o Synapse antigo para sempre: a pasta era copiada sem sobrescrever e a correcao da 2.4.10 nunca chegava — o Claude Code recusava o pacote de regras em toda mensagem, enquanto a manutencao carimbava a versao nova. A manutencao agora troca todo arquivo do Synapse que seja uma versao oficial antiga (hashes das 90 versoes publicadas em `lib/synapse-hashes.json`) e guarda em `.auroq-core/preservado/synapse/` qualquer arquivo diferente de todas elas antes da troca. Integridade e `doctor` apontam o Synapse antigo em vez de dizer que esta tudo em dia.
4
+ - **MCP arcane com CONNECT_TIMEOUT no Claude Code (EMB-041).** O Claude Code desiste do conteudo ao vivo aos 30s; o npx a frio no Windows leva 44-77s. Instalar, manutencao, register-mcp e clone gravam `env.MCP_TIMEOUT = 120000` em `.claude/settings.local.json` (o Codex ja tinha 120s); o `doctor` cobra esse tempo.
5
+ - `.claude/settings.local.json` ilegivel deixa de virar `{}` (o aluno perdia os hooks): o original fica guardado ao lado e o arquivo volta a partir do modelo.
6
+ - Instaladores fixam 2.5.2. Correcao feita a partir da 2.5.1 publicada; o candidato de telemetria segue separado.
7
+
1
8
  ## 2.5.1 — 2026-09-04
2
9
 
3
10
  - Motor registra arcane-mcp 0.5.0: diagnostico de tentativas, erros, ambiente e reenvio apos falha de rede. Conteudo de conversas e arquivos nao e coletado. Instaladores fixam esta versao validada.
package/bin/auroq-os.js CHANGED
@@ -246,6 +246,11 @@ async function runHealthChecks(targetDir) {
246
246
  missing.push(`${label} (${file})`);
247
247
  }
248
248
  }
249
+ if (await synapseDesatualizado(targetDir)) {
250
+ // Aviso, nao trava: um clone de negocio antigo traz o arquivo velho pelo git e so a
251
+ // manutencao nesta maquina (ou na outra, depois entregue) troca.
252
+ warn('Synapse antigo nesta pasta (erro "hookEventName" a cada mensagem). Peca ao Ops: manutencao do motor.');
253
+ }
249
254
  if (passed === HEALTH_CHECKS.length) {
250
255
  success(`${passed}/${HEALTH_CHECKS.length} verificacoes OK`);
251
256
  } else {
@@ -280,6 +285,14 @@ async function runDoctor(targetDir) {
280
285
  error(`Arquivos do sistema: faltam ${faltando}`);
281
286
  problemas.push('Peca manutencao do motor ao Ops dentro do Claude Code pra repor o que falta.');
282
287
  }
288
+ if (!(await synapseRegistrado(targetDir))) {
289
+ error('O hook do Synapse nao esta registrado: as regras do sistema nao chegam ao modelo');
290
+ problemas.push('Rode: npx auroq-os@latest register-mcp na pasta (repoe o registro sem tirar nada seu). Depois feche e abra o Claude Code.');
291
+ }
292
+ if (await synapseDesatualizado(targetDir)) {
293
+ error('Synapse antigo: o Claude Code recusa as regras a cada mensagem ("hookEventName")');
294
+ problemas.push('Peca manutencao do motor ao Ops dentro do Claude Code (ou rode npx auroq-os@latest manutencao na pasta) pra trocar o Synapse antigo.');
295
+ }
283
296
 
284
297
  // 2. O motor — e, principalmente, se quem abre pelo icone vai enxergar ele.
285
298
  // Esta e a falha silenciosa do §5.4: no terminal funciona, no app nao, e
@@ -327,6 +340,15 @@ async function runDoctor(targetDir) {
327
340
  }
328
341
  if (pin) {
329
342
  success(`MCP arcane registrado no Claude Code (${pin})`);
343
+ let espera = NaN;
344
+ try {
345
+ const local = JSON.parse((await fs.readFile(path.join(targetDir, '.claude', 'settings.local.json'), 'utf8')).replace(/^\uFEFF/, ''));
346
+ espera = Number(local?.env?.MCP_TIMEOUT);
347
+ } catch { /* sem arquivo ou ilegivel = sem tempo de espera */ }
348
+ if (!(espera >= CLAUDE_MCP_TIMEOUT_MS)) {
349
+ error('O Claude Code esta com a espera padrao de 30s pelo conteudo ao vivo — no Windows a abertura pode cair (CONNECT_TIMEOUT)');
350
+ problemas.push('Rode: npx auroq-os@latest register-mcp (da ao Claude Code 2 minutos de espera). Depois feche e abra o Claude Code.');
351
+ }
330
352
  } else {
331
353
  error('MCP arcane nao registrado em .mcp.json');
332
354
  problemas.push('Rode: npx auroq-os register-mcp (reescreve o registro). Depois feche e abra o Claude Code.');
@@ -461,6 +483,10 @@ async function runDoctor(targetDir) {
461
483
  // pacote, (3) o doctor mede o arranque de verdade em vez de so olhar o registro.
462
484
  const ARCANE_MCP_PIN = 'arcane-mcp@0.5.0';
463
485
  const CODEX_MCP_STARTUP_SEC = 120;
486
+ // O Claude Code tambem desistia aos 30s (MCP_TIMEOUT) e o aluno via CONNECT_TIMEOUT com o
487
+ // servidor no ar e nenhum pedido chegando nele (11/09, EMB-041). Ele le o tempo do `env` das
488
+ // configuracoes da pasta: provado no 2.1.267, servidor de 40s cai aos 30s sem isto e conecta com isto.
489
+ const CLAUDE_MCP_TIMEOUT_MS = 120000;
464
490
  const CODEX_ENV_MINIMO = ['PATH', 'PATHEXT', 'USERNAME', 'USERDOMAIN', 'USERPROFILE', 'TEMP', 'TMP',
465
491
  'HOME', 'LOGNAME', 'SHELL', 'TERM', 'USER'];
466
492
 
@@ -768,6 +794,16 @@ function rodarNoCodex(pasta) {
768
794
  }
769
795
 
770
796
  async function writeArcaneMcpConfig(targetDir) {
797
+ // Todo caminho que registra o MCP (instalar, manutencao, register-mcp, clone) passa aqui,
798
+ // entao e aqui que o Claude Code ganha o tempo de espera. Falhar em gravar isso (arquivo
799
+ // somente leitura, dono root) nao pode derrubar o registro nem o resto da manutencao.
800
+ let esperaOk = false;
801
+ try {
802
+ await patchEnableAllProjectMcpServers(targetDir);
803
+ esperaOk = true;
804
+ } catch (e) {
805
+ warn(`Nao consegui gravar .claude/settings.local.json (${e.code || e.message}): o Claude Code segue esperando so 30s pelo conteudo ao vivo. Confira a permissao desse arquivo e rode register-mcp de novo.`);
806
+ }
771
807
  const pin = ARCANE_MCP_PIN;
772
808
  const mcpPath = path.join(targetDir, '.mcp.json');
773
809
  let json = { mcpServers: {} };
@@ -791,22 +827,181 @@ async function writeArcaneMcpConfig(targetDir) {
791
827
  const next = (toml.trimEnd() ? `${toml.trimEnd()}\n\n` : '') + block;
792
828
  await fs.writeFile(tomlPath, next);
793
829
  }
830
+ return { esperaOk };
831
+ }
832
+
833
+ async function modeloSettingsLocal() {
834
+ try {
835
+ return await fs.readJSON(path.resolve(__dirname, '..', '.claude', 'settings.local.json'));
836
+ } catch {
837
+ return {};
838
+ }
839
+ }
840
+
841
+ // Copia dos bytes do aluno antes de reescrever o arquivo dele. Vai pra `.auroq/` (fora do
842
+ // git): um settings.local.json pode ter token no `env` e nao pode subir pro GitHub.
843
+ async function guardarSettingsLocal(targetDir, bruto, motivo) {
844
+ const quando = new Date().toISOString().slice(0, 19).replace(/[:T]/g, '-');
845
+ const guarda = path.join(targetDir, '.auroq', 'preservado', `settings.local.json.${motivo}-${quando}`);
846
+ await fs.ensureDir(path.dirname(guarda));
847
+ await fs.writeFile(guarda, bruto);
848
+ const giPath = path.join(targetDir, '.gitignore');
849
+ const gi = (await fs.pathExists(giPath)) ? await fs.readFile(giPath, 'utf8') : '';
850
+ if (!gi.split('\n').map(l => l.trim()).includes('.auroq/')) {
851
+ await fs.writeFile(giPath, `${gi.replace(/\s*$/, gi.trim() ? '\n' : '')}.auroq/\n`);
852
+ }
853
+ return path.relative(targetDir, guarda).split(path.sep).join('/');
794
854
  }
795
855
 
856
+ const ehObjeto = v => Boolean(v) && typeof v === 'object' && !Array.isArray(v);
857
+
858
+ // `.claude/settings.local.json` e do aluno: so acrescenta o que falta, nunca tira nada.
859
+ // E o unico lugar que registra os hooks do Synapse e do PreCompact; se o arquivo nasce
860
+ // sem eles (clone numa maquina nova, ou criado pelo proprio Claude Code), as regras
861
+ // deixam de chegar ao modelo em silencio. Por isso os hooks do modelo que faltarem entram.
796
862
  async function patchEnableAllProjectMcpServers(targetDir) {
797
863
  const settingsPath = path.join(targetDir, '.claude', 'settings.local.json');
798
- let json = {};
864
+ const modelo = await modeloSettingsLocal();
865
+ let json;
866
+ let mudou = false;
799
867
  if (await fs.pathExists(settingsPath)) {
868
+ const bruto = await fs.readFile(settingsPath);
800
869
  try {
801
- json = await fs.readJSON(settingsPath);
870
+ json = JSON.parse(bruto.toString('utf8').replace(/^\uFEFF/, ''));
871
+ if (!ehObjeto(json)) throw new Error('nao e um objeto');
802
872
  } catch {
803
- json = {};
873
+ // Antes virava {} e o aluno perdia os hooks e o que mais tivesse ali.
874
+ const guarda = await guardarSettingsLocal(targetDir, bruto, 'ilegivel');
875
+ warn(`.claude/settings.local.json estava ilegivel: guardei o original em ${guarda} e refiz a partir do modelo`);
876
+ json = JSON.parse(JSON.stringify(modelo));
877
+ mudou = true;
878
+ }
879
+ if (json.env !== undefined && !ehObjeto(json.env)) {
880
+ const guarda = await guardarSettingsLocal(targetDir, bruto, 'env-invalido');
881
+ warn(`O "env" de .claude/settings.local.json nao era uma lista de variaveis: guardei o original em ${guarda}`);
882
+ delete json.env;
883
+ mudou = true;
804
884
  }
885
+ } else {
886
+ json = JSON.parse(JSON.stringify(modelo));
887
+ mudou = true;
888
+ }
889
+ if (ehObjeto(modelo.hooks)) {
890
+ // Hook ja registrado (aqui ou no settings.json, com qualquer forma de caminho) nao
891
+ // entra de novo: rodar o Synapse duas vezes duplicaria as regras.
892
+ let doProjeto = {};
893
+ try {
894
+ doProjeto = JSON.parse((await fs.readFile(path.join(targetDir, '.claude', 'settings.json'), 'utf8')).replace(/^/, ''));
895
+ } catch { /* sem settings.json legivel */ }
896
+ const scripts = (grupos) => (Array.isArray(grupos) ? grupos : [])
897
+ .flatMap(g => (Array.isArray(g?.hooks) ? g.hooks : []))
898
+ .map(h => (String(h?.command || '').match(/[\w.-]+\.c?js\b/) || [''])[0]);
899
+ if (!ehObjeto(json.hooks)) json.hooks = {};
900
+ for (const [evento, grupos] of Object.entries(modelo.hooks)) {
901
+ const atuais = Array.isArray(json.hooks[evento]) ? json.hooks[evento] : [];
902
+ const presentes = new Set([...scripts(atuais), ...scripts(doProjeto?.hooks?.[evento])].filter(Boolean));
903
+ const faltando = (grupos || []).filter(g => scripts([g]).some(s => s && !presentes.has(s)));
904
+ if (faltando.length) {
905
+ json.hooks[evento] = [...atuais, ...faltando];
906
+ mudou = true;
907
+ }
908
+ }
909
+ }
910
+ if (json.enableAllProjectMcpServers !== true) {
911
+ json.enableAllProjectMcpServers = true;
912
+ mudou = true;
805
913
  }
806
- if (json.enableAllProjectMcpServers === true) return;
807
- json.enableAllProjectMcpServers = true;
914
+ const env = ehObjeto(json.env) ? json.env : {};
915
+ const atual = Number(env.MCP_TIMEOUT);
916
+ if (!(Number.isFinite(atual) && atual >= CLAUDE_MCP_TIMEOUT_MS)) {
917
+ json.env = { ...env, MCP_TIMEOUT: String(CLAUDE_MCP_TIMEOUT_MS) };
918
+ mudou = true;
919
+ }
920
+ if (!mudou) return false;
808
921
  await fs.ensureDir(path.dirname(settingsPath));
809
922
  await fs.writeJSON(settingsPath, json, { spaces: 2 });
923
+ return true;
924
+ }
925
+
926
+ // ─── Synapse: o motor que reforca as regras do sistema a cada mensagem ───
927
+ // Ate a 2.5.1 esta pasta era copiada com overwrite:false. Quem instalou ate a 2.4.9 ficou
928
+ // para sempre com o hook-runtime.js sem `hookEventName`: o Claude Code recusava o pacote
929
+ // inteiro ("UserPromptSubmit hook error" a cada mensagem) e nenhuma regra chegava ao modelo,
930
+ // enquanto a manutencao carimbava a versao nova (EMB-040). Agora: arquivo identico a uma
931
+ // versao que publicamos e trocado; arquivo que ninguem publicou (mexido a mao) e guardado
932
+ // em .auroq-core/preservado/synapse/ antes da troca.
933
+ function hashNormalizado(buf) {
934
+ return require('crypto').createHash('sha256').update(buf.toString('utf8').replace(/\r\n/g, '\n')).digest('hex');
935
+ }
936
+
937
+ async function listarArquivos(dir, base = dir) {
938
+ const saida = [];
939
+ for (const nome of await fs.readdir(dir)) {
940
+ const abs = path.join(dir, nome);
941
+ const st = await fs.lstat(abs);
942
+ if (st.isDirectory()) saida.push(...(await listarArquivos(abs, base)));
943
+ else if (st.isFile()) saida.push(path.relative(base, abs).split(path.sep).join('/'));
944
+ }
945
+ return saida;
946
+ }
947
+
948
+ async function atualizarSynapse(sourceDir, targetDir) {
949
+ const origem = path.join(sourceDir, '.auroq-core', 'core', 'synapse');
950
+ const destino = path.join(targetDir, '.auroq-core', 'core', 'synapse');
951
+ if (!(await fs.pathExists(origem))) return null;
952
+ const oficiais = require('../lib/synapse-hashes.json');
953
+ const r = { novos: 0, atualizados: 0, iguais: 0, preservados: [], falhas: [] };
954
+ for (const rel of await listarArquivos(origem)) {
955
+ const src = path.join(origem, ...rel.split('/'));
956
+ const dst = path.join(destino, ...rel.split('/'));
957
+ try {
958
+ if (!(await fs.pathExists(dst))) {
959
+ await fs.copy(src, dst);
960
+ r.novos++;
961
+ continue;
962
+ }
963
+ const atual = await fs.readFile(dst);
964
+ const hAtual = hashNormalizado(atual);
965
+ if (hAtual === hashNormalizado(await fs.readFile(src))) {
966
+ r.iguais++;
967
+ continue;
968
+ }
969
+ if (!(oficiais[rel] || []).includes(hAtual)) {
970
+ const guarda = path.join(targetDir, '.auroq-core', 'preservado', 'synapse', `${rel}.${hAtual.slice(0, 12)}`);
971
+ if (!(await fs.pathExists(guarda))) {
972
+ await fs.ensureDir(path.dirname(guarda));
973
+ await fs.writeFile(guarda, atual);
974
+ }
975
+ r.preservados.push(rel);
976
+ }
977
+ await fs.copy(src, dst, { overwrite: true });
978
+ r.atualizados++;
979
+ } catch (e) {
980
+ r.falhas.push(`${rel} (${e.code || e.message})`);
981
+ }
982
+ }
983
+ return r;
984
+ }
985
+
986
+ async function synapseRegistrado(targetDir) {
987
+ for (const nome of ['settings.local.json', 'settings.json']) {
988
+ try {
989
+ const json = JSON.parse((await fs.readFile(path.join(targetDir, '.claude', nome), 'utf8')).replace(/^/, ''));
990
+ const grupos = Array.isArray(json?.hooks?.UserPromptSubmit) ? json.hooks.UserPromptSubmit : [];
991
+ if (grupos.some(g => (g?.hooks || []).some(h => String(h?.command || '').includes('synapse-engine.cjs')))) return true;
992
+ } catch { /* arquivo ausente ou ilegivel */ }
993
+ }
994
+ return false;
995
+ }
996
+
997
+ // O hook-runtime sem `hookEventName` e a assinatura do Synapse antigo (EMB-040).
998
+ async function synapseDesatualizado(targetDir) {
999
+ const arq = path.join(targetDir, '.auroq-core', 'core', 'synapse', 'runtime', 'hook-runtime.js');
1000
+ try {
1001
+ return !(await fs.readFile(arq, 'utf8')).includes('hookEventName');
1002
+ } catch {
1003
+ return false;
1004
+ }
810
1005
  }
811
1006
 
812
1007
  // ─── INSTALACAO ──────────────────────────────────────────
@@ -1196,25 +1391,26 @@ async function init({ pasta = null, maintenance = false } = {}) {
1196
1391
  await fs.copy(seedRoot, targetDir, { overwrite: false });
1197
1392
  success('Semente do aluno instalada (memoria, docs, cockpit — nunca sobrescreve)');
1198
1393
  }
1199
- await patchEnableAllProjectMcpServers(targetDir);
1200
- await writeArcaneMcpConfig(targetDir);
1201
- step('Preparando o conteudo ao vivo (baixa uma vez; no Windows prepara tambem pro Codex; pode levar 1-3 min)...');
1202
- if (aquecerArcaneMcp()) success('Conteudo ao vivo pronto pra abrir rapido');
1203
- else warn('Nao consegui baixar o conteudo ao vivo agora — a primeira abertura vai demorar mais');
1204
-
1205
- // ─── Fase 4: Copiar Synapse Engine
1394
+ // ─── Fase 4: Synapse Engine (troca versao oficial antiga; guarda o que foi mexido a mao).
1395
+ // Antes do registro do MCP: se algo ali falhar, a correcao do hook (EMB-040) ja entrou.
1206
1396
  step('Instalando Synapse Engine...');
1207
1397
 
1208
- const synapseSrc = path.join(sourceDir, '.auroq-core', 'core', 'synapse');
1209
- const synapseDst = path.join(targetDir, '.auroq-core', 'core', 'synapse');
1210
- if (await fs.pathExists(synapseSrc)) {
1211
- await fs.copy(synapseSrc, synapseDst, { overwrite: false });
1212
- const synapseFiles = await fs.readdir(synapseSrc, { recursive: true });
1213
- success(`Synapse Engine instalado (${synapseFiles.length} arquivos)`);
1214
- } else {
1398
+ const sinapse = await atualizarSynapse(sourceDir, targetDir);
1399
+ if (!sinapse) {
1215
1400
  warn('Synapse Engine nao encontrado na fonte — pulando');
1401
+ } else {
1402
+ success(`Synapse Engine em dia (${sinapse.novos} novo(s), ${sinapse.atualizados} atualizado(s))`);
1403
+ if (sinapse.preservados.length) {
1404
+ warn(`Arquivo(s) do Synapse diferente(s) de qualquer versao oficial guardado(s) em .auroq-core/preservado/synapse antes da troca: ${sinapse.preservados.join(', ')}`);
1405
+ }
1406
+ if (sinapse.falhas.length) warn(`Nao consegui atualizar: ${sinapse.falhas.join(', ')}`);
1216
1407
  }
1217
1408
 
1409
+ await writeArcaneMcpConfig(targetDir);
1410
+ step('Preparando o conteudo ao vivo (baixa uma vez; no Windows prepara tambem pro Codex; pode levar 1-3 min)...');
1411
+ if (aquecerArcaneMcp()) success('Conteudo ao vivo pronto pra abrir rapido');
1412
+ else warn('Nao consegui baixar o conteudo ao vivo agora — a primeira abertura vai demorar mais');
1413
+
1218
1414
  // ─── Fase 4b: Copiar Meta Squads e scripts (diretorios inteiros)
1219
1415
  step('Instalando Meta Squads e scripts...');
1220
1416
 
@@ -1591,9 +1787,9 @@ if (['init', 'install', 'update'].includes(command)) {
1591
1787
  error('Rode este comando na raiz do seu negocio.');
1592
1788
  process.exit(1);
1593
1789
  }
1594
- await patchEnableAllProjectMcpServers(targetDir);
1595
- await writeArcaneMcpConfig(targetDir);
1790
+ const { esperaOk } = await writeArcaneMcpConfig(targetDir);
1596
1791
  success('Conteudo ao vivo registrado (.mcp.json e .codex/config.toml).');
1792
+ if (esperaOk) success(`Claude Code espera o conteudo ao vivo por ate ${CLAUDE_MCP_TIMEOUT_MS / 1000}s (.claude/settings.local.json)`);
1597
1793
  log(`${DIM}Baixando o conteudo ao vivo uma vez (pode levar 1-2 min)...${RESET}`);
1598
1794
  if (aquecerArcaneMcp()) success('Conteudo ao vivo pronto pra abrir rapido');
1599
1795
  else warn('Nao consegui baixar o conteudo ao vivo agora — a primeira abertura vai demorar mais');
@@ -486,7 +486,7 @@ function Invoke-AuroqLogin {
486
486
  # sucesso. Usado como pergunta de sim/nao, ele dizia "voce ja estava logado"
487
487
  # pra quem nunca logou, pulava o portao e deixava a conta sem acesso chegar ate
488
488
  # a criacao da pasta.
489
- & (Get-AuroqNpx) -y auroq-os@2.5.1 check-access
489
+ & (Get-AuroqNpx) -y auroq-os@2.5.2 check-access
490
490
  if ($LASTEXITCODE -ne 0) {
491
491
  Write-AuroqLog 'login' 'recusado'
492
492
  Write-Host ''
@@ -574,7 +574,7 @@ function Invoke-AuroqInit {
574
574
  if ($env:AUROQ_INSTALL_DRY_RUN) { Write-AuroqOk 'Sistema - seria montado aqui'; return }
575
575
 
576
576
  Set-Location $script:AuroqPastaAlvo
577
- & (Get-AuroqNpx) -y auroq-os@2.5.1 instalar
577
+ & (Get-AuroqNpx) -y auroq-os@2.5.2 instalar
578
578
  if ($LASTEXITCODE -ne 0) {
579
579
  Write-AuroqLog 'init' 'falhou'
580
580
  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.'
@@ -151,9 +151,9 @@ auroq_tem_terminal() {
151
151
  # recebem pedaco do script no lugar da resposta dele.
152
152
  auroq_npx_aluno() {
153
153
  if [ -t 0 ]; then
154
- npx -y auroq-os@2.5.1 "$@"
154
+ npx -y auroq-os@2.5.2 "$@"
155
155
  else
156
- npx -y auroq-os@2.5.1 "$@" < /dev/tty
156
+ npx -y auroq-os@2.5.2 "$@" < /dev/tty
157
157
  fi
158
158
  }
159
159
 
@@ -0,0 +1,110 @@
1
+ {
2
+ "context/context-builder.js": [
3
+ "121cd0a1df8a44098831cd4335536e8facf4e65b8aec48f4ce9c2d432dc6252a"
4
+ ],
5
+ "context/context-tracker.js": [
6
+ "48e94db7b1778dedecc8eae829139579ad7778ff47668597ebe766610696553f"
7
+ ],
8
+ "diagnostics/collectors/consistency-collector.js": [
9
+ "65f4255f87c9900400649dc8b9aedaac4851b5939d93e127778bd93cee99db12"
10
+ ],
11
+ "diagnostics/collectors/hook-collector.js": [
12
+ "c2cfa1b760bcb05decf5ad05f9159140cbe0cdc6b0f91581790e44d83dc6b660"
13
+ ],
14
+ "diagnostics/collectors/manifest-collector.js": [
15
+ "3dc895eb94485320ecbaca3a1d29e3776cfb691dd7dcc71cf44b34af30e8ebb6"
16
+ ],
17
+ "diagnostics/collectors/output-analyzer.js": [
18
+ "e6846b1aba0a6cba17c297a871861d4f8199d7500220bff296a6a3291e32493e"
19
+ ],
20
+ "diagnostics/collectors/pipeline-collector.js": [
21
+ "8655b6240e2f54b70def1a8c2fae00d40e2615cb95fd7ca0d64c2e0a6dfe3b73"
22
+ ],
23
+ "diagnostics/collectors/quality-collector.js": [
24
+ "30ae299eab6d569d09afe3530a5b2f1ff35ef75366a1ab56a9e2a57d39d3611c"
25
+ ],
26
+ "diagnostics/collectors/relevance-matrix.js": [
27
+ "f92c4f7061dc82eed4310a27b69eade33d3015f9beb1bed688601a2dccbad22e"
28
+ ],
29
+ "diagnostics/collectors/safe-read-json.js": [
30
+ "dc7bcd13779207ad67b1c3929b7e1e0ccfa3563f3458c20cad28cb1922e9a74c"
31
+ ],
32
+ "diagnostics/collectors/session-collector.js": [
33
+ "a116d884d6947ddc8e5f3def012d93696576c584c4fde1639b8d895924fc09ea"
34
+ ],
35
+ "diagnostics/collectors/timing-collector.js": [
36
+ "2523ce93f863a28f798d992c4f2fab041c91a09413b3186fd290e6035b391587"
37
+ ],
38
+ "diagnostics/collectors/uap-collector.js": [
39
+ "dd025894f8f0d3bd22a147dbc0debef8b83e96f3c59483653404b3cd5a01d5aa"
40
+ ],
41
+ "diagnostics/report-formatter.js": [
42
+ "1aa2853928df194b669ce32c3b050a90de1311739045074f699d10210ed8d381"
43
+ ],
44
+ "diagnostics/synapse-diagnostics.js": [
45
+ "de9dffce0e380637027cbd64b062d3eeffc37e42a84a337e5758fbef39fe3a00"
46
+ ],
47
+ "domain/domain-loader.js": [
48
+ "af788f9da956b89eef1e5eb4ef4efdf05ca758c8969a2c375f568119495ebc05"
49
+ ],
50
+ "engine.js": [
51
+ "47bab93a2144edce875ee68cc2717fee1bd824c9affdd5964454f5141310b8e0",
52
+ "c061df38ec24956da9a752f13f9455c7cd69546adb330c7587b9d456e79b4aa1"
53
+ ],
54
+ "layers/l0-constitution.js": [
55
+ "2123a6a44915aaac2a6bbd26c67c285c9d1e12b50fe42a8ada668306b07d1c4a"
56
+ ],
57
+ "layers/l1-global.js": [
58
+ "21f6969e6d64e9a85c876be6799db4ca7d090f0009057f4a06ead8da12392d45"
59
+ ],
60
+ "layers/l2-agent.js": [
61
+ "a8677dc58ae7927c5292a4b52883bbc905c8112573b8b8631f0b8bc01ea2b6e6"
62
+ ],
63
+ "layers/l3-workflow.js": [
64
+ "496cbd71d7dac9c1daa534ffac45c622d0c032f334fedf493e9322a565b2b181"
65
+ ],
66
+ "layers/l4-task.js": [
67
+ "30df70c04b16e3aff95899211ef6ae3d9f0a8097ebdc7de92599fc6cb792e5f0"
68
+ ],
69
+ "layers/l5-squad.js": [
70
+ "d6d35cbf966deb5a7d2df2b09f5abe8da8c6d4e346b385418f8dc1fae3ddf830"
71
+ ],
72
+ "layers/l6-keyword.js": [
73
+ "8e5405999a2ce2f3ca4e62e863cf702ba27448914241f5eb8f02760bc7477523"
74
+ ],
75
+ "layers/l7-star-command.js": [
76
+ "3b8372ac1c51830c1ef560b1012b112a3559651b0750e42f2037f7fe9e6787d6"
77
+ ],
78
+ "layers/layer-processor.js": [
79
+ "73cb0e5b4bada80d8e256009004679e483792077fac4358c6466cd77136f79fa"
80
+ ],
81
+ "memory/memory-bridge.js": [
82
+ "820875f97ceea80fc6402c0dab1706cfe58de527897b22dea68db40b0d6ec368"
83
+ ],
84
+ "memory/synapse-memory-provider.js": [
85
+ "5d613d1fac7ee82c49a3f03b38735fd3cabfe87dd868494672ddfef300ea3145"
86
+ ],
87
+ "output/formatter.js": [
88
+ "fe4f6c2f6091defb6af66dad71db0640f919b983111087f8cc5821e3d44ca864",
89
+ "3e722c4736642ef96ec73a54cd2011eed7bd1074394a38eac66cb6f0af2c855b"
90
+ ],
91
+ "runtime/hook-runtime.js": [
92
+ "5518692eeee7dcb570507c4bb96ef68a1ef51d6ad6c417e9d1f649cd8b21b199",
93
+ "7c34b84c5693045a007356081959c335493bbd3afc69822fb6661e19cc10d56c"
94
+ ],
95
+ "scripts/generate-constitution.js": [
96
+ "e2f645d5de44e6b3721a5de9b19982bc7b8cf7eed3ca4d62bc53221649c59af1"
97
+ ],
98
+ "session/session-manager.js": [
99
+ "98e8c8fa15b074b6102bcd51c6f91f101743338e8cde6de9c31d6b6eea5d6580"
100
+ ],
101
+ "utils/atomic-write.js": [
102
+ "efeef0fbcebb184df5b79f4ba4b4b7fe274c3ba7d1c705ce1af92628e920bd8b"
103
+ ],
104
+ "utils/paths.js": [
105
+ "bf8cf93c1a16295e7de055bee292e2778a152b6e7d6c648dbc054a4b04dffc10"
106
+ ],
107
+ "utils/tokens.js": [
108
+ "3b927daec51d0a791f3fe4ef9aafc362773450e7cf50eb4b6d8ae9011d70df9a"
109
+ ]
110
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auroq-os",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "Auroq OS \u2014 Sistema Operacional de IA para Experts",
5
5
  "bin": {
6
6
  "auroq-os": "bin/auroq-os.js"
@@ -18,7 +18,7 @@
18
18
  "auroq:sync:codex:check": "npm run sync:codex:check",
19
19
  "auroq:validate": "npm run validate:hybrid",
20
20
  "validate:hybrid": "node scripts/validate-hybrid.mjs",
21
- "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",
21
+ "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/synapse-hashes.mjs",
22
22
  "typecheck": "npm run validate:hybrid",
23
23
  "test": "node --test tests/*.test.mjs",
24
24
  "prepack": "node scripts/prepack-casca.mjs",
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Lista de versoes OFICIAIS de cada arquivo do Synapse (`.auroq-core/core/synapse`).
4
+ *
5
+ * A manutencao so troca sem cerimonia um arquivo do aluno se ele for identico a
6
+ * alguma versao que nos publicamos; o que ninguem publicou (mexido a mao) e
7
+ * guardado antes da troca. Por isso esta lista so cresce: toda versao nova do
8
+ * Synapse precisa entrar aqui ANTES de publicar (o teste cobra).
9
+ *
10
+ * node scripts/synapse-hashes.mjs # acrescenta os arquivos atuais
11
+ * node scripts/synapse-hashes.mjs <pasta>... # acrescenta de pacotes extraidos (package/)
12
+ *
13
+ * Hash sobre o texto com CRLF normalizado para LF: a mesma versao vinda de um
14
+ * clone no Windows (autocrlf) continua reconhecida como oficial.
15
+ */
16
+ import crypto from 'node:crypto';
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+
21
+ const raiz = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
22
+ const destino = path.join(raiz, 'lib', 'synapse-hashes.json');
23
+ const REL = path.join('.auroq-core', 'core', 'synapse');
24
+
25
+ export function hashNormalizado(buf) {
26
+ return crypto.createHash('sha256').update(buf.toString('utf8').replace(/\r\n/g, '\n')).digest('hex');
27
+ }
28
+
29
+ function listar(dir, base = dir) {
30
+ const saida = [];
31
+ for (const nome of fs.readdirSync(dir)) {
32
+ const abs = path.join(dir, nome);
33
+ const st = fs.lstatSync(abs);
34
+ if (st.isDirectory()) saida.push(...listar(abs, base));
35
+ else if (st.isFile()) saida.push(path.relative(base, abs).split(path.sep).join('/'));
36
+ }
37
+ return saida;
38
+ }
39
+
40
+ function acrescentar(mapa, pacoteRaiz) {
41
+ const dir = path.join(pacoteRaiz, REL);
42
+ if (!fs.existsSync(dir)) return 0;
43
+ let novos = 0;
44
+ for (const rel of listar(dir)) {
45
+ const h = hashNormalizado(fs.readFileSync(path.join(dir, rel)));
46
+ mapa[rel] = mapa[rel] || [];
47
+ if (!mapa[rel].includes(h)) { mapa[rel].push(h); novos++; }
48
+ }
49
+ return novos;
50
+ }
51
+
52
+ if (process.argv[1] === fileURLToPath(import.meta.url)) {
53
+ const mapa = fs.existsSync(destino) ? JSON.parse(fs.readFileSync(destino, 'utf8')) : {};
54
+ const fontes = process.argv.slice(2);
55
+ let novos = 0;
56
+ for (const fonte of fontes.length ? fontes : [raiz]) novos += acrescentar(mapa, fonte);
57
+ const ordenado = Object.fromEntries(Object.keys(mapa).sort().map(k => [k, mapa[k]]));
58
+ fs.writeFileSync(destino, `${JSON.stringify(ordenado, null, 2)}\n`);
59
+ console.log(`synapse-hashes: ${novos} hash(es) novo(s), ${Object.keys(ordenado).length} arquivo(s)`);
60
+ }