vibeostheog 0.24.15 → 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/CHANGELOG.md +5 -0
- package/dist/vibeOS.js +324 -191
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
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;
|
|
@@ -2451,14 +2437,16 @@ function loadSelection() {
|
|
|
2451
2437
|
function writeSelection(key, value) {
|
|
2452
2438
|
const TIERS_FILE3 = join3(getVibeOSHome2(), "model-tiers.json");
|
|
2453
2439
|
try {
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
j.selection
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2440
|
+
return withFileLock(TIERS_FILE3, () => {
|
|
2441
|
+
const j = safeJsonParse2(readFileSync3(TIERS_FILE3, "utf-8"));
|
|
2442
|
+
if (!j.selection)
|
|
2443
|
+
j.selection = {};
|
|
2444
|
+
j.selection[key] = value;
|
|
2445
|
+
const tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
|
|
2446
|
+
writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
|
|
2447
|
+
renameSync2(tmp, TIERS_FILE3);
|
|
2448
|
+
return true;
|
|
2449
|
+
});
|
|
2462
2450
|
} catch (err) {
|
|
2463
2451
|
console.error(`[vibeOS] writeSelection failed: ${err.message}`);
|
|
2464
2452
|
return false;
|
|
@@ -2535,7 +2523,7 @@ function writeSessionOptMode(sid, mode) {
|
|
|
2535
2523
|
}
|
|
2536
2524
|
|
|
2537
2525
|
// src/lib/pattern-helpers.js
|
|
2538
|
-
import { relative, basename
|
|
2526
|
+
import { relative, basename } from "node:path";
|
|
2539
2527
|
function normalizeObservedPath(filePath, directory3) {
|
|
2540
2528
|
if (!filePath || typeof filePath !== "string")
|
|
2541
2529
|
return "unknown";
|
|
@@ -2556,7 +2544,7 @@ function normalizeObservedPath(filePath, directory3) {
|
|
|
2556
2544
|
return `src/*.${m[1].toLowerCase()}`;
|
|
2557
2545
|
if (p.startsWith("tests/") && m)
|
|
2558
2546
|
return `tests/*.${m[1].toLowerCase()}`;
|
|
2559
|
-
return
|
|
2547
|
+
return basename(p) || "unknown";
|
|
2560
2548
|
}
|
|
2561
2549
|
function commandFamily(command) {
|
|
2562
2550
|
const c = String(command || "").trim().toLowerCase();
|
|
@@ -3289,6 +3277,12 @@ var MAX_SCRATCHPAD_FILES = 1e3;
|
|
|
3289
3277
|
var MAX_SCRATCHPAD_BYTES = 10 * 1024 * 1024;
|
|
3290
3278
|
var MAX_SESSION_SCRATCHPAD_FILES = 200;
|
|
3291
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;
|
|
3292
3286
|
var MAX_PTR_CANDIDATES = 50;
|
|
3293
3287
|
var SUMMARY_HEAD_TRUNCATE = 500;
|
|
3294
3288
|
function getVibeOSHome3() {
|
|
@@ -3419,19 +3413,48 @@ var tool = Object.assign((def) => def, {
|
|
|
3419
3413
|
enum: (values) => _zType({ kind: "enum", values })
|
|
3420
3414
|
}
|
|
3421
3415
|
});
|
|
3422
|
-
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) {
|
|
3423
3444
|
const backupDir = join4(VIBEOS_HOME, ".backups");
|
|
3424
|
-
|
|
3425
|
-
const backupPath = join4(backupDir,
|
|
3445
|
+
mkdirSync3(backupDir, { recursive: true });
|
|
3446
|
+
const backupPath = join4(backupDir, basename2(path) + ".corrupted." + Date.now());
|
|
3426
3447
|
try {
|
|
3427
|
-
|
|
3448
|
+
copyFileSync(path, backupPath);
|
|
3428
3449
|
} catch {
|
|
3429
3450
|
}
|
|
3430
3451
|
const logPath = join4(VIBEOS_HOME, ".state-corruption-log.jsonl");
|
|
3431
3452
|
try {
|
|
3432
|
-
|
|
3453
|
+
appendFileSync2(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
3433
3454
|
} catch {
|
|
3434
3455
|
}
|
|
3456
|
+
_pruneCorruptionBackups(backupDir);
|
|
3457
|
+
return backupPath;
|
|
3435
3458
|
}
|
|
3436
3459
|
function _lockPathFor(filePath) {
|
|
3437
3460
|
const hash = createHash("sha1").update(String(filePath || "")).digest("hex");
|
|
@@ -3444,7 +3467,7 @@ function withFileLock(filePath, fn, opts = {}) {
|
|
|
3444
3467
|
const start = Date.now();
|
|
3445
3468
|
while (Date.now() - start < timeoutMs) {
|
|
3446
3469
|
try {
|
|
3447
|
-
|
|
3470
|
+
mkdirSync3(FILE_LOCK_DIR, { recursive: true });
|
|
3448
3471
|
const fd = openSync(lockPath, "wx");
|
|
3449
3472
|
try {
|
|
3450
3473
|
writeFileSync4(fd, `${process.pid}
|
|
@@ -3522,12 +3545,12 @@ function readJsonOrEmpty(filePath) {
|
|
|
3522
3545
|
return {};
|
|
3523
3546
|
const st = statSync4(filePath);
|
|
3524
3547
|
if (st.size > 10485760) {
|
|
3525
|
-
|
|
3548
|
+
_handleStateCorruption(filePath);
|
|
3526
3549
|
return {};
|
|
3527
3550
|
}
|
|
3528
3551
|
return safeJsonParse3(readFileSync4(filePath, "utf-8"));
|
|
3529
3552
|
} catch {
|
|
3530
|
-
|
|
3553
|
+
_handleStateCorruption(filePath);
|
|
3531
3554
|
return {};
|
|
3532
3555
|
}
|
|
3533
3556
|
}
|
|
@@ -3552,7 +3575,7 @@ function updateState(mutator) {
|
|
|
3552
3575
|
state._gen = preGen + 1;
|
|
3553
3576
|
const next = mutator(state) ?? state;
|
|
3554
3577
|
validateState(next, delegationStateFile);
|
|
3555
|
-
|
|
3578
|
+
mkdirSync3(dirname4(delegationStateFile), { recursive: true });
|
|
3556
3579
|
const tmp = delegationStateFile + ".tmp";
|
|
3557
3580
|
writeFileSync4(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
3558
3581
|
renameSync3(tmp, delegationStateFile);
|
|
@@ -3578,12 +3601,12 @@ function readFullState() {
|
|
|
3578
3601
|
return {};
|
|
3579
3602
|
const st = statSync4(delegationStateFile);
|
|
3580
3603
|
if (st.size > 10485760) {
|
|
3581
|
-
|
|
3604
|
+
_handleStateCorruption(delegationStateFile);
|
|
3582
3605
|
return {};
|
|
3583
3606
|
}
|
|
3584
3607
|
return safeJsonParse3(readFileSync4(delegationStateFile, "utf-8"));
|
|
3585
3608
|
} catch {
|
|
3586
|
-
|
|
3609
|
+
_handleStateCorruption(delegationStateFile);
|
|
3587
3610
|
return {};
|
|
3588
3611
|
}
|
|
3589
3612
|
}
|
|
@@ -3623,7 +3646,7 @@ function loadGlobalLearning() {
|
|
|
3623
3646
|
return DFLT_GL;
|
|
3624
3647
|
const st = statSync4(globalLearningFile);
|
|
3625
3648
|
if (st.size > 10485760) {
|
|
3626
|
-
|
|
3649
|
+
_handleStateCorruption(globalLearningFile);
|
|
3627
3650
|
return DFLT_GL;
|
|
3628
3651
|
}
|
|
3629
3652
|
const j = safeJsonParse3(readFileSync4(globalLearningFile, "utf-8"));
|
|
@@ -3636,7 +3659,7 @@ function loadGlobalLearning() {
|
|
|
3636
3659
|
j.context7_last_seen ??= null;
|
|
3637
3660
|
return j;
|
|
3638
3661
|
} catch {
|
|
3639
|
-
|
|
3662
|
+
_handleStateCorruption(globalLearningFile);
|
|
3640
3663
|
return DFLT_GL;
|
|
3641
3664
|
}
|
|
3642
3665
|
}
|
|
@@ -3646,7 +3669,7 @@ function updateGlobalLearning(mutator) {
|
|
|
3646
3669
|
const s = loadGlobalLearning();
|
|
3647
3670
|
const next = mutator(s) ?? s;
|
|
3648
3671
|
next.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3649
|
-
|
|
3672
|
+
mkdirSync3(dirname4(globalLearningFile), { recursive: true });
|
|
3650
3673
|
const tmp = globalLearningFile + ".tmp";
|
|
3651
3674
|
writeFileSync4(tmp, JSON.stringify(next, null, 2));
|
|
3652
3675
|
renameSync3(tmp, globalLearningFile);
|
|
@@ -3698,19 +3721,19 @@ function loadBlackboxState() {
|
|
|
3698
3721
|
return { enabled: true, sessions: {} };
|
|
3699
3722
|
const st = statSync4(blackboxFile);
|
|
3700
3723
|
if (st.size > 10485760) {
|
|
3701
|
-
|
|
3724
|
+
_handleStateCorruption(blackboxFile);
|
|
3702
3725
|
return { enabled: false, sessions: {} };
|
|
3703
3726
|
}
|
|
3704
3727
|
return safeJsonParse3(readFileSync4(blackboxFile, "utf-8")) || { enabled: false, sessions: {} };
|
|
3705
3728
|
} catch {
|
|
3706
|
-
|
|
3729
|
+
_handleStateCorruption(blackboxFile);
|
|
3707
3730
|
return { enabled: false, sessions: {} };
|
|
3708
3731
|
}
|
|
3709
3732
|
}
|
|
3710
3733
|
function saveBlackboxState(state) {
|
|
3711
3734
|
const blackboxFile = join4(getVibeOSHome3(), "blackbox-state.json");
|
|
3712
3735
|
try {
|
|
3713
|
-
|
|
3736
|
+
mkdirSync3(dirname4(blackboxFile), { recursive: true });
|
|
3714
3737
|
const tmp = blackboxFile + ".tmp";
|
|
3715
3738
|
writeFileSync4(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
3716
3739
|
renameSync3(tmp, blackboxFile);
|
|
@@ -3732,7 +3755,7 @@ function getGlobalIndexPath() {
|
|
|
3732
3755
|
}
|
|
3733
3756
|
function ensureSessionScratchpadDirs() {
|
|
3734
3757
|
try {
|
|
3735
|
-
|
|
3758
|
+
mkdirSync3(getSessionScratchpadDir(), { recursive: true });
|
|
3736
3759
|
return true;
|
|
3737
3760
|
} catch {
|
|
3738
3761
|
return false;
|
|
@@ -3776,7 +3799,8 @@ function _flushLedgerBuffer() {
|
|
|
3776
3799
|
const lines = batch.map((e) => typeof e === "string" ? e.trimEnd() : String(e).trimEnd());
|
|
3777
3800
|
const joined = lines.filter(Boolean).map((l) => l + "\n").join("");
|
|
3778
3801
|
try {
|
|
3779
|
-
|
|
3802
|
+
appendFileSync2(SAVINGS_LEDGER_FILE, joined);
|
|
3803
|
+
_compactSavingsLedgerIfNeeded();
|
|
3780
3804
|
} catch {
|
|
3781
3805
|
}
|
|
3782
3806
|
}
|
|
@@ -3923,10 +3947,10 @@ function indexAppend(hash, tool2, size, extra) {
|
|
|
3923
3947
|
const entry = JSON.stringify(entryObj) + "\n";
|
|
3924
3948
|
const globalIndex = getGlobalIndexPath();
|
|
3925
3949
|
const sessionIndex = getSessionIndexPath();
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3950
|
+
mkdirSync3(dirname4(globalIndex), { recursive: true });
|
|
3951
|
+
mkdirSync3(dirname4(sessionIndex), { recursive: true });
|
|
3952
|
+
appendFileSync2(globalIndex, entry);
|
|
3953
|
+
appendFileSync2(sessionIndex, entry);
|
|
3930
3954
|
} catch (err) {
|
|
3931
3955
|
console.error(`[vibeOS] index write failed: ${err.message}`);
|
|
3932
3956
|
}
|
|
@@ -4179,21 +4203,83 @@ function pruneScratchpadOnce() {
|
|
|
4179
4203
|
}
|
|
4180
4204
|
cleanupStaleSessionScratchpads();
|
|
4181
4205
|
}
|
|
4182
|
-
function
|
|
4206
|
+
function _readActiveJobsRaw() {
|
|
4183
4207
|
try {
|
|
4184
4208
|
if (!existsSync5(ACTIVE_JOBS_FILE))
|
|
4185
4209
|
return {};
|
|
4186
|
-
const st = statSync4(ACTIVE_JOBS_FILE);
|
|
4187
|
-
if (st.size > 10485760) {
|
|
4188
|
-
_handleStateCorruption2(ACTIVE_JOBS_FILE);
|
|
4189
|
-
return {};
|
|
4190
|
-
}
|
|
4191
4210
|
const raw = safeJsonParse3(readFileSync4(ACTIVE_JOBS_FILE, "utf-8"));
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
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
|
+
});
|
|
4195
4281
|
} catch {
|
|
4196
|
-
|
|
4282
|
+
_handleStateCorruption(ACTIVE_JOBS_FILE);
|
|
4197
4283
|
return {};
|
|
4198
4284
|
}
|
|
4199
4285
|
}
|
|
@@ -4210,15 +4296,19 @@ function saveActiveJobForProject(job, fp2 = currentProjectFingerprint) {
|
|
|
4210
4296
|
if (!fp2 || !job || typeof job !== "object")
|
|
4211
4297
|
return;
|
|
4212
4298
|
try {
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4299
|
+
withFileLock(ACTIVE_JOBS_FILE, () => {
|
|
4300
|
+
const jobs = _readActiveJobsRaw();
|
|
4301
|
+
const norm = _normalizeActiveJobRecord(job);
|
|
4302
|
+
jobs[fp2] = norm.record || job;
|
|
4303
|
+
_writeActiveJobsRaw(jobs);
|
|
4304
|
+
});
|
|
4219
4305
|
} catch {
|
|
4220
4306
|
}
|
|
4221
4307
|
}
|
|
4308
|
+
try {
|
|
4309
|
+
loadActiveJobs();
|
|
4310
|
+
} catch {
|
|
4311
|
+
}
|
|
4222
4312
|
function projectFingerprint(dir) {
|
|
4223
4313
|
if (!dir)
|
|
4224
4314
|
return "unknown";
|
|
@@ -4240,7 +4330,7 @@ function saveProjectState(state) {
|
|
|
4240
4330
|
const projectStateFile = join4(getVibeOSHome3(), "project-states.json");
|
|
4241
4331
|
try {
|
|
4242
4332
|
withFileLock(projectStateFile, () => {
|
|
4243
|
-
|
|
4333
|
+
mkdirSync3(dirname4(projectStateFile), { recursive: true });
|
|
4244
4334
|
const _tmp = projectStateFile + ".tmp." + Date.now();
|
|
4245
4335
|
writeFileSync4(_tmp, JSON.stringify(state, null, 2) + "\n", "utf-8");
|
|
4246
4336
|
renameSync3(_tmp, projectStateFile);
|
|
@@ -4477,7 +4567,7 @@ function loadTodos() {
|
|
|
4477
4567
|
}
|
|
4478
4568
|
function saveTodos(todos) {
|
|
4479
4569
|
try {
|
|
4480
|
-
|
|
4570
|
+
mkdirSync3(dirname4(TODOS_FILE), { recursive: true });
|
|
4481
4571
|
const tmp = TODOS_FILE + ".tmp." + Date.now();
|
|
4482
4572
|
writeFileSync4(tmp, JSON.stringify(todos, null, 2), "utf-8");
|
|
4483
4573
|
renameSync3(tmp, TODOS_FILE);
|
|
@@ -4516,6 +4606,57 @@ function markTodoDone(id2) {
|
|
|
4516
4606
|
function getTodos() {
|
|
4517
4607
|
return loadTodos();
|
|
4518
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
|
+
}
|
|
4519
4660
|
function readLedgerTotals() {
|
|
4520
4661
|
const empty = { delegation: 0, cache: 0, context7: 0, total: 0, entries: 0 };
|
|
4521
4662
|
try {
|
|
@@ -4524,15 +4665,19 @@ function readLedgerTotals() {
|
|
|
4524
4665
|
return empty;
|
|
4525
4666
|
}
|
|
4526
4667
|
const st = statSync4(SAVINGS_LEDGER_FILE);
|
|
4527
|
-
if (st.size > 10485760) {
|
|
4528
|
-
_handleStateCorruption2(SAVINGS_LEDGER_FILE);
|
|
4529
|
-
return empty;
|
|
4530
|
-
}
|
|
4531
4668
|
if (st.size === 0) {
|
|
4532
4669
|
_ledgerTotalsCache = { mtime: st.mtimeMs, size: 0, delegation: 0, cache: 0, context7: 0, entries: 0 };
|
|
4533
4670
|
return empty;
|
|
4534
4671
|
}
|
|
4535
|
-
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) {
|
|
4536
4681
|
return {
|
|
4537
4682
|
delegation: Math.round(_ledgerTotalsCache.delegation * 1e3) / 1e3,
|
|
4538
4683
|
cache: Math.round(_ledgerTotalsCache.cache * 1e3) / 1e3,
|
|
@@ -4546,9 +4691,9 @@ function readLedgerTotals() {
|
|
|
4546
4691
|
let context7 = 0;
|
|
4547
4692
|
let entries = 0;
|
|
4548
4693
|
let raw = "";
|
|
4549
|
-
let incremental = _ledgerTotalsCache.size > 0 &&
|
|
4694
|
+
let incremental = _ledgerTotalsCache.size > 0 && currentStat.size >= _ledgerTotalsCache.size && _ledgerTotalsCache.mtime > 0;
|
|
4550
4695
|
if (incremental) {
|
|
4551
|
-
const deltaSize =
|
|
4696
|
+
const deltaSize = currentStat.size - _ledgerTotalsCache.size;
|
|
4552
4697
|
if (deltaSize > 0) {
|
|
4553
4698
|
const fd = openSync(SAVINGS_LEDGER_FILE, "r");
|
|
4554
4699
|
try {
|
|
@@ -4574,8 +4719,8 @@ function readLedgerTotals() {
|
|
|
4574
4719
|
}
|
|
4575
4720
|
if (!raw.trim()) {
|
|
4576
4721
|
_ledgerTotalsCache = {
|
|
4577
|
-
mtime:
|
|
4578
|
-
size:
|
|
4722
|
+
mtime: currentStat.mtimeMs,
|
|
4723
|
+
size: currentStat.size,
|
|
4579
4724
|
delegation,
|
|
4580
4725
|
cache,
|
|
4581
4726
|
context7,
|
|
@@ -4618,7 +4763,7 @@ function readLedgerTotals() {
|
|
|
4618
4763
|
else
|
|
4619
4764
|
delegation += amt;
|
|
4620
4765
|
}
|
|
4621
|
-
_ledgerTotalsCache = { mtime:
|
|
4766
|
+
_ledgerTotalsCache = { mtime: currentStat.mtimeMs, size: currentStat.size, delegation, cache, context7, entries };
|
|
4622
4767
|
const total = delegation + cache;
|
|
4623
4768
|
return {
|
|
4624
4769
|
delegation: Math.round(delegation * 1e3) / 1e3,
|
|
@@ -4703,7 +4848,7 @@ function saveSessionCheckpoint() {
|
|
|
4703
4848
|
model: session.model || ""
|
|
4704
4849
|
};
|
|
4705
4850
|
const cpPath = join4(getSessionRoot(), "checkpoint.json");
|
|
4706
|
-
|
|
4851
|
+
mkdirSync3(dirname4(cpPath), { recursive: true });
|
|
4707
4852
|
const tmp = cpPath + ".tmp";
|
|
4708
4853
|
writeFileSync4(tmp, JSON.stringify(cp, null, 2) + "\n");
|
|
4709
4854
|
renameSync3(tmp, cpPath);
|
|
@@ -4744,20 +4889,6 @@ function getOpenCodeDesktopHome() {
|
|
|
4744
4889
|
return process.env.VIBEOS_OPENCODE_DESKTOP_HOME || join5(process.env.HOME || homedir4(), "Library", "Application Support", "ai.opencode.desktop");
|
|
4745
4890
|
}
|
|
4746
4891
|
var TIERS_FILE2 = join5(getVibeOSHome4(), "model-tiers.json");
|
|
4747
|
-
function _handleStateCorruption3(path) {
|
|
4748
|
-
const backupDir = join5(getVibeOSHome4(), ".backups");
|
|
4749
|
-
mkdirSync5(backupDir, { recursive: true });
|
|
4750
|
-
const backupPath = join5(backupDir, basename4(path) + ".corrupted." + Date.now());
|
|
4751
|
-
try {
|
|
4752
|
-
copyFileSync3(path, backupPath);
|
|
4753
|
-
} catch {
|
|
4754
|
-
}
|
|
4755
|
-
const logPath = join5(getVibeOSHome4(), ".state-corruption-log.jsonl");
|
|
4756
|
-
try {
|
|
4757
|
-
appendFileSync4(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
4758
|
-
} catch {
|
|
4759
|
-
}
|
|
4760
|
-
}
|
|
4761
4892
|
function _lockPathFor2(filePath) {
|
|
4762
4893
|
const hash = createHash2("sha1").update(String(filePath || "")).digest("hex");
|
|
4763
4894
|
return join5(getVibeOSHome4(), ".vibeOS-locks", `${hash}.lock`);
|
|
@@ -4769,7 +4900,7 @@ function withFileLock2(filePath, fn, opts = {}) {
|
|
|
4769
4900
|
const start = Date.now();
|
|
4770
4901
|
while (Date.now() - start < timeoutMs) {
|
|
4771
4902
|
try {
|
|
4772
|
-
|
|
4903
|
+
mkdirSync4(join5(getVibeOSHome4(), ".vibeOS-locks"), { recursive: true });
|
|
4773
4904
|
const fd = openSync2(lockPath, "wx");
|
|
4774
4905
|
try {
|
|
4775
4906
|
writeFileSync5(fd, `${process.pid}
|
|
@@ -5287,7 +5418,7 @@ function _loadDynamicPricingCache() {
|
|
|
5287
5418
|
return {};
|
|
5288
5419
|
const st = statSync5(PRICING_CACHE_FILE2);
|
|
5289
5420
|
if (st.size > 10485760) {
|
|
5290
|
-
|
|
5421
|
+
_handleStateCorruption(PRICING_CACHE_FILE2);
|
|
5291
5422
|
_dynamicPricingCache = {};
|
|
5292
5423
|
return {};
|
|
5293
5424
|
}
|
|
@@ -5295,7 +5426,7 @@ function _loadDynamicPricingCache() {
|
|
|
5295
5426
|
const map = raw?.models && typeof raw.models === "object" ? raw.models : {};
|
|
5296
5427
|
_dynamicPricingCache = map;
|
|
5297
5428
|
} catch {
|
|
5298
|
-
|
|
5429
|
+
_handleStateCorruption(PRICING_CACHE_FILE2);
|
|
5299
5430
|
_dynamicPricingCache = {};
|
|
5300
5431
|
}
|
|
5301
5432
|
return _dynamicPricingCache;
|
|
@@ -5332,7 +5463,7 @@ function _writeDynamicPricingCache(modelsMap) {
|
|
|
5332
5463
|
const PRICING_CACHE_FILE2 = join5(getVibeOSHome4(), "model-pricing-cache.json");
|
|
5333
5464
|
try {
|
|
5334
5465
|
withFileLock2(PRICING_CACHE_FILE2, () => {
|
|
5335
|
-
|
|
5466
|
+
mkdirSync4(dirname5(PRICING_CACHE_FILE2), { recursive: true });
|
|
5336
5467
|
let merged = {};
|
|
5337
5468
|
try {
|
|
5338
5469
|
if (existsSync6(PRICING_CACHE_FILE2)) {
|
|
@@ -5390,7 +5521,7 @@ function _loadPricingOverrides() {
|
|
|
5390
5521
|
return {};
|
|
5391
5522
|
const st = statSync5(tiersFile);
|
|
5392
5523
|
if (st.size > 10485760) {
|
|
5393
|
-
|
|
5524
|
+
_handleStateCorruption(tiersFile);
|
|
5394
5525
|
_pricingOverridesCache = {};
|
|
5395
5526
|
return {};
|
|
5396
5527
|
}
|
|
@@ -5421,7 +5552,7 @@ function _loadPricingOverrides() {
|
|
|
5421
5552
|
}
|
|
5422
5553
|
_pricingOverridesCache = out;
|
|
5423
5554
|
} catch {
|
|
5424
|
-
|
|
5555
|
+
_handleStateCorruption(join5(home, "model-tiers.json"));
|
|
5425
5556
|
_pricingOverridesCache = {};
|
|
5426
5557
|
}
|
|
5427
5558
|
return _pricingOverridesCache;
|
|
@@ -5557,7 +5688,7 @@ function loadSelection2() {
|
|
|
5557
5688
|
return DFLT_SEL2;
|
|
5558
5689
|
const st = statSync5(TIERS_FILE3);
|
|
5559
5690
|
if (st.size > 10485760) {
|
|
5560
|
-
|
|
5691
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5561
5692
|
return DFLT_SEL2;
|
|
5562
5693
|
}
|
|
5563
5694
|
const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
@@ -5580,7 +5711,7 @@ function loadSelection2() {
|
|
|
5580
5711
|
executed_model: j?.selection?.executed_model || null
|
|
5581
5712
|
};
|
|
5582
5713
|
} catch {
|
|
5583
|
-
|
|
5714
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5584
5715
|
return DFLT_SEL2;
|
|
5585
5716
|
}
|
|
5586
5717
|
}
|
|
@@ -5808,7 +5939,7 @@ function loadTrinitySlotsFromTiersFile() {
|
|
|
5808
5939
|
return false;
|
|
5809
5940
|
const st = statSync5(TIERS_FILE3);
|
|
5810
5941
|
if (st.size > 10485760) {
|
|
5811
|
-
|
|
5942
|
+
_handleStateCorruption(TIERS_FILE3);
|
|
5812
5943
|
return false;
|
|
5813
5944
|
}
|
|
5814
5945
|
const tiersData = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8")) || {};
|
|
@@ -5874,18 +6005,20 @@ function _refreshModel(directory3) {
|
|
|
5874
6005
|
console.error(`[vibeOS] model refresh (config): ${oldModel}(${oldTier}) \u2192 ${currentModel}(${currentTier})`);
|
|
5875
6006
|
try {
|
|
5876
6007
|
if (existsSync6(TIERS_FILE3)) {
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
t
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
6008
|
+
withFileLock2(TIERS_FILE3, () => {
|
|
6009
|
+
const t = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
6010
|
+
for (const s of getTrinitySlotOrder(t)) {
|
|
6011
|
+
if (t?.trinity?.[s]?.oc === cfgModel) {
|
|
6012
|
+
t.selection.active_slot = s;
|
|
6013
|
+
const _tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
|
|
6014
|
+
writeFileSync5(_tmp, JSON.stringify(t, null, 2) + "\n", "utf-8");
|
|
6015
|
+
renameSync4(_tmp, TIERS_FILE3);
|
|
6016
|
+
if (DEBUG_INTERNALS)
|
|
6017
|
+
console.error(`[vibeOS] model refresh (config): synced active_slot \u2192 ${s}`);
|
|
6018
|
+
break;
|
|
6019
|
+
}
|
|
5887
6020
|
}
|
|
5888
|
-
}
|
|
6021
|
+
});
|
|
5889
6022
|
}
|
|
5890
6023
|
} catch {
|
|
5891
6024
|
}
|
|
@@ -5897,32 +6030,34 @@ function _refreshModel(directory3) {
|
|
|
5897
6030
|
function applySlot2(slot, projectDir = "") {
|
|
5898
6031
|
try {
|
|
5899
6032
|
const TIERS_FILE3 = join5(getVibeOSHome4(), "model-tiers.json");
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
6033
|
+
return withFileLock2(TIERS_FILE3, () => {
|
|
6034
|
+
const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
6035
|
+
const ocModel = j?.trinity?.[slot]?.oc;
|
|
6036
|
+
if (!ocModel)
|
|
6037
|
+
return { ok: false, reason: `slot '${slot}' has no oc model` };
|
|
6038
|
+
j.selection.active_slot = slot;
|
|
6039
|
+
const _tmp = TIERS_FILE3 + ".tmp." + Date.now();
|
|
6040
|
+
writeFileSync5(_tmp, JSON.stringify(j, null, 2) + "\n", "utf-8");
|
|
6041
|
+
renameSync4(_tmp, TIERS_FILE3);
|
|
6042
|
+
const dir = projectDir || process.cwd();
|
|
6043
|
+
const localOcConfig = join5(dir, "opencode.json");
|
|
6044
|
+
const ocConfig = existsSync6(localOcConfig) ? localOcConfig : join5(getOpenCodeHome(), "opencode.json");
|
|
6045
|
+
if (existsSync6(ocConfig)) {
|
|
6046
|
+
const oc = safeJsonParse3(readFileSync5(ocConfig, "utf-8"));
|
|
6047
|
+
oc.model = ocModel;
|
|
6048
|
+
writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
|
|
6049
|
+
}
|
|
6050
|
+
clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
|
|
6051
|
+
_refreshModel(dir);
|
|
6052
|
+
return { ok: true, ocModel };
|
|
6053
|
+
});
|
|
5919
6054
|
} catch (err) {
|
|
5920
6055
|
return { ok: false, reason: err.message };
|
|
5921
6056
|
}
|
|
5922
6057
|
}
|
|
5923
6058
|
|
|
5924
6059
|
// src/lib/turn-classify.js
|
|
5925
|
-
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";
|
|
5926
6061
|
import { join as join7, dirname as dirname8 } from "node:path";
|
|
5927
6062
|
|
|
5928
6063
|
// src/vibeOS-lib/blackbox/resolution-tracker.js
|
|
@@ -7356,8 +7491,8 @@ function projectStructuredFromText(raw, selection, creditPercent = 0) {
|
|
|
7356
7491
|
}
|
|
7357
7492
|
|
|
7358
7493
|
// src/lib/reporting.js
|
|
7359
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as
|
|
7360
|
-
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";
|
|
7361
7496
|
function getVibeOSHome7() {
|
|
7362
7497
|
return process.env.VIBEOS_HOME || join9(process.env.HOME || "", ".claude");
|
|
7363
7498
|
}
|
|
@@ -7372,27 +7507,18 @@ var REPORTS_INDEX = getReportsIndexPath();
|
|
|
7372
7507
|
var currentProjectFingerprint2 = "";
|
|
7373
7508
|
var currentProjectName2 = "";
|
|
7374
7509
|
var currentSessionId2 = "";
|
|
7375
|
-
function _handleStateCorruption4(path) {
|
|
7376
|
-
const backupDir = join9(getVibeOSHome7(), ".backups");
|
|
7377
|
-
mkdirSync9(backupDir, { recursive: true });
|
|
7378
|
-
const backupPath = join9(backupDir, basename5(path) + ".corrupted." + Date.now());
|
|
7379
|
-
try {
|
|
7380
|
-
copyFileSync4(path, backupPath);
|
|
7381
|
-
} catch {
|
|
7382
|
-
}
|
|
7383
|
-
}
|
|
7384
7510
|
function readJsonOrEmpty2(filePath) {
|
|
7385
7511
|
try {
|
|
7386
7512
|
if (!existsSync11(filePath))
|
|
7387
7513
|
return {};
|
|
7388
7514
|
const st = statSync6(filePath);
|
|
7389
7515
|
if (st.size > 10485760) {
|
|
7390
|
-
|
|
7516
|
+
_handleStateCorruption(filePath);
|
|
7391
7517
|
return {};
|
|
7392
7518
|
}
|
|
7393
7519
|
return safeJsonParse3(readFileSync10(filePath, "utf-8"));
|
|
7394
7520
|
} catch {
|
|
7395
|
-
|
|
7521
|
+
_handleStateCorruption(filePath);
|
|
7396
7522
|
return {};
|
|
7397
7523
|
}
|
|
7398
7524
|
}
|
|
@@ -7407,7 +7533,7 @@ function saveReportsIndex(idx) {
|
|
|
7407
7533
|
const reportsIndexPath = getReportsIndexPath();
|
|
7408
7534
|
const reportsDir = getReportsDir();
|
|
7409
7535
|
withFileLock(reportsIndexPath, () => {
|
|
7410
|
-
|
|
7536
|
+
mkdirSync8(reportsDir, { recursive: true });
|
|
7411
7537
|
writeFileSync9(reportsIndexPath, JSON.stringify(idx, null, 2) + "\n");
|
|
7412
7538
|
});
|
|
7413
7539
|
} catch (err) {
|
|
@@ -7525,7 +7651,7 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
7525
7651
|
const reportsIndexPath = getReportsIndexPath();
|
|
7526
7652
|
const reportsDir = getReportsDir();
|
|
7527
7653
|
withFileLock(reportsIndexPath, () => {
|
|
7528
|
-
|
|
7654
|
+
mkdirSync8(reportsDir, { recursive: true });
|
|
7529
7655
|
writeFileSync9(join9(reportsDir, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
7530
7656
|
const idx = reportsIndex();
|
|
7531
7657
|
const _sum = (summary || "").slice(0, 80);
|
|
@@ -7888,6 +8014,14 @@ var RAW_MODE = {
|
|
|
7888
8014
|
desc: "Pure v4 Pro baseline. No vibeOS overhead."
|
|
7889
8015
|
};
|
|
7890
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
|
+
}
|
|
7891
8025
|
|
|
7892
8026
|
// src/lib/trinity-tool.js
|
|
7893
8027
|
var MIN_TOOL_BREAKDOWN_THRESHOLD = 5e-3;
|
|
@@ -8171,8 +8305,7 @@ function createTrinityTool(deps) {
|
|
|
8171
8305
|
const allEntries = [...BRANDED_MODES, ...RUNTIME_MODES];
|
|
8172
8306
|
const modeEntry = allEntries.find((e) => e.id === slot);
|
|
8173
8307
|
if (modeEntry) {
|
|
8174
|
-
const
|
|
8175
|
-
const tierSlot = (/* @__PURE__ */ new Set(["brain", "medium", "cheap"])).has(rawTier) ? rawTier : "cheap";
|
|
8308
|
+
const tierSlot = resolveCascadeSlot(modeEntry.pipeline);
|
|
8176
8309
|
deps.writeSessionSlot(deps._OC_SID, tierSlot);
|
|
8177
8310
|
deps.writeSelection("slot_locked", resolvedSlot !== "auto");
|
|
8178
8311
|
deps.writeSelection("active_slot", tierSlot);
|
|
@@ -9505,12 +9638,12 @@ async function probeModel(modelId, auth, providers = null) {
|
|
|
9505
9638
|
}
|
|
9506
9639
|
|
|
9507
9640
|
// src/lib/hooks/footer.js
|
|
9508
|
-
import { readFileSync as readFileSync14, appendFileSync as
|
|
9641
|
+
import { readFileSync as readFileSync14, appendFileSync as appendFileSync4, mkdirSync as mkdirSync10 } from "node:fs";
|
|
9509
9642
|
import { join as join15 } from "node:path";
|
|
9510
9643
|
|
|
9511
9644
|
// src/lib/hooks/chat-transform.js
|
|
9512
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync12, appendFileSync as
|
|
9513
|
-
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";
|
|
9514
9647
|
import { createHash as createHash3 } from "node:crypto";
|
|
9515
9648
|
|
|
9516
9649
|
// src/lib/mode-policy.js
|
|
@@ -10297,14 +10430,14 @@ function observeUserCorrection(text) {
|
|
|
10297
10430
|
}
|
|
10298
10431
|
}
|
|
10299
10432
|
function buildProjectBriefing(directory3) {
|
|
10300
|
-
const label = currentProjectName || (directory3 ?
|
|
10433
|
+
const label = currentProjectName || (directory3 ? basename3(directory3) : "");
|
|
10301
10434
|
if (!label)
|
|
10302
10435
|
return null;
|
|
10303
10436
|
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
10304
10437
|
}
|
|
10305
10438
|
function ensureProjectSkill(dir, fp2) {
|
|
10306
10439
|
const skillsDir = join14(dir, ".opencode", "skills");
|
|
10307
|
-
const projectName =
|
|
10440
|
+
const projectName = basename3(dir);
|
|
10308
10441
|
const skillDir = join14(skillsDir, projectName);
|
|
10309
10442
|
const skillPath = join14(skillDir, "SKILL.md");
|
|
10310
10443
|
if (existsSync14(skillPath)) {
|
|
@@ -10369,7 +10502,7 @@ function ensureProjectSkill(dir, fp2) {
|
|
|
10369
10502
|
content += "\n";
|
|
10370
10503
|
}
|
|
10371
10504
|
try {
|
|
10372
|
-
|
|
10505
|
+
mkdirSync9(skillDir, { recursive: true });
|
|
10373
10506
|
writeFileSync12(skillPath, content, "utf-8");
|
|
10374
10507
|
console.error(`[vibeOS] Project Guard: created .opencode/skills/${projectName}/SKILL.md`);
|
|
10375
10508
|
return { created: true, path: skillPath, skipped: false };
|
|
@@ -10528,7 +10661,7 @@ ${raw}
|
|
|
10528
10661
|
const sessPath = join14(getSessionScratchpadDir(), `${hash}.txt`);
|
|
10529
10662
|
const globalPath = join14(globalDir, `${hash}.txt`);
|
|
10530
10663
|
try {
|
|
10531
|
-
|
|
10664
|
+
mkdirSync9(globalDir, { recursive: true });
|
|
10532
10665
|
ensureSessionScratchpadDirs();
|
|
10533
10666
|
if (!existsSync14(globalPath)) {
|
|
10534
10667
|
writeFileSync12(globalPath, raw);
|
|
@@ -10941,8 +11074,8 @@ var onSystemTransform = async (_input, output) => {
|
|
|
10941
11074
|
fp: currentProjectFingerprint || ""
|
|
10942
11075
|
}) + "\n";
|
|
10943
11076
|
try {
|
|
10944
|
-
|
|
10945
|
-
|
|
11077
|
+
mkdirSync9(calDir, { recursive: true });
|
|
11078
|
+
appendFileSync3(calFile, calRecord);
|
|
10946
11079
|
} catch {
|
|
10947
11080
|
}
|
|
10948
11081
|
if (!oneShot("vibeos_dashboard_instruct")) {
|
|
@@ -11358,8 +11491,8 @@ ${vibeLine}`;
|
|
|
11358
11491
|
tracker.recordOutcome(finalOutcome);
|
|
11359
11492
|
syncOutcomeToApi(finalOutcome);
|
|
11360
11493
|
try {
|
|
11361
|
-
|
|
11362
|
-
|
|
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");
|
|
11363
11496
|
} catch {
|
|
11364
11497
|
}
|
|
11365
11498
|
}
|
|
@@ -11385,8 +11518,8 @@ ${vibeLine} \u2014`);
|
|
|
11385
11518
|
}
|
|
11386
11519
|
|
|
11387
11520
|
// src/lib/hooks/tool-execute.js
|
|
11388
|
-
import { writeFileSync as writeFileSync14, appendFileSync as
|
|
11389
|
-
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";
|
|
11390
11523
|
import { createHash as createHash5 } from "node:crypto";
|
|
11391
11524
|
|
|
11392
11525
|
// src/lib/cost-anomaly.js
|
|
@@ -11450,7 +11583,7 @@ function getCostAnomalyDetector() {
|
|
|
11450
11583
|
init_flow_enforcer();
|
|
11451
11584
|
|
|
11452
11585
|
// src/lib/tdd-enforcer.js
|
|
11453
|
-
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";
|
|
11454
11587
|
import { join as join16, dirname as dirname11 } from "node:path";
|
|
11455
11588
|
import { createHash as createHash4 } from "node:crypto";
|
|
11456
11589
|
|
|
@@ -12553,7 +12686,7 @@ var COOLDOWN_MS = 6e4;
|
|
|
12553
12686
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
12554
12687
|
function _acquireLock(testPath) {
|
|
12555
12688
|
try {
|
|
12556
|
-
|
|
12689
|
+
mkdirSync11(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
12557
12690
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
12558
12691
|
const lockPath = join16(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
12559
12692
|
try {
|
|
@@ -12610,10 +12743,10 @@ function _isInCooldown(testPath) {
|
|
|
12610
12743
|
}
|
|
12611
12744
|
function _recordCooldown(testPath) {
|
|
12612
12745
|
try {
|
|
12613
|
-
|
|
12746
|
+
mkdirSync11(dirname11(ENFORCEMENT_COOLDOWN_FILE2), { recursive: true });
|
|
12614
12747
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
12615
12748
|
const entry = JSON.stringify({ h: hash, ts: Date.now() }) + "\n";
|
|
12616
|
-
|
|
12749
|
+
appendFileSync5(ENFORCEMENT_COOLDOWN_FILE2, entry);
|
|
12617
12750
|
const lines = readFileSync15(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
12618
12751
|
if (lines.length > 500) {
|
|
12619
12752
|
writeFileSync13(ENFORCEMENT_COOLDOWN_FILE2, lines.slice(-200).join("\n") + "\n");
|
|
@@ -12702,7 +12835,7 @@ function enforceTestFile(filePath) {
|
|
|
12702
12835
|
if (!_acquireLock(skeleton.path))
|
|
12703
12836
|
return null;
|
|
12704
12837
|
try {
|
|
12705
|
-
|
|
12838
|
+
mkdirSync11(skeleton.dir, { recursive: true });
|
|
12706
12839
|
writeFileSync13(skeleton.path, skeleton.content);
|
|
12707
12840
|
_enforcementCooldown.add(skeleton.path);
|
|
12708
12841
|
_recordCooldown(skeleton.path);
|
|
@@ -12928,7 +13061,7 @@ function _isProtectedToolPath(pathValue) {
|
|
|
12928
13061
|
}
|
|
12929
13062
|
function _mutateBlockedToolArgs(toolName, sources, blockedPath, outputObj) {
|
|
12930
13063
|
const tLower = String(toolName || "").toLowerCase();
|
|
12931
|
-
const blockedBase =
|
|
13064
|
+
const blockedBase = basename4(blockedPath || "") || "blocked";
|
|
12932
13065
|
for (const src of sources) {
|
|
12933
13066
|
if (!src || typeof src !== "object")
|
|
12934
13067
|
continue;
|
|
@@ -13237,7 +13370,7 @@ ${argsJson}
|
|
|
13237
13370
|
_mutateBlockedToolArgs(t, argSources, checkPath, output);
|
|
13238
13371
|
if (shouldLogWarn(`${t}|protect|${checkPath}`))
|
|
13239
13372
|
console.error(`[vibeOS] [protection] BLOCKED direct ${t} in self-protected directory: ${checkPath}`);
|
|
13240
|
-
pendingUiNote = `[LOCK] Self-modification paused: ${
|
|
13373
|
+
pendingUiNote = `[LOCK] Self-modification paused: ${basename4(checkPath)} is in a protected project tree. Use a manual git workflow.`;
|
|
13241
13374
|
enforcementBlocked = true;
|
|
13242
13375
|
return;
|
|
13243
13376
|
}
|
|
@@ -13275,7 +13408,7 @@ ${argsJson}
|
|
|
13275
13408
|
const tLower = String(t || "").toLowerCase();
|
|
13276
13409
|
if (!compatibilityMode && sel.delegation_enforce && currentTier === "high" && argSources.length > 0) {
|
|
13277
13410
|
const originalPath = argSources.flatMap((src) => [src?.filePath, src?.file_path, src?.path]).find((v) => typeof v === "string" && v.trim()) || "";
|
|
13278
|
-
const
|
|
13411
|
+
const basename6 = originalPath.split("/").pop() || "blocked";
|
|
13279
13412
|
const apiResult = await remoteCall("delegateCheck", [tLower, currentTier, currentModel, _prompt], () => ({
|
|
13280
13413
|
blocked: true,
|
|
13281
13414
|
savings: _estEdit
|
|
@@ -13315,7 +13448,7 @@ ${argsJson}
|
|
|
13315
13448
|
const missed = recordMissedContext7(_estC7);
|
|
13316
13449
|
if (!existsSync16(CONTEXT7_INSTALL_FLAG)) {
|
|
13317
13450
|
try {
|
|
13318
|
-
|
|
13451
|
+
mkdirSync12(dirname12(CONTEXT7_INSTALL_FLAG), { recursive: true });
|
|
13319
13452
|
writeFileSync14(CONTEXT7_INSTALL_FLAG, "");
|
|
13320
13453
|
} catch {
|
|
13321
13454
|
}
|
|
@@ -13501,7 +13634,7 @@ var onToolExecuteAfter = async (input, output) => {
|
|
|
13501
13634
|
const taskPrompt = input?.args?.prompt || input?.args?.description || "";
|
|
13502
13635
|
const quality = scoreTaskQuality(taskOutput, taskPrompt);
|
|
13503
13636
|
try {
|
|
13504
|
-
|
|
13637
|
+
appendFileSync6(SAVINGS_LEDGER_FILE, JSON.stringify({
|
|
13505
13638
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
13506
13639
|
kind: "quality",
|
|
13507
13640
|
score: quality,
|
|
@@ -13667,7 +13800,7 @@ ${pendingUiNote}`;
|
|
|
13667
13800
|
if (guardRe.test(fp3)) {
|
|
13668
13801
|
const guardIcons = { flag: "!", warn: "!!", hint: "_" };
|
|
13669
13802
|
const guardIcon = guardIcons.flag || "!";
|
|
13670
|
-
const fn =
|
|
13803
|
+
const fn = basename4(fp3);
|
|
13671
13804
|
console.error(`[flow-enforcer] ${guardIcon} [guard] ${fn}: protected project doc modified \u2014 verify user intent`);
|
|
13672
13805
|
}
|
|
13673
13806
|
}
|
|
@@ -13975,7 +14108,7 @@ async function _seedModelTiersIfMissing(directory3) {
|
|
|
13975
14108
|
cheap: { oc: cheap, cc: modelToCcAlias(cheap) }
|
|
13976
14109
|
}
|
|
13977
14110
|
};
|
|
13978
|
-
|
|
14111
|
+
mkdirSync13(dirname13(TIERS_FILE3), { recursive: true });
|
|
13979
14112
|
writeFileSync15(TIERS_FILE3, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
13980
14113
|
return true;
|
|
13981
14114
|
}
|
|
@@ -14044,7 +14177,7 @@ function persistMcpPort(port) {
|
|
|
14044
14177
|
tiers.selection.mcp_port = port;
|
|
14045
14178
|
if ("mcp_port" in tiers)
|
|
14046
14179
|
delete tiers.mcp_port;
|
|
14047
|
-
|
|
14180
|
+
mkdirSync13(dirname13(getTiersFile()), { recursive: true });
|
|
14048
14181
|
const tmp = getTiersFile() + ".tmp." + Date.now();
|
|
14049
14182
|
writeFileSync15(tmp, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
14050
14183
|
renameSync6(tmp, getTiersFile());
|
|
@@ -14135,7 +14268,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14135
14268
|
};
|
|
14136
14269
|
const saveProjectStateStable = (state) => {
|
|
14137
14270
|
try {
|
|
14138
|
-
|
|
14271
|
+
mkdirSync13(dirname13(hookProjectStateFile), { recursive: true });
|
|
14139
14272
|
const tmp = hookProjectStateFile + ".tmp";
|
|
14140
14273
|
writeFileSync15(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
14141
14274
|
renameSync6(tmp, hookProjectStateFile);
|
|
@@ -14154,7 +14287,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14154
14287
|
};
|
|
14155
14288
|
const saveReportsIndexStable = (idx) => {
|
|
14156
14289
|
try {
|
|
14157
|
-
|
|
14290
|
+
mkdirSync13(hookReportsDir, { recursive: true });
|
|
14158
14291
|
writeFileSync15(hookReportsIndex, JSON.stringify(idx, null, 2) + "\n");
|
|
14159
14292
|
} catch {
|
|
14160
14293
|
}
|
|
@@ -14164,9 +14297,9 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14164
14297
|
if (!existsSync18(path))
|
|
14165
14298
|
return null;
|
|
14166
14299
|
const bkDir = join18(hookVibeHome, ".backups");
|
|
14167
|
-
|
|
14168
|
-
const bk = join18(bkDir, `${
|
|
14169
|
-
|
|
14300
|
+
mkdirSync13(bkDir, { recursive: true });
|
|
14301
|
+
const bk = join18(bkDir, `${basename5(path)}.${label}.${Date.now()}.bak`);
|
|
14302
|
+
copyFileSync2(path, bk);
|
|
14170
14303
|
return bk;
|
|
14171
14304
|
} catch {
|
|
14172
14305
|
return null;
|
|
@@ -14204,7 +14337,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14204
14337
|
writeFileSync: writeFileSync15,
|
|
14205
14338
|
existsSync: existsSync18,
|
|
14206
14339
|
renameSync: renameSync6,
|
|
14207
|
-
mkdirSync:
|
|
14340
|
+
mkdirSync: mkdirSync13,
|
|
14208
14341
|
get TIERS_FILE() {
|
|
14209
14342
|
return hookTiersFile;
|
|
14210
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",
|