vibeostheog 0.24.17 → 0.24.19
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 +10 -0
- package/dist/vibeOS.js +224 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 0.24.19
|
|
2
|
+
- test: cover cold start maintenance user flow (#144)
|
|
3
|
+
Prune stale active jobs and stabilize report tests
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## 0.24.18
|
|
7
|
+
- fix: keep Return codename through 0.24 patch releases (#143)
|
|
8
|
+
- fix: preserve live metrics context in reports (#137)
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
## 0.24.16
|
|
2
12
|
- fix: serialize model tiers writes
|
|
3
13
|
- test: add concurrent tiers write regression
|
package/dist/vibeOS.js
CHANGED
|
@@ -3279,9 +3279,9 @@ var MAX_SESSION_SCRATCHPAD_FILES = 200;
|
|
|
3279
3279
|
var MAX_SESSION_SCRATCHPAD_BYTES = 2 * 1024 * 1024;
|
|
3280
3280
|
var CORRUPTION_BACKUP_MAX = 5;
|
|
3281
3281
|
var CORRUPTION_BACKUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
3282
|
-
var LEDGER_ROTATE_MAX_BYTES =
|
|
3283
|
-
var LEDGER_ROTATE_MAX_LINES =
|
|
3284
|
-
var LEDGER_ROTATE_MAX_AGE_MS =
|
|
3282
|
+
var LEDGER_ROTATE_MAX_BYTES = 256 * 1024;
|
|
3283
|
+
var LEDGER_ROTATE_MAX_LINES = 1e4;
|
|
3284
|
+
var LEDGER_ROTATE_MAX_AGE_MS = 48 * 60 * 60 * 1e3;
|
|
3285
3285
|
var ACTIVE_JOBS_STALE_MS = 72 * 60 * 60 * 1e3;
|
|
3286
3286
|
var MAX_PTR_CANDIDATES = 50;
|
|
3287
3287
|
var SUMMARY_HEAD_TRUNCATE = 500;
|
|
@@ -3440,6 +3440,19 @@ function _pruneCorruptionBackups(backupDir) {
|
|
|
3440
3440
|
} catch {
|
|
3441
3441
|
}
|
|
3442
3442
|
}
|
|
3443
|
+
var _startupMaintenanceHome = "";
|
|
3444
|
+
function runStartupMaintenanceOnce() {
|
|
3445
|
+
try {
|
|
3446
|
+
const home = getVibeOSHome3();
|
|
3447
|
+
if (!home || home === _startupMaintenanceHome)
|
|
3448
|
+
return;
|
|
3449
|
+
_startupMaintenanceHome = home;
|
|
3450
|
+
_pruneCorruptionBackups(join4(home, ".backups"));
|
|
3451
|
+
loadActiveJobs();
|
|
3452
|
+
_compactSavingsLedgerIfNeeded();
|
|
3453
|
+
} catch {
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3443
3456
|
function _handleStateCorruption(path) {
|
|
3444
3457
|
const backupDir = join4(VIBEOS_HOME, ".backups");
|
|
3445
3458
|
mkdirSync3(backupDir, { recursive: true });
|
|
@@ -3724,7 +3737,42 @@ function loadBlackboxState() {
|
|
|
3724
3737
|
_handleStateCorruption(blackboxFile);
|
|
3725
3738
|
return { enabled: false, sessions: {} };
|
|
3726
3739
|
}
|
|
3727
|
-
|
|
3740
|
+
const raw = safeJsonParse3(readFileSync4(blackboxFile, "utf-8")) || { enabled: false, sessions: {} };
|
|
3741
|
+
if (!raw.sessions || typeof raw.sessions !== "object")
|
|
3742
|
+
raw.sessions = {};
|
|
3743
|
+
const now = Date.now();
|
|
3744
|
+
let changed = false;
|
|
3745
|
+
for (const [sid, session] of Object.entries(raw.sessions)) {
|
|
3746
|
+
if (!session || typeof session !== "object")
|
|
3747
|
+
continue;
|
|
3748
|
+
const next = { ...session };
|
|
3749
|
+
const createdAtRaw = typeof next.createdAt === "string" ? next.createdAt : "";
|
|
3750
|
+
const updatedAtRaw = typeof next.updatedAt === "string" ? next.updatedAt : "";
|
|
3751
|
+
const startedRaw = typeof next.started === "string" ? next.started : "";
|
|
3752
|
+
const sessionStartedRaw = typeof next.session_started_at === "string" ? next.session_started_at : "";
|
|
3753
|
+
const anchorRaw = [createdAtRaw, updatedAtRaw, startedRaw, sessionStartedRaw].find((v) => v && !Number.isNaN(Date.parse(v)));
|
|
3754
|
+
const anchorMs = anchorRaw ? Date.parse(anchorRaw) : NaN;
|
|
3755
|
+
if (!Number.isFinite(Date.parse(createdAtRaw))) {
|
|
3756
|
+
next.createdAt = Number.isFinite(anchorMs) ? new Date(anchorMs).toISOString() : new Date(now).toISOString();
|
|
3757
|
+
changed = true;
|
|
3758
|
+
}
|
|
3759
|
+
if (!Number.isFinite(Date.parse(updatedAtRaw))) {
|
|
3760
|
+
next.updatedAt = next.createdAt || new Date(now).toISOString();
|
|
3761
|
+
changed = true;
|
|
3762
|
+
}
|
|
3763
|
+
if (typeof next.sessionId !== "string" || !next.sessionId.trim()) {
|
|
3764
|
+
next.sessionId = String(sid || "");
|
|
3765
|
+
changed = true;
|
|
3766
|
+
}
|
|
3767
|
+
raw.sessions[sid] = next;
|
|
3768
|
+
}
|
|
3769
|
+
if (changed) {
|
|
3770
|
+
try {
|
|
3771
|
+
saveBlackboxState(raw);
|
|
3772
|
+
} catch {
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
return raw;
|
|
3728
3776
|
} catch {
|
|
3729
3777
|
_handleStateCorruption(blackboxFile);
|
|
3730
3778
|
return { enabled: false, sessions: {} };
|
|
@@ -3733,9 +3781,32 @@ function loadBlackboxState() {
|
|
|
3733
3781
|
function saveBlackboxState(state) {
|
|
3734
3782
|
const blackboxFile = join4(getVibeOSHome3(), "blackbox-state.json");
|
|
3735
3783
|
try {
|
|
3784
|
+
const next = state && typeof state === "object" ? state : { enabled: true, sessions: {} };
|
|
3785
|
+
next.sessions ??= {};
|
|
3786
|
+
const now = Date.now();
|
|
3787
|
+
for (const [sid, session] of Object.entries(next.sessions)) {
|
|
3788
|
+
if (!session || typeof session !== "object")
|
|
3789
|
+
continue;
|
|
3790
|
+
const record = session;
|
|
3791
|
+
const createdAtRaw = typeof record.createdAt === "string" ? record.createdAt : "";
|
|
3792
|
+
const updatedAtRaw = typeof record.updatedAt === "string" ? record.updatedAt : "";
|
|
3793
|
+
const startedRaw = typeof record.started === "string" ? record.started : "";
|
|
3794
|
+
const sessionStartedRaw = typeof record.session_started_at === "string" ? record.session_started_at : "";
|
|
3795
|
+
const anchorRaw = [createdAtRaw, updatedAtRaw, startedRaw, sessionStartedRaw].find((v) => v && !Number.isNaN(Date.parse(v)));
|
|
3796
|
+
const anchorMs = anchorRaw ? Date.parse(anchorRaw) : NaN;
|
|
3797
|
+
if (!Number.isFinite(Date.parse(createdAtRaw))) {
|
|
3798
|
+
record.createdAt = Number.isFinite(anchorMs) ? new Date(anchorMs).toISOString() : new Date(now).toISOString();
|
|
3799
|
+
}
|
|
3800
|
+
if (!Number.isFinite(Date.parse(updatedAtRaw))) {
|
|
3801
|
+
record.updatedAt = record.createdAt || new Date(now).toISOString();
|
|
3802
|
+
}
|
|
3803
|
+
if (typeof record.sessionId !== "string" || !record.sessionId.trim()) {
|
|
3804
|
+
record.sessionId = String(sid || "");
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3736
3807
|
mkdirSync3(dirname4(blackboxFile), { recursive: true });
|
|
3737
3808
|
const tmp = blackboxFile + ".tmp";
|
|
3738
|
-
writeFileSync4(tmp, JSON.stringify(
|
|
3809
|
+
writeFileSync4(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
3739
3810
|
renameSync3(tmp, blackboxFile);
|
|
3740
3811
|
} catch (err) {
|
|
3741
3812
|
console.error(`[vibeOS] saveBlackboxState failed: ${err.message}`);
|
|
@@ -4266,7 +4337,7 @@ function loadActiveJobs() {
|
|
|
4266
4337
|
const now = Date.now();
|
|
4267
4338
|
for (const [key, value] of Object.entries(raw || {})) {
|
|
4268
4339
|
const norm = _normalizeActiveJobRecord(value, now, true);
|
|
4269
|
-
if (!norm.record) {
|
|
4340
|
+
if (!norm.record || norm.stale && norm.record.status === "completed" && norm.record.completedAt) {
|
|
4270
4341
|
changed = true;
|
|
4271
4342
|
continue;
|
|
4272
4343
|
}
|
|
@@ -4347,11 +4418,49 @@ function ensureProjectBucket(state, fp2) {
|
|
|
4347
4418
|
researchChains: 0,
|
|
4348
4419
|
context7Bypasses: 0,
|
|
4349
4420
|
commonTopics: [],
|
|
4421
|
+
sessions: [],
|
|
4422
|
+
reports: [],
|
|
4423
|
+
updatedAt: null,
|
|
4424
|
+
lastSeen: null,
|
|
4350
4425
|
techStack: detectTechStack(process.cwd())
|
|
4351
4426
|
};
|
|
4352
4427
|
}
|
|
4353
4428
|
return state.project_hashes[fp2];
|
|
4354
4429
|
}
|
|
4430
|
+
function touchProjectBucket(state, fp2, meta = {}) {
|
|
4431
|
+
if (!fp2 || fp2 === "unknown")
|
|
4432
|
+
return null;
|
|
4433
|
+
const bucket = ensureProjectBucket(state, fp2);
|
|
4434
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4435
|
+
bucket.updatedAt = now;
|
|
4436
|
+
bucket.lastSeen = now;
|
|
4437
|
+
if (typeof meta.projectName === "string" && meta.projectName.trim()) {
|
|
4438
|
+
bucket.projectName = meta.projectName.trim();
|
|
4439
|
+
}
|
|
4440
|
+
if (typeof meta.sessionId === "string" && meta.sessionId.trim()) {
|
|
4441
|
+
bucket.sessions ??= [];
|
|
4442
|
+
if (!bucket.sessions.includes(meta.sessionId)) {
|
|
4443
|
+
bucket.sessions.push(meta.sessionId);
|
|
4444
|
+
bucket.sessions = bucket.sessions.slice(-30);
|
|
4445
|
+
}
|
|
4446
|
+
bucket.totalSessions = Math.max(Number(bucket.totalSessions || 0), bucket.sessions.length);
|
|
4447
|
+
}
|
|
4448
|
+
if (typeof meta.reportId === "string" && meta.reportId.trim()) {
|
|
4449
|
+
bucket.reports ??= [];
|
|
4450
|
+
if (!bucket.reports.includes(meta.reportId)) {
|
|
4451
|
+
bucket.reports.push(meta.reportId);
|
|
4452
|
+
bucket.reports = bucket.reports.slice(-50);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
if (typeof meta.topic === "string" && meta.topic.trim()) {
|
|
4456
|
+
bucket.commonTopics ??= [];
|
|
4457
|
+
if (!bucket.commonTopics.includes(meta.topic)) {
|
|
4458
|
+
bucket.commonTopics.push(meta.topic);
|
|
4459
|
+
bucket.commonTopics = bucket.commonTopics.slice(-20);
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
return bucket;
|
|
4463
|
+
}
|
|
4355
4464
|
function detectTechStack(dir) {
|
|
4356
4465
|
const stacks = [];
|
|
4357
4466
|
try {
|
|
@@ -4482,6 +4591,18 @@ function recordCacheSaving(tool2, saveEst, meta = {}) {
|
|
|
4482
4591
|
s.sessions[sid2].cache_savings_usd = roundUsd(Number(s.sessions[sid2].cache_savings_usd || 0) + delta);
|
|
4483
4592
|
s.lifetime.cache_savings_usd = roundUsd(Number(s.lifetime.cache_savings_usd || 0) + delta);
|
|
4484
4593
|
}
|
|
4594
|
+
try {
|
|
4595
|
+
if (currentProjectFingerprint) {
|
|
4596
|
+
const pstate = loadProjectState();
|
|
4597
|
+
touchProjectBucket(pstate, currentProjectFingerprint, {
|
|
4598
|
+
sessionId: sid2,
|
|
4599
|
+
projectName: currentProjectName || "",
|
|
4600
|
+
topic: meta?.hash ? String(meta.hash).slice(0, 16) : "cache"
|
|
4601
|
+
});
|
|
4602
|
+
saveProjectState(pstate);
|
|
4603
|
+
}
|
|
4604
|
+
} catch {
|
|
4605
|
+
}
|
|
4485
4606
|
_pruneOldSessions(s);
|
|
4486
4607
|
return s;
|
|
4487
4608
|
});
|
|
@@ -4512,6 +4633,20 @@ function recordMissedContext7(saveEst) {
|
|
|
4512
4633
|
const sid = _OC_SID;
|
|
4513
4634
|
s.sessions[sid] ??= { total_savings_usd: 0, cache_savings_usd: 0, project_name: "", warns: [], cache_hits: [], seenWarnKeys: {} };
|
|
4514
4635
|
s.sessions[sid].context7_missed_usd = Math.round(((s.sessions[sid].context7_missed_usd || 0) + saveEst) * 100) / 100;
|
|
4636
|
+
try {
|
|
4637
|
+
if (currentProjectFingerprint) {
|
|
4638
|
+
const pstate = loadProjectState();
|
|
4639
|
+
const bucket = touchProjectBucket(pstate, currentProjectFingerprint, {
|
|
4640
|
+
sessionId: sid,
|
|
4641
|
+
projectName: currentProjectName || "",
|
|
4642
|
+
topic: "context7"
|
|
4643
|
+
});
|
|
4644
|
+
if (bucket)
|
|
4645
|
+
bucket.context7Bypasses = (bucket.context7Bypasses || 0) + 1;
|
|
4646
|
+
saveProjectState(pstate);
|
|
4647
|
+
}
|
|
4648
|
+
} catch {
|
|
4649
|
+
}
|
|
4515
4650
|
return s;
|
|
4516
4651
|
});
|
|
4517
4652
|
try {
|
|
@@ -4530,16 +4665,6 @@ function recordMissedContext7(saveEst) {
|
|
|
4530
4665
|
_ledgerBufferTimer = setTimeout(_flushLedgerBuffer, LEDGER_BUFFER_FLUSH_MS);
|
|
4531
4666
|
} catch {
|
|
4532
4667
|
}
|
|
4533
|
-
try {
|
|
4534
|
-
if (currentProjectFingerprint) {
|
|
4535
|
-
const pstate = loadProjectState();
|
|
4536
|
-
const bucket = ensureProjectBucket(pstate, currentProjectFingerprint);
|
|
4537
|
-
bucket.context7Bypasses = (bucket.context7Bypasses || 0) + 1;
|
|
4538
|
-
bucket.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
|
|
4539
|
-
saveProjectState(pstate);
|
|
4540
|
-
}
|
|
4541
|
-
} catch {
|
|
4542
|
-
}
|
|
4543
4668
|
try {
|
|
4544
4669
|
updateGlobalLearning((gl) => {
|
|
4545
4670
|
gl.context7_bypasses = Number(gl.context7_bypasses || 0) + 1;
|
|
@@ -7628,13 +7753,22 @@ function _parseMetrics(v) {
|
|
|
7628
7753
|
function saveReport({ type = "manual", summary = "", findings = null, metrics = null, narrative = "", tags = [], fingerprint = null, status = "pending", task_description = "", outcome_verified = false } = {}) {
|
|
7629
7754
|
const parsedFindings = _parseFindings(findings);
|
|
7630
7755
|
const parsedMetrics = _parseMetrics(metrics);
|
|
7756
|
+
const metricsObject = parsedMetrics && typeof parsedMetrics === "object" && !Array.isArray(parsedMetrics) ? parsedMetrics : {};
|
|
7757
|
+
const metricsSessionId = typeof metricsObject.sessionId === "string" && metricsObject.sessionId.trim() ? metricsObject.sessionId.trim() : "";
|
|
7758
|
+
const metricsProjectName = typeof metricsObject.projectName === "string" && metricsObject.projectName.trim() ? metricsObject.projectName.trim() : "";
|
|
7759
|
+
const metricsProjectFingerprint = typeof metricsObject.projectFingerprint === "string" && metricsObject.projectFingerprint.trim() ? metricsObject.projectFingerprint.trim() : "";
|
|
7631
7760
|
if (_wouldBeDuplicate(type, summary))
|
|
7632
7761
|
return null;
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7762
|
+
if (!currentProjectFingerprint2 && metricsProjectFingerprint)
|
|
7763
|
+
currentProjectFingerprint2 = metricsProjectFingerprint;
|
|
7764
|
+
if (!currentProjectName2 && metricsProjectName)
|
|
7765
|
+
currentProjectName2 = metricsProjectName;
|
|
7766
|
+
if (!currentSessionId2 && metricsSessionId)
|
|
7767
|
+
currentSessionId2 = metricsSessionId;
|
|
7768
|
+
const liveSessionId = getCurrentSessionId() || getOcSessionId() || "";
|
|
7769
|
+
const fp2 = fingerprint || metricsProjectFingerprint || currentProjectFingerprint || currentProjectFingerprint2 || "unknown";
|
|
7770
|
+
const projectName = metricsProjectName || currentProjectName || currentProjectName2 || "unknown";
|
|
7771
|
+
const sessionId = metricsSessionId || liveSessionId || currentSessionId2 || "unknown";
|
|
7638
7772
|
const id2 = generateReportId(type, fp2);
|
|
7639
7773
|
const report = {
|
|
7640
7774
|
meta: { id: id2, project: projectName, fingerprint: fp2, type, created: (/* @__PURE__ */ new Date()).toISOString(), sessionId },
|
|
@@ -7658,6 +7792,19 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
7658
7792
|
idx.reports.push({ id: id2, type, project: report.meta.project, fingerprint: fp2, created: report.meta.created, summary: _sum });
|
|
7659
7793
|
writeFileSync9(reportsIndexPath, JSON.stringify(idx, null, 2) + "\n");
|
|
7660
7794
|
});
|
|
7795
|
+
try {
|
|
7796
|
+
if (fp2 && fp2 !== "unknown") {
|
|
7797
|
+
const pstate = loadProjectState();
|
|
7798
|
+
touchProjectBucket(pstate, fp2, {
|
|
7799
|
+
sessionId,
|
|
7800
|
+
projectName: projectName || "",
|
|
7801
|
+
reportId: id2,
|
|
7802
|
+
topic: type || "report"
|
|
7803
|
+
});
|
|
7804
|
+
saveProjectState(pstate);
|
|
7805
|
+
}
|
|
7806
|
+
} catch {
|
|
7807
|
+
}
|
|
7661
7808
|
} catch (err) {
|
|
7662
7809
|
console.error(`[vibeOS] report/index write failed: ${err.message}`);
|
|
7663
7810
|
return null;
|
|
@@ -9957,6 +10104,11 @@ function noteProjectPattern(kind, key, summary, meta = {}) {
|
|
|
9957
10104
|
if (meta.path)
|
|
9958
10105
|
row.path = meta.path;
|
|
9959
10106
|
target[key] = row;
|
|
10107
|
+
touchProjectBucket(pstate, currentProjectFingerprint, {
|
|
10108
|
+
sessionId: getCurrentSessionId(),
|
|
10109
|
+
projectName: currentProjectName || "",
|
|
10110
|
+
topic: key
|
|
10111
|
+
});
|
|
9960
10112
|
const entries = Object.entries(target);
|
|
9961
10113
|
if (entries.length > 50) {
|
|
9962
10114
|
entries.sort((a, b) => String(b[1]?.lastSeen || "").localeCompare(String(a[1]?.lastSeen || "")));
|
|
@@ -10190,6 +10342,9 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
10190
10342
|
s.last_updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
10191
10343
|
_pruneOldSessions(s);
|
|
10192
10344
|
});
|
|
10345
|
+
const projectFingerprint2 = typeof meta?.projectFingerprint === "string" && meta.projectFingerprint.trim() ? meta.projectFingerprint.trim() : currentProjectFingerprint || "";
|
|
10346
|
+
const projectName = typeof meta?.projectName === "string" && meta.projectName.trim() ? meta.projectName.trim() : currentProjectName || "";
|
|
10347
|
+
const sessionId = typeof meta?.sessionId === "string" && meta.sessionId.trim() ? meta.sessionId.trim() : getCurrentSessionId() || _OC_SID;
|
|
10193
10348
|
const entry = JSON.stringify({
|
|
10194
10349
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10195
10350
|
usd: saveEst,
|
|
@@ -10197,9 +10352,21 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
10197
10352
|
tool: tool2,
|
|
10198
10353
|
reason,
|
|
10199
10354
|
saveEst,
|
|
10200
|
-
fgp:
|
|
10355
|
+
fgp: projectFingerprint2
|
|
10201
10356
|
});
|
|
10202
10357
|
_ledgerBuffer.push(entry);
|
|
10358
|
+
try {
|
|
10359
|
+
if (projectFingerprint2) {
|
|
10360
|
+
const pstate = loadProjectState();
|
|
10361
|
+
touchProjectBucket(pstate, projectFingerprint2, {
|
|
10362
|
+
sessionId,
|
|
10363
|
+
projectName,
|
|
10364
|
+
topic: tool2 || reason || "saving"
|
|
10365
|
+
});
|
|
10366
|
+
saveProjectState(pstate);
|
|
10367
|
+
}
|
|
10368
|
+
} catch {
|
|
10369
|
+
}
|
|
10203
10370
|
if (_ledgerBuffer.length >= LEDGER_BUFFER_MAX)
|
|
10204
10371
|
_flushLedgerBuffer();
|
|
10205
10372
|
else if (!_ledgerBufferTimer)
|
|
@@ -10370,6 +10537,17 @@ function ensureProjectContext(hookDirectory) {
|
|
|
10370
10537
|
if (name && name !== currentProjectName)
|
|
10371
10538
|
setCurrentProjectName(name);
|
|
10372
10539
|
}
|
|
10540
|
+
try {
|
|
10541
|
+
if (resolved) {
|
|
10542
|
+
const pstate = loadProjectState();
|
|
10543
|
+
touchProjectBucket(pstate, resolved, {
|
|
10544
|
+
sessionId: _OC_SID3,
|
|
10545
|
+
projectName: currentProjectName || (hookDirectory ? hookDirectory.split("/").filter(Boolean).pop() || "" : "")
|
|
10546
|
+
});
|
|
10547
|
+
saveProjectState(pstate);
|
|
10548
|
+
}
|
|
10549
|
+
} catch {
|
|
10550
|
+
}
|
|
10373
10551
|
return resolved;
|
|
10374
10552
|
}
|
|
10375
10553
|
var latestUserIntent = null;
|
|
@@ -13393,7 +13571,12 @@ ${argsJson}
|
|
|
13393
13571
|
costDetector.record(modelCost);
|
|
13394
13572
|
}
|
|
13395
13573
|
if (_credit < 40 && !compatibilityMode) {
|
|
13396
|
-
const total = recordSaving(t, "credit<40% high-tier", _estOpus, {
|
|
13574
|
+
const total = recordSaving(t, "credit<40% high-tier", _estOpus, {
|
|
13575
|
+
firstWord: _firstWord,
|
|
13576
|
+
projectFingerprint: currentProjectFingerprint,
|
|
13577
|
+
projectName: currentProjectName || "",
|
|
13578
|
+
sessionId: getCurrentSessionId()
|
|
13579
|
+
});
|
|
13397
13580
|
const msg = `[vibeOS] Quick win: ${resolveTierIcon("cheap")} cheap lane open \xB7 switch to ${resolveTierIcon("medium")} medium to save about ~$${_estOpus.toFixed(3)}/turn.`;
|
|
13398
13581
|
if (shouldLogWarn(`${t}|credit|${_tierWord}`) && process.env.VIBEOS_DEBUG_DELEGATION === "1") {
|
|
13399
13582
|
console.error(`[vibeOS] [delegation] ${msg}`);
|
|
@@ -13416,7 +13599,12 @@ ${argsJson}
|
|
|
13416
13599
|
const isBlocked = apiResult?.blocked !== false;
|
|
13417
13600
|
const savings = apiResult?.savings ?? _estEdit;
|
|
13418
13601
|
if (isBlocked) {
|
|
13419
|
-
const total2 = recordSaving(t, "delegation enforced", savings, {
|
|
13602
|
+
const total2 = recordSaving(t, "delegation enforced", savings, {
|
|
13603
|
+
firstWord: _firstWord,
|
|
13604
|
+
projectFingerprint: currentProjectFingerprint,
|
|
13605
|
+
projectName: currentProjectName || "",
|
|
13606
|
+
sessionId: getCurrentSessionId()
|
|
13607
|
+
});
|
|
13420
13608
|
pendingUiNote = `[delegation] This is a good candidate for a Task subagent \u2014 ${resolveTierIcon("brain")} brain handles orchestration, let cheaper tiers do the write/edit. Switch to ${resolveTierIcon("medium")} medium with \`trinity medium\` if you'd rather do it directly.`;
|
|
13421
13609
|
enforcementBlocked = true;
|
|
13422
13610
|
if (shouldLogWarn(`${t}|enforced|${_tierWord}`))
|
|
@@ -13424,7 +13612,12 @@ ${argsJson}
|
|
|
13424
13612
|
return;
|
|
13425
13613
|
}
|
|
13426
13614
|
}
|
|
13427
|
-
const total = recordSaving(t, "direct edit", _estEdit, {
|
|
13615
|
+
const total = recordSaving(t, "direct edit", _estEdit, {
|
|
13616
|
+
firstWord: _firstWord,
|
|
13617
|
+
projectFingerprint: currentProjectFingerprint,
|
|
13618
|
+
projectName: currentProjectName || "",
|
|
13619
|
+
sessionId: getCurrentSessionId()
|
|
13620
|
+
});
|
|
13428
13621
|
if (!compatibilityMode) {
|
|
13429
13622
|
const msg = `[vibeOS] ${resolveTierIcon("cheap")} cheap lane \xB7 save about ~$${_estEdit.toFixed(3)} by delegating to Task. Try ${resolveTierIcon("medium")} medium.`;
|
|
13430
13623
|
if (shouldLogWarn(`${t}|direct|${_tierWord}`) && process.env.VIBEOS_DEBUG_DELEGATION === "1") {
|
|
@@ -13463,7 +13656,11 @@ ${argsJson}
|
|
|
13463
13656
|
softQuotaCounts[t] = (softQuotaCounts[t] ?? 0) + 1;
|
|
13464
13657
|
const n = softQuotaCounts[t];
|
|
13465
13658
|
if (n === SOFT_QUOTA_LIMIT + 1) {
|
|
13466
|
-
const total = recordSaving(t, `soft quota exceeded (limit ${SOFT_QUOTA_LIMIT})`, SAVE_EST.SOFT_QUOTA
|
|
13659
|
+
const total = recordSaving(t, `soft quota exceeded (limit ${SOFT_QUOTA_LIMIT})`, SAVE_EST.SOFT_QUOTA, {
|
|
13660
|
+
projectFingerprint: currentProjectFingerprint,
|
|
13661
|
+
projectName: currentProjectName || "",
|
|
13662
|
+
sessionId: getCurrentSessionId()
|
|
13663
|
+
});
|
|
13467
13664
|
console.error(`[vibeOS] Bash usage is getting heavy (${n}/${SOFT_QUOTA_LIMIT}) \u2014 hand the next step to a Task subagent.`);
|
|
13468
13665
|
}
|
|
13469
13666
|
return;
|
|
@@ -14204,6 +14401,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
14204
14401
|
setShellDirectory(directory3 || "");
|
|
14205
14402
|
registerSessionCleanupHandlers();
|
|
14206
14403
|
pruneScratchpadOnce();
|
|
14404
|
+
runStartupMaintenanceOnce();
|
|
14207
14405
|
const _bootstrapModel = await _resolveBootstrapModel(client2, directory3);
|
|
14208
14406
|
if (_bootstrapModel.model) {
|
|
14209
14407
|
setCurrentModel(_bootstrapModel.model);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.19",
|
|
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",
|