vibeostheog 0.15.6 → 0.15.8
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 +8 -0
- package/package.json +1 -1
- package/src/index.js +141 -122
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## 0.15.8
|
|
2
|
+
- fix: load VIBEOS_API_TOKEN from .env.production if env var not set
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## 0.15.7
|
|
6
|
+
- fix: auto mode now actually applies optimization mode from API response
|
|
7
|
+
|
|
8
|
+
|
|
1
9
|
## 0.15.6
|
|
2
10
|
- fix: auto mode cache with TTL 60s, preserve last mode on API failure
|
|
3
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.8",
|
|
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",
|
package/src/index.js
CHANGED
|
@@ -344,8 +344,8 @@ var init_flow_enforcer = __esm({
|
|
|
344
344
|
|
|
345
345
|
// src/index.ts
|
|
346
346
|
init_flow_enforcer();
|
|
347
|
-
import { readFileSync as
|
|
348
|
-
import { join as
|
|
347
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync12, existsSync as existsSync15, mkdirSync as mkdirSync10, copyFileSync as copyFileSync6, renameSync as renameSync6 } from "node:fs";
|
|
348
|
+
import { join as join17, dirname as dirname8, basename as basename9 } from "node:path";
|
|
349
349
|
|
|
350
350
|
// src/vibeOS-lib/session-metrics.js
|
|
351
351
|
function formatDuration(totalSeconds) {
|
|
@@ -3230,9 +3230,9 @@ function applySlot2(slot) {
|
|
|
3230
3230
|
}
|
|
3231
3231
|
|
|
3232
3232
|
// src/lib/turn-classify.js
|
|
3233
|
-
import { readFileSync as
|
|
3234
|
-
import { join as
|
|
3235
|
-
import { homedir as
|
|
3233
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, appendFileSync as appendFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync5, statSync as statSync6, copyFileSync as copyFileSync4, renameSync as renameSync5, openSync as openSync3, closeSync as closeSync3, rmSync as rmSync3 } from "node:fs";
|
|
3234
|
+
import { join as join7, dirname as dirname5, basename as basename5 } from "node:path";
|
|
3235
|
+
import { homedir as homedir6, tmpdir as tmpdir4 } from "node:os";
|
|
3236
3236
|
import { createHash as createHash3 } from "node:crypto";
|
|
3237
3237
|
|
|
3238
3238
|
// ../vibeOScore/client.js
|
|
@@ -3491,8 +3491,26 @@ var VibeOSNetworkError = class extends Error {
|
|
|
3491
3491
|
};
|
|
3492
3492
|
|
|
3493
3493
|
// src/lib/api-client.js
|
|
3494
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
3495
|
+
import { join as join6 } from "node:path";
|
|
3496
|
+
import { homedir as homedir5 } from "node:os";
|
|
3494
3497
|
var VIBEOS_API_URL = process.env.VIBEOS_API_URL || "https://api.vibetheog.com";
|
|
3495
|
-
var
|
|
3498
|
+
var _envToken2 = "";
|
|
3499
|
+
try {
|
|
3500
|
+
const env = readFileSync5(join6(process.cwd(), ".env.production"), "utf8");
|
|
3501
|
+
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
3502
|
+
if (m) _envToken2 = m[1].trim();
|
|
3503
|
+
} catch {
|
|
3504
|
+
}
|
|
3505
|
+
if (!_envToken2) {
|
|
3506
|
+
try {
|
|
3507
|
+
const env = readFileSync5(join6(homedir5(), ".env.production"), "utf8");
|
|
3508
|
+
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
3509
|
+
if (m) _envToken2 = m[1].trim();
|
|
3510
|
+
} catch {
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN || _envToken2 || "";
|
|
3496
3514
|
var VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
3497
3515
|
var _apiClient = null;
|
|
3498
3516
|
var _apiFallbackMode = false;
|
|
@@ -3744,16 +3762,16 @@ var _BlackboxStub = class __BlackboxStub {
|
|
|
3744
3762
|
};
|
|
3745
3763
|
var USER_HOME4 = (() => {
|
|
3746
3764
|
try {
|
|
3747
|
-
return
|
|
3765
|
+
return homedir6();
|
|
3748
3766
|
} catch {
|
|
3749
3767
|
return tmpdir4();
|
|
3750
3768
|
}
|
|
3751
3769
|
})();
|
|
3752
|
-
var FILE_LOCK_DIR3 =
|
|
3753
|
-
var BLACKBOX_STATE_FILE2 =
|
|
3754
|
-
var GLOBAL_LEARNING_FILE2 =
|
|
3755
|
-
var STATE_FILE3 =
|
|
3756
|
-
var PROJECT_STATE_FILE2 =
|
|
3770
|
+
var FILE_LOCK_DIR3 = join7(USER_HOME4, ".claude/.vibeOS-locks");
|
|
3771
|
+
var BLACKBOX_STATE_FILE2 = join7(USER_HOME4, ".claude/blackbox-state.json");
|
|
3772
|
+
var GLOBAL_LEARNING_FILE2 = join7(USER_HOME4, ".claude/global-learning.json");
|
|
3773
|
+
var STATE_FILE3 = join7(USER_HOME4, ".claude/delegation-state.json");
|
|
3774
|
+
var PROJECT_STATE_FILE2 = join7(USER_HOME4, ".claude/project-states.json");
|
|
3757
3775
|
var DFLT_GL2 = { exploratory_words: {}, task_first_words: {}, updatedAt: null };
|
|
3758
3776
|
var _blackboxTracker = null;
|
|
3759
3777
|
var _OC_SID2 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
@@ -3768,14 +3786,14 @@ var WARN_MAX_PER_SESSION = 3;
|
|
|
3768
3786
|
var WARN_COALESCE_THRESHOLD = 10;
|
|
3769
3787
|
var warnCoalesceCounters = /* @__PURE__ */ new Map();
|
|
3770
3788
|
function _handleStateCorruption4(path) {
|
|
3771
|
-
const backupDir =
|
|
3789
|
+
const backupDir = join7(USER_HOME4, ".claude", ".backups");
|
|
3772
3790
|
mkdirSync5(backupDir, { recursive: true });
|
|
3773
|
-
const backupPath =
|
|
3791
|
+
const backupPath = join7(backupDir, basename5(path) + ".corrupted." + Date.now());
|
|
3774
3792
|
try {
|
|
3775
3793
|
copyFileSync4(path, backupPath);
|
|
3776
3794
|
} catch {
|
|
3777
3795
|
}
|
|
3778
|
-
const logPath =
|
|
3796
|
+
const logPath = join7(USER_HOME4, ".claude", ".state-corruption-log.jsonl");
|
|
3779
3797
|
try {
|
|
3780
3798
|
appendFileSync5(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
3781
3799
|
} catch {
|
|
@@ -3783,7 +3801,7 @@ function _handleStateCorruption4(path) {
|
|
|
3783
3801
|
}
|
|
3784
3802
|
function _lockPathFor3(filePath) {
|
|
3785
3803
|
const hash = createHash3("sha1").update(String(filePath || "")).digest("hex");
|
|
3786
|
-
return
|
|
3804
|
+
return join7(FILE_LOCK_DIR3, `${hash}.lock`);
|
|
3787
3805
|
}
|
|
3788
3806
|
function withFileLock3(filePath, fn, opts = {}) {
|
|
3789
3807
|
const staleMs = Number(opts.staleMs || 3e4);
|
|
@@ -3838,7 +3856,7 @@ function readJsonOrEmpty2(filePath) {
|
|
|
3838
3856
|
_handleStateCorruption4(filePath);
|
|
3839
3857
|
return {};
|
|
3840
3858
|
}
|
|
3841
|
-
return safeJsonParse3(
|
|
3859
|
+
return safeJsonParse3(readFileSync6(filePath, "utf-8"));
|
|
3842
3860
|
} catch {
|
|
3843
3861
|
_handleStateCorruption4(filePath);
|
|
3844
3862
|
return {};
|
|
@@ -3846,10 +3864,10 @@ function readJsonOrEmpty2(filePath) {
|
|
|
3846
3864
|
}
|
|
3847
3865
|
function loadTrinityModels() {
|
|
3848
3866
|
try {
|
|
3849
|
-
const p =
|
|
3867
|
+
const p = join7(USER_HOME4, ".claude/model-tiers.json");
|
|
3850
3868
|
if (!existsSync6(p))
|
|
3851
3869
|
return { brain: "", cheap: "", medium: "" };
|
|
3852
|
-
const j = safeJsonParse3(
|
|
3870
|
+
const j = safeJsonParse3(readFileSync6(p, "utf-8"));
|
|
3853
3871
|
return {
|
|
3854
3872
|
brain: j?.trinity?.brain?.oc || j?.trinity?.brain || "",
|
|
3855
3873
|
cheap: j?.trinity?.cheap?.oc || j?.trinity?.cheap || "",
|
|
@@ -3871,7 +3889,7 @@ function loadBlackboxState() {
|
|
|
3871
3889
|
_handleStateCorruption4(BLACKBOX_STATE_FILE2);
|
|
3872
3890
|
return { enabled: false, sessions: {} };
|
|
3873
3891
|
}
|
|
3874
|
-
return safeJsonParse3(
|
|
3892
|
+
return safeJsonParse3(readFileSync6(BLACKBOX_STATE_FILE2, "utf-8")) || { enabled: false, sessions: {} };
|
|
3875
3893
|
} catch {
|
|
3876
3894
|
_handleStateCorruption4(BLACKBOX_STATE_FILE2);
|
|
3877
3895
|
return { enabled: false, sessions: {} };
|
|
@@ -4024,7 +4042,7 @@ function loadGlobalLearning2() {
|
|
|
4024
4042
|
_handleStateCorruption4(GLOBAL_LEARNING_FILE2);
|
|
4025
4043
|
return DFLT_GL2;
|
|
4026
4044
|
}
|
|
4027
|
-
const j = safeJsonParse3(
|
|
4045
|
+
const j = safeJsonParse3(readFileSync6(GLOBAL_LEARNING_FILE2, "utf-8"));
|
|
4028
4046
|
if (!j || typeof j !== "object")
|
|
4029
4047
|
return DFLT_GL2;
|
|
4030
4048
|
j.exploratory_words ??= {};
|
|
@@ -4090,9 +4108,9 @@ function saveProjectState2(state) {
|
|
|
4090
4108
|
function detectTechStack2(dir) {
|
|
4091
4109
|
const stacks = [];
|
|
4092
4110
|
try {
|
|
4093
|
-
const pkg = safeJsonParse3(
|
|
4111
|
+
const pkg = safeJsonParse3(readFileSync6(join7(dir, "package.json"), "utf-8"));
|
|
4094
4112
|
if (pkg) {
|
|
4095
|
-
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(
|
|
4113
|
+
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(join7(dir, "tsconfig.json")))
|
|
4096
4114
|
stacks.push("typescript");
|
|
4097
4115
|
if (pkg.dependencies?.react || pkg.devDependencies?.react)
|
|
4098
4116
|
stacks.push("react");
|
|
@@ -4101,21 +4119,21 @@ function detectTechStack2(dir) {
|
|
|
4101
4119
|
} catch {
|
|
4102
4120
|
}
|
|
4103
4121
|
try {
|
|
4104
|
-
if (existsSync6(
|
|
4122
|
+
if (existsSync6(join7(dir, "Cargo.toml")))
|
|
4105
4123
|
stacks.push("rust");
|
|
4106
4124
|
} catch {
|
|
4107
4125
|
}
|
|
4108
4126
|
try {
|
|
4109
|
-
if (existsSync6(
|
|
4127
|
+
if (existsSync6(join7(dir, "go.mod")))
|
|
4110
4128
|
stacks.push("go");
|
|
4111
4129
|
} catch {
|
|
4112
4130
|
}
|
|
4113
4131
|
try {
|
|
4114
|
-
if (existsSync6(
|
|
4132
|
+
if (existsSync6(join7(dir, "requirements.txt")))
|
|
4115
4133
|
stacks.push("python");
|
|
4116
|
-
if (existsSync6(
|
|
4134
|
+
if (existsSync6(join7(dir, "setup.py")))
|
|
4117
4135
|
stacks.push("python");
|
|
4118
|
-
if (existsSync6(
|
|
4136
|
+
if (existsSync6(join7(dir, "pyproject.toml")))
|
|
4119
4137
|
stacks.push("python");
|
|
4120
4138
|
} catch {
|
|
4121
4139
|
}
|
|
@@ -4223,30 +4241,30 @@ function saveOptimizationMode(mode) {
|
|
|
4223
4241
|
}
|
|
4224
4242
|
|
|
4225
4243
|
// src/lib/research-audit.js
|
|
4226
|
-
import { readFileSync as
|
|
4227
|
-
import { join as
|
|
4228
|
-
import { homedir as
|
|
4244
|
+
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "node:fs";
|
|
4245
|
+
import { join as join8 } from "node:path";
|
|
4246
|
+
import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
|
|
4229
4247
|
var USER_HOME5 = (() => {
|
|
4230
4248
|
try {
|
|
4231
|
-
return
|
|
4249
|
+
return homedir7();
|
|
4232
4250
|
} catch {
|
|
4233
4251
|
return tmpdir5();
|
|
4234
4252
|
}
|
|
4235
4253
|
})();
|
|
4236
4254
|
var _OC_SID3 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4237
|
-
var SCRATCHPAD_ROOT2 =
|
|
4238
|
-
var SCRATCHPAD_GLOBAL_DIR2 =
|
|
4239
|
-
var SCRATCHPAD_SESSIONS_DIR2 =
|
|
4240
|
-
var STATE_FILE4 =
|
|
4255
|
+
var SCRATCHPAD_ROOT2 = join8(USER_HOME5, ".claude/scratch");
|
|
4256
|
+
var SCRATCHPAD_GLOBAL_DIR2 = join8(SCRATCHPAD_ROOT2, "by-hash");
|
|
4257
|
+
var SCRATCHPAD_SESSIONS_DIR2 = join8(SCRATCHPAD_ROOT2, "sessions");
|
|
4258
|
+
var STATE_FILE4 = join8(USER_HOME5, ".claude/delegation-state.json");
|
|
4241
4259
|
var currentModel2 = null;
|
|
4242
4260
|
function getSessionRoot2() {
|
|
4243
|
-
return
|
|
4261
|
+
return join8(SCRATCHPAD_SESSIONS_DIR2, _OC_SID3);
|
|
4244
4262
|
}
|
|
4245
4263
|
function getSessionScratchpadDir2() {
|
|
4246
|
-
return
|
|
4264
|
+
return join8(getSessionRoot2(), "by-hash");
|
|
4247
4265
|
}
|
|
4248
4266
|
function getGlobalIndexPath2() {
|
|
4249
|
-
return
|
|
4267
|
+
return join8(SCRATCHPAD_ROOT2, "index.jsonl");
|
|
4250
4268
|
}
|
|
4251
4269
|
var FETCH_TOOLS = /* @__PURE__ */ new Set(["WebFetch", "WebSearch", "webfetch", "websearch"]);
|
|
4252
4270
|
function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
@@ -4255,7 +4273,7 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4255
4273
|
try {
|
|
4256
4274
|
const indexPath = getGlobalIndexPath2();
|
|
4257
4275
|
if (existsSync7(indexPath)) {
|
|
4258
|
-
const lines =
|
|
4276
|
+
const lines = readFileSync7(indexPath, "utf-8").trim().split("\n").filter(Boolean);
|
|
4259
4277
|
const domainCache = {};
|
|
4260
4278
|
for (const line of lines) {
|
|
4261
4279
|
const e = JSON.parse(line);
|
|
@@ -4269,11 +4287,11 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4269
4287
|
report.totalFetches++;
|
|
4270
4288
|
report.totalBytes += e.size || 0;
|
|
4271
4289
|
const hash = e.hash;
|
|
4272
|
-
const summaryPathSession =
|
|
4273
|
-
const summaryPathGlobal =
|
|
4290
|
+
const summaryPathSession = join8(getSessionScratchpadDir2(), hash + ".summary.txt");
|
|
4291
|
+
const summaryPathGlobal = join8(SCRATCHPAD_GLOBAL_DIR2, hash + ".summary.txt");
|
|
4274
4292
|
const summaryPath = existsSync7(summaryPathSession) ? summaryPathSession : summaryPathGlobal;
|
|
4275
4293
|
if (existsSync7(summaryPath)) {
|
|
4276
|
-
const summary =
|
|
4294
|
+
const summary = readFileSync7(summaryPath, "utf-8").slice(0, 200);
|
|
4277
4295
|
const urlMatch = summary.match(/https?:\/\/([^\/\s\)]+)/i);
|
|
4278
4296
|
const queryMatch = summary.match(/"query":"([^"]+)"/);
|
|
4279
4297
|
let domain;
|
|
@@ -4320,7 +4338,7 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4320
4338
|
}
|
|
4321
4339
|
try {
|
|
4322
4340
|
if (existsSync7(STATE_FILE4)) {
|
|
4323
|
-
const state = safeJsonParse3(
|
|
4341
|
+
const state = safeJsonParse3(readFileSync7(STATE_FILE4, "utf-8"));
|
|
4324
4342
|
for (const [sid, s] of Object.entries(state.sessions || {})) {
|
|
4325
4343
|
if (sessionFilter && sid !== sessionFilter)
|
|
4326
4344
|
continue;
|
|
@@ -4343,25 +4361,25 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4343
4361
|
}
|
|
4344
4362
|
|
|
4345
4363
|
// src/lib/reporting.js
|
|
4346
|
-
import { readFileSync as
|
|
4347
|
-
import { join as
|
|
4348
|
-
import { homedir as
|
|
4364
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as mkdirSync6, statSync as statSync7, copyFileSync as copyFileSync5, rmSync as rmSync4 } from "node:fs";
|
|
4365
|
+
import { join as join9, basename as basename6 } from "node:path";
|
|
4366
|
+
import { homedir as homedir8, tmpdir as tmpdir6 } from "node:os";
|
|
4349
4367
|
var USER_HOME6 = (() => {
|
|
4350
4368
|
try {
|
|
4351
|
-
return
|
|
4369
|
+
return homedir8();
|
|
4352
4370
|
} catch {
|
|
4353
4371
|
return tmpdir6();
|
|
4354
4372
|
}
|
|
4355
4373
|
})();
|
|
4356
|
-
var REPORTS_DIR2 =
|
|
4357
|
-
var REPORTS_INDEX =
|
|
4374
|
+
var REPORTS_DIR2 = join9(USER_HOME6, ".claude/reports");
|
|
4375
|
+
var REPORTS_INDEX = join9(REPORTS_DIR2, "index.json");
|
|
4358
4376
|
var _OC_SID4 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4359
4377
|
var currentProjectFingerprint3 = "";
|
|
4360
4378
|
var currentProjectName2 = "";
|
|
4361
4379
|
function _handleStateCorruption5(path) {
|
|
4362
|
-
const backupDir =
|
|
4380
|
+
const backupDir = join9(USER_HOME6, ".claude", ".backups");
|
|
4363
4381
|
mkdirSync6(backupDir, { recursive: true });
|
|
4364
|
-
const backupPath =
|
|
4382
|
+
const backupPath = join9(backupDir, basename6(path) + ".corrupted." + Date.now());
|
|
4365
4383
|
try {
|
|
4366
4384
|
copyFileSync5(path, backupPath);
|
|
4367
4385
|
} catch {
|
|
@@ -4376,7 +4394,7 @@ function readJsonOrEmpty3(filePath) {
|
|
|
4376
4394
|
_handleStateCorruption5(filePath);
|
|
4377
4395
|
return {};
|
|
4378
4396
|
}
|
|
4379
|
-
return safeJsonParse3(
|
|
4397
|
+
return safeJsonParse3(readFileSync8(filePath, "utf-8"));
|
|
4380
4398
|
} catch {
|
|
4381
4399
|
_handleStateCorruption5(filePath);
|
|
4382
4400
|
return {};
|
|
@@ -4431,7 +4449,7 @@ function _pruneReports() {
|
|
|
4431
4449
|
continue;
|
|
4432
4450
|
if (now - created > 90 * 24 * 3600 * 1e3) {
|
|
4433
4451
|
try {
|
|
4434
|
-
rmSync4(
|
|
4452
|
+
rmSync4(join9(REPORTS_DIR2, `${r.id}.json`));
|
|
4435
4453
|
} catch {
|
|
4436
4454
|
}
|
|
4437
4455
|
continue;
|
|
@@ -4502,7 +4520,7 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
4502
4520
|
try {
|
|
4503
4521
|
withFileLock(REPORTS_INDEX, () => {
|
|
4504
4522
|
mkdirSync6(REPORTS_DIR2, { recursive: true });
|
|
4505
|
-
writeFileSync6(
|
|
4523
|
+
writeFileSync6(join9(REPORTS_DIR2, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
4506
4524
|
const idx = reportsIndex();
|
|
4507
4525
|
const _sum = (summary || "").slice(0, 80);
|
|
4508
4526
|
idx.reports.push({ id: id2, type, project: report.meta.project, fingerprint: fp3, created: report.meta.created, summary: _sum });
|
|
@@ -4536,19 +4554,19 @@ function readReport(id2) {
|
|
|
4536
4554
|
return null;
|
|
4537
4555
|
if (!/^[\w-]+$/.test(String(id2)))
|
|
4538
4556
|
return null;
|
|
4539
|
-
const path =
|
|
4557
|
+
const path = join9(REPORTS_DIR2, `${id2}.json`);
|
|
4540
4558
|
try {
|
|
4541
4559
|
if (!existsSync8(path))
|
|
4542
4560
|
return null;
|
|
4543
|
-
return safeJsonParse3(
|
|
4561
|
+
return safeJsonParse3(readFileSync8(path, "utf-8"));
|
|
4544
4562
|
} catch {
|
|
4545
4563
|
return null;
|
|
4546
4564
|
}
|
|
4547
4565
|
}
|
|
4548
4566
|
|
|
4549
4567
|
// src/lib/credit-api.js
|
|
4550
|
-
import { readFileSync as
|
|
4551
|
-
import { join as
|
|
4568
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "node:fs";
|
|
4569
|
+
import { join as join10 } from "node:path";
|
|
4552
4570
|
function safeJsonParse4(raw) {
|
|
4553
4571
|
try {
|
|
4554
4572
|
return JSON.parse(raw);
|
|
@@ -4579,7 +4597,7 @@ var BALANCE_APIS = {
|
|
|
4579
4597
|
var _creditTimer = null;
|
|
4580
4598
|
function _readAuth() {
|
|
4581
4599
|
try {
|
|
4582
|
-
return existsSync9(AUTH_F) ? safeJsonParse4(
|
|
4600
|
+
return existsSync9(AUTH_F) ? safeJsonParse4(readFileSync9(AUTH_F, "utf-8")) : {};
|
|
4583
4601
|
} catch {
|
|
4584
4602
|
return {};
|
|
4585
4603
|
}
|
|
@@ -4622,14 +4640,14 @@ function _cachedPct() {
|
|
|
4622
4640
|
try {
|
|
4623
4641
|
if (!existsSync9(CREDIT_CACHE_F))
|
|
4624
4642
|
return null;
|
|
4625
|
-
const s = safeJsonParse4(
|
|
4643
|
+
const s = safeJsonParse4(readFileSync9(CREDIT_CACHE_F, "utf-8"));
|
|
4626
4644
|
if (s?.total == null || !s.ts)
|
|
4627
4645
|
return null;
|
|
4628
4646
|
let budget = 50;
|
|
4629
4647
|
try {
|
|
4630
|
-
const p =
|
|
4648
|
+
const p = join10(USER_HOME2, ".claude/model-tiers.json");
|
|
4631
4649
|
if (existsSync9(p)) {
|
|
4632
|
-
const j = safeJsonParse4(
|
|
4650
|
+
const j = safeJsonParse4(readFileSync9(p, "utf-8"));
|
|
4633
4651
|
if (j?.selection?.monthly_budget_usd)
|
|
4634
4652
|
budget = j.selection.monthly_budget_usd;
|
|
4635
4653
|
}
|
|
@@ -4660,9 +4678,9 @@ function loadCredit() {
|
|
|
4660
4678
|
return n;
|
|
4661
4679
|
}
|
|
4662
4680
|
try {
|
|
4663
|
-
const f =
|
|
4681
|
+
const f = join10(USER_HOME2, ".claude/credit-percent");
|
|
4664
4682
|
if (existsSync9(f)) {
|
|
4665
|
-
const n = parseInt(
|
|
4683
|
+
const n = parseInt(readFileSync9(f, "utf-8").trim(), 10);
|
|
4666
4684
|
if (!isNaN(n))
|
|
4667
4685
|
return n;
|
|
4668
4686
|
}
|
|
@@ -4679,7 +4697,7 @@ function thinkingLevel(credit) {
|
|
|
4679
4697
|
}
|
|
4680
4698
|
|
|
4681
4699
|
// src/lib/trinity-tool.js
|
|
4682
|
-
import { join as
|
|
4700
|
+
import { join as join11 } from "node:path";
|
|
4683
4701
|
function createTrinityTool(deps) {
|
|
4684
4702
|
return {
|
|
4685
4703
|
description: "Control the vibeOS plugin and active model slot. Use action='status' to see current state. Use action='enable' or 'disable' to toggle the plugin (takes effect immediately, no restart needed). Use action='set' with slot='brain'|'medium'|'cheap' to switch model tiers (writes opencode.json \u2014 active immediately). Use action='rebuild' to auto-detect available models from all configured providers and reassign brain/medium/cheap slots. Use action='flow' with slot='on'|'off' to toggle flow enforcer, or action='flow' alone for audit. Use action='flow' with slot='enforce' and level='on'|'off' to toggle auto-extract TODOs. Use action='enforce' with slot='on'|'off' to toggle delegation enforcement (blocks direct writes/edits on brain tier). Use action='tdd' with slot='on'|'off' to toggle auto-create test skeletons. Use action='tdd' with slot='strict' and level='on'|'off' to toggle strict failing TODO test templates. Use action='tdd' alone for audit. Use action='project' to show per-project analytics and optimization suggestions. Use action='patterns' to inspect learned project patterns or slot='clear' to clear them. Use action='guard' to ensure AGENTS.md and README.md exist and stay current. Call this when the user says things like 'switch to medium', 'use cheap model', 'disable plugin', 'trinity status'.",
|
|
@@ -4934,7 +4952,7 @@ Lock is per-session (resets on restart).`;
|
|
|
4934
4952
|
const ok = deps.writeSelection("tdd_enforce", slot === "on");
|
|
4935
4953
|
return ok ? `\u2705 TDD enforcement ${slot === "on" ? "ENABLED (auto-create skeletons)" : "DISABLED (nudge only)"}` : `\u274C Failed to write model-tiers.json`;
|
|
4936
4954
|
}
|
|
4937
|
-
const stateFile =
|
|
4955
|
+
const stateFile = join11(deps.USER_HOME, ".claude/delegation-state.json");
|
|
4938
4956
|
let enforced = 0;
|
|
4939
4957
|
try {
|
|
4940
4958
|
if (deps.existsSync(stateFile)) {
|
|
@@ -5314,7 +5332,7 @@ ${L.repeat(40)}`);
|
|
|
5314
5332
|
}
|
|
5315
5333
|
if (action === "diagnose") {
|
|
5316
5334
|
const results = [];
|
|
5317
|
-
const ocConfig =
|
|
5335
|
+
const ocConfig = join11(deps.USER_HOME, ".config/opencode/opencode.json");
|
|
5318
5336
|
const checks = [
|
|
5319
5337
|
{ path: deps.TIERS_FILE, label: "model-tiers.json" },
|
|
5320
5338
|
{ path: ocConfig, label: "opencode.json" },
|
|
@@ -5486,7 +5504,7 @@ ${L.repeat(40)}`);
|
|
|
5486
5504
|
for (const r of idx.reports || []) {
|
|
5487
5505
|
if (r.project !== name || r.fingerprint !== dstFp)
|
|
5488
5506
|
continue;
|
|
5489
|
-
const rf =
|
|
5507
|
+
const rf = join11(deps.REPORTS_DIR, `${r.id}.json`);
|
|
5490
5508
|
try {
|
|
5491
5509
|
if (!deps.existsSync(rf))
|
|
5492
5510
|
continue;
|
|
@@ -5605,8 +5623,8 @@ ${L.repeat(40)}`);
|
|
|
5605
5623
|
}
|
|
5606
5624
|
|
|
5607
5625
|
// src/lib/trinity-rebuild.js
|
|
5608
|
-
import { readFileSync as
|
|
5609
|
-
import { join as
|
|
5626
|
+
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "node:fs";
|
|
5627
|
+
import { join as join12 } from "node:path";
|
|
5610
5628
|
var MODEL_RANK = { high: 3, mid: 2, budget: 1 };
|
|
5611
5629
|
var OPENCODE_GO_CATALOG = [
|
|
5612
5630
|
"deepseek/deepseek-v4-flash",
|
|
@@ -5809,17 +5827,17 @@ async function probeModel(modelId, auth) {
|
|
|
5809
5827
|
}
|
|
5810
5828
|
|
|
5811
5829
|
// src/lib/hooks/footer.js
|
|
5812
|
-
import { readFileSync as
|
|
5813
|
-
import { join as
|
|
5814
|
-
import { homedir as
|
|
5830
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
5831
|
+
import { join as join15 } from "node:path";
|
|
5832
|
+
import { homedir as homedir9, tmpdir as tmpdir7 } from "node:os";
|
|
5815
5833
|
|
|
5816
5834
|
// src/lib/hooks/chat-transform.js
|
|
5817
|
-
import { readFileSync as
|
|
5818
|
-
import { join as
|
|
5835
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5836
|
+
import { join as join14, basename as basename7 } from "node:path";
|
|
5819
5837
|
import { createHash as createHash4 } from "node:crypto";
|
|
5820
5838
|
|
|
5821
5839
|
// src/lib/index-helpers.js
|
|
5822
|
-
import { join as
|
|
5840
|
+
import { join as join13 } from "node:path";
|
|
5823
5841
|
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
5824
5842
|
|
|
5825
5843
|
// src/lib/text-compress.js
|
|
@@ -6154,7 +6172,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
6154
6172
|
try {
|
|
6155
6173
|
const sd = getSessionScratchpadDir();
|
|
6156
6174
|
if (sd) {
|
|
6157
|
-
const sp =
|
|
6175
|
+
const sp = join13(sd, "delegation-state-hint.txt");
|
|
6158
6176
|
try {
|
|
6159
6177
|
writeFileSync8(sp, JSON.stringify({ sid, total_savings: s.lifetime.total_savings_usd, last_reason: reason }), "utf8");
|
|
6160
6178
|
} catch {
|
|
@@ -6283,10 +6301,10 @@ function buildProjectBriefing(directory3) {
|
|
|
6283
6301
|
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
6284
6302
|
}
|
|
6285
6303
|
function ensureProjectSkill(dir, fp3) {
|
|
6286
|
-
const skillsDir =
|
|
6304
|
+
const skillsDir = join14(dir, ".opencode", "skills");
|
|
6287
6305
|
const projectName = basename7(dir);
|
|
6288
|
-
const skillDir =
|
|
6289
|
-
const skillPath =
|
|
6306
|
+
const skillDir = join14(skillsDir, projectName);
|
|
6307
|
+
const skillPath = join14(skillDir, "SKILL.md");
|
|
6290
6308
|
if (existsSync11(skillPath)) {
|
|
6291
6309
|
return { created: false, skipped: true, path: skillPath };
|
|
6292
6310
|
}
|
|
@@ -6443,7 +6461,7 @@ var onMessagesTransform = async (_input, output) => {
|
|
|
6443
6461
|
const hash = createHash4("sha256").update(`tool_result
|
|
6444
6462
|
${raw}
|
|
6445
6463
|
`).digest("hex").slice(0, 16);
|
|
6446
|
-
const fullPath =
|
|
6464
|
+
const fullPath = join14(getSessionScratchpadDir(), `${hash}.txt`);
|
|
6447
6465
|
try {
|
|
6448
6466
|
ensureSessionScratchpadDirs();
|
|
6449
6467
|
if (!existsSync11(fullPath)) {
|
|
@@ -6617,7 +6635,7 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6617
6635
|
const mediumModel = TRINITY_MEDIUM || "the medium model";
|
|
6618
6636
|
let brainModel = "(brain)";
|
|
6619
6637
|
try {
|
|
6620
|
-
brainModel = safeJsonParse3(
|
|
6638
|
+
brainModel = safeJsonParse3(readFileSync11(TIERS_FILE2, "utf-8")).trinity?.brain?.oc || brainModel;
|
|
6621
6639
|
} catch {
|
|
6622
6640
|
}
|
|
6623
6641
|
const targetModel = tierBias === "cheap" ? cheapModel : tierBias === "medium" ? mediumModel : tierBias === "brain" ? brainModel : `${cheapModel} or ${mediumModel}`;
|
|
@@ -6668,7 +6686,7 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6668
6686
|
const sel2 = loadSelection();
|
|
6669
6687
|
let tiers = {};
|
|
6670
6688
|
try {
|
|
6671
|
-
tiers = safeJsonParse3(
|
|
6689
|
+
tiers = safeJsonParse3(readFileSync11(TIERS_FILE2, "utf-8")).trinity || {};
|
|
6672
6690
|
} catch {
|
|
6673
6691
|
}
|
|
6674
6692
|
const active = sel2.active_slot || "medium";
|
|
@@ -6710,19 +6728,19 @@ async function apiAutoSelectMode(regime, stress) {
|
|
|
6710
6728
|
}
|
|
6711
6729
|
var USER_HOME7 = (() => {
|
|
6712
6730
|
try {
|
|
6713
|
-
return
|
|
6731
|
+
return homedir9();
|
|
6714
6732
|
} catch {
|
|
6715
6733
|
return tmpdir7();
|
|
6716
6734
|
}
|
|
6717
6735
|
})();
|
|
6718
|
-
var STATE_FILE5 =
|
|
6719
|
-
var SAVINGS_LEDGER_FILE2 =
|
|
6736
|
+
var STATE_FILE5 = join15(USER_HOME7, ".claude/delegation-state.json");
|
|
6737
|
+
var SAVINGS_LEDGER_FILE2 = join15(USER_HOME7, ".claude/savings-ledger.jsonl");
|
|
6720
6738
|
var _prevOutputText = "";
|
|
6721
6739
|
var _autoReportCount = 0;
|
|
6722
6740
|
var textCompletePainted = /* @__PURE__ */ new Set();
|
|
6723
6741
|
function loadSelection3() {
|
|
6724
6742
|
try {
|
|
6725
|
-
const raw =
|
|
6743
|
+
const raw = readFileSync12(join15(USER_HOME7, ".claude/model-tiers.json"), "utf-8");
|
|
6726
6744
|
return safeJsonParse3(raw)?.selection || { active_slot: "medium", enabled: true, delegation_enforce: false, flow_enabled: false, flow_enforce: false, tdd_enforce: false, tdd_strict: false };
|
|
6727
6745
|
} catch {
|
|
6728
6746
|
return { active_slot: "medium", enabled: true, delegation_enforce: false, flow_enabled: false, flow_enforce: false, tdd_enforce: false, tdd_strict: false };
|
|
@@ -6731,7 +6749,7 @@ function loadSelection3() {
|
|
|
6731
6749
|
function readLifetimeSavings2() {
|
|
6732
6750
|
try {
|
|
6733
6751
|
reconcileStateFromLedger();
|
|
6734
|
-
const raw =
|
|
6752
|
+
const raw = readFileSync12(STATE_FILE5, "utf-8");
|
|
6735
6753
|
const state = safeJsonParse3(raw);
|
|
6736
6754
|
const ses = state?.sessions?.[typeof _OC_SID6 !== "undefined" ? _OC_SID6 : ""] || {};
|
|
6737
6755
|
return {
|
|
@@ -6878,6 +6896,7 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6878
6896
|
const autoStress = scoreStress(latestUserIntent || "");
|
|
6879
6897
|
const autoActive = await apiAutoSelectMode(autoRegime, autoStress);
|
|
6880
6898
|
const autoTag = { audit: "AUDIT", budget: "BUDGET", quality: "QUALITY", speed: "SPEED", longrun: "LONGRUN", balanced: "BALANCED" };
|
|
6899
|
+
saveOptimizationMode(autoActive);
|
|
6881
6900
|
optTagFooter = `[AUTO\u2192${autoTag[autoActive] || autoActive.toUpperCase()}]`;
|
|
6882
6901
|
const slot2 = autoActive === "quality" ? "brain" : autoActive === "speed" ? "medium" : "cheap";
|
|
6883
6902
|
if (!_modelLocked) {
|
|
@@ -6960,8 +6979,8 @@ import { dirname as dirname7, basename as basename8 } from "node:path";
|
|
|
6960
6979
|
init_flow_enforcer();
|
|
6961
6980
|
|
|
6962
6981
|
// src/lib/tdd-enforcer.js
|
|
6963
|
-
import { readFileSync as
|
|
6964
|
-
import { join as
|
|
6982
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, appendFileSync as appendFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync8, statSync as statSync8, readdirSync as readdirSync2, rmSync as rmSync5, openSync as openSync4 } from "node:fs";
|
|
6983
|
+
import { join as join16, dirname as dirname6 } from "node:path";
|
|
6965
6984
|
import { createHash as createHash5 } from "node:crypto";
|
|
6966
6985
|
|
|
6967
6986
|
// src/utils/tdd-helpers.js
|
|
@@ -8000,9 +8019,9 @@ function _detectTestFramework() {
|
|
|
8000
8019
|
let testExt = null;
|
|
8001
8020
|
try {
|
|
8002
8021
|
const root = directory || process.cwd();
|
|
8003
|
-
const pkgPath =
|
|
8022
|
+
const pkgPath = join16(root, "package.json");
|
|
8004
8023
|
if (existsSync12(pkgPath)) {
|
|
8005
|
-
const pkg = JSON.parse(
|
|
8024
|
+
const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
8006
8025
|
const testScript = String(pkg?.scripts?.test || "");
|
|
8007
8026
|
const deps = { ...pkg?.devDependencies, ...pkg?.dependencies };
|
|
8008
8027
|
if (testScript.includes("vitest") || deps["vitest"]) {
|
|
@@ -8022,12 +8041,12 @@ function _detectTestFramework() {
|
|
|
8022
8041
|
if (!framework) {
|
|
8023
8042
|
const testDirs = ["src/tests", "tests", "test", "__tests__"];
|
|
8024
8043
|
for (const td of testDirs) {
|
|
8025
|
-
const dirPath =
|
|
8044
|
+
const dirPath = join16(root, td);
|
|
8026
8045
|
if (!existsSync12(dirPath))
|
|
8027
8046
|
continue;
|
|
8028
8047
|
const files = readdirSync2(dirPath).filter((f) => /\.test\./.test(f) || /\.spec\./.test(f));
|
|
8029
8048
|
if (files.length > 0) {
|
|
8030
|
-
const content =
|
|
8049
|
+
const content = readFileSync13(join16(dirPath, files[0]), "utf-8");
|
|
8031
8050
|
if (/from\s+['"]node:test['"]/.test(content)) {
|
|
8032
8051
|
framework = "node-test";
|
|
8033
8052
|
testExt = files[0].split(".").pop();
|
|
@@ -8053,16 +8072,16 @@ function _detectTestFramework() {
|
|
|
8053
8072
|
console.error(`[vibeOS] [tdd] detected test framework: ${framework || "default"} (ext: ${testExt || "match source"})`);
|
|
8054
8073
|
return _detectedFramework;
|
|
8055
8074
|
}
|
|
8056
|
-
var ENFORCEMENT_LOCK_DIR =
|
|
8075
|
+
var ENFORCEMENT_LOCK_DIR = join16(USER_HOME2, ".claude/.enforcement-lock");
|
|
8057
8076
|
var LOCK_EXPIRE_MS = 3e4;
|
|
8058
|
-
var ENFORCEMENT_COOLDOWN_FILE2 =
|
|
8077
|
+
var ENFORCEMENT_COOLDOWN_FILE2 = join16(USER_HOME2, ".claude/.enforcement-cooldown.jsonl");
|
|
8059
8078
|
var COOLDOWN_MS = 6e4;
|
|
8060
8079
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
8061
8080
|
function _acquireLock(testPath) {
|
|
8062
8081
|
try {
|
|
8063
8082
|
mkdirSync8(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
8064
8083
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8065
|
-
const lockPath =
|
|
8084
|
+
const lockPath = join16(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8066
8085
|
try {
|
|
8067
8086
|
openSync4(lockPath, "wx");
|
|
8068
8087
|
return true;
|
|
@@ -8090,7 +8109,7 @@ function _acquireLock(testPath) {
|
|
|
8090
8109
|
function _releaseLock(testPath) {
|
|
8091
8110
|
try {
|
|
8092
8111
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8093
|
-
const lockPath =
|
|
8112
|
+
const lockPath = join16(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8094
8113
|
rmSync5(lockPath);
|
|
8095
8114
|
} catch {
|
|
8096
8115
|
}
|
|
@@ -8100,7 +8119,7 @@ function _isInCooldown(testPath) {
|
|
|
8100
8119
|
if (!existsSync12(ENFORCEMENT_COOLDOWN_FILE2))
|
|
8101
8120
|
return false;
|
|
8102
8121
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8103
|
-
const lines =
|
|
8122
|
+
const lines = readFileSync13(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
8104
8123
|
const now = Date.now();
|
|
8105
8124
|
for (const line of lines) {
|
|
8106
8125
|
try {
|
|
@@ -8121,7 +8140,7 @@ function _recordCooldown(testPath) {
|
|
|
8121
8140
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8122
8141
|
const entry = JSON.stringify({ h: hash, ts: Date.now() }) + "\n";
|
|
8123
8142
|
appendFileSync6(ENFORCEMENT_COOLDOWN_FILE2, entry);
|
|
8124
|
-
const lines =
|
|
8143
|
+
const lines = readFileSync13(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
8125
8144
|
if (lines.length > 500) {
|
|
8126
8145
|
writeFileSync10(ENFORCEMENT_COOLDOWN_FILE2, lines.slice(-200).join("\n") + "\n");
|
|
8127
8146
|
}
|
|
@@ -8192,7 +8211,7 @@ function enforceTestFile(filePath) {
|
|
|
8192
8211
|
let sourceContent = "";
|
|
8193
8212
|
try {
|
|
8194
8213
|
if (existsSync12(filePath)) {
|
|
8195
|
-
sourceContent =
|
|
8214
|
+
sourceContent = readFileSync13(filePath, "utf-8");
|
|
8196
8215
|
}
|
|
8197
8216
|
} catch {
|
|
8198
8217
|
}
|
|
@@ -8813,7 +8832,7 @@ ${pendingUiNote}`;
|
|
|
8813
8832
|
};
|
|
8814
8833
|
|
|
8815
8834
|
// src/lib/hooks/session-compact.js
|
|
8816
|
-
import { readFileSync as
|
|
8835
|
+
import { readFileSync as readFileSync14, existsSync as existsSync14 } from "node:fs";
|
|
8817
8836
|
var onSessionCompacting = async (_input, output) => {
|
|
8818
8837
|
if (!loadSelection().enabled)
|
|
8819
8838
|
return;
|
|
@@ -8822,7 +8841,7 @@ var onSessionCompacting = async (_input, output) => {
|
|
|
8822
8841
|
let recent = "";
|
|
8823
8842
|
if (existsSync14(indexPath)) {
|
|
8824
8843
|
try {
|
|
8825
|
-
const lines =
|
|
8844
|
+
const lines = readFileSync14(indexPath, "utf-8").trim().split("\n").slice(-30);
|
|
8826
8845
|
recent = lines.map((l) => {
|
|
8827
8846
|
try {
|
|
8828
8847
|
return JSON.parse(l);
|
|
@@ -8876,17 +8895,17 @@ var _mcpServerRuntime = null;
|
|
|
8876
8895
|
var _mcpServerHooked = false;
|
|
8877
8896
|
function _loadOpenCodeProviders() {
|
|
8878
8897
|
try {
|
|
8879
|
-
const cfg = _readOpenCodeConfigObject(
|
|
8898
|
+
const cfg = _readOpenCodeConfigObject(join17(USER_HOME2, ".config", "opencode"));
|
|
8880
8899
|
return cfg?.provider || {};
|
|
8881
8900
|
} catch {
|
|
8882
8901
|
return {};
|
|
8883
8902
|
}
|
|
8884
8903
|
}
|
|
8885
8904
|
function _readOpenCodeConfigObject(dir) {
|
|
8886
|
-
const jsonPath =
|
|
8887
|
-
const jsoncPath =
|
|
8888
|
-
if (existsSync15(jsonPath)) return safeJsonParse3(
|
|
8889
|
-
if (existsSync15(jsoncPath)) return _parseJsonc(
|
|
8905
|
+
const jsonPath = join17(dir, "opencode.json");
|
|
8906
|
+
const jsoncPath = join17(dir, "opencode.jsonc");
|
|
8907
|
+
if (existsSync15(jsonPath)) return safeJsonParse3(readFileSync15(jsonPath, "utf-8"));
|
|
8908
|
+
if (existsSync15(jsoncPath)) return _parseJsonc(readFileSync15(jsoncPath, "utf-8"));
|
|
8890
8909
|
return {};
|
|
8891
8910
|
}
|
|
8892
8911
|
function _parseJsonc(raw) {
|
|
@@ -8912,9 +8931,9 @@ function _modelTier2(id2) {
|
|
|
8912
8931
|
function backupFile(path, label) {
|
|
8913
8932
|
try {
|
|
8914
8933
|
if (!existsSync15(path)) return null;
|
|
8915
|
-
const bkDir =
|
|
8934
|
+
const bkDir = join17(USER_HOME2, ".claude", ".backups");
|
|
8916
8935
|
mkdirSync10(bkDir, { recursive: true });
|
|
8917
|
-
const bk =
|
|
8936
|
+
const bk = join17(bkDir, `${basename9(path)}.${label}.${Date.now()}.bak`);
|
|
8918
8937
|
copyFileSync6(path, bk);
|
|
8919
8938
|
return bk;
|
|
8920
8939
|
} catch {
|
|
@@ -8923,7 +8942,7 @@ function backupFile(path, label) {
|
|
|
8923
8942
|
}
|
|
8924
8943
|
function readPackageVersion() {
|
|
8925
8944
|
try {
|
|
8926
|
-
const pkg = safeJsonParse3(
|
|
8945
|
+
const pkg = safeJsonParse3(readFileSync15(join17(process.cwd(), "package.json"), "utf-8"));
|
|
8927
8946
|
return String(pkg?.version || "");
|
|
8928
8947
|
} catch {
|
|
8929
8948
|
return "";
|
|
@@ -8938,7 +8957,7 @@ function loadMcpPort() {
|
|
|
8938
8957
|
}
|
|
8939
8958
|
try {
|
|
8940
8959
|
if (existsSync15(TIERS_FILE2)) {
|
|
8941
|
-
const tiers = safeJsonParse3(
|
|
8960
|
+
const tiers = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
8942
8961
|
const cfg = tiers?.selection?.mcp_port ?? tiers?.mcp_port;
|
|
8943
8962
|
if (cfg === false || cfg === "disabled" || cfg === 0) return 0;
|
|
8944
8963
|
const n = Number(cfg);
|
|
@@ -8951,7 +8970,7 @@ function loadMcpPort() {
|
|
|
8951
8970
|
function persistMcpPort(port) {
|
|
8952
8971
|
try {
|
|
8953
8972
|
if (!existsSync15(TIERS_FILE2)) return;
|
|
8954
|
-
const tiers = safeJsonParse3(
|
|
8973
|
+
const tiers = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
8955
8974
|
tiers.selection ??= {};
|
|
8956
8975
|
if (Number(tiers.selection.mcp_port) === Number(port)) return;
|
|
8957
8976
|
tiers.selection.mcp_port = port;
|
|
@@ -8966,7 +8985,7 @@ function computeStatusPayload() {
|
|
|
8966
8985
|
const sel = loadSelection();
|
|
8967
8986
|
let tiersData = {};
|
|
8968
8987
|
try {
|
|
8969
|
-
tiersData = safeJsonParse3(
|
|
8988
|
+
tiersData = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
8970
8989
|
} catch {
|
|
8971
8990
|
}
|
|
8972
8991
|
const credit = loadCredit();
|
|
@@ -9119,13 +9138,13 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9119
9138
|
setCurrentModel(readConfig(directory3));
|
|
9120
9139
|
if (!currentModel) {
|
|
9121
9140
|
const home = process.env.HOME || "";
|
|
9122
|
-
if (home) setCurrentModel(readConfig(
|
|
9141
|
+
if (home) setCurrentModel(readConfig(join17(home, ".config/opencode")));
|
|
9123
9142
|
}
|
|
9124
9143
|
if (!currentModel) setCurrentModel(process?.env?.OPENCODE_MODEL || "");
|
|
9125
9144
|
if (currentModel) {
|
|
9126
9145
|
setCurrentTier(classify(currentModel));
|
|
9127
9146
|
try {
|
|
9128
|
-
const _tiersData2 = safeJsonParse3(
|
|
9147
|
+
const _tiersData2 = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
9129
9148
|
const _activeSlot = _tiersData2?.selection?.active_slot || "brain";
|
|
9130
9149
|
if (_activeSlot === "brain") {
|
|
9131
9150
|
const _brainOcModel = _tiersData2?.trinity?.brain?.oc || "";
|
|
@@ -9150,7 +9169,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9150
9169
|
let _wasCorrupted = false;
|
|
9151
9170
|
if (existsSync15(TIERS_FILE2)) {
|
|
9152
9171
|
try {
|
|
9153
|
-
_tiersData2 = safeJsonParse3(
|
|
9172
|
+
_tiersData2 = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
9154
9173
|
} catch {
|
|
9155
9174
|
_tiersData2 = { selection: { enabled: true, active_slot: "brain", delegation_enforce: true, tdd_strict: true }, trinity: {} };
|
|
9156
9175
|
_wasCorrupted = true;
|
|
@@ -9226,7 +9245,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9226
9245
|
writeFileSync12(_tmp, JSON.stringify(_tiersData2, null, 2) + "\n", "utf-8");
|
|
9227
9246
|
renameSync6(_tmp, TIERS_FILE2);
|
|
9228
9247
|
console.error(`[vibeOS] auto-synced model-tiers.json: brain=${_brain.id} medium=${_tiersData2.trinity?.medium?.oc || ""} cheap=${_tiersData2.trinity?.cheap?.oc || ""}`);
|
|
9229
|
-
const _tiersCfg = safeJsonParse3(
|
|
9248
|
+
const _tiersCfg = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
9230
9249
|
const _b = _tiersCfg?.trinity?.brain?.oc;
|
|
9231
9250
|
const _m = _tiersCfg?.trinity?.medium?.oc;
|
|
9232
9251
|
const _c = _tiersCfg?.trinity?.cheap?.oc;
|
|
@@ -9243,7 +9262,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9243
9262
|
}
|
|
9244
9263
|
}
|
|
9245
9264
|
try {
|
|
9246
|
-
const _mt = safeJsonParse3(
|
|
9265
|
+
const _mt = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
9247
9266
|
if (_mt.selection && (_mt.selection.mcp_port === void 0 || _mt.selection.mcp_port === null)) {
|
|
9248
9267
|
_mt.selection.mcp_port = 9578;
|
|
9249
9268
|
const _tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
@@ -9281,7 +9300,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9281
9300
|
}
|
|
9282
9301
|
const _tiersData = (() => {
|
|
9283
9302
|
try {
|
|
9284
|
-
return safeJsonParse3(
|
|
9303
|
+
return safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
9285
9304
|
} catch {
|
|
9286
9305
|
return {};
|
|
9287
9306
|
}
|
|
@@ -9304,7 +9323,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9304
9323
|
latestUserIntent,
|
|
9305
9324
|
directory: directory3,
|
|
9306
9325
|
safeJsonParse: safeJsonParse3,
|
|
9307
|
-
readFileSync:
|
|
9326
|
+
readFileSync: readFileSync15,
|
|
9308
9327
|
writeFileSync: writeFileSync12,
|
|
9309
9328
|
existsSync: existsSync15,
|
|
9310
9329
|
renameSync: renameSync6,
|