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.
Files changed (2) hide show
  1. package/dist/vibeOS.js +280 -153
  2. 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 mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "node:fs";
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
- mkdirSync6(dir, { recursive: true });
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 mkdirSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync7 } from "node:fs";
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
- mkdirSync7(dirname7(MODEL_PATH), { recursive: true });
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 mkdirSync14, copyFileSync as copyFileSync5, renameSync as renameSync6 } from "node:fs";
1108
- import { join as join18, dirname as dirname13, basename as basename8 } from "node:path";
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, appendFileSync as appendFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync5, statSync as statSync5, copyFileSync as copyFileSync3, 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, basename as basename4, resolve } from "node:path";
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 appendFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync4, statSync as statSync4, readdirSync, openSync, readSync, closeSync, rmSync as rmSync2, copyFileSync as copyFileSync2, renameSync as renameSync3 } from "node:fs";
2364
- import { join as join4, dirname as dirname4, basename as basename3 } from "node:path";
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, appendFileSync as appendFileSync2, existsSync as existsSync4, mkdirSync as mkdirSync3, statSync as statSync3, copyFileSync, renameSync as renameSync2 } from "node:fs";
2372
- import { join as join3, basename } from "node:path";
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 as basename2 } from "node:path";
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 basename2(p) || "unknown";
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 _handleStateCorruption2(path) {
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
- mkdirSync4(backupDir, { recursive: true });
3427
- const backupPath = join4(backupDir, basename3(path) + ".corrupted." + Date.now());
3445
+ mkdirSync3(backupDir, { recursive: true });
3446
+ const backupPath = join4(backupDir, basename2(path) + ".corrupted." + Date.now());
3428
3447
  try {
3429
- copyFileSync2(path, backupPath);
3448
+ copyFileSync(path, backupPath);
3430
3449
  } catch {
3431
3450
  }
3432
3451
  const logPath = join4(VIBEOS_HOME, ".state-corruption-log.jsonl");
3433
3452
  try {
3434
- appendFileSync3(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
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
- mkdirSync4(FILE_LOCK_DIR, { recursive: true });
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
- _handleStateCorruption2(filePath);
3548
+ _handleStateCorruption(filePath);
3528
3549
  return {};
3529
3550
  }
3530
3551
  return safeJsonParse3(readFileSync4(filePath, "utf-8"));
3531
3552
  } catch {
3532
- _handleStateCorruption2(filePath);
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
- mkdirSync4(dirname4(delegationStateFile), { recursive: true });
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
- _handleStateCorruption2(delegationStateFile);
3604
+ _handleStateCorruption(delegationStateFile);
3584
3605
  return {};
3585
3606
  }
3586
3607
  return safeJsonParse3(readFileSync4(delegationStateFile, "utf-8"));
3587
3608
  } catch {
3588
- _handleStateCorruption2(delegationStateFile);
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
- _handleStateCorruption2(globalLearningFile);
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
- _handleStateCorruption2(globalLearningFile);
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
- mkdirSync4(dirname4(globalLearningFile), { recursive: true });
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
- _handleStateCorruption2(blackboxFile);
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
- _handleStateCorruption2(blackboxFile);
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
- mkdirSync4(dirname4(blackboxFile), { recursive: true });
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
- mkdirSync4(getSessionScratchpadDir(), { recursive: true });
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
- appendFileSync3(SAVINGS_LEDGER_FILE, joined);
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
- mkdirSync4(dirname4(globalIndex), { recursive: true });
3929
- mkdirSync4(dirname4(sessionIndex), { recursive: true });
3930
- appendFileSync3(globalIndex, entry);
3931
- appendFileSync3(sessionIndex, entry);
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 loadActiveJobs() {
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
- if (!raw || typeof raw !== "object")
4195
- return {};
4196
- return raw;
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
- _handleStateCorruption2(ACTIVE_JOBS_FILE);
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
- const jobs = loadActiveJobs();
4216
- jobs[fp2] = job;
4217
- mkdirSync4(dirname4(ACTIVE_JOBS_FILE), { recursive: true });
4218
- const tmp = ACTIVE_JOBS_FILE + ".tmp";
4219
- writeFileSync4(tmp, JSON.stringify(jobs, null, 2));
4220
- renameSync3(tmp, ACTIVE_JOBS_FILE);
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
- mkdirSync4(dirname4(projectStateFile), { recursive: true });
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
- mkdirSync4(dirname4(TODOS_FILE), { recursive: true });
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 (_ledgerTotalsCache.mtime === st.mtimeMs && _ledgerTotalsCache.size === st.size) {
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 && st.size >= _ledgerTotalsCache.size && _ledgerTotalsCache.mtime > 0;
4694
+ let incremental = _ledgerTotalsCache.size > 0 && currentStat.size >= _ledgerTotalsCache.size && _ledgerTotalsCache.mtime > 0;
4552
4695
  if (incremental) {
4553
- const deltaSize = st.size - _ledgerTotalsCache.size;
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: st.mtimeMs,
4580
- size: st.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: st.mtimeMs, size: st.size, delegation, cache, context7, entries };
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
- mkdirSync4(dirname4(cpPath), { recursive: true });
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
- mkdirSync5(join5(getVibeOSHome4(), ".vibeOS-locks"), { recursive: true });
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
- _handleStateCorruption3(PRICING_CACHE_FILE2);
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
- _handleStateCorruption3(PRICING_CACHE_FILE2);
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
- mkdirSync5(dirname5(PRICING_CACHE_FILE2), { recursive: true });
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
- _handleStateCorruption3(tiersFile);
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
- _handleStateCorruption3(join5(home, "model-tiers.json"));
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
- _handleStateCorruption3(TIERS_FILE3);
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
- _handleStateCorruption3(TIERS_FILE3);
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
- _handleStateCorruption3(TIERS_FILE3);
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 mkdirSync8, renameSync as renameSync5 } from "node:fs";
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 mkdirSync9, statSync as statSync6, copyFileSync as copyFileSync4, rmSync as rmSync4 } from "node:fs";
7366
- import { join as join9, basename as basename5 } from "node:path";
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
- _handleStateCorruption4(filePath);
7516
+ _handleStateCorruption(filePath);
7397
7517
  return {};
7398
7518
  }
7399
7519
  return safeJsonParse3(readFileSync10(filePath, "utf-8"));
7400
7520
  } catch {
7401
- _handleStateCorruption4(filePath);
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
- mkdirSync9(reportsDir, { recursive: true });
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
- mkdirSync9(reportsDir, { recursive: true });
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 rawTier = modeEntry.pipeline[0] || "cheap";
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 appendFileSync6, mkdirSync as mkdirSync11 } from "node:fs";
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 appendFileSync5, existsSync as existsSync14, mkdirSync as mkdirSync10, rmSync as rmSync5, readdirSync as readdirSync3, statSync as statSync7 } from "node:fs";
9519
- import { join as join14, dirname as dirname10, basename as basename6 } from "node:path";
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 ? basename6(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 = basename6(dir);
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
- mkdirSync10(skillDir, { recursive: true });
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
- mkdirSync10(globalDir, { recursive: true });
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
- mkdirSync10(calDir, { recursive: true });
10951
- appendFileSync5(calFile, calRecord);
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
- mkdirSync11(getVibeOSHome10(), { recursive: true });
11368
- appendFileSync6(join15(getVibeOSHome10(), "calibration-data.jsonl"), JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), event: "outcome", sid: getSessionId(), outcome: finalOutcome }) + "\n");
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 appendFileSync8, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "node:fs";
11395
- import { join as join17, dirname as dirname12, basename as basename7 } from "node:path";
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 appendFileSync7, existsSync as existsSync15, mkdirSync as mkdirSync12, statSync as statSync8, readdirSync as readdirSync4, rmSync as rmSync6, openSync as openSync3 } from "node:fs";
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
- mkdirSync12(ENFORCEMENT_LOCK_DIR, { recursive: true });
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
- mkdirSync12(dirname11(ENFORCEMENT_COOLDOWN_FILE2), { recursive: true });
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
- appendFileSync7(ENFORCEMENT_COOLDOWN_FILE2, entry);
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
- mkdirSync12(skeleton.dir, { recursive: true });
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 = basename7(blockedPath || "") || "blocked";
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: ${basename7(checkPath)} is in a protected project tree. Use a manual git workflow.`;
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 basename9 = originalPath.split("/").pop() || "blocked";
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
- mkdirSync13(dirname12(CONTEXT7_INSTALL_FLAG), { recursive: true });
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
- appendFileSync8(SAVINGS_LEDGER_FILE, JSON.stringify({
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 = basename7(fp3);
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
- mkdirSync14(dirname13(TIERS_FILE3), { recursive: true });
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
- mkdirSync14(dirname13(getTiersFile()), { recursive: true });
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
- mkdirSync14(dirname13(hookProjectStateFile), { recursive: true });
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
- mkdirSync14(hookReportsDir, { recursive: true });
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
- mkdirSync14(bkDir, { recursive: true });
14174
- const bk = join18(bkDir, `${basename8(path)}.${label}.${Date.now()}.bak`);
14175
- copyFileSync5(path, bk);
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: mkdirSync14,
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.16",
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",