auroq-os 2.5.10 → 2.5.12
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/synapse/engine.js +54 -11
- package/.auroq-core/core/synapse/layers/layer-processor.js +11 -2
- package/.auroq-core/core/synapse/runtime/hook-runtime.js +27 -15
- package/.auroq-core/core-config.yaml +1 -1
- package/CHANGELOG.md +17 -0
- package/README.md +7 -8
- package/bin/auroq-os.js +52 -7
- package/installer/install.ps1 +2 -2
- package/installer/install.sh +2 -2
- package/lib/runtime-integrity.json +288 -0
- package/lib/synapse-hashes.json +6 -3
- package/lib/telemetry.mjs +4 -1
- package/package.json +5 -4
- package/scripts/build-pack.mjs +43 -12
- package/scripts/pack-state.mjs +64 -0
- package/scripts/postpack-casca.mjs +3 -26
- package/scripts/prepack-casca.mjs +32 -32
- package/scripts/runtime-integrity.mjs +173 -0
|
@@ -123,9 +123,8 @@ class PipelineMetrics {
|
|
|
123
123
|
* Record that a layer encountered an error.
|
|
124
124
|
*
|
|
125
125
|
* @param {string} name - Layer name
|
|
126
|
-
* @param {Error} error - The error object
|
|
127
126
|
*/
|
|
128
|
-
errorLayer(name
|
|
127
|
+
errorLayer(name) {
|
|
129
128
|
const existing = this.layers[name] || {};
|
|
130
129
|
if (existing.start) {
|
|
131
130
|
const endTime = process.hrtime.bigint();
|
|
@@ -135,7 +134,7 @@ class PipelineMetrics {
|
|
|
135
134
|
this.layers[name] = {
|
|
136
135
|
...existing,
|
|
137
136
|
status: 'error',
|
|
138
|
-
|
|
137
|
+
errorCode: 'SYNAPSE_LAYER_FAILED',
|
|
139
138
|
};
|
|
140
139
|
}
|
|
141
140
|
|
|
@@ -170,8 +169,27 @@ class PipelineMetrics {
|
|
|
170
169
|
// SynapseEngine
|
|
171
170
|
// ---------------------------------------------------------------------------
|
|
172
171
|
|
|
173
|
-
/**
|
|
172
|
+
/** Cooperative budget between layers; synchronous work cannot be interrupted. */
|
|
174
173
|
const PIPELINE_TIMEOUT_MS = 100;
|
|
174
|
+
// Keep substantial headroom below the outer hook's 5000 ms safety timeout.
|
|
175
|
+
const MAX_PIPELINE_TIMEOUT_MS = 1000;
|
|
176
|
+
const SYNAPSE_PIPELINE_TIMEOUT_ENV = 'AUROQ_SYNAPSE_PIPELINE_TIMEOUT_MS';
|
|
177
|
+
|
|
178
|
+
/** Resolve a short pipeline budget. Invalid values preserve the safe default. */
|
|
179
|
+
function resolvePipelineTimeoutMs(config = {}) {
|
|
180
|
+
const fromEnv = process.env[SYNAPSE_PIPELINE_TIMEOUT_ENV];
|
|
181
|
+
const value = fromEnv !== undefined && fromEnv !== ''
|
|
182
|
+
? fromEnv
|
|
183
|
+
: config.synapse?.pipelineTimeoutMs;
|
|
184
|
+
if (value === undefined || value === null) return PIPELINE_TIMEOUT_MS;
|
|
185
|
+
const timeout = typeof value === 'number' || typeof value === 'string' ? Number(value) : NaN;
|
|
186
|
+
if (!Number.isInteger(timeout) || timeout <= 0 || timeout > MAX_PIPELINE_TIMEOUT_MS) {
|
|
187
|
+
// Do not echo invalid values: environment/config may contain private text.
|
|
188
|
+
console.warn('[synapse:engine] SYNAPSE_INVALID_PIPELINE_TIMEOUT');
|
|
189
|
+
return PIPELINE_TIMEOUT_MS;
|
|
190
|
+
}
|
|
191
|
+
return timeout;
|
|
192
|
+
}
|
|
175
193
|
|
|
176
194
|
/**
|
|
177
195
|
* NOG-18: Default active layers (L0-L2 only).
|
|
@@ -250,8 +268,13 @@ class SynapseEngine {
|
|
|
250
268
|
async process(prompt, session, processConfig) {
|
|
251
269
|
const safeProcessConfig = (processConfig && typeof processConfig === 'object') ? processConfig : {};
|
|
252
270
|
const mergedConfig = { ...this.config, ...safeProcessConfig };
|
|
271
|
+
mergedConfig.synapse = { ...(this.config.synapse || {}), ...(safeProcessConfig.synapse || {}) };
|
|
272
|
+
const pipelineTimeoutMs = resolvePipelineTimeoutMs(mergedConfig);
|
|
273
|
+
const pipelineNow = typeof safeProcessConfig.nowNs === 'function'
|
|
274
|
+
? safeProcessConfig.nowNs
|
|
275
|
+
: process.hrtime.bigint;
|
|
253
276
|
const metrics = new PipelineMetrics();
|
|
254
|
-
metrics.totalStart =
|
|
277
|
+
metrics.totalStart = pipelineNow();
|
|
255
278
|
|
|
256
279
|
// 1. Calculate bracket (or use fixed layers in non-legacy mode)
|
|
257
280
|
const promptCount = (session && session.prompt_count) || 0;
|
|
@@ -266,7 +289,7 @@ class SynapseEngine {
|
|
|
266
289
|
|
|
267
290
|
// Guard: no layer config (invalid bracket — should not happen)
|
|
268
291
|
if (!layerConfig) {
|
|
269
|
-
metrics.totalEnd =
|
|
292
|
+
metrics.totalEnd = pipelineNow();
|
|
270
293
|
return { xml: '', metrics: metrics.getSummary() };
|
|
271
294
|
}
|
|
272
295
|
activeLayers = layerConfig.layers;
|
|
@@ -291,8 +314,8 @@ class SynapseEngine {
|
|
|
291
314
|
continue;
|
|
292
315
|
}
|
|
293
316
|
|
|
294
|
-
//
|
|
295
|
-
if (Number(
|
|
317
|
+
// Cooperative check between layers; the host owns interruption of a stuck process.
|
|
318
|
+
if (Number(pipelineNow() - metrics.totalStart) / 1e6 >= pipelineTimeoutMs) {
|
|
296
319
|
// Log remaining layers as skipped
|
|
297
320
|
const remaining = this.layers.slice(this.layers.indexOf(layer));
|
|
298
321
|
for (const r of remaining) {
|
|
@@ -314,14 +337,28 @@ class SynapseEngine {
|
|
|
314
337
|
previousLayers,
|
|
315
338
|
});
|
|
316
339
|
|
|
317
|
-
|
|
340
|
+
let result;
|
|
341
|
+
try {
|
|
342
|
+
result = layer._safeProcess(context);
|
|
343
|
+
} catch (_error) {
|
|
344
|
+
metrics.errorLayer(layer.name);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
318
347
|
|
|
319
348
|
if (result && Array.isArray(result.rules)) {
|
|
320
349
|
metrics.endLayer(layer.name, result.rules.length);
|
|
321
350
|
results.push(result);
|
|
322
351
|
previousLayers.push(result);
|
|
323
352
|
} else if (result === null || result === undefined) {
|
|
324
|
-
|
|
353
|
+
try {
|
|
354
|
+
if (typeof layer.getLastError === 'function' && layer.getLastError()) {
|
|
355
|
+
metrics.errorLayer(layer.name);
|
|
356
|
+
} else {
|
|
357
|
+
metrics.skipLayer(layer.name, 'Returned null');
|
|
358
|
+
}
|
|
359
|
+
} catch (_error) {
|
|
360
|
+
metrics.errorLayer(layer.name);
|
|
361
|
+
}
|
|
325
362
|
} else {
|
|
326
363
|
metrics.skipLayer(layer.name, 'Invalid result format');
|
|
327
364
|
}
|
|
@@ -341,8 +378,9 @@ class SynapseEngine {
|
|
|
341
378
|
}
|
|
342
379
|
}
|
|
343
380
|
|
|
344
|
-
metrics.totalEnd =
|
|
381
|
+
metrics.totalEnd = pipelineNow();
|
|
345
382
|
const summary = metrics.getSummary();
|
|
383
|
+
summary.pipeline_timeout_ms = pipelineTimeoutMs;
|
|
346
384
|
|
|
347
385
|
// Persist hook metrics (fire-and-forget)
|
|
348
386
|
this._persistHookMetrics(summary, bracket, mergedConfig);
|
|
@@ -382,6 +420,7 @@ class SynapseEngine {
|
|
|
382
420
|
const hookBootMs = hookBootTime ? Number(process.hrtime.bigint() - hookBootTime) / 1e6 : 0;
|
|
383
421
|
const data = {
|
|
384
422
|
totalDuration: summary.total_ms,
|
|
423
|
+
pipelineTimeoutMs: summary.pipeline_timeout_ms,
|
|
385
424
|
hookBootMs,
|
|
386
425
|
bracket,
|
|
387
426
|
layersLoaded: summary.layers_loaded,
|
|
@@ -397,6 +436,7 @@ class SynapseEngine {
|
|
|
397
436
|
duration: info.duration || 0,
|
|
398
437
|
status: info.status || 'unknown',
|
|
399
438
|
rules: info.rules || 0,
|
|
439
|
+
...(info.errorCode ? { errorCode: info.errorCode } : {}),
|
|
400
440
|
};
|
|
401
441
|
}
|
|
402
442
|
fs.writeFileSync(
|
|
@@ -413,4 +453,7 @@ module.exports = {
|
|
|
413
453
|
SynapseEngine,
|
|
414
454
|
PipelineMetrics,
|
|
415
455
|
PIPELINE_TIMEOUT_MS,
|
|
456
|
+
MAX_PIPELINE_TIMEOUT_MS,
|
|
457
|
+
SYNAPSE_PIPELINE_TIMEOUT_ENV,
|
|
458
|
+
resolvePipelineTimeoutMs,
|
|
416
459
|
};
|
|
@@ -34,6 +34,7 @@ class LayerProcessor {
|
|
|
34
34
|
this.name = name;
|
|
35
35
|
this.layer = layer;
|
|
36
36
|
this.timeout = timeout;
|
|
37
|
+
this._lastError = null;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -65,6 +66,7 @@ class LayerProcessor {
|
|
|
65
66
|
*/
|
|
66
67
|
_safeProcess(context) {
|
|
67
68
|
const start = Date.now();
|
|
69
|
+
this._lastError = null;
|
|
68
70
|
try {
|
|
69
71
|
const result = this.process(context);
|
|
70
72
|
const elapsed = Date.now() - start;
|
|
@@ -72,11 +74,18 @@ class LayerProcessor {
|
|
|
72
74
|
console.warn(`[synapse:${this.name}] Warning: Layer exceeded timeout (${elapsed}ms > ${this.timeout}ms)`);
|
|
73
75
|
}
|
|
74
76
|
return result;
|
|
75
|
-
} catch (
|
|
76
|
-
|
|
77
|
+
} catch (_error) {
|
|
78
|
+
// Raw error messages/stacks can contain prompt or domain content.
|
|
79
|
+
this._lastError = new Error('SYNAPSE_LAYER_FAILED');
|
|
80
|
+
console.warn(`[synapse:${this.name}] SYNAPSE_LAYER_FAILED`);
|
|
77
81
|
return null;
|
|
78
82
|
}
|
|
79
83
|
}
|
|
84
|
+
|
|
85
|
+
/** Return a content-free failure marker for the engine's metrics. */
|
|
86
|
+
getLastError() {
|
|
87
|
+
return this._lastError;
|
|
88
|
+
}
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
module.exports = LayerProcessor;
|
|
@@ -6,25 +6,29 @@ const fs = require('fs');
|
|
|
6
6
|
const DEFAULT_STALE_TTL_HOURS = 168; // 7 days
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* Read
|
|
10
|
-
* Falls back to DEFAULT_STALE_TTL_HOURS (168h = 7 days).
|
|
9
|
+
* Read optional project configuration without disclosing parse failures.
|
|
11
10
|
*
|
|
12
11
|
* @param {string} cwd - Working directory
|
|
13
|
-
* @returns {
|
|
12
|
+
* @returns {object} Configuration or an empty object
|
|
14
13
|
*/
|
|
15
|
-
function
|
|
14
|
+
function loadCoreConfig(cwd) {
|
|
16
15
|
try {
|
|
17
|
-
const yaml = require('js-yaml');
|
|
18
16
|
const configPath = path.join(cwd, '.auroq-core', 'core-config.yaml');
|
|
19
|
-
if (!fs.existsSync(configPath)) return
|
|
17
|
+
if (!fs.existsSync(configPath)) return {};
|
|
18
|
+
const yaml = require('js-yaml');
|
|
20
19
|
const config = yaml.load(fs.readFileSync(configPath, 'utf8'));
|
|
21
|
-
|
|
22
|
-
return typeof ttl === 'number' && ttl > 0 ? ttl : DEFAULT_STALE_TTL_HOURS;
|
|
20
|
+
return config && typeof config === 'object' ? config : {};
|
|
23
21
|
} catch (_err) {
|
|
24
|
-
|
|
22
|
+
// YAML errors can contain configuration values; never log their text.
|
|
23
|
+
return {};
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
function getStaleSessionTTL(config) {
|
|
28
|
+
const ttl = config && config.synapse && config.synapse.session && config.synapse.session.staleTTLHours;
|
|
29
|
+
return typeof ttl === 'number' && ttl > 0 ? ttl : DEFAULT_STALE_TTL_HOURS;
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
/**
|
|
29
33
|
* Resolve runtime dependencies for Synapse hook execution.
|
|
30
34
|
*
|
|
@@ -46,7 +50,7 @@ function resolveHookRuntime(input) {
|
|
|
46
50
|
if (!fs.existsSync(synapsePath)) return null;
|
|
47
51
|
|
|
48
52
|
try {
|
|
49
|
-
const { loadSession, cleanStaleSessions } = require(
|
|
53
|
+
const { loadSession, createSession, cleanStaleSessions } = require(
|
|
50
54
|
path.join(cwd, '.auroq-core', 'core', 'synapse', 'session', 'session-manager.js'),
|
|
51
55
|
);
|
|
52
56
|
const { SynapseEngine } = require(
|
|
@@ -54,13 +58,21 @@ function resolveHookRuntime(input) {
|
|
|
54
58
|
);
|
|
55
59
|
|
|
56
60
|
const sessionsDir = path.join(synapsePath, 'sessions');
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
let session = sessionId ? loadSession(sessionId, sessionsDir) : null;
|
|
62
|
+
// loadSession validates the ID before we use it as a filename. Create only
|
|
63
|
+
// a missing session: an unreadable/corrupt existing file is kept intact.
|
|
64
|
+
if (!session && sessionId && !fs.existsSync(path.join(sessionsDir, `${sessionId}.json`))) {
|
|
65
|
+
session = createSession(sessionId, cwd, sessionsDir);
|
|
66
|
+
}
|
|
67
|
+
const shouldCleanStaleSessions = session?.prompt_count === 0;
|
|
68
|
+
session = session || { prompt_count: 0 };
|
|
69
|
+
const coreConfig = loadCoreConfig(cwd);
|
|
70
|
+
const engine = new SynapseEngine(synapsePath, { synapse: coreConfig.synapse || {} });
|
|
59
71
|
|
|
60
72
|
// AC3: Run cleanup on first prompt only (fire-and-forget)
|
|
61
|
-
if (
|
|
73
|
+
if (shouldCleanStaleSessions) {
|
|
62
74
|
try {
|
|
63
|
-
const ttlHours = getStaleSessionTTL(
|
|
75
|
+
const ttlHours = getStaleSessionTTL(coreConfig);
|
|
64
76
|
const removed = cleanStaleSessions(sessionsDir, ttlHours);
|
|
65
77
|
if (removed > 0 && process.env.DEBUG === '1') {
|
|
66
78
|
console.error(`[hook-runtime] Cleaned ${removed} stale session(s) (TTL: ${ttlHours}h)`);
|
|
@@ -73,7 +85,7 @@ function resolveHookRuntime(input) {
|
|
|
73
85
|
return { engine, session, sessionId, sessionsDir, cwd };
|
|
74
86
|
} catch (error) {
|
|
75
87
|
if (process.env.DEBUG === '1') {
|
|
76
|
-
console.error(
|
|
88
|
+
console.error('[hook-runtime] SYNAPSE_RUNTIME_FAILED');
|
|
77
89
|
}
|
|
78
90
|
return null;
|
|
79
91
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## 2.5.12 — 2026-09-21
|
|
2
|
+
|
|
3
|
+
- SYNAPSE persiste a sessao desde o primeiro prompt, limita o orcamento total entre camadas e distingue falhas sem expor mensagens/conteudo privado. Mantem manifest, eventos dos hosts e camadas opcionais desligadas.
|
|
4
|
+
- Pacote real passa por inventario SHA-256 apos a casca, arquivos obrigatorios/proibidos e referencias locais do runtime. O empacotamento restaura o checkout, inclusive em falhas. Integridade de conteudo nao equivale a assinatura de autoria.
|
|
5
|
+
- Atualiza js-yaml para 4.3.2, corrigindo avisos de consumo excessivo de CPU no parser usado pelo motor.
|
|
6
|
+
- Manutencao reconhece as versoes oficiais anteriores do SYNAPSE e preserva arquivos personalizados e dados do negocio. Mantem arcane-mcp@0.6.1.
|
|
7
|
+
- Instaladores preparados para esta versao; copias publicas so sao promovidas depois dos gates nativos macOS/Windows Node 22/24 e da verificacao no npm. Maquinas existentes atualizam pelo fluxo de manutencao.
|
|
8
|
+
|
|
9
|
+
## 2.5.11 — 2026-09-21
|
|
10
|
+
|
|
11
|
+
### O diagnostico passa a dizer o que achou (EMB-050)
|
|
12
|
+
|
|
13
|
+
- Sair com 1 no `doctor` nao e mais `INSTALL_FAILED`: agora e `DOCTOR_FINDINGS`. Pendencia encontrada e o diagnostico trabalhando, nao instalacao quebrada — na janela de 20/09 isso gerou 3 alarmes de gravidade maxima para zero instalacoes quebradas.
|
|
14
|
+
- O `doctor` grava o resultado em `~/.auroq/install.log`: `pendencias=N etiqueta,etiqueta` quando acha algo e `ok` quando fecha limpo. As etiquetas sao vocabulario fechado (`arquivos-faltando`, `motor-fora-do-perfil`, `sem-login`, ...) e nunca levam caminho, e-mail, token nem nome de maquina. O suporte pede uma linha: `cat ~/.auroq/install.log`.
|
|
15
|
+
- Registro MCP passa a `arcane-mcp@0.6.1` (publicado no npm em 21/09/2026), que conhece o codigo novo: os dois clientes compartilham a mesma fila local e qualquer um dos dois a envia, entao a lista de codigos tem que ser a mesma nos dois e no servidor. Feche e abra o Claude Code e o Codex depois da manutencao.
|
|
16
|
+
- Instaladores oficiais continuam fixando 2.5.10; promover a versao que instalacoes NOVAS recebem segue sendo ato explicito.
|
|
17
|
+
|
|
1
18
|
## 2.5.10 — 2026-09-19
|
|
2
19
|
|
|
3
20
|
### Conteudo ao vivo passa a usar o cliente 0.6.0
|
package/README.md
CHANGED
|
@@ -228,14 +228,14 @@ agents/ → Seu exercito (companion, workers, minds, squads)
|
|
|
228
228
|
*Auroq OS — by Euriler Jube / Arka*
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
## Observabilidade do motor
|
|
231
|
+
## Observabilidade e integridade do motor
|
|
232
232
|
|
|
233
|
-
|
|
234
|
-
manutencao/diagnostico. `npx -y auroq-os@2.5.
|
|
233
|
+
`npx -y auroq-os@2.5.12 doctor` mostra a fila local segura e os comandos pinados de
|
|
234
|
+
manutencao/diagnostico. `npx -y auroq-os@2.5.12 manutencao` preserva o caminho existente
|
|
235
235
|
de consentimento legado, studentFiles, customizacoes e dados do negocio. Nao ha
|
|
236
|
-
migracao forcada. O registro MCP aponta para `arcane-mcp@0.6.
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
migracao forcada. O registro MCP aponta para `arcane-mcp@0.6.1`, publicado no npm em
|
|
237
|
+
21/09/2026; `npm run release:verify` recusa publicar com um pin que o npm nao resolva.
|
|
238
|
+
A versao 2.5.12 so deve chegar aos instaladores publicos apos os gates nativos e a verificacao do tarball publicado. 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.
|
|
239
239
|
|
|
240
240
|
O CLI inicia captura antes das dependencias pesadas e registra resultado ao sair.
|
|
241
241
|
Eventos com identidade ja existente podem seguir pela rota autenticada na proxima
|
|
@@ -254,8 +254,7 @@ instalacao/manutencao/doctor/login/register-mcp. Bootstrap conversacional e o tr
|
|
|
254
254
|
final do squad nao sao inferidos como sucesso por sair do CLI ou preparar arquivos.
|
|
255
255
|
Antes de o script chegar ou em computador que nunca executa nosso codigo, nao ha sinal.
|
|
256
256
|
A rota events continua autenticada, limitada e idempotente. A plataforma deve receber
|
|
257
|
-
a whitelist antes de distribuir/promover os clientes;
|
|
258
|
-
mantem o pin 2.5.1 publicado ate a promocao npm ser possivel. Nao precisa migration adicional.
|
|
257
|
+
a whitelist antes de distribuir/promover os clientes; a promocao dos instaladores sincronizados depende da publicacao e verificacao da versao fixada. Nao precisa migration adicional.
|
|
259
258
|
|
|
260
259
|
O canal de adocao e o instalador oficial, o README/changelog, o doctor e o aviso de
|
|
261
260
|
comando aposentado quando a versao nova e executada. Isso nao atualiza silenciosamente
|
package/bin/auroq-os.js
CHANGED
|
@@ -20,7 +20,10 @@ async function observedMain() {
|
|
|
20
20
|
const record = (outcome, error_code) => telemetry.enqueue(owner,{endpoint:'lifecycle',stage,outcome,error_code});
|
|
21
21
|
telemetry.setHost('auroq-os');telemetry.importInstallerSpool();record('started');
|
|
22
22
|
let importing = true;
|
|
23
|
-
|
|
23
|
+
// Sair com 1 no `doctor` e o diagnostico fazendo o trabalho dele, nao a instalacao quebrando:
|
|
24
|
+
// `DOCTOR_FINDINGS` = achou pendencia pra resolver. Chamar isso de INSTALL_FAILED gerava alarme
|
|
25
|
+
// de gravidade maxima pra aluno com o caminho inteiro de pe (Marinei e Alessandra, 20/09).
|
|
26
|
+
process.once('exit',code=>record(code===0?'ok':'error',code===0?null:importing?'BOOTSTRAP_IMPORT':stage==='update'?'UPDATE_FAILED':stage==='doctor'?'DOCTOR_FINDINGS':'INSTALL_FAILED'));
|
|
24
27
|
process.once('uncaughtException',()=>{console.error('[auroq-os] RUNTIME_FAILURE');process.exit(1);});
|
|
25
28
|
process.once('unhandledRejection',()=>{console.error('[auroq-os] RUNTIME_FAILURE');process.exit(1);});
|
|
26
29
|
const cred = credentials.load();await telemetry.flush(cred?.user?.id,cred?.access_token);
|
|
@@ -28,7 +31,7 @@ async function observedMain() {
|
|
|
28
31
|
telemetry.runtimeReady=()=>{importing=false;};
|
|
29
32
|
runRuntime(telemetry);
|
|
30
33
|
} catch {
|
|
31
|
-
console.error('[auroq-os] '+(importing?'BOOTSTRAP_IMPORT':'RUNTIME_FAILURE')+'. Rode: npx -y auroq-os@2.5.
|
|
34
|
+
console.error('[auroq-os] '+(importing?'BOOTSTRAP_IMPORT':'RUNTIME_FAILURE')+'. Rode: npx -y auroq-os@2.5.12 doctor');
|
|
32
35
|
process.exitCode=1;
|
|
33
36
|
}
|
|
34
37
|
}
|
|
@@ -214,13 +217,45 @@ function registrarInstallLog(evento, detalhe = '') {
|
|
|
214
217
|
const dir = path.join(require('os').homedir(), '.auroq');
|
|
215
218
|
fs.ensureDirSync(dir);
|
|
216
219
|
const quando = new Date().toISOString().replace(/\.\d+Z$/, 'Z');
|
|
217
|
-
const limpo = String(detalhe).replace(/[^\w
|
|
220
|
+
const limpo = String(detalhe).replace(/[^\w ,.:=+/\\-]/g, '');
|
|
218
221
|
fs.appendFileSync(path.join(dir, 'install.log'), `${quando}\t${evento}\t${limpo}\n`);
|
|
219
222
|
} catch {
|
|
220
223
|
/* registro e conveniencia pro suporte */
|
|
221
224
|
}
|
|
222
225
|
}
|
|
223
226
|
|
|
227
|
+
/**
|
|
228
|
+
* Etiqueta curta e FIXA pra cada pendencia que o `doctor` lista (EMB-050).
|
|
229
|
+
*
|
|
230
|
+
* O suporte precisa saber "falhou no que", nao so "falhou": a lista do doctor morria na tela do
|
|
231
|
+
* aluno e o plantao ficava adivinhando (da Alessandra nunca soubemos qual item era). A etiqueta e
|
|
232
|
+
* vocabulario fechado de proposito — nunca caminho, e-mail, token, nome de maquina nem o texto da
|
|
233
|
+
* pendencia. O casamento e por trecho estavel da mensagem; o teste `doctor-recibo` reprova qualquer
|
|
234
|
+
* pendencia nova que caia em `outro`.
|
|
235
|
+
*/
|
|
236
|
+
const ETIQUETAS_DOCTOR = [
|
|
237
|
+
['repor o que falta', 'arquivos-faltando'],
|
|
238
|
+
['sem tirar nada seu', 'synapse-nao-registrado'],
|
|
239
|
+
['Synapse antigo', 'synapse-antigo'],
|
|
240
|
+
['no Windows, install.ps1', 'motor-ausente'],
|
|
241
|
+
['FECHE e abra', 'motor-fora-do-perfil'],
|
|
242
|
+
['2 minutos de espera', 'mcp-timeout-curto'],
|
|
243
|
+
['com o tempo certo', 'codex-timeout-curto'],
|
|
244
|
+
['mais tempo ao Codex', 'arranque-lento'],
|
|
245
|
+
['reescreve o registro)', 'mcp-nao-registrado'],
|
|
246
|
+
['register-mcp na pasta. Depois', 'mcp-pin-antigo'],
|
|
247
|
+
['arcane-mcp login', 'sem-login'],
|
|
248
|
+
['fora do ar', 'servidor-fora'],
|
|
249
|
+
['Confira sua internet', 'servidor-fora'],
|
|
250
|
+
['whoami', 'mcp-nao-abre'],
|
|
251
|
+
['tela INTEIRA', 'codex-sem-conteudo'],
|
|
252
|
+
];
|
|
253
|
+
function rotulo(pendencia) {
|
|
254
|
+
const texto = String(pendencia || '');
|
|
255
|
+
for (const [marca, etiqueta] of ETIQUETAS_DOCTOR) if (texto.includes(marca)) return etiqueta;
|
|
256
|
+
return 'outro';
|
|
257
|
+
}
|
|
258
|
+
|
|
224
259
|
/**
|
|
225
260
|
* Identificador curto e nao reversivel da maquina — so pro suporte casar dois
|
|
226
261
|
* registros do mesmo computador. Nao sai da maquina e nao contem nome nem e-mail.
|
|
@@ -503,12 +538,22 @@ async function runDoctor(targetDir) {
|
|
|
503
538
|
}
|
|
504
539
|
|
|
505
540
|
log('');
|
|
541
|
+
// Recibo duravel pro suporte, inclusive quando fechou limpo: sem o historico completo o plantao
|
|
542
|
+
// nao sabe se a pendencia de ontem foi resolvida. Conveniencia — nunca pode derrubar o doctor,
|
|
543
|
+
// por isso montar o texto tambem fica DENTRO do try.
|
|
544
|
+
const recibo = pendencias => {
|
|
545
|
+
try {
|
|
546
|
+
registrarInstallLog('doctor', pendencias.length ? `pendencias=${pendencias.length} ${pendencias.map(p => rotulo(p)).join(',')}` : 'ok');
|
|
547
|
+
} catch { /* recibo e conveniencia pro suporte */ }
|
|
548
|
+
};
|
|
506
549
|
if (problemas.length === 0) {
|
|
507
550
|
success('Tudo certo. Pode chamar o Companion.');
|
|
551
|
+
recibo(problemas);
|
|
508
552
|
return 0;
|
|
509
553
|
}
|
|
510
554
|
error(`${problemas.length} coisa(s) pra resolver:`);
|
|
511
555
|
for (const p of problemas) log(` ${DIM}- ${p}${RESET}`);
|
|
556
|
+
recibo(problemas);
|
|
512
557
|
log('');
|
|
513
558
|
log(`${DIM}Se travar, chame o suporte: 11 93621-4486${RESET}`);
|
|
514
559
|
return 1;
|
|
@@ -524,7 +569,7 @@ async function runDoctor(targetDir) {
|
|
|
524
569
|
// 2.5.4/2.5.5 pinaram uma versao que ainda nao estava no npm e o MCP fechava a conexao.
|
|
525
570
|
// Por isso `scripts/assert-mcp-pin.mjs` (release:verify/prepublishOnly) recusa publicar
|
|
526
571
|
// com um pin que o `npm view` nao resolva exatamente. Trocar o pin aqui exige o pacote ja publicado.
|
|
527
|
-
const ARCANE_MCP_PIN = 'arcane-mcp@0.6.
|
|
572
|
+
const ARCANE_MCP_PIN = 'arcane-mcp@0.6.1';
|
|
528
573
|
const CODEX_MCP_STARTUP_SEC = 120;
|
|
529
574
|
// O Claude Code tambem desistia aos 30s (MCP_TIMEOUT) e o aluno via CONNECT_TIMEOUT com o
|
|
530
575
|
// servidor no ar e nenhum pedido chegando nele (11/09, EMB-041). Ele le o tempo do `env` das
|
|
@@ -577,7 +622,7 @@ function blocoCodexArcane(pin, opcoes) {
|
|
|
577
622
|
}
|
|
578
623
|
|
|
579
624
|
// Baixa o pacote do conteudo ao vivo com o MESMO nome que o registro usa (o cache do
|
|
580
|
-
// npx e por nome+versao: `arcane-mcp` e `arcane-mcp@0.6.
|
|
625
|
+
// npx e por nome+versao: `arcane-mcp` e `arcane-mcp@0.6.1` sao caches diferentes).
|
|
581
626
|
// `npx` no Windows e um .cmd: sem shell o Node recusa (EINVAL) e com `shell: true` o Node 24
|
|
582
627
|
// imprime um DeprecationWarning na tela do aluno (DEP0190). Chamar o cmd.exe direto, sem shell.
|
|
583
628
|
function comandoNpx(args) {
|
|
@@ -1803,7 +1848,7 @@ if (['init', 'install', 'update'].includes(command)) {
|
|
|
1803
1848
|
error('Comando aposentado. Nada foi instalado ou alterado.');
|
|
1804
1849
|
error('Primeira instalacao: https://arcane.arka.education/auroq');
|
|
1805
1850
|
error('No negocio existente, peca ao Ops: manutencao do motor. Conteudo chega pelo MCP.');
|
|
1806
|
-
error('Diagnostico: npx -y auroq-os@2.5.
|
|
1851
|
+
error('Diagnostico: npx -y auroq-os@2.5.12 doctor. Manutencao: npx -y auroq-os@2.5.12 manutencao.');
|
|
1807
1852
|
process.exitCode = 1;
|
|
1808
1853
|
} else if (command === 'instalar' || command === 'manutencao') {
|
|
1809
1854
|
// `--pasta <nome>`: o instalador manda o CLI criar e entrar na pasta do negocio,
|
|
@@ -1930,6 +1975,6 @@ if (['init', 'install', 'update'].includes(command)) {
|
|
|
1930
1975
|
log('');
|
|
1931
1976
|
}
|
|
1932
1977
|
|
|
1933
|
-
if (process.env.AUROQ_EXPORTA_INTERNOS === '1') module.exports = { blocoCodexArcane, envCodexArcane, lerBlocoArcane, lerEnvDoBloco, limparArcaneDoGlobal, envComoCodex, argumentosCodexSmoke, avaliarEventosCodex, ARCANE_MCP_PIN };
|
|
1978
|
+
if (process.env.AUROQ_EXPORTA_INTERNOS === '1') module.exports = { blocoCodexArcane, envCodexArcane, lerBlocoArcane, lerEnvDoBloco, limparArcaneDoGlobal, envComoCodex, argumentosCodexSmoke, avaliarEventosCodex, rotulo, ARCANE_MCP_PIN };
|
|
1934
1979
|
|
|
1935
1980
|
}
|
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.5.
|
|
592
|
+
& (Get-AuroqNpx) -y auroq-os@2.5.12 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.5.
|
|
680
|
+
& (Get-AuroqNpx) -y auroq-os@2.5.12 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.5.
|
|
222
|
+
npx -y auroq-os@2.5.12 "$@"
|
|
223
223
|
else
|
|
224
|
-
npx -y auroq-os@2.5.
|
|
224
|
+
npx -y auroq-os@2.5.12 "$@" < /dev/tty
|
|
225
225
|
fi
|
|
226
226
|
}
|
|
227
227
|
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"algorithm": "sha256",
|
|
4
|
+
"scope": "packaged-runtime-and-cascas",
|
|
5
|
+
"version": "2.5.12",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"path": ".auroq-core/constitution.md",
|
|
9
|
+
"sha256": "8b6df553e2708e3d9eff3f12627808ca953a4272cfbd2f94cb9ae3d4c70a73de"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"path": ".auroq-core/core-config.yaml",
|
|
13
|
+
"sha256": "bb98d40d411423cfd4e92100a003a029309d5db1a5514b1a7fed880b96fc1f56"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": ".auroq-core/core/synapse/context/context-builder.js",
|
|
17
|
+
"sha256": "121cd0a1df8a44098831cd4335536e8facf4e65b8aec48f4ce9c2d432dc6252a"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": ".auroq-core/core/synapse/context/context-tracker.js",
|
|
21
|
+
"sha256": "48e94db7b1778dedecc8eae829139579ad7778ff47668597ebe766610696553f"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/consistency-collector.js",
|
|
25
|
+
"sha256": "65f4255f87c9900400649dc8b9aedaac4851b5939d93e127778bd93cee99db12"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/hook-collector.js",
|
|
29
|
+
"sha256": "c2cfa1b760bcb05decf5ad05f9159140cbe0cdc6b0f91581790e44d83dc6b660"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/manifest-collector.js",
|
|
33
|
+
"sha256": "3dc895eb94485320ecbaca3a1d29e3776cfb691dd7dcc71cf44b34af30e8ebb6"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/output-analyzer.js",
|
|
37
|
+
"sha256": "e6846b1aba0a6cba17c297a871861d4f8199d7500220bff296a6a3291e32493e"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/pipeline-collector.js",
|
|
41
|
+
"sha256": "8655b6240e2f54b70def1a8c2fae00d40e2615cb95fd7ca0d64c2e0a6dfe3b73"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/quality-collector.js",
|
|
45
|
+
"sha256": "30ae299eab6d569d09afe3530a5b2f1ff35ef75366a1ab56a9e2a57d39d3611c"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/relevance-matrix.js",
|
|
49
|
+
"sha256": "f92c4f7061dc82eed4310a27b69eade33d3015f9beb1bed688601a2dccbad22e"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/safe-read-json.js",
|
|
53
|
+
"sha256": "dc7bcd13779207ad67b1c3929b7e1e0ccfa3563f3458c20cad28cb1922e9a74c"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/session-collector.js",
|
|
57
|
+
"sha256": "a116d884d6947ddc8e5f3def012d93696576c584c4fde1639b8d895924fc09ea"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/timing-collector.js",
|
|
61
|
+
"sha256": "2523ce93f863a28f798d992c4f2fab041c91a09413b3186fd290e6035b391587"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"path": ".auroq-core/core/synapse/diagnostics/collectors/uap-collector.js",
|
|
65
|
+
"sha256": "dd025894f8f0d3bd22a147dbc0debef8b83e96f3c59483653404b3cd5a01d5aa"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"path": ".auroq-core/core/synapse/diagnostics/report-formatter.js",
|
|
69
|
+
"sha256": "1aa2853928df194b669ce32c3b050a90de1311739045074f699d10210ed8d381"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"path": ".auroq-core/core/synapse/diagnostics/synapse-diagnostics.js",
|
|
73
|
+
"sha256": "de9dffce0e380637027cbd64b062d3eeffc37e42a84a337e5758fbef39fe3a00"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"path": ".auroq-core/core/synapse/domain/domain-loader.js",
|
|
77
|
+
"sha256": "af788f9da956b89eef1e5eb4ef4efdf05ca758c8969a2c375f568119495ebc05"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"path": ".auroq-core/core/synapse/engine.js",
|
|
81
|
+
"sha256": "775d232f67c92596f4a4a4302d5f4c69b6473680badead6ff4772f46e157381c"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"path": ".auroq-core/core/synapse/layers/l0-constitution.js",
|
|
85
|
+
"sha256": "2123a6a44915aaac2a6bbd26c67c285c9d1e12b50fe42a8ada668306b07d1c4a"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"path": ".auroq-core/core/synapse/layers/l1-global.js",
|
|
89
|
+
"sha256": "21f6969e6d64e9a85c876be6799db4ca7d090f0009057f4a06ead8da12392d45"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"path": ".auroq-core/core/synapse/layers/l2-agent.js",
|
|
93
|
+
"sha256": "a8677dc58ae7927c5292a4b52883bbc905c8112573b8b8631f0b8bc01ea2b6e6"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"path": ".auroq-core/core/synapse/layers/l3-workflow.js",
|
|
97
|
+
"sha256": "496cbd71d7dac9c1daa534ffac45c622d0c032f334fedf493e9322a565b2b181"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"path": ".auroq-core/core/synapse/layers/l4-task.js",
|
|
101
|
+
"sha256": "30df70c04b16e3aff95899211ef6ae3d9f0a8097ebdc7de92599fc6cb792e5f0"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"path": ".auroq-core/core/synapse/layers/l5-squad.js",
|
|
105
|
+
"sha256": "d6d35cbf966deb5a7d2df2b09f5abe8da8c6d4e346b385418f8dc1fae3ddf830"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"path": ".auroq-core/core/synapse/layers/l6-keyword.js",
|
|
109
|
+
"sha256": "8e5405999a2ce2f3ca4e62e863cf702ba27448914241f5eb8f02760bc7477523"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"path": ".auroq-core/core/synapse/layers/l7-star-command.js",
|
|
113
|
+
"sha256": "3b8372ac1c51830c1ef560b1012b112a3559651b0750e42f2037f7fe9e6787d6"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": ".auroq-core/core/synapse/layers/layer-processor.js",
|
|
117
|
+
"sha256": "46a7d08e088017a61fa6033ce4d9b3b8caba622e2c732fe158e0f531690fa3d9"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"path": ".auroq-core/core/synapse/memory/memory-bridge.js",
|
|
121
|
+
"sha256": "820875f97ceea80fc6402c0dab1706cfe58de527897b22dea68db40b0d6ec368"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"path": ".auroq-core/core/synapse/memory/synapse-memory-provider.js",
|
|
125
|
+
"sha256": "5d613d1fac7ee82c49a3f03b38735fd3cabfe87dd868494672ddfef300ea3145"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"path": ".auroq-core/core/synapse/output/formatter.js",
|
|
129
|
+
"sha256": "3e722c4736642ef96ec73a54cd2011eed7bd1074394a38eac66cb6f0af2c855b"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"path": ".auroq-core/core/synapse/runtime/hook-runtime.js",
|
|
133
|
+
"sha256": "77a88b9324940b4feb14de6fe4de51c0fd82e2062ef4470b93de2e57bd02c88a"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"path": ".auroq-core/core/synapse/scripts/generate-constitution.js",
|
|
137
|
+
"sha256": "e2f645d5de44e6b3721a5de9b19982bc7b8cf7eed3ca4d62bc53221649c59af1"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"path": ".auroq-core/core/synapse/session/session-manager.js",
|
|
141
|
+
"sha256": "98e8c8fa15b074b6102bcd51c6f91f101743338e8cde6de9c31d6b6eea5d6580"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"path": ".auroq-core/core/synapse/utils/atomic-write.js",
|
|
145
|
+
"sha256": "efeef0fbcebb184df5b79f4ba4b4b7fe274c3ba7d1c705ce1af92628e920bd8b"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"path": ".auroq-core/core/synapse/utils/paths.js",
|
|
149
|
+
"sha256": "bf8cf93c1a16295e7de055bee292e2778a152b6e7d6c648dbc054a4b04dffc10"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"path": ".auroq-core/core/synapse/utils/tokens.js",
|
|
153
|
+
"sha256": "3b927daec51d0a791f3fe4ef9aafc362773450e7cf50eb4b6d8ae9011d70df9a"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"path": ".auroq-core/dna-operacional.md",
|
|
157
|
+
"sha256": "36d3118831d1d406a1e5eef2394fef6628396712534c59888a5968f9ffdba796"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"path": ".claude/commands/AuroqOS/agents/ops.md",
|
|
161
|
+
"sha256": "6f0df7c0dfbe28f4efa4d49d010f5a2520293c972623eb5c7dc25aa62ba7fc37"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"path": ".claude/commands/auroq-companion.md",
|
|
165
|
+
"sha256": "789bb61f076847f5695be0ea1133cfe026024c3e7a77a48f142297cc30e02196"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"path": ".claude/hooks/ahi-capture.cjs",
|
|
169
|
+
"sha256": "d99564a5bebc23281da5dbba2e82ef099c390768bed2b63f70be17c75ab8fd57"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"path": ".claude/hooks/ahi/auth-config.cjs",
|
|
173
|
+
"sha256": "bbe1f01165f0cf4562b8685a59bd2aac94758dbd0b072d287c09db10d9c6e0eb"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"path": ".claude/hooks/ahi/runtime.cjs",
|
|
177
|
+
"sha256": "82c0b93351f25959e5cbe0a9a57b7ae29a3b497298ab351bddd7361a2ef6ce1a"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"path": ".claude/hooks/ahi/security.cjs",
|
|
181
|
+
"sha256": "dc27db1392acd0abd8102490860bfad6a94276bbc92f63e086dc997dbe6b208c"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"path": ".claude/hooks/ahi/worker.cjs",
|
|
185
|
+
"sha256": "3eabd293f3c9c6887f6850ca4be9ad7021d6659967f2f5eecadefb2bb78e9b85"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"path": ".claude/hooks/auroq-sync.cjs",
|
|
189
|
+
"sha256": "2655dbd0a6f73ae83d0fabfb9567fc7dbf79708adcf9bfa455ea6da6fc183b9f"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"path": ".claude/hooks/precompact-session-digest.cjs",
|
|
193
|
+
"sha256": "cca89df5591fd52581d62bd35cc097d7e3d2622bd2227e7e53b425d5a6d8bdb2"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"path": ".claude/hooks/synapse-engine.cjs",
|
|
197
|
+
"sha256": "4d01f376993b570b9ca995b839d292ce9b73c597a0a1ebc8cb1ffbd214093bfe"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"path": ".claude/settings.json",
|
|
201
|
+
"sha256": "3d0a9836997e7524d1538e96799bd5ea06575620c97a2eb03d3410b6df5d0e5a"
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"path": ".claude/settings.local.json",
|
|
205
|
+
"sha256": "cb81d47fef6536bd472841811bb85f36a8219994d55399eac85732f920c566c6"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"path": "bin/auroq-os.js",
|
|
209
|
+
"sha256": "b043982de702e524799b51968b29578c04e8a6ed5f66c318d661bf776f0ef838"
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"path": "lib/ahi/client.mjs",
|
|
213
|
+
"sha256": "ded0ba89b58193e59b4ced26321965f85b8b19abc498ed8b079cab956806d789"
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
"path": "lib/ahi/historico.mjs",
|
|
217
|
+
"sha256": "cb85e53dae59e793bdb83f59c3f8d14342912953b43dd9408d757a7b7182733a"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"path": "lib/ahi/install.cjs",
|
|
221
|
+
"sha256": "f3a9fec92e64b8624fb45e062b51777788831337dec6a89ce8222d7813baca9d"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"path": "lib/auth.js",
|
|
225
|
+
"sha256": "e775938f20b86c305e44c2b5834eeb886fec0316dccc0f3565536689b7bfb46a"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"path": "lib/credentials.js",
|
|
229
|
+
"sha256": "92ecfba2b7ded12de5b236d64b24781ffdf05c1e770614a8d02bf05ab78d59e0"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
"path": "lib/diagnostico.js",
|
|
233
|
+
"sha256": "a7c15e8aa9dd3a7ceca3784ce7207f9593baaabedc87e88d0a674096b20c6835"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
"path": "lib/legacy-shims.json",
|
|
237
|
+
"sha256": "1ea331604dfcadc579a7a27d53bfb2c1d1a2263e1d2ca83ed780c5ce5d2fe877"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"path": "lib/onepassword.js",
|
|
241
|
+
"sha256": "a65d425182e0698d3f80b8d81bb088b13c5e5b60ae1aa92b095ab38d60e22ea9"
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"path": "lib/supabase.js",
|
|
245
|
+
"sha256": "a922dee14500e95b4b1f7a8d2a67baedee71c547f863e69e63f25830f9786f28"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"path": "lib/synapse-hashes.json",
|
|
249
|
+
"sha256": "061dfe2e2c7e2a75472ae133e3465931c1267cc18e0740e7c1515404095b47e6"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"path": "lib/telemetry.mjs",
|
|
253
|
+
"sha256": "13643a1f8c33d7063a07b37190ba157755f8e26aadd4059e1afdc25fada0cf38"
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"path": "package.json",
|
|
257
|
+
"sha256": "17d5e5a26ffd8044fd8b98260ca7961b37a326acbe8b63dd3a65af73edff1317"
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"path": "scripts/build-pack.mjs",
|
|
261
|
+
"sha256": "c4f7bbc40320dcf848307ab9d7d7c84c864ddc70a0e4db933a35406f55dcf881"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"path": "scripts/pack-state.mjs",
|
|
265
|
+
"sha256": "7399b388eab97dd35da49055b126aba39a0c95d82cf422c62b603e9bf5de7f36"
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
"path": "scripts/postpack-casca.mjs",
|
|
269
|
+
"sha256": "e361ed44a688d0cd6804bdbf3e240649b69171c2396433f0fdb55cb0f739d993"
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
"path": "scripts/prepack-casca.mjs",
|
|
273
|
+
"sha256": "ecd4381a411d275af339e0bdc3acc5a0ea33ad65c1eaafad6ff3d6c79b415aff"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"path": "scripts/runtime-integrity.mjs",
|
|
277
|
+
"sha256": "af0cb75622dcf4c049da3fc053817087648a86fc31df3be4762e974279eb87a3"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"path": "scripts/sync-codex-skills.mjs",
|
|
281
|
+
"sha256": "36e703e8d298a5fc4cff3a85828b93a5123ab9563eeb2808c30f23f3eefd58f8"
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
"path": "scripts/validate-hybrid.mjs",
|
|
285
|
+
"sha256": "d70636ad4fd6a7975df552de5cc4a88d535f0ec8596b7cf74c20e9ff73f02505"
|
|
286
|
+
}
|
|
287
|
+
]
|
|
288
|
+
}
|
package/lib/synapse-hashes.json
CHANGED
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
],
|
|
50
50
|
"engine.js": [
|
|
51
51
|
"47bab93a2144edce875ee68cc2717fee1bd824c9affdd5964454f5141310b8e0",
|
|
52
|
-
"c061df38ec24956da9a752f13f9455c7cd69546adb330c7587b9d456e79b4aa1"
|
|
52
|
+
"c061df38ec24956da9a752f13f9455c7cd69546adb330c7587b9d456e79b4aa1",
|
|
53
|
+
"775d232f67c92596f4a4a4302d5f4c69b6473680badead6ff4772f46e157381c"
|
|
53
54
|
],
|
|
54
55
|
"layers/l0-constitution.js": [
|
|
55
56
|
"2123a6a44915aaac2a6bbd26c67c285c9d1e12b50fe42a8ada668306b07d1c4a"
|
|
@@ -76,7 +77,8 @@
|
|
|
76
77
|
"3b8372ac1c51830c1ef560b1012b112a3559651b0750e42f2037f7fe9e6787d6"
|
|
77
78
|
],
|
|
78
79
|
"layers/layer-processor.js": [
|
|
79
|
-
"73cb0e5b4bada80d8e256009004679e483792077fac4358c6466cd77136f79fa"
|
|
80
|
+
"73cb0e5b4bada80d8e256009004679e483792077fac4358c6466cd77136f79fa",
|
|
81
|
+
"46a7d08e088017a61fa6033ce4d9b3b8caba622e2c732fe158e0f531690fa3d9"
|
|
80
82
|
],
|
|
81
83
|
"memory/memory-bridge.js": [
|
|
82
84
|
"820875f97ceea80fc6402c0dab1706cfe58de527897b22dea68db40b0d6ec368"
|
|
@@ -90,7 +92,8 @@
|
|
|
90
92
|
],
|
|
91
93
|
"runtime/hook-runtime.js": [
|
|
92
94
|
"5518692eeee7dcb570507c4bb96ef68a1ef51d6ad6c417e9d1f649cd8b21b199",
|
|
93
|
-
"7c34b84c5693045a007356081959c335493bbd3afc69822fb6661e19cc10d56c"
|
|
95
|
+
"7c34b84c5693045a007356081959c335493bbd3afc69822fb6661e19cc10d56c",
|
|
96
|
+
"77a88b9324940b4feb14de6fe4de51c0fd82e2062ef4470b93de2e57bd02c88a"
|
|
94
97
|
],
|
|
95
98
|
"scripts/generate-constitution.js": [
|
|
96
99
|
"e2f645d5de44e6b3721a5de9b19982bc7b8cf7eed3ca4d62bc53221649c59af1"
|
package/lib/telemetry.mjs
CHANGED
|
@@ -20,7 +20,10 @@ export function networkCode(e) {
|
|
|
20
20
|
}
|
|
21
21
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
22
22
|
const uuid = v => typeof v === 'string' && UUID.test(v) ? v : null;
|
|
23
|
-
|
|
23
|
+
// DOCTOR_FINDINGS: o doctor achou pendencia e saiu com 1 — diagnostico trabalhando, nao instalacao
|
|
24
|
+
// quebrada. Os dois clientes gravam no MESMO outbox e qualquer um faz o flush, entao a lista tem que
|
|
25
|
+
// ser a mesma nos dois (e no servidor): o que falta aqui vira null e apaga o alarme (EMB-050).
|
|
26
|
+
const ERRORS = new Set(['NETWORK_TLS','NETWORK_DNS','NETWORK_TIMEOUT','NETWORK_OTHER','AUTH_MISSING','AUTH_REFRESH','HTTP_ERROR','CLIENT_ERROR','BOOTSTRAP_IMPORT','RUNTIME_FAILURE','INSTALL_FAILED','UPDATE_FAILED','DOCTOR_FINDINGS']);
|
|
24
27
|
const STAGES = new Set(['startup','runtime','install','update','doctor','login','bootstrap','git','node','access','folder','framework']);
|
|
25
28
|
const tools = new Set(['catalogo_listar','squad_ativar','squad_passo','squad_conhecimento','forja_bundle','busca']);
|
|
26
29
|
const TTL = 7*86400000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "auroq-os",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.12",
|
|
4
4
|
"description": "Auroq OS — Sistema Operacional de IA para Experts",
|
|
5
5
|
"bin": {
|
|
6
6
|
"auroq-os": "bin/auroq-os.js"
|
|
@@ -18,14 +18,15 @@
|
|
|
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 && 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 .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",
|
|
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/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 .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
22
|
"typecheck": "npm run validate:hybrid",
|
|
23
23
|
"test": "node --test tests/*.test.mjs",
|
|
24
24
|
"release:verify": "node scripts/assert-mcp-pin.mjs && node scripts/assert-native-release.mjs",
|
|
25
25
|
"prepublishOnly": "npm run release:verify",
|
|
26
26
|
"prepack": "node scripts/prepack-casca.mjs",
|
|
27
27
|
"postpack": "node scripts/postpack-casca.mjs",
|
|
28
|
-
"build": "node scripts/build-pack.mjs"
|
|
28
|
+
"build": "node scripts/build-pack.mjs",
|
|
29
|
+
"integrity:verify": "node scripts/runtime-integrity.mjs --verify"
|
|
29
30
|
},
|
|
30
31
|
"files": [
|
|
31
32
|
"bin/",
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"dependencies": {
|
|
57
58
|
"@supabase/supabase-js": "^2.103.0",
|
|
58
59
|
"fs-extra": "^11.3.0",
|
|
59
|
-
"js-yaml": "^4.
|
|
60
|
+
"js-yaml": "^4.3.2",
|
|
60
61
|
"prompts": "^2.4.2"
|
|
61
62
|
},
|
|
62
63
|
"author": "Euriler Jube / Arka",
|
package/scripts/build-pack.mjs
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
//
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
2
|
+
// Validate actual tarball bytes AFTER the casca overlay; never pack this checkout.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { execFileSync } from 'node:child_process';
|
|
8
|
+
import { verifyRuntimeInventory } from './runtime-integrity.mjs';
|
|
9
|
+
|
|
10
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
11
|
+
const temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'auroq-build-pack-'));
|
|
12
|
+
try {
|
|
13
|
+
const copy = path.join(temporary, 'source');
|
|
14
|
+
const excluded = new Set(['.git', 'node_modules', '.pack-casca-backup']);
|
|
15
|
+
if (fs.existsSync(path.join(root, '.pack-casca-backup'))) throw new Error('Pending casca backup: restore the checkout before building.');
|
|
16
|
+
fs.cpSync(root, copy, { recursive: true, filter: source => !path.relative(root, source).split(path.sep).some(part => excluded.has(part) || part.endsWith('.tgz')) });
|
|
17
|
+
const cli = process.env.npm_execpath || (process.platform === 'win32'
|
|
18
|
+
? path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js') : null);
|
|
19
|
+
const args = ['pack', '--json', '--pack-destination', temporary];
|
|
20
|
+
const output = execFileSync(cli ? process.execPath : 'npm', cli ? [cli, ...args] : args,
|
|
21
|
+
{ cwd: copy, encoding: 'utf8', maxBuffer: 8 * 1024 * 1024, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
22
|
+
const match = output.match(/(\[\s*\{[\s\S]*\}\s*\])/);
|
|
23
|
+
if (!match) throw new Error('Package manifest unavailable');
|
|
24
|
+
const packages = JSON.parse(match[1]);
|
|
25
|
+
if (packages.length !== 1 || !packages[0].filename || path.basename(packages[0].filename) !== packages[0].filename) throw new Error('Invalid package result');
|
|
26
|
+
const artifact = path.join(temporary, packages[0].filename);
|
|
27
|
+
const listing = execFileSync('tar', ['-tzf', artifact], { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 });
|
|
28
|
+
const packedPaths = listing.split(/\r?\n/).filter(Boolean).map(file => {
|
|
29
|
+
if (!file.startsWith('package/') || file.endsWith('/') || file.includes('..') || file.includes('\\')) throw new Error('Invalid tarball path');
|
|
30
|
+
return file.slice('package/'.length);
|
|
31
|
+
});
|
|
32
|
+
const extracted = path.join(temporary, 'extracted');
|
|
33
|
+
fs.mkdirSync(extracted);
|
|
34
|
+
execFileSync('tar', ['-xzf', artifact, '-C', extracted], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
35
|
+
const result = verifyRuntimeInventory(path.join(extracted, 'package'), packedPaths);
|
|
36
|
+
if (fs.existsSync(path.join(copy, '.pack-casca-backup'))) throw new Error('Pack did not restore its casca overlay');
|
|
37
|
+
process.stdout.write(`Package validated: ${result.files} protected files, SHA256 and local runtime references.\n`);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// Do not print npm lifecycle output: it may include environment-specific data.
|
|
40
|
+
console.error(`Package validation failed: ${error.status !== undefined ? 'pack/extraction command failed' : error.message}`);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
} finally {
|
|
43
|
+
fs.rmSync(temporary, { recursive: true, force: true });
|
|
44
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Journal the temporary casca overlay, including files absent before packing. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const BACKUP = '.pack-casca-backup';
|
|
6
|
+
const JOURNAL = 'overlay-state.json';
|
|
7
|
+
|
|
8
|
+
function assertPath(relative) {
|
|
9
|
+
if (!relative || path.isAbsolute(relative) || /^[A-Za-z]:/.test(relative) || relative.includes('\\') || relative.split('/').some(p => !p || p === '.' || p === '..')) {
|
|
10
|
+
throw new Error('Invalid overlay path');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function assertNoSymlink(root, relative) {
|
|
15
|
+
let current = root;
|
|
16
|
+
for (const segment of relative.split('/')) {
|
|
17
|
+
current = path.join(current, segment);
|
|
18
|
+
let stat;
|
|
19
|
+
try { stat = fs.lstatSync(current); } catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
20
|
+
if (stat?.isSymbolicLink()) throw new Error(`Symlink in overlay path: ${relative}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function beginOverlay(root) {
|
|
25
|
+
const backup = path.join(root, BACKUP);
|
|
26
|
+
if (fs.existsSync(backup)) throw new Error('Pending casca backup: restore with node scripts/postpack-casca.mjs before packing again.');
|
|
27
|
+
fs.mkdirSync(backup);
|
|
28
|
+
fs.writeFileSync(path.join(backup, JOURNAL), '[]\n');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function preserveOverlayFile(root, relative) {
|
|
32
|
+
assertPath(relative);
|
|
33
|
+
assertNoSymlink(root, relative);
|
|
34
|
+
const backup = path.join(root, BACKUP);
|
|
35
|
+
const journalFile = path.join(backup, JOURNAL);
|
|
36
|
+
const journal = JSON.parse(fs.readFileSync(journalFile, 'utf8'));
|
|
37
|
+
if (journal.some(entry => entry.path === relative)) return;
|
|
38
|
+
const source = path.join(root, relative);
|
|
39
|
+
const existed = fs.existsSync(source);
|
|
40
|
+
if (existed) {
|
|
41
|
+
if (!fs.lstatSync(source).isFile()) throw new Error(`Overlay target is not a regular file: ${relative}`);
|
|
42
|
+
const target = path.join(backup, 'files', relative);
|
|
43
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
44
|
+
fs.copyFileSync(source, target);
|
|
45
|
+
}
|
|
46
|
+
journal.push({ path: relative, existed });
|
|
47
|
+
fs.writeFileSync(journalFile, `${JSON.stringify(journal)}\n`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function restoreOverlay(root) {
|
|
51
|
+
const backup = path.join(root, BACKUP);
|
|
52
|
+
if (!fs.existsSync(backup)) return;
|
|
53
|
+
const journal = JSON.parse(fs.readFileSync(path.join(backup, JOURNAL), 'utf8'));
|
|
54
|
+
for (const entry of journal.reverse()) {
|
|
55
|
+
assertPath(entry.path);
|
|
56
|
+
assertNoSymlink(root, entry.path);
|
|
57
|
+
const target = path.join(root, entry.path);
|
|
58
|
+
if (entry.existed) {
|
|
59
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
60
|
+
fs.copyFileSync(path.join(backup, 'files', entry.path), target);
|
|
61
|
+
} else fs.rmSync(target, { force: true });
|
|
62
|
+
}
|
|
63
|
+
fs.rmSync(backup, { recursive: true });
|
|
64
|
+
}
|
|
@@ -1,32 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/** Restaura o miolo depois do npm pack/publish. */
|
|
3
|
-
import fs from 'node:fs';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { restoreOverlay } from './pack-state.mjs';
|
|
6
6
|
|
|
7
|
-
const root =
|
|
8
|
-
|
|
9
|
-
const backupRoot = path.join(root, '.pack-casca-backup');
|
|
10
|
-
|
|
11
|
-
function walk(dir) {
|
|
12
|
-
const out = [];
|
|
13
|
-
if (!fs.existsSync(dir)) return out;
|
|
14
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
15
|
-
const full = path.join(dir, entry.name);
|
|
16
|
-
if (entry.isDirectory()) out.push(...walk(full));
|
|
17
|
-
else out.push(full);
|
|
18
|
-
}
|
|
19
|
-
return out;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (!fs.existsSync(backupRoot)) process.exit(0);
|
|
23
|
-
|
|
24
|
-
for (const bak of walk(backupRoot)) {
|
|
25
|
-
const rel = path.relative(backupRoot, bak);
|
|
26
|
-
const dest = path.join(root, rel);
|
|
27
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
28
|
-
fs.copyFileSync(bak, dest);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
fs.rmSync(backupRoot, { recursive: true, force: true });
|
|
7
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
8
|
+
restoreOverlay(root);
|
|
32
9
|
console.log('postpack-casca: working tree restaurado');
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { beginOverlay, preserveOverlayFile, restoreOverlay } from './pack-state.mjs';
|
|
10
|
+
import { INVENTORY_PATH, writeRuntimeInventory, verifyRuntimeInventory } from './runtime-integrity.mjs';
|
|
9
11
|
|
|
10
12
|
const root = fs.realpathSync(path.join(path.dirname(fileURLToPath(import.meta.url)), '..'));
|
|
11
13
|
const cascaRoot = path.join(root, 'casca');
|
|
12
|
-
const backupRoot = path.join(root, '.pack-casca-backup');
|
|
13
14
|
|
|
14
15
|
function walk(dir) {
|
|
15
16
|
const out = [];
|
|
@@ -22,45 +23,44 @@ function walk(dir) {
|
|
|
22
23
|
return out;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
if (fs.existsSync(backupRoot)) {
|
|
26
|
-
fs.rmSync(backupRoot, { recursive: true, force: true });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
26
|
const files = walk(cascaRoot);
|
|
30
27
|
if (!files.length) {
|
|
31
28
|
console.error('casca/ vazia — recusando pack');
|
|
32
29
|
process.exit(1);
|
|
33
30
|
}
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
// A missing validator fails at import time, before touching the checkout.
|
|
33
|
+
beginOverlay(root);
|
|
34
|
+
try {
|
|
35
|
+
for (const src of files) {
|
|
36
|
+
const rel = path.relative(cascaRoot, src).split(path.sep).join('/');
|
|
37
|
+
const dest = path.join(root, rel);
|
|
38
|
+
preserveOverlayFile(root, rel);
|
|
39
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
40
|
+
fs.copyFileSync(src, dest);
|
|
42
41
|
}
|
|
43
|
-
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
44
|
-
fs.copyFileSync(src, dest);
|
|
45
|
-
}
|
|
46
42
|
|
|
47
|
-
// O hook auroq-sync compara a versao lida de .auroq-core/core-config.yaml com a
|
|
48
|
-
// do npm para avisar de update. Se o core-config ficar para tras, TODO aluno ja
|
|
49
|
-
// atualizado ve "saiu versao nova" para sempre. Sincroniza no pack.
|
|
50
|
-
const pkgVersion = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version;
|
|
51
|
-
const cfgPath = path.join(root, '.auroq-core', 'core-config.yaml');
|
|
52
|
-
if (fs.existsSync(cfgPath)) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
fs.copyFileSync(cfgPath, bak);
|
|
43
|
+
// O hook auroq-sync compara a versao lida de .auroq-core/core-config.yaml com a
|
|
44
|
+
// do npm para avisar de update. Se o core-config ficar para tras, TODO aluno ja
|
|
45
|
+
// atualizado ve "saiu versao nova" para sempre. Sincroniza no pack.
|
|
46
|
+
const pkgVersion = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version;
|
|
47
|
+
const cfgPath = path.join(root, '.auroq-core', 'core-config.yaml');
|
|
48
|
+
if (fs.existsSync(cfgPath)) {
|
|
49
|
+
const cfg = fs.readFileSync(cfgPath, 'utf8');
|
|
50
|
+
const synced = cfg.replace(/^(\s*version:\s*)["']?\d+\.\d+\.\d+["']?/m, `$1${pkgVersion}`);
|
|
51
|
+
if (synced !== cfg) {
|
|
52
|
+
preserveOverlayFile(root, '.auroq-core/core-config.yaml');
|
|
53
|
+
fs.writeFileSync(cfgPath, synced);
|
|
54
|
+
console.log(`prepack-casca: core-config.yaml sincronizado para ${pkgVersion}`);
|
|
60
55
|
}
|
|
61
|
-
fs.writeFileSync(cfgPath, synced);
|
|
62
|
-
console.log(`prepack-casca: core-config.yaml sincronizado para ${pkgVersion}`);
|
|
63
56
|
}
|
|
64
|
-
}
|
|
65
57
|
|
|
66
|
-
|
|
58
|
+
preserveOverlayFile(root, INVENTORY_PATH);
|
|
59
|
+
writeRuntimeInventory(root);
|
|
60
|
+
const verified = verifyRuntimeInventory(root);
|
|
61
|
+
console.log(`prepack-casca: ${files.length} arquivos sobrepostos`);
|
|
62
|
+
console.log(`prepack-casca: inventario SHA256 de ${verified.files} arquivos (nao e assinatura)`);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
restoreOverlay(root);
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** Package completeness and accidental-change checks; SHA256 is not a signature.
|
|
3
|
+
* Scope: shipped engine/cascas only. Business files and optional legacy modules
|
|
4
|
+
* are not a source of dependencies. Generate AFTER the casca overlay.
|
|
5
|
+
*/
|
|
6
|
+
import fs from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import crypto from 'node:crypto';
|
|
9
|
+
import { fileURLToPath } from 'node:url';
|
|
10
|
+
|
|
11
|
+
export const INVENTORY_PATH = 'lib/runtime-integrity.json';
|
|
12
|
+
const SYNAPSE_ROOT = '.auroq-core/core/synapse/';
|
|
13
|
+
const SYNAPSE_LAYERS = ['l0-constitution', 'l1-global', 'l2-agent', 'l3-workflow', 'l4-task', 'l5-squad', 'l6-keyword', 'l7-star-command'];
|
|
14
|
+
export const REQUIRED_FILES = [
|
|
15
|
+
'package.json', 'bin/auroq-os.js',
|
|
16
|
+
'lib/auth.js', 'lib/credentials.js', 'lib/diagnostico.js', 'lib/supabase.js',
|
|
17
|
+
'lib/onepassword.js', 'lib/telemetry.mjs', 'lib/synapse-hashes.json', 'lib/legacy-shims.json',
|
|
18
|
+
'lib/ahi/install.cjs', 'lib/ahi/client.mjs', 'lib/ahi/historico.mjs',
|
|
19
|
+
'scripts/runtime-integrity.mjs', 'scripts/pack-state.mjs',
|
|
20
|
+
'scripts/prepack-casca.mjs', 'scripts/postpack-casca.mjs', 'scripts/build-pack.mjs',
|
|
21
|
+
'scripts/sync-codex-skills.mjs', 'scripts/validate-hybrid.mjs',
|
|
22
|
+
'.auroq-core/core-config.yaml', '.auroq-core/constitution.md', '.auroq-core/dna-operacional.md',
|
|
23
|
+
'.auroq-core/core/synapse/engine.js', '.auroq-core/core/synapse/runtime/hook-runtime.js',
|
|
24
|
+
'.auroq-core/core/synapse/session/session-manager.js', '.auroq-core/core/synapse/domain/domain-loader.js',
|
|
25
|
+
...SYNAPSE_LAYERS.map(layer => `${SYNAPSE_ROOT}layers/${layer}.js`),
|
|
26
|
+
'.claude/settings.json', '.claude/settings.local.json',
|
|
27
|
+
'.claude/commands/AuroqOS/agents/ops.md', '.claude/commands/auroq-companion.md',
|
|
28
|
+
'.claude/hooks/synapse-engine.cjs', '.claude/hooks/auroq-sync.cjs',
|
|
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',
|
|
31
|
+
];
|
|
32
|
+
const PROTECTED_TREES = ['lib/', '.auroq-core/core/synapse/', '.claude/hooks/'];
|
|
33
|
+
const FORBIDDEN_PREFIXES = ['business/', 'docs/knowledge/', 'casca/', '.git/', '.pack-casca-backup/'];
|
|
34
|
+
|
|
35
|
+
function safeRelative(relative) {
|
|
36
|
+
if (typeof relative !== 'string' || !relative || relative.includes('\\') || relative.startsWith('/')
|
|
37
|
+
|| relative.split('/').some(part => !part || part === '.' || part === '..') || /^[A-Za-z]:/.test(relative)) {
|
|
38
|
+
throw new Error('Invalid package path');
|
|
39
|
+
}
|
|
40
|
+
return relative;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function checkedFile(root, relative) {
|
|
44
|
+
safeRelative(relative);
|
|
45
|
+
let current = root;
|
|
46
|
+
for (const segment of relative.split('/')) {
|
|
47
|
+
current = path.join(current, segment);
|
|
48
|
+
if (fs.lstatSync(current).isSymbolicLink()) throw new Error(`Symlink in protected path: ${relative}`);
|
|
49
|
+
}
|
|
50
|
+
if (!fs.statSync(current).isFile()) throw new Error(`Not a regular file: ${relative}`);
|
|
51
|
+
return current;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function walk(root, relative) {
|
|
55
|
+
const out = [];
|
|
56
|
+
const dir = path.join(root, relative);
|
|
57
|
+
if (!fs.existsSync(dir)) throw new Error(`Missing protected directory: ${relative}`);
|
|
58
|
+
if (fs.lstatSync(dir).isSymbolicLink()) throw new Error(`Symlink in protected directory: ${relative}`);
|
|
59
|
+
for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
60
|
+
const rel = `${relative}${item.name}`;
|
|
61
|
+
if (item.isSymbolicLink()) throw new Error(`Symlink in protected path: ${rel}`);
|
|
62
|
+
if (item.isDirectory()) out.push(...walk(root, `${rel}/`));
|
|
63
|
+
else if (item.isFile() && rel !== INVENTORY_PATH) out.push(rel);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function inventoryPaths(root) {
|
|
69
|
+
return [...new Set([...REQUIRED_FILES, ...PROTECTED_TREES.flatMap(dir => walk(root, dir))])].sort();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function digest(root, relative) {
|
|
73
|
+
return crypto.createHash('sha256').update(fs.readFileSync(checkedFile(root, relative))).digest('hex');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function resolveLocal(root, source, reference) {
|
|
77
|
+
const relative = path.posix.normalize(path.posix.join(path.posix.dirname(source), reference));
|
|
78
|
+
safeRelative(relative);
|
|
79
|
+
const candidates = path.posix.extname(relative) ? [relative] : [relative, `${relative}.js`, `${relative}.json`, `${relative}/index.js`];
|
|
80
|
+
const found = candidates.find(candidate => fs.existsSync(path.join(root, candidate)) && fs.statSync(path.join(root, candidate)).isFile());
|
|
81
|
+
if (!found) throw new Error(`Broken required local reference: ${source} -> ${reference}`);
|
|
82
|
+
checkedFile(root, found);
|
|
83
|
+
return found;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Literal imports/requires in active CLI/lib/AHI/SYNAPSE code.
|
|
87
|
+
* Dynamic SYNAPSE layers/entry targets are explicitly required above. Diagnostic
|
|
88
|
+
* tooling is outside this runtime scope; only the precise optional Pro edge is exempt.
|
|
89
|
+
*/
|
|
90
|
+
function verifyReferences(root, paths) {
|
|
91
|
+
const sources = paths.filter(p => p === 'bin/auroq-os.js'
|
|
92
|
+
|| (/\.(?:js|mjs|cjs)$/.test(p) && (p.startsWith('lib/') || p.startsWith('.claude/hooks/ahi/')))
|
|
93
|
+
|| p === `${SYNAPSE_ROOT}engine.js`
|
|
94
|
+
|| /^\.auroq-core\/core\/synapse\/(?:context|domain|layers|output|session|runtime|memory|utils)\/.*\.js$/.test(p)
|
|
95
|
+
|| p === '.claude/hooks/ahi-capture.cjs');
|
|
96
|
+
const protectedSet = new Set(paths);
|
|
97
|
+
for (const source of sources) {
|
|
98
|
+
const content = fs.readFileSync(checkedFile(root, source), 'utf8')
|
|
99
|
+
.replace(/\/\*[\s\S]*?\*\//g, '').replace(/^\s*\/\/.*$/gm, '');
|
|
100
|
+
const references = /(?:\brequire\s*\(\s*|\bimport\s*\(\s*|\bfrom\s+|\bimport\s+)['"](\.[^'"\r\n]+)['"]/g;
|
|
101
|
+
for (const match of content.matchAll(references)) {
|
|
102
|
+
if (source === `${SYNAPSE_ROOT}memory/synapse-memory-provider.js`
|
|
103
|
+
&& match[1] === '../../../../pro/memory/memory-loader') continue;
|
|
104
|
+
const target = resolveLocal(root, source, match[1]);
|
|
105
|
+
if (!protectedSet.has(target)) throw new Error(`Required reference outside protected inventory: ${source} -> ${match[1]}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
for (const source of ['.claude/settings.json', '.claude/settings.local.json']) {
|
|
109
|
+
const settings = JSON.parse(fs.readFileSync(checkedFile(root, source), 'utf8'));
|
|
110
|
+
for (const groups of Object.values(settings.hooks || {})) {
|
|
111
|
+
for (const group of groups) for (const hook of group.hooks || []) {
|
|
112
|
+
const match = typeof hook.command === 'string' && hook.command.match(/^node\s+(\.claude\/hooks\/[^\s]+)(?:\s|$)/);
|
|
113
|
+
if (match) checkedFile(root, match[1]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function writeRuntimeInventory(root) {
|
|
120
|
+
const paths = inventoryPaths(root);
|
|
121
|
+
verifyReferences(root, paths);
|
|
122
|
+
const version = JSON.parse(fs.readFileSync(checkedFile(root, 'package.json'), 'utf8')).version;
|
|
123
|
+
const inventory = { schema: 1, algorithm: 'sha256', scope: 'packaged-runtime-and-cascas', version,
|
|
124
|
+
files: paths.map(file => ({ path: file, sha256: digest(root, file) })) };
|
|
125
|
+
fs.writeFileSync(path.join(root, INVENTORY_PATH), `${JSON.stringify(inventory, null, 2)}\n`);
|
|
126
|
+
return inventory;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function verifyRuntimeInventory(root, packedPaths) {
|
|
130
|
+
const inventory = JSON.parse(fs.readFileSync(checkedFile(root, INVENTORY_PATH), 'utf8'));
|
|
131
|
+
const version = JSON.parse(fs.readFileSync(checkedFile(root, 'package.json'), 'utf8')).version;
|
|
132
|
+
if (inventory.schema !== 1 || inventory.algorithm !== 'sha256' || inventory.scope !== 'packaged-runtime-and-cascas'
|
|
133
|
+
|| inventory.version !== version || !Array.isArray(inventory.files)) throw new Error('Invalid runtime inventory');
|
|
134
|
+
const expected = inventoryPaths(root);
|
|
135
|
+
const entries = new Map();
|
|
136
|
+
for (const entry of inventory.files) {
|
|
137
|
+
safeRelative(entry.path);
|
|
138
|
+
if (entries.has(entry.path) || !/^[a-f0-9]{64}$/.test(entry.sha256)) throw new Error('Invalid or duplicate inventory entry');
|
|
139
|
+
entries.set(entry.path, entry.sha256);
|
|
140
|
+
}
|
|
141
|
+
if (entries.size !== expected.length || expected.some(file => !entries.has(file))) throw new Error('Protected inventory is incomplete or changed');
|
|
142
|
+
for (const file of expected) {
|
|
143
|
+
if (digest(root, file) !== entries.get(file)) throw new Error(`Runtime hash mismatch: ${file}`);
|
|
144
|
+
}
|
|
145
|
+
verifyReferences(root, expected);
|
|
146
|
+
if (packedPaths) {
|
|
147
|
+
const included = new Set(packedPaths.map(safeRelative));
|
|
148
|
+
for (const file of [...expected, INVENTORY_PATH]) {
|
|
149
|
+
if (!included.has(file)) throw new Error(`Protected file missing from package: ${file}`);
|
|
150
|
+
}
|
|
151
|
+
for (const file of included) {
|
|
152
|
+
const parts = file.split('/');
|
|
153
|
+
if (FORBIDDEN_PREFIXES.some(prefix => file.startsWith(prefix))
|
|
154
|
+
|| (file.startsWith('agents/') && !file.startsWith('agents/organizer/'))
|
|
155
|
+
|| parts.some(part => part === '.npmrc' || part === '.env' || (part.startsWith('.env.') && part !== '.env.example'))
|
|
156
|
+
|| file.includes('arcane-method') || file.includes('consultor/knowledge')) throw new Error(`Forbidden package file: ${file}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { version, files: expected.length };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (process.argv[1] && fs.existsSync(process.argv[1])
|
|
163
|
+
&& fs.realpathSync(process.argv[1]) === fs.realpathSync(fileURLToPath(import.meta.url))) {
|
|
164
|
+
try {
|
|
165
|
+
const args = process.argv.slice(2).filter(arg => arg !== '--verify');
|
|
166
|
+
if (args.length > 1 || args.some(arg => arg.startsWith('--'))) throw new Error('Usage: runtime-integrity.mjs [--verify] [package-root]');
|
|
167
|
+
const result = verifyRuntimeInventory(path.resolve(args[0] || '.'));
|
|
168
|
+
console.log(`Runtime inventory verified: ${result.files} files (SHA256; not a signature).`);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(`Runtime inventory failed: ${error.message}`);
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
}
|
|
173
|
+
}
|