vibeostheog 0.24.16 → 0.24.17
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/dist/vibeOS.js +280 -153
- package/package.json +1 -1
package/dist/vibeOS.js
CHANGED
|
@@ -587,7 +587,7 @@ var init_meta_controller = __esm({
|
|
|
587
587
|
});
|
|
588
588
|
|
|
589
589
|
// src/vibeOS-lib/blackbox/pivot-cache.js
|
|
590
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
590
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
|
|
591
591
|
import { join as join6, dirname as dirname6 } from "node:path";
|
|
592
592
|
import { homedir as homedir5 } from "node:os";
|
|
593
593
|
var PivotCache;
|
|
@@ -625,7 +625,7 @@ var init_pivot_cache = __esm({
|
|
|
625
625
|
const p = this._storePath();
|
|
626
626
|
const dir = dirname6(p);
|
|
627
627
|
if (!existsSync7(dir))
|
|
628
|
-
|
|
628
|
+
mkdirSync5(dir, { recursive: true });
|
|
629
629
|
writeFileSync6(p, JSON.stringify(this.store, null, 2), "utf-8");
|
|
630
630
|
} catch {
|
|
631
631
|
}
|
|
@@ -796,7 +796,7 @@ __export(vibemax_exports, {
|
|
|
796
796
|
vibemaxPipeline: () => vibemaxPipeline,
|
|
797
797
|
vibemaxSelectMode: () => vibemaxSelectMode
|
|
798
798
|
});
|
|
799
|
-
import { existsSync as existsSync8, mkdirSync as
|
|
799
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
800
800
|
import { resolve as resolve2, dirname as dirname7 } from "node:path";
|
|
801
801
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
802
802
|
function fallback(sr, text) {
|
|
@@ -1078,7 +1078,7 @@ function loadVibeMaXModel() {
|
|
|
1078
1078
|
return null;
|
|
1079
1079
|
}
|
|
1080
1080
|
function saveVibeMaXModel(model) {
|
|
1081
|
-
|
|
1081
|
+
mkdirSync6(dirname7(MODEL_PATH), { recursive: true });
|
|
1082
1082
|
writeFileSync7(MODEL_PATH, JSON.stringify(model, null, 2) + "\n", "utf-8");
|
|
1083
1083
|
}
|
|
1084
1084
|
function getVibeMaXModelMeta() {
|
|
@@ -1104,8 +1104,8 @@ var init_vibemax = __esm({
|
|
|
1104
1104
|
|
|
1105
1105
|
// src/index.ts
|
|
1106
1106
|
init_flow_enforcer();
|
|
1107
|
-
import { readFileSync as readFileSync17, writeFileSync as writeFileSync15, existsSync as existsSync18, mkdirSync as
|
|
1108
|
-
import { join as join18, dirname as dirname13, basename as
|
|
1107
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync15, existsSync as existsSync18, mkdirSync as mkdirSync13, copyFileSync as copyFileSync2, renameSync as renameSync6 } from "node:fs";
|
|
1108
|
+
import { join as join18, dirname as dirname13, basename as basename5 } from "node:path";
|
|
1109
1109
|
|
|
1110
1110
|
// src/vibeOS-lib/session-metrics.js
|
|
1111
1111
|
function formatDuration(totalSeconds) {
|
|
@@ -2354,22 +2354,22 @@ async function remoteCall(method, args, fallbackFn) {
|
|
|
2354
2354
|
}
|
|
2355
2355
|
|
|
2356
2356
|
// src/lib/pricing.js
|
|
2357
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5,
|
|
2358
|
-
import { join as join5, dirname as dirname5,
|
|
2357
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4, statSync as statSync5, renameSync as renameSync4, openSync as openSync2, closeSync as closeSync2, rmSync as rmSync3, readdirSync as readdirSync2 } from "node:fs";
|
|
2358
|
+
import { join as join5, dirname as dirname5, resolve } from "node:path";
|
|
2359
2359
|
import { homedir as homedir4, tmpdir as tmpdir3 } from "node:os";
|
|
2360
2360
|
import { createHash as createHash2 } from "node:crypto";
|
|
2361
2361
|
|
|
2362
2362
|
// src/lib/state.js
|
|
2363
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, appendFileSync as
|
|
2364
|
-
import { join as join4, dirname as dirname4, basename as
|
|
2363
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, appendFileSync as appendFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3, statSync as statSync4, readdirSync, openSync, readSync, closeSync, rmSync as rmSync2, copyFileSync, renameSync as renameSync3 } from "node:fs";
|
|
2364
|
+
import { join as join4, dirname as dirname4, basename as basename2 } from "node:path";
|
|
2365
2365
|
import { spawn } from "node:child_process";
|
|
2366
2366
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
|
|
2367
2367
|
import { createHash } from "node:crypto";
|
|
2368
2368
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2369
2369
|
|
|
2370
2370
|
// src/lib/selection-manager.js
|
|
2371
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3,
|
|
2372
|
-
import { join as join3
|
|
2371
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync4, statSync as statSync3, renameSync as renameSync2 } from "node:fs";
|
|
2372
|
+
import { join as join3 } from "node:path";
|
|
2373
2373
|
import { homedir as homedir2, tmpdir } from "node:os";
|
|
2374
2374
|
var USER_HOME = (() => {
|
|
2375
2375
|
try {
|
|
@@ -2381,20 +2381,6 @@ var USER_HOME = (() => {
|
|
|
2381
2381
|
function getVibeOSHome2() {
|
|
2382
2382
|
return process.env.VIBEOS_HOME || join3(process.env.HOME || homedir2(), ".claude");
|
|
2383
2383
|
}
|
|
2384
|
-
function _handleStateCorruption(path) {
|
|
2385
|
-
const backupDir = join3(getVibeOSHome2(), ".backups");
|
|
2386
|
-
mkdirSync3(backupDir, { recursive: true });
|
|
2387
|
-
const backupPath = join3(backupDir, basename(path) + ".corrupted." + Date.now());
|
|
2388
|
-
try {
|
|
2389
|
-
copyFileSync(path, backupPath);
|
|
2390
|
-
} catch {
|
|
2391
|
-
}
|
|
2392
|
-
const logPath = join3(getVibeOSHome2(), ".state-corruption-log.jsonl");
|
|
2393
|
-
try {
|
|
2394
|
-
appendFileSync2(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
2395
|
-
} catch {
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
2384
|
function safeJsonParse2(raw) {
|
|
2399
2385
|
if (raw == null || raw === "")
|
|
2400
2386
|
return null;
|
|
@@ -2537,7 +2523,7 @@ function writeSessionOptMode(sid, mode) {
|
|
|
2537
2523
|
}
|
|
2538
2524
|
|
|
2539
2525
|
// src/lib/pattern-helpers.js
|
|
2540
|
-
import { relative, basename
|
|
2526
|
+
import { relative, basename } from "node:path";
|
|
2541
2527
|
function normalizeObservedPath(filePath, directory3) {
|
|
2542
2528
|
if (!filePath || typeof filePath !== "string")
|
|
2543
2529
|
return "unknown";
|
|
@@ -2558,7 +2544,7 @@ function normalizeObservedPath(filePath, directory3) {
|
|
|
2558
2544
|
return `src/*.${m[1].toLowerCase()}`;
|
|
2559
2545
|
if (p.startsWith("tests/") && m)
|
|
2560
2546
|
return `tests/*.${m[1].toLowerCase()}`;
|
|
2561
|
-
return
|
|
2547
|
+
return basename(p) || "unknown";
|
|
2562
2548
|
}
|
|
2563
2549
|
function commandFamily(command) {
|
|
2564
2550
|
const c = String(command || "").trim().toLowerCase();
|
|
@@ -3291,6 +3277,12 @@ var MAX_SCRATCHPAD_FILES = 1e3;
|
|
|
3291
3277
|
var MAX_SCRATCHPAD_BYTES = 10 * 1024 * 1024;
|
|
3292
3278
|
var MAX_SESSION_SCRATCHPAD_FILES = 200;
|
|
3293
3279
|
var MAX_SESSION_SCRATCHPAD_BYTES = 2 * 1024 * 1024;
|
|
3280
|
+
var CORRUPTION_BACKUP_MAX = 5;
|
|
3281
|
+
var CORRUPTION_BACKUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3282
|
+
var LEDGER_ROTATE_MAX_BYTES = 1 * 1024 * 1024;
|
|
3283
|
+
var LEDGER_ROTATE_MAX_LINES = 5e4;
|
|
3284
|
+
var LEDGER_ROTATE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3285
|
+
var ACTIVE_JOBS_STALE_MS = 72 * 60 * 60 * 1e3;
|
|
3294
3286
|
var MAX_PTR_CANDIDATES = 50;
|
|
3295
3287
|
var SUMMARY_HEAD_TRUNCATE = 500;
|
|
3296
3288
|
function getVibeOSHome3() {
|
|
@@ -3421,19 +3413,48 @@ var tool = Object.assign((def) => def, {
|
|
|
3421
3413
|
enum: (values) => _zType({ kind: "enum", values })
|
|
3422
3414
|
}
|
|
3423
3415
|
});
|
|
3424
|
-
function
|
|
3416
|
+
function _pruneCorruptionBackups(backupDir) {
|
|
3417
|
+
try {
|
|
3418
|
+
if (!existsSync5(backupDir))
|
|
3419
|
+
return;
|
|
3420
|
+
const now = Date.now();
|
|
3421
|
+
const backups = readdirSync(backupDir).map((name) => {
|
|
3422
|
+
const path = join4(backupDir, name);
|
|
3423
|
+
try {
|
|
3424
|
+
const st = statSync4(path);
|
|
3425
|
+
return { name, path, mtimeMs: st.mtimeMs };
|
|
3426
|
+
} catch {
|
|
3427
|
+
return null;
|
|
3428
|
+
}
|
|
3429
|
+
}).filter((entry) => !!entry && entry.name.includes(".corrupted.")).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
3430
|
+
const keep = new Set(backups.slice(0, CORRUPTION_BACKUP_MAX).map((b) => b.path));
|
|
3431
|
+
for (const backup of backups) {
|
|
3432
|
+
const isExpired = now - backup.mtimeMs > CORRUPTION_BACKUP_TTL_MS;
|
|
3433
|
+
if (isExpired || !keep.has(backup.path)) {
|
|
3434
|
+
try {
|
|
3435
|
+
rmSync2(backup.path, { force: true });
|
|
3436
|
+
} catch {
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
} catch {
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
function _handleStateCorruption(path) {
|
|
3425
3444
|
const backupDir = join4(VIBEOS_HOME, ".backups");
|
|
3426
|
-
|
|
3427
|
-
const backupPath = join4(backupDir,
|
|
3445
|
+
mkdirSync3(backupDir, { recursive: true });
|
|
3446
|
+
const backupPath = join4(backupDir, basename2(path) + ".corrupted." + Date.now());
|
|
3428
3447
|
try {
|
|
3429
|
-
|
|
3448
|
+
copyFileSync(path, backupPath);
|
|
3430
3449
|
} catch {
|
|
3431
3450
|
}
|
|
3432
3451
|
const logPath = join4(VIBEOS_HOME, ".state-corruption-log.jsonl");
|
|
3433
3452
|
try {
|
|
3434
|
-
|
|
3453
|
+
appendFileSync2(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
3435
3454
|
} catch {
|
|
3436
3455
|
}
|
|
3456
|
+
_pruneCorruptionBackups(backupDir);
|
|
3457
|
+
return backupPath;
|
|
3437
3458
|
}
|
|
3438
3459
|
function _lockPathFor(filePath) {
|
|
3439
3460
|
const hash = createHash("sha1").update(String(filePath || "")).digest("hex");
|
|
@@ -3446,7 +3467,7 @@ function withFileLock(filePath, fn, opts = {}) {
|
|
|
3446
3467
|
const start = Date.now();
|
|
3447
3468
|
while (Date.now() - start < timeoutMs) {
|
|
3448
3469
|
try {
|
|
3449
|
-
|
|
3470
|
+
mkdirSync3(FILE_LOCK_DIR, { recursive: true });
|
|
3450
3471
|
const fd = openSync(lockPath, "wx");
|
|
3451
3472
|
try {
|
|
3452
3473
|
writeFileSync4(fd, `${process.pid}
|
|
@@ -3524,12 +3545,12 @@ function readJsonOrEmpty(filePath) {
|
|
|
3524
3545
|
return {};
|
|
3525
3546
|
const st = statSync4(filePath);
|
|
3526
3547
|
if (st.size > 10485760) {
|
|
3527
|
-
|
|
3548
|
+
_handleStateCorruption(filePath);
|
|
3528
3549
|
return {};
|
|
3529
3550
|
}
|
|
3530
3551
|
return safeJsonParse3(readFileSync4(filePath, "utf-8"));
|
|
3531
3552
|
} catch {
|
|
3532
|
-
|
|
3553
|
+
_handleStateCorruption(filePath);
|
|
3533
3554
|
return {};
|
|
3534
3555
|
}
|
|
3535
3556
|
}
|
|
@@ -3554,7 +3575,7 @@ function updateState(mutator) {
|
|
|
3554
3575
|
state._gen = preGen + 1;
|
|
3555
3576
|
const next = mutator(state) ?? state;
|
|
3556
3577
|
validateState(next, delegationStateFile);
|
|
3557
|
-
|
|
3578
|
+
mkdirSync3(dirname4(delegationStateFile), { recursive: true });
|
|
3558
3579
|
const tmp = delegationStateFile + ".tmp";
|
|
3559
3580
|
writeFileSync4(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
3560
3581
|
renameSync3(tmp, delegationStateFile);
|
|
@@ -3580,12 +3601,12 @@ function readFullState() {
|
|
|
3580
3601
|
return {};
|
|
3581
3602
|
const st = statSync4(delegationStateFile);
|
|
3582
3603
|
if (st.size > 10485760) {
|
|
3583
|
-
|
|
3604
|
+
_handleStateCorruption(delegationStateFile);
|
|
3584
3605
|
return {};
|
|
3585
3606
|
}
|
|
3586
3607
|
return safeJsonParse3(readFileSync4(delegationStateFile, "utf-8"));
|
|
3587
3608
|
} catch {
|
|
3588
|
-
|
|
3609
|
+
_handleStateCorruption(delegationStateFile);
|
|
3589
3610
|
return {};
|
|
3590
3611
|
}
|
|
3591
3612
|
}
|
|
@@ -3625,7 +3646,7 @@ function loadGlobalLearning() {
|
|
|
3625
3646
|
return DFLT_GL;
|
|
3626
3647
|
const st = statSync4(globalLearningFile);
|
|
3627
3648
|
if (st.size > 10485760) {
|
|
3628
|
-
|
|
3649
|
+
_handleStateCorruption(globalLearningFile);
|
|
3629
3650
|
return DFLT_GL;
|
|
3630
3651
|
}
|
|
3631
3652
|
const j = safeJsonParse3(readFileSync4(globalLearningFile, "utf-8"));
|
|
@@ -3638,7 +3659,7 @@ function loadGlobalLearning() {
|
|
|
3638
3659
|
j.context7_last_seen ??= null;
|
|
3639
3660
|
return j;
|
|
3640
3661
|
} catch {
|
|
3641
|
-
|
|
3662
|
+
_handleStateCorruption(globalLearningFile);
|
|
3642
3663
|
return DFLT_GL;
|
|
3643
3664
|
}
|
|
3644
3665
|
}
|
|
@@ -3648,7 +3669,7 @@ function updateGlobalLearning(mutator) {
|
|
|
3648
3669
|
const s = loadGlobalLearning();
|
|
3649
3670
|
const next = mutator(s) ?? s;
|
|
3650
3671
|
next.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3651
|
-
|
|
3672
|
+
mkdirSync3(dirname4(globalLearningFile), { recursive: true });
|
|
3652
3673
|
const tmp = globalLearningFile + ".tmp";
|
|
3653
3674
|
writeFileSync4(tmp, JSON.stringify(next, null, 2));
|
|
3654
3675
|
renameSync3(tmp, globalLearningFile);
|
|
@@ -3700,19 +3721,19 @@ function loadBlackboxState() {
|
|
|
3700
3721
|
return { enabled: true, sessions: {} };
|
|
3701
3722
|
const st = statSync4(blackboxFile);
|
|
3702
3723
|
if (st.size > 10485760) {
|
|
3703
|
-
|
|
3724
|
+
_handleStateCorruption(blackboxFile);
|
|
3704
3725
|
return { enabled: false, sessions: {} };
|
|
3705
3726
|
}
|
|
3706
3727
|
return safeJsonParse3(readFileSync4(blackboxFile, "utf-8")) || { enabled: false, sessions: {} };
|
|
3707
3728
|
} catch {
|
|
3708
|
-
|
|
3729
|
+
_handleStateCorruption(blackboxFile);
|
|
3709
3730
|
return { enabled: false, sessions: {} };
|
|
3710
3731
|
}
|
|
3711
3732
|
}
|
|
3712
3733
|
function saveBlackboxState(state) {
|
|
3713
3734
|
const blackboxFile = join4(getVibeOSHome3(), "blackbox-state.json");
|
|
3714
3735
|
try {
|
|
3715
|
-
|
|
3736
|
+
mkdirSync3(dirname4(blackboxFile), { recursive: true });
|
|
3716
3737
|
const tmp = blackboxFile + ".tmp";
|
|
3717
3738
|
writeFileSync4(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
3718
3739
|
renameSync3(tmp, blackboxFile);
|
|
@@ -3734,7 +3755,7 @@ function getGlobalIndexPath() {
|
|
|
3734
3755
|
}
|
|
3735
3756
|
function ensureSessionScratchpadDirs() {
|
|
3736
3757
|
try {
|
|
3737
|
-
|
|
3758
|
+
mkdirSync3(getSessionScratchpadDir(), { recursive: true });
|
|
3738
3759
|
return true;
|
|
3739
3760
|
} catch {
|
|
3740
3761
|
return false;
|
|
@@ -3778,7 +3799,8 @@ function _flushLedgerBuffer() {
|
|
|
3778
3799
|
const lines = batch.map((e) => typeof e === "string" ? e.trimEnd() : String(e).trimEnd());
|
|
3779
3800
|
const joined = lines.filter(Boolean).map((l) => l + "\n").join("");
|
|
3780
3801
|
try {
|
|
3781
|
-
|
|
3802
|
+
appendFileSync2(SAVINGS_LEDGER_FILE, joined);
|
|
3803
|
+
_compactSavingsLedgerIfNeeded();
|
|
3782
3804
|
} catch {
|
|
3783
3805
|
}
|
|
3784
3806
|
}
|
|
@@ -3925,10 +3947,10 @@ function indexAppend(hash, tool2, size, extra) {
|
|
|
3925
3947
|
const entry = JSON.stringify(entryObj) + "\n";
|
|
3926
3948
|
const globalIndex = getGlobalIndexPath();
|
|
3927
3949
|
const sessionIndex = getSessionIndexPath();
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3950
|
+
mkdirSync3(dirname4(globalIndex), { recursive: true });
|
|
3951
|
+
mkdirSync3(dirname4(sessionIndex), { recursive: true });
|
|
3952
|
+
appendFileSync2(globalIndex, entry);
|
|
3953
|
+
appendFileSync2(sessionIndex, entry);
|
|
3932
3954
|
} catch (err) {
|
|
3933
3955
|
console.error(`[vibeOS] index write failed: ${err.message}`);
|
|
3934
3956
|
}
|
|
@@ -4181,21 +4203,83 @@ function pruneScratchpadOnce() {
|
|
|
4181
4203
|
}
|
|
4182
4204
|
cleanupStaleSessionScratchpads();
|
|
4183
4205
|
}
|
|
4184
|
-
function
|
|
4206
|
+
function _readActiveJobsRaw() {
|
|
4185
4207
|
try {
|
|
4186
4208
|
if (!existsSync5(ACTIVE_JOBS_FILE))
|
|
4187
4209
|
return {};
|
|
4188
|
-
const st = statSync4(ACTIVE_JOBS_FILE);
|
|
4189
|
-
if (st.size > 10485760) {
|
|
4190
|
-
_handleStateCorruption2(ACTIVE_JOBS_FILE);
|
|
4191
|
-
return {};
|
|
4192
|
-
}
|
|
4193
4210
|
const raw = safeJsonParse3(readFileSync4(ACTIVE_JOBS_FILE, "utf-8"));
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4211
|
+
return raw && typeof raw === "object" ? raw : {};
|
|
4212
|
+
} catch {
|
|
4213
|
+
_handleStateCorruption(ACTIVE_JOBS_FILE);
|
|
4214
|
+
return {};
|
|
4215
|
+
}
|
|
4216
|
+
}
|
|
4217
|
+
function _writeActiveJobsRaw(jobs) {
|
|
4218
|
+
try {
|
|
4219
|
+
mkdirSync3(dirname4(ACTIVE_JOBS_FILE), { recursive: true });
|
|
4220
|
+
const tmp = ACTIVE_JOBS_FILE + ".tmp";
|
|
4221
|
+
writeFileSync4(tmp, JSON.stringify(jobs, null, 2) + "\n");
|
|
4222
|
+
renameSync3(tmp, ACTIVE_JOBS_FILE);
|
|
4223
|
+
} catch {
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
function _normalizeActiveJobRecord(record, now = Date.now(), strict = false) {
|
|
4227
|
+
if (!record || typeof record !== "object")
|
|
4228
|
+
return { record: null, changed: false, stale: false };
|
|
4229
|
+
const next = { ...record };
|
|
4230
|
+
let changed = false;
|
|
4231
|
+
const updatedAtRaw = typeof next.updatedAt === "string" ? next.updatedAt : "";
|
|
4232
|
+
const createdAtRaw = typeof next.createdAt === "string" ? next.createdAt : "";
|
|
4233
|
+
const updatedAtMs = Date.parse(updatedAtRaw);
|
|
4234
|
+
const createdAtMs = Date.parse(createdAtRaw);
|
|
4235
|
+
const anchorMs = Number.isFinite(updatedAtMs) ? updatedAtMs : createdAtMs;
|
|
4236
|
+
const stale = Number.isFinite(anchorMs) && now - anchorMs > ACTIVE_JOBS_STALE_MS;
|
|
4237
|
+
if (strict && (!next.status || typeof next.status !== "string" || !next.status.trim()))
|
|
4238
|
+
return { record: null, changed: false, stale };
|
|
4239
|
+
if (strict && !Number.isFinite(createdAtMs))
|
|
4240
|
+
return { record: null, changed: false, stale };
|
|
4241
|
+
if (!Number.isFinite(createdAtMs)) {
|
|
4242
|
+
next.createdAt = Number.isFinite(anchorMs) ? new Date(anchorMs).toISOString() : new Date(now).toISOString();
|
|
4243
|
+
changed = true;
|
|
4244
|
+
}
|
|
4245
|
+
if (!Number.isFinite(updatedAtMs)) {
|
|
4246
|
+
next.updatedAt = next.createdAt || new Date(now).toISOString();
|
|
4247
|
+
changed = true;
|
|
4248
|
+
}
|
|
4249
|
+
if (typeof next.status !== "string" || !next.status.trim()) {
|
|
4250
|
+
next.status = "active";
|
|
4251
|
+
changed = true;
|
|
4252
|
+
}
|
|
4253
|
+
if (stale && next.status !== "completed") {
|
|
4254
|
+
next.status = "completed";
|
|
4255
|
+
next.completedAt = new Date(now).toISOString();
|
|
4256
|
+
changed = true;
|
|
4257
|
+
}
|
|
4258
|
+
return { record: next, changed, stale };
|
|
4259
|
+
}
|
|
4260
|
+
function loadActiveJobs() {
|
|
4261
|
+
try {
|
|
4262
|
+
return withFileLock(ACTIVE_JOBS_FILE, () => {
|
|
4263
|
+
const raw = _readActiveJobsRaw();
|
|
4264
|
+
const next = {};
|
|
4265
|
+
let changed = false;
|
|
4266
|
+
const now = Date.now();
|
|
4267
|
+
for (const [key, value] of Object.entries(raw || {})) {
|
|
4268
|
+
const norm = _normalizeActiveJobRecord(value, now, true);
|
|
4269
|
+
if (!norm.record) {
|
|
4270
|
+
changed = true;
|
|
4271
|
+
continue;
|
|
4272
|
+
}
|
|
4273
|
+
next[key] = norm.record;
|
|
4274
|
+
if (norm.changed)
|
|
4275
|
+
changed = true;
|
|
4276
|
+
}
|
|
4277
|
+
if (changed)
|
|
4278
|
+
_writeActiveJobsRaw(next);
|
|
4279
|
+
return next;
|
|
4280
|
+
});
|
|
4197
4281
|
} catch {
|
|
4198
|
-
|
|
4282
|
+
_handleStateCorruption(ACTIVE_JOBS_FILE);
|
|
4199
4283
|
return {};
|
|
4200
4284
|
}
|
|
4201
4285
|
}
|
|
@@ -4212,15 +4296,19 @@ function saveActiveJobForProject(job, fp2 = currentProjectFingerprint) {
|
|
|
4212
4296
|
if (!fp2 || !job || typeof job !== "object")
|
|
4213
4297
|
return;
|
|
4214
4298
|
try {
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4299
|
+
withFileLock(ACTIVE_JOBS_FILE, () => {
|
|
4300
|
+
const jobs = _readActiveJobsRaw();
|
|
4301
|
+
const norm = _normalizeActiveJobRecord(job);
|
|
4302
|
+
jobs[fp2] = norm.record || job;
|
|
4303
|
+
_writeActiveJobsRaw(jobs);
|
|
4304
|
+
});
|
|
4221
4305
|
} catch {
|
|
4222
4306
|
}
|
|
4223
4307
|
}
|
|
4308
|
+
try {
|
|
4309
|
+
loadActiveJobs();
|
|
4310
|
+
} catch {
|
|
4311
|
+
}
|
|
4224
4312
|
function projectFingerprint(dir) {
|
|
4225
4313
|
if (!dir)
|
|
4226
4314
|
return "unknown";
|
|
@@ -4242,7 +4330,7 @@ function saveProjectState(state) {
|
|
|
4242
4330
|
const projectStateFile = join4(getVibeOSHome3(), "project-states.json");
|
|
4243
4331
|
try {
|
|
4244
4332
|
withFileLock(projectStateFile, () => {
|
|
4245
|
-
|
|
4333
|
+
mkdirSync3(dirname4(projectStateFile), { recursive: true });
|
|
4246
4334
|
const _tmp = projectStateFile + ".tmp." + Date.now();
|
|
4247
4335
|
writeFileSync4(_tmp, JSON.stringify(state, null, 2) + "\n", "utf-8");
|
|
4248
4336
|
renameSync3(_tmp, projectStateFile);
|
|
@@ -4479,7 +4567,7 @@ function loadTodos() {
|
|
|
4479
4567
|
}
|
|
4480
4568
|
function saveTodos(todos) {
|
|
4481
4569
|
try {
|
|
4482
|
-
|
|
4570
|
+
mkdirSync3(dirname4(TODOS_FILE), { recursive: true });
|
|
4483
4571
|
const tmp = TODOS_FILE + ".tmp." + Date.now();
|
|
4484
4572
|
writeFileSync4(tmp, JSON.stringify(todos, null, 2), "utf-8");
|
|
4485
4573
|
renameSync3(tmp, TODOS_FILE);
|
|
@@ -4518,6 +4606,57 @@ function markTodoDone(id2) {
|
|
|
4518
4606
|
function getTodos() {
|
|
4519
4607
|
return loadTodos();
|
|
4520
4608
|
}
|
|
4609
|
+
function _compactSavingsLedgerIfNeeded() {
|
|
4610
|
+
try {
|
|
4611
|
+
if (!existsSync5(SAVINGS_LEDGER_FILE))
|
|
4612
|
+
return;
|
|
4613
|
+
const st = statSync4(SAVINGS_LEDGER_FILE);
|
|
4614
|
+
if (st.size <= LEDGER_ROTATE_MAX_BYTES)
|
|
4615
|
+
return;
|
|
4616
|
+
withFileLock(SAVINGS_LEDGER_FILE, () => {
|
|
4617
|
+
if (!existsSync5(SAVINGS_LEDGER_FILE))
|
|
4618
|
+
return;
|
|
4619
|
+
const lockedStat = statSync4(SAVINGS_LEDGER_FILE);
|
|
4620
|
+
if (lockedStat.size <= LEDGER_ROTATE_MAX_BYTES)
|
|
4621
|
+
return;
|
|
4622
|
+
const raw = readFileSync4(SAVINGS_LEDGER_FILE, "utf-8");
|
|
4623
|
+
if (!raw.trim())
|
|
4624
|
+
return;
|
|
4625
|
+
const now = Date.now();
|
|
4626
|
+
const rows = raw.split("\n").filter(Boolean).map((line) => {
|
|
4627
|
+
let rec = null;
|
|
4628
|
+
try {
|
|
4629
|
+
rec = JSON.parse(line);
|
|
4630
|
+
} catch {
|
|
4631
|
+
rec = null;
|
|
4632
|
+
}
|
|
4633
|
+
const atRaw = rec && typeof rec === "object" ? String(rec.at || rec.ts || "") : "";
|
|
4634
|
+
const atMs = Date.parse(atRaw);
|
|
4635
|
+
return { raw: line.trim(), atMs: Number.isFinite(atMs) ? atMs : null };
|
|
4636
|
+
}).filter((row) => row.raw);
|
|
4637
|
+
const recent = rows.filter((row) => row.atMs != null && now - Number(row.atMs) <= LEDGER_ROTATE_MAX_AGE_MS);
|
|
4638
|
+
const pool = recent.length > 0 ? recent : rows;
|
|
4639
|
+
const capped = pool.length > LEDGER_ROTATE_MAX_LINES ? pool.slice(-LEDGER_ROTATE_MAX_LINES) : pool;
|
|
4640
|
+
let size = 0;
|
|
4641
|
+
const kept = [];
|
|
4642
|
+
for (let i = capped.length - 1; i >= 0; i--) {
|
|
4643
|
+
const line = capped[i].raw;
|
|
4644
|
+
const lineBytes = Buffer.byteLength(line + "\n", "utf-8");
|
|
4645
|
+
if (kept.length > 0 && size + lineBytes > LEDGER_ROTATE_MAX_BYTES)
|
|
4646
|
+
break;
|
|
4647
|
+
kept.push(line);
|
|
4648
|
+
size += lineBytes;
|
|
4649
|
+
}
|
|
4650
|
+
const compacted = kept.reverse().join("\n") + "\n";
|
|
4651
|
+
if (compacted.trim() && compacted !== raw) {
|
|
4652
|
+
const tmp = SAVINGS_LEDGER_FILE + ".tmp." + Date.now();
|
|
4653
|
+
writeFileSync4(tmp, compacted, "utf-8");
|
|
4654
|
+
renameSync3(tmp, SAVINGS_LEDGER_FILE);
|
|
4655
|
+
}
|
|
4656
|
+
}, { timeoutMs: 4e3 });
|
|
4657
|
+
} catch {
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4521
4660
|
function readLedgerTotals() {
|
|
4522
4661
|
const empty = { delegation: 0, cache: 0, context7: 0, total: 0, entries: 0 };
|
|
4523
4662
|
try {
|
|
@@ -4526,15 +4665,19 @@ function readLedgerTotals() {
|
|
|
4526
4665
|
return empty;
|
|
4527
4666
|
}
|
|
4528
4667
|
const st = statSync4(SAVINGS_LEDGER_FILE);
|
|
4529
|
-
if (st.size > 10485760) {
|
|
4530
|
-
_handleStateCorruption2(SAVINGS_LEDGER_FILE);
|
|
4531
|
-
return empty;
|
|
4532
|
-
}
|
|
4533
4668
|
if (st.size === 0) {
|
|
4534
4669
|
_ledgerTotalsCache = { mtime: st.mtimeMs, size: 0, delegation: 0, cache: 0, context7: 0, entries: 0 };
|
|
4535
4670
|
return empty;
|
|
4536
4671
|
}
|
|
4537
|
-
if (
|
|
4672
|
+
if (st.size > LEDGER_ROTATE_MAX_BYTES) {
|
|
4673
|
+
_compactSavingsLedgerIfNeeded();
|
|
4674
|
+
}
|
|
4675
|
+
const currentStat = statSync4(SAVINGS_LEDGER_FILE);
|
|
4676
|
+
if (currentStat.size === 0) {
|
|
4677
|
+
_ledgerTotalsCache = { mtime: currentStat.mtimeMs, size: 0, delegation: 0, cache: 0, context7: 0, entries: 0 };
|
|
4678
|
+
return empty;
|
|
4679
|
+
}
|
|
4680
|
+
if (_ledgerTotalsCache.mtime === currentStat.mtimeMs && _ledgerTotalsCache.size === currentStat.size) {
|
|
4538
4681
|
return {
|
|
4539
4682
|
delegation: Math.round(_ledgerTotalsCache.delegation * 1e3) / 1e3,
|
|
4540
4683
|
cache: Math.round(_ledgerTotalsCache.cache * 1e3) / 1e3,
|
|
@@ -4548,9 +4691,9 @@ function readLedgerTotals() {
|
|
|
4548
4691
|
let context7 = 0;
|
|
4549
4692
|
let entries = 0;
|
|
4550
4693
|
let raw = "";
|
|
4551
|
-
let incremental = _ledgerTotalsCache.size > 0 &&
|
|
4694
|
+
let incremental = _ledgerTotalsCache.size > 0 && currentStat.size >= _ledgerTotalsCache.size && _ledgerTotalsCache.mtime > 0;
|
|
4552
4695
|
if (incremental) {
|
|
4553
|
-
const deltaSize =
|
|
4696
|
+
const deltaSize = currentStat.size - _ledgerTotalsCache.size;
|
|
4554
4697
|
if (deltaSize > 0) {
|
|
4555
4698
|
const fd = openSync(SAVINGS_LEDGER_FILE, "r");
|
|
4556
4699
|
try {
|
|
@@ -4576,8 +4719,8 @@ function readLedgerTotals() {
|
|
|
4576
4719
|
}
|
|
4577
4720
|
if (!raw.trim()) {
|
|
4578
4721
|
_ledgerTotalsCache = {
|
|
4579
|
-
mtime:
|
|
4580
|
-
size:
|
|
4722
|
+
mtime: currentStat.mtimeMs,
|
|
4723
|
+
size: currentStat.size,
|
|
4581
4724
|
delegation,
|
|
4582
4725
|
cache,
|
|
4583
4726
|
context7,
|
|
@@ -4620,7 +4763,7 @@ function readLedgerTotals() {
|
|
|
4620
4763
|
else
|
|
4621
4764
|
delegation += amt;
|
|
4622
4765
|
}
|
|
4623
|
-
_ledgerTotalsCache = { mtime:
|
|
4766
|
+
_ledgerTotalsCache = { mtime: currentStat.mtimeMs, size: currentStat.size, delegation, cache, context7, entries };
|
|
4624
4767
|
const total = delegation + cache;
|
|
4625
4768
|
return {
|
|
4626
4769
|
delegation: Math.round(delegation * 1e3) / 1e3,
|
|
@@ -4705,7 +4848,7 @@ function saveSessionCheckpoint() {
|
|
|
4705
4848
|
model: session.model || ""
|
|
4706
4849
|
};
|
|
4707
4850
|
const cpPath = join4(getSessionRoot(), "checkpoint.json");
|
|
4708
|
-
|
|
4851
|
+
mkdirSync3(dirname4(cpPath), { recursive: true });
|
|
4709
4852
|
const tmp = cpPath + ".tmp";
|
|
4710
4853
|
writeFileSync4(tmp, JSON.stringify(cp, null, 2) + "\n");
|
|
4711
4854
|
renameSync3(tmp, cpPath);
|
|
@@ -4746,20 +4889,6 @@ function getOpenCodeDesktopHome() {
|
|
|
4746
4889
|
return process.env.VIBEOS_OPENCODE_DESKTOP_HOME || join5(process.env.HOME || homedir4(), "Library", "Application Support", "ai.opencode.desktop");
|
|
4747
4890
|
}
|
|
4748
4891
|
var TIERS_FILE2 = join5(getVibeOSHome4(), "model-tiers.json");
|
|
4749
|
-
function _handleStateCorruption3(path) {
|
|
4750
|
-
const backupDir = join5(getVibeOSHome4(), ".backups");
|
|
4751
|
-
mkdirSync5(backupDir, { recursive: true });
|
|
4752
|
-
const backupPath = join5(backupDir, basename4(path) + ".corrupted." + Date.now());
|
|
4753
|
-
try {
|
|
4754
|
-
copyFileSync3(path, backupPath);
|
|
4755
|
-
} catch {
|
|
4756
|
-
}
|
|
4757
|
-
const logPath = join5(getVibeOSHome4(), ".state-corruption-log.jsonl");
|
|
4758
|
-
try {
|
|
4759
|
-
appendFileSync4(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
4760
|
-
} catch {
|
|
4761
|
-
}
|
|
4762
|
-
}
|
|
4763
4892
|
function _lockPathFor2(filePath) {
|
|
4764
4893
|
const hash = createHash2("sha1").update(String(filePath || "")).digest("hex");
|
|
4765
4894
|
return join5(getVibeOSHome4(), ".vibeOS-locks", `${hash}.lock`);
|
|
@@ -4771,7 +4900,7 @@ function withFileLock2(filePath, fn, opts = {}) {
|
|
|
4771
4900
|
const start = Date.now();
|
|
4772
4901
|
while (Date.now() - start < timeoutMs) {
|
|
4773
4902
|
try {
|
|
4774
|
-
|
|
4903
|
+
mkdirSync4(join5(getVibeOSHome4(), ".vibeOS-locks"), { recursive: true });
|
|
4775
4904
|
const fd = openSync2(lockPath, "wx");
|
|
4776
4905
|
try {
|
|
4777
4906
|
writeFileSync5(fd, `${process.pid}
|
|
@@ -5289,7 +5418,7 @@ function _loadDynamicPricingCache() {
|
|
|
5289
5418
|
return {};
|
|
5290
5419
|
const st = statSync5(PRICING_CACHE_FILE2);
|
|
5291
5420
|
if (st.size > 10485760) {
|
|
5292
|
-
|
|
5421
|
+
_handleStateCorruption(PRICING_CACHE_FILE2);
|
|
5293
5422
|
_dynamicPricingCache = {};
|
|
5294
5423
|
return {};
|
|
5295
5424
|
}
|
|
@@ -5297,7 +5426,7 @@ function _loadDynamicPricingCache() {
|
|
|
5297
5426
|
const map = raw?.models && typeof raw.models === "object" ? raw.models : {};
|
|
5298
5427
|
_dynamicPricingCache = map;
|
|
5299
5428
|
} catch {
|
|
5300
|
-
|
|
5429
|
+
_handleStateCorruption(PRICING_CACHE_FILE2);
|
|
5301
5430
|
_dynamicPricingCache = {};
|
|
5302
5431
|
}
|
|
5303
5432
|
return _dynamicPricingCache;
|
|
@@ -5334,7 +5463,7 @@ function _writeDynamicPricingCache(modelsMap) {
|
|
|
5334
5463
|
const PRICING_CACHE_FILE2 = join5(getVibeOSHome4(), "model-pricing-cache.json");
|
|
5335
5464
|
try {
|
|
5336
5465
|
withFileLock2(PRICING_CACHE_FILE2, () => {
|
|
5337
|
-
|
|
5466
|
+
mkdirSync4(dirname5(PRICING_CACHE_FILE2), { recursive: true });
|
|
5338
5467
|
let merged = {};
|
|
5339
5468
|
try {
|
|
5340
5469
|
if (existsSync6(PRICING_CACHE_FILE2)) {
|
|
@@ -5392,7 +5521,7 @@ function _loadPricingOverrides() {
|
|
|
5392
5521
|
return {};
|
|
5393
5522
|
const st = statSync5(tiersFile);
|
|
5394
5523
|
if (st.size > 10485760) {
|
|
5395
|
-
|
|
5524
|
+
_handleStateCorruption(tiersFile);
|
|
5396
5525
|
_pricingOverridesCache = {};
|
|
5397
5526
|
return {};
|
|
5398
5527
|
}
|
|
@@ -5423,7 +5552,7 @@ function _loadPricingOverrides() {
|
|
|
5423
5552
|
}
|
|
5424
5553
|
_pricingOverridesCache = out;
|
|
5425
5554
|
} catch {
|
|
5426
|
-
|
|
5555
|
+
_handleStateCorruption(join5(home, "model-tiers.json"));
|
|
5427
5556
|
_pricingOverridesCache = {};
|
|
5428
5557
|
}
|
|
5429
5558
|
return _pricingOverridesCache;
|
|
@@ -5559,7 +5688,7 @@ function loadSelection2() {
|
|
|
5559
5688
|
return DFLT_SEL2;
|
|
5560
5689
|
const st = statSync5(TIERS_FILE3);
|
|
5561
5690
|
if (st.size > 10485760) {
|
|
5562
|
-
|
|
5691
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5563
5692
|
return DFLT_SEL2;
|
|
5564
5693
|
}
|
|
5565
5694
|
const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
@@ -5582,7 +5711,7 @@ function loadSelection2() {
|
|
|
5582
5711
|
executed_model: j?.selection?.executed_model || null
|
|
5583
5712
|
};
|
|
5584
5713
|
} catch {
|
|
5585
|
-
|
|
5714
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5586
5715
|
return DFLT_SEL2;
|
|
5587
5716
|
}
|
|
5588
5717
|
}
|
|
@@ -5810,7 +5939,7 @@ function loadTrinitySlotsFromTiersFile() {
|
|
|
5810
5939
|
return false;
|
|
5811
5940
|
const st = statSync5(TIERS_FILE3);
|
|
5812
5941
|
if (st.size > 10485760) {
|
|
5813
|
-
|
|
5942
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5814
5943
|
return false;
|
|
5815
5944
|
}
|
|
5816
5945
|
const tiersData = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8")) || {};
|
|
@@ -5928,7 +6057,7 @@ function applySlot2(slot, projectDir = "") {
|
|
|
5928
6057
|
}
|
|
5929
6058
|
|
|
5930
6059
|
// src/lib/turn-classify.js
|
|
5931
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, existsSync as existsSync9, mkdirSync as
|
|
6060
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, existsSync as existsSync9, mkdirSync as mkdirSync7, renameSync as renameSync5 } from "node:fs";
|
|
5932
6061
|
import { join as join7, dirname as dirname8 } from "node:path";
|
|
5933
6062
|
|
|
5934
6063
|
// src/vibeOS-lib/blackbox/resolution-tracker.js
|
|
@@ -7362,8 +7491,8 @@ function projectStructuredFromText(raw, selection, creditPercent = 0) {
|
|
|
7362
7491
|
}
|
|
7363
7492
|
|
|
7364
7493
|
// src/lib/reporting.js
|
|
7365
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as
|
|
7366
|
-
import { join as join9
|
|
7494
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as mkdirSync8, statSync as statSync6, rmSync as rmSync4 } from "node:fs";
|
|
7495
|
+
import { join as join9 } from "node:path";
|
|
7367
7496
|
function getVibeOSHome7() {
|
|
7368
7497
|
return process.env.VIBEOS_HOME || join9(process.env.HOME || "", ".claude");
|
|
7369
7498
|
}
|
|
@@ -7378,27 +7507,18 @@ var REPORTS_INDEX = getReportsIndexPath();
|
|
|
7378
7507
|
var currentProjectFingerprint2 = "";
|
|
7379
7508
|
var currentProjectName2 = "";
|
|
7380
7509
|
var currentSessionId2 = "";
|
|
7381
|
-
function _handleStateCorruption4(path) {
|
|
7382
|
-
const backupDir = join9(getVibeOSHome7(), ".backups");
|
|
7383
|
-
mkdirSync9(backupDir, { recursive: true });
|
|
7384
|
-
const backupPath = join9(backupDir, basename5(path) + ".corrupted." + Date.now());
|
|
7385
|
-
try {
|
|
7386
|
-
copyFileSync4(path, backupPath);
|
|
7387
|
-
} catch {
|
|
7388
|
-
}
|
|
7389
|
-
}
|
|
7390
7510
|
function readJsonOrEmpty2(filePath) {
|
|
7391
7511
|
try {
|
|
7392
7512
|
if (!existsSync11(filePath))
|
|
7393
7513
|
return {};
|
|
7394
7514
|
const st = statSync6(filePath);
|
|
7395
7515
|
if (st.size > 10485760) {
|
|
7396
|
-
|
|
7516
|
+
_handleStateCorruption(filePath);
|
|
7397
7517
|
return {};
|
|
7398
7518
|
}
|
|
7399
7519
|
return safeJsonParse3(readFileSync10(filePath, "utf-8"));
|
|
7400
7520
|
} catch {
|
|
7401
|
-
|
|
7521
|
+
_handleStateCorruption(filePath);
|
|
7402
7522
|
return {};
|
|
7403
7523
|
}
|
|
7404
7524
|
}
|
|
@@ -7413,7 +7533,7 @@ function saveReportsIndex(idx) {
|
|
|
7413
7533
|
const reportsIndexPath = getReportsIndexPath();
|
|
7414
7534
|
const reportsDir = getReportsDir();
|
|
7415
7535
|
withFileLock(reportsIndexPath, () => {
|
|
7416
|
-
|
|
7536
|
+
mkdirSync8(reportsDir, { recursive: true });
|
|
7417
7537
|
writeFileSync9(reportsIndexPath, JSON.stringify(idx, null, 2) + "\n");
|
|
7418
7538
|
});
|
|
7419
7539
|
} catch (err) {
|
|
@@ -7531,7 +7651,7 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
7531
7651
|
const reportsIndexPath = getReportsIndexPath();
|
|
7532
7652
|
const reportsDir = getReportsDir();
|
|
7533
7653
|
withFileLock(reportsIndexPath, () => {
|
|
7534
|
-
|
|
7654
|
+
mkdirSync8(reportsDir, { recursive: true });
|
|
7535
7655
|
writeFileSync9(join9(reportsDir, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
7536
7656
|
const idx = reportsIndex();
|
|
7537
7657
|
const _sum = (summary || "").slice(0, 80);
|
|
@@ -7894,6 +8014,14 @@ var RAW_MODE = {
|
|
|
7894
8014
|
desc: "Pure v4 Pro baseline. No vibeOS overhead."
|
|
7895
8015
|
};
|
|
7896
8016
|
var ALL_MODES = [...BRANDED_MODES, ...RUNTIME_MODES, RAW_MODE];
|
|
8017
|
+
function resolveCascadeSlot(pipeline = []) {
|
|
8018
|
+
const normalized = Array.isArray(pipeline) ? pipeline.map((t) => String(t || "").toLowerCase()) : [];
|
|
8019
|
+
if (normalized.includes("brain"))
|
|
8020
|
+
return "brain";
|
|
8021
|
+
if (normalized.includes("medium"))
|
|
8022
|
+
return "medium";
|
|
8023
|
+
return "cheap";
|
|
8024
|
+
}
|
|
7897
8025
|
|
|
7898
8026
|
// src/lib/trinity-tool.js
|
|
7899
8027
|
var MIN_TOOL_BREAKDOWN_THRESHOLD = 5e-3;
|
|
@@ -8177,8 +8305,7 @@ function createTrinityTool(deps) {
|
|
|
8177
8305
|
const allEntries = [...BRANDED_MODES, ...RUNTIME_MODES];
|
|
8178
8306
|
const modeEntry = allEntries.find((e) => e.id === slot);
|
|
8179
8307
|
if (modeEntry) {
|
|
8180
|
-
const
|
|
8181
|
-
const tierSlot = (/* @__PURE__ */ new Set(["brain", "medium", "cheap"])).has(rawTier) ? rawTier : "cheap";
|
|
8308
|
+
const tierSlot = resolveCascadeSlot(modeEntry.pipeline);
|
|
8182
8309
|
deps.writeSessionSlot(deps._OC_SID, tierSlot);
|
|
8183
8310
|
deps.writeSelection("slot_locked", resolvedSlot !== "auto");
|
|
8184
8311
|
deps.writeSelection("active_slot", tierSlot);
|
|
@@ -9511,12 +9638,12 @@ async function probeModel(modelId, auth, providers = null) {
|
|
|
9511
9638
|
}
|
|
9512
9639
|
|
|
9513
9640
|
// src/lib/hooks/footer.js
|
|
9514
|
-
import { readFileSync as readFileSync14, appendFileSync as
|
|
9641
|
+
import { readFileSync as readFileSync14, appendFileSync as appendFileSync4, mkdirSync as mkdirSync10 } from "node:fs";
|
|
9515
9642
|
import { join as join15 } from "node:path";
|
|
9516
9643
|
|
|
9517
9644
|
// src/lib/hooks/chat-transform.js
|
|
9518
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync12, appendFileSync as
|
|
9519
|
-
import { join as join14, dirname as dirname10, basename as
|
|
9645
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync12, appendFileSync as appendFileSync3, existsSync as existsSync14, mkdirSync as mkdirSync9, rmSync as rmSync5, readdirSync as readdirSync3, statSync as statSync7 } from "node:fs";
|
|
9646
|
+
import { join as join14, dirname as dirname10, basename as basename3 } from "node:path";
|
|
9520
9647
|
import { createHash as createHash3 } from "node:crypto";
|
|
9521
9648
|
|
|
9522
9649
|
// src/lib/mode-policy.js
|
|
@@ -10303,14 +10430,14 @@ function observeUserCorrection(text) {
|
|
|
10303
10430
|
}
|
|
10304
10431
|
}
|
|
10305
10432
|
function buildProjectBriefing(directory3) {
|
|
10306
|
-
const label = currentProjectName || (directory3 ?
|
|
10433
|
+
const label = currentProjectName || (directory3 ? basename3(directory3) : "");
|
|
10307
10434
|
if (!label)
|
|
10308
10435
|
return null;
|
|
10309
10436
|
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
10310
10437
|
}
|
|
10311
10438
|
function ensureProjectSkill(dir, fp2) {
|
|
10312
10439
|
const skillsDir = join14(dir, ".opencode", "skills");
|
|
10313
|
-
const projectName =
|
|
10440
|
+
const projectName = basename3(dir);
|
|
10314
10441
|
const skillDir = join14(skillsDir, projectName);
|
|
10315
10442
|
const skillPath = join14(skillDir, "SKILL.md");
|
|
10316
10443
|
if (existsSync14(skillPath)) {
|
|
@@ -10375,7 +10502,7 @@ function ensureProjectSkill(dir, fp2) {
|
|
|
10375
10502
|
content += "\n";
|
|
10376
10503
|
}
|
|
10377
10504
|
try {
|
|
10378
|
-
|
|
10505
|
+
mkdirSync9(skillDir, { recursive: true });
|
|
10379
10506
|
writeFileSync12(skillPath, content, "utf-8");
|
|
10380
10507
|
console.error(`[vibeOS] Project Guard: created .opencode/skills/${projectName}/SKILL.md`);
|
|
10381
10508
|
return { created: true, path: skillPath, skipped: false };
|
|
@@ -10534,7 +10661,7 @@ ${raw}
|
|
|
10534
10661
|
const sessPath = join14(getSessionScratchpadDir(), `${hash}.txt`);
|
|
10535
10662
|
const globalPath = join14(globalDir, `${hash}.txt`);
|
|
10536
10663
|
try {
|
|
10537
|
-
|
|
10664
|
+
mkdirSync9(globalDir, { recursive: true });
|
|
10538
10665
|
ensureSessionScratchpadDirs();
|
|
10539
10666
|
if (!existsSync14(globalPath)) {
|
|
10540
10667
|
writeFileSync12(globalPath, raw);
|
|
@@ -10947,8 +11074,8 @@ var onSystemTransform = async (_input, output) => {
|
|
|
10947
11074
|
fp: currentProjectFingerprint || ""
|
|
10948
11075
|
}) + "\n";
|
|
10949
11076
|
try {
|
|
10950
|
-
|
|
10951
|
-
|
|
11077
|
+
mkdirSync9(calDir, { recursive: true });
|
|
11078
|
+
appendFileSync3(calFile, calRecord);
|
|
10952
11079
|
} catch {
|
|
10953
11080
|
}
|
|
10954
11081
|
if (!oneShot("vibeos_dashboard_instruct")) {
|
|
@@ -11364,8 +11491,8 @@ ${vibeLine}`;
|
|
|
11364
11491
|
tracker.recordOutcome(finalOutcome);
|
|
11365
11492
|
syncOutcomeToApi(finalOutcome);
|
|
11366
11493
|
try {
|
|
11367
|
-
|
|
11368
|
-
|
|
11494
|
+
mkdirSync10(getVibeOSHome10(), { recursive: true });
|
|
11495
|
+
appendFileSync4(join15(getVibeOSHome10(), "calibration-data.jsonl"), JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), event: "outcome", sid: getSessionId(), outcome: finalOutcome }) + "\n");
|
|
11369
11496
|
} catch {
|
|
11370
11497
|
}
|
|
11371
11498
|
}
|
|
@@ -11391,8 +11518,8 @@ ${vibeLine} \u2014`);
|
|
|
11391
11518
|
}
|
|
11392
11519
|
|
|
11393
11520
|
// src/lib/hooks/tool-execute.js
|
|
11394
|
-
import { writeFileSync as writeFileSync14, appendFileSync as
|
|
11395
|
-
import { join as join17, dirname as dirname12, basename as
|
|
11521
|
+
import { writeFileSync as writeFileSync14, appendFileSync as appendFileSync6, existsSync as existsSync16, mkdirSync as mkdirSync12 } from "node:fs";
|
|
11522
|
+
import { join as join17, dirname as dirname12, basename as basename4 } from "node:path";
|
|
11396
11523
|
import { createHash as createHash5 } from "node:crypto";
|
|
11397
11524
|
|
|
11398
11525
|
// src/lib/cost-anomaly.js
|
|
@@ -11456,7 +11583,7 @@ function getCostAnomalyDetector() {
|
|
|
11456
11583
|
init_flow_enforcer();
|
|
11457
11584
|
|
|
11458
11585
|
// src/lib/tdd-enforcer.js
|
|
11459
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, appendFileSync as
|
|
11586
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, appendFileSync as appendFileSync5, existsSync as existsSync15, mkdirSync as mkdirSync11, statSync as statSync8, readdirSync as readdirSync4, rmSync as rmSync6, openSync as openSync3 } from "node:fs";
|
|
11460
11587
|
import { join as join16, dirname as dirname11 } from "node:path";
|
|
11461
11588
|
import { createHash as createHash4 } from "node:crypto";
|
|
11462
11589
|
|
|
@@ -12559,7 +12686,7 @@ var COOLDOWN_MS = 6e4;
|
|
|
12559
12686
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
12560
12687
|
function _acquireLock(testPath) {
|
|
12561
12688
|
try {
|
|
12562
|
-
|
|
12689
|
+
mkdirSync11(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
12563
12690
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
12564
12691
|
const lockPath = join16(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
12565
12692
|
try {
|
|
@@ -12616,10 +12743,10 @@ function _isInCooldown(testPath) {
|
|
|
12616
12743
|
}
|
|
12617
12744
|
function _recordCooldown(testPath) {
|
|
12618
12745
|
try {
|
|
12619
|
-
|
|
12746
|
+
mkdirSync11(dirname11(ENFORCEMENT_COOLDOWN_FILE2), { recursive: true });
|
|
12620
12747
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
12621
12748
|
const entry = JSON.stringify({ h: hash, ts: Date.now() }) + "\n";
|
|
12622
|
-
|
|
12749
|
+
appendFileSync5(ENFORCEMENT_COOLDOWN_FILE2, entry);
|
|
12623
12750
|
const lines = readFileSync15(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
12624
12751
|
if (lines.length > 500) {
|
|
12625
12752
|
writeFileSync13(ENFORCEMENT_COOLDOWN_FILE2, lines.slice(-200).join("\n") + "\n");
|
|
@@ -12708,7 +12835,7 @@ function enforceTestFile(filePath) {
|
|
|
12708
12835
|
if (!_acquireLock(skeleton.path))
|
|
12709
12836
|
return null;
|
|
12710
12837
|
try {
|
|
12711
|
-
|
|
12838
|
+
mkdirSync11(skeleton.dir, { recursive: true });
|
|
12712
12839
|
writeFileSync13(skeleton.path, skeleton.content);
|
|
12713
12840
|
_enforcementCooldown.add(skeleton.path);
|
|
12714
12841
|
_recordCooldown(skeleton.path);
|
|
@@ -12934,7 +13061,7 @@ function _isProtectedToolPath(pathValue) {
|
|
|
12934
13061
|
}
|
|
12935
13062
|
function _mutateBlockedToolArgs(toolName, sources, blockedPath, outputObj) {
|
|
12936
13063
|
const tLower = String(toolName || "").toLowerCase();
|
|
12937
|
-
const blockedBase =
|
|
13064
|
+
const blockedBase = basename4(blockedPath || "") || "blocked";
|
|
12938
13065
|
for (const src of sources) {
|
|
12939
13066
|
if (!src || typeof src !== "object")
|
|
12940
13067
|
continue;
|
|
@@ -13243,7 +13370,7 @@ ${argsJson}
|
|
|
13243
13370
|
_mutateBlockedToolArgs(t, argSources, checkPath, output);
|
|
13244
13371
|
if (shouldLogWarn(`${t}|protect|${checkPath}`))
|
|
13245
13372
|
console.error(`[vibeOS] [protection] BLOCKED direct ${t} in self-protected directory: ${checkPath}`);
|
|
13246
|
-
pendingUiNote = `[LOCK] Self-modification paused: ${
|
|
13373
|
+
pendingUiNote = `[LOCK] Self-modification paused: ${basename4(checkPath)} is in a protected project tree. Use a manual git workflow.`;
|
|
13247
13374
|
enforcementBlocked = true;
|
|
13248
13375
|
return;
|
|
13249
13376
|
}
|
|
@@ -13281,7 +13408,7 @@ ${argsJson}
|
|
|
13281
13408
|
const tLower = String(t || "").toLowerCase();
|
|
13282
13409
|
if (!compatibilityMode && sel.delegation_enforce && currentTier === "high" && argSources.length > 0) {
|
|
13283
13410
|
const originalPath = argSources.flatMap((src) => [src?.filePath, src?.file_path, src?.path]).find((v) => typeof v === "string" && v.trim()) || "";
|
|
13284
|
-
const
|
|
13411
|
+
const basename6 = originalPath.split("/").pop() || "blocked";
|
|
13285
13412
|
const apiResult = await remoteCall("delegateCheck", [tLower, currentTier, currentModel, _prompt], () => ({
|
|
13286
13413
|
blocked: true,
|
|
13287
13414
|
savings: _estEdit
|
|
@@ -13321,7 +13448,7 @@ ${argsJson}
|
|
|
13321
13448
|
const missed = recordMissedContext7(_estC7);
|
|
13322
13449
|
if (!existsSync16(CONTEXT7_INSTALL_FLAG)) {
|
|
13323
13450
|
try {
|
|
13324
|
-
|
|
13451
|
+
mkdirSync12(dirname12(CONTEXT7_INSTALL_FLAG), { recursive: true });
|
|
13325
13452
|
writeFileSync14(CONTEXT7_INSTALL_FLAG, "");
|
|
13326
13453
|
} catch {
|
|
13327
13454
|
}
|
|
@@ -13507,7 +13634,7 @@ var onToolExecuteAfter = async (input, output) => {
|
|
|
13507
13634
|
const taskPrompt = input?.args?.prompt || input?.args?.description || "";
|
|
13508
13635
|
const quality = scoreTaskQuality(taskOutput, taskPrompt);
|
|
13509
13636
|
try {
|
|
13510
|
-
|
|
13637
|
+
appendFileSync6(SAVINGS_LEDGER_FILE, JSON.stringify({
|
|
13511
13638
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13512
13639
|
kind: "quality",
|
|
13513
13640
|
score: quality,
|
|
@@ -13673,7 +13800,7 @@ ${pendingUiNote}`;
|
|
|
13673
13800
|
if (guardRe.test(fp3)) {
|
|
13674
13801
|
const guardIcons = { flag: "!", warn: "!!", hint: "_" };
|
|
13675
13802
|
const guardIcon = guardIcons.flag || "!";
|
|
13676
|
-
const fn =
|
|
13803
|
+
const fn = basename4(fp3);
|
|
13677
13804
|
console.error(`[flow-enforcer] ${guardIcon} [guard] ${fn}: protected project doc modified \u2014 verify user intent`);
|
|
13678
13805
|
}
|
|
13679
13806
|
}
|
|
@@ -13981,7 +14108,7 @@ async function _seedModelTiersIfMissing(directory3) {
|
|
|
13981
14108
|
cheap: { oc: cheap, cc: modelToCcAlias(cheap) }
|
|
13982
14109
|
}
|
|
13983
14110
|
};
|
|
13984
|
-
|
|
14111
|
+
mkdirSync13(dirname13(TIERS_FILE3), { recursive: true });
|
|
13985
14112
|
writeFileSync15(TIERS_FILE3, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
13986
14113
|
return true;
|
|
13987
14114
|
}
|
|
@@ -14050,7 +14177,7 @@ function persistMcpPort(port) {
|
|
|
14050
14177
|
tiers.selection.mcp_port = port;
|
|
14051
14178
|
if ("mcp_port" in tiers)
|
|
14052
14179
|
delete tiers.mcp_port;
|
|
14053
|
-
|
|
14180
|
+
mkdirSync13(dirname13(getTiersFile()), { recursive: true });
|
|
14054
14181
|
const tmp = getTiersFile() + ".tmp." + Date.now();
|
|
14055
14182
|
writeFileSync15(tmp, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
14056
14183
|
renameSync6(tmp, getTiersFile());
|
|
@@ -14141,7 +14268,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14141
14268
|
};
|
|
14142
14269
|
const saveProjectStateStable = (state) => {
|
|
14143
14270
|
try {
|
|
14144
|
-
|
|
14271
|
+
mkdirSync13(dirname13(hookProjectStateFile), { recursive: true });
|
|
14145
14272
|
const tmp = hookProjectStateFile + ".tmp";
|
|
14146
14273
|
writeFileSync15(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
14147
14274
|
renameSync6(tmp, hookProjectStateFile);
|
|
@@ -14160,7 +14287,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14160
14287
|
};
|
|
14161
14288
|
const saveReportsIndexStable = (idx) => {
|
|
14162
14289
|
try {
|
|
14163
|
-
|
|
14290
|
+
mkdirSync13(hookReportsDir, { recursive: true });
|
|
14164
14291
|
writeFileSync15(hookReportsIndex, JSON.stringify(idx, null, 2) + "\n");
|
|
14165
14292
|
} catch {
|
|
14166
14293
|
}
|
|
@@ -14170,9 +14297,9 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14170
14297
|
if (!existsSync18(path))
|
|
14171
14298
|
return null;
|
|
14172
14299
|
const bkDir = join18(hookVibeHome, ".backups");
|
|
14173
|
-
|
|
14174
|
-
const bk = join18(bkDir, `${
|
|
14175
|
-
|
|
14300
|
+
mkdirSync13(bkDir, { recursive: true });
|
|
14301
|
+
const bk = join18(bkDir, `${basename5(path)}.${label}.${Date.now()}.bak`);
|
|
14302
|
+
copyFileSync2(path, bk);
|
|
14176
14303
|
return bk;
|
|
14177
14304
|
} catch {
|
|
14178
14305
|
return null;
|
|
@@ -14210,7 +14337,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14210
14337
|
writeFileSync: writeFileSync15,
|
|
14211
14338
|
existsSync: existsSync18,
|
|
14212
14339
|
renameSync: renameSync6,
|
|
14213
|
-
mkdirSync:
|
|
14340
|
+
mkdirSync: mkdirSync13,
|
|
14214
14341
|
get TIERS_FILE() {
|
|
14215
14342
|
return hookTiersFile;
|
|
14216
14343
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.17",
|
|
4
4
|
"description": "Cost-aware delegation enforcer for OpenCode. Tracks model usage, routes Task subagents to cheaper tiers, surfaces cumulative savings in chat. Includes research audit, reporting framework, project memory, progressive scratchpad decadence, and trinity CLI for brain/medium/cheap slot switching.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"release": "node scripts/release.mjs",
|