vibeostheog 0.15.9 → 0.15.10
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 +6 -0
- package/package.json +1 -1
- package/src/index.js +91 -100
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## 0.15.10
|
|
2
|
+
- fix: prevent empty footer from message.updated blocking text.complete
|
|
3
|
+
- fix: prevent empty footer from message.updated blocking text.complete
|
|
4
|
+
- fix: deploy copies .env.production alongside plugin
|
|
5
|
+
|
|
6
|
+
|
|
1
7
|
## 0.15.9
|
|
2
8
|
- fix: VIBEOS_API_TOKEN lookup from __dirname, ~/.claude/, ~/, cwd/
|
|
3
9
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.10",
|
|
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
|
@@ -285,12 +285,12 @@ function recordFlowTodo({ filePath, content }) {
|
|
|
285
285
|
return 0;
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
|
-
var
|
|
288
|
+
var __dirname2, RULES_PATH, GUARD_AGENTS_TEMPLATE, GUARD_README_TEMPLATE, STATE_FILE, FLOW_TODO_FILE, FLOW_DEDUP_FILE, MAX_FLOW_TODOS, _flowWarnsSeen, _stateWriter, _cachedRules, _rulesMtime;
|
|
289
289
|
var init_flow_enforcer = __esm({
|
|
290
290
|
"src/vibeOS-lib/flow-enforcer.js"() {
|
|
291
291
|
"use strict";
|
|
292
|
-
|
|
293
|
-
RULES_PATH = join(
|
|
292
|
+
__dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
293
|
+
RULES_PATH = join(__dirname2, "flow-rules.json");
|
|
294
294
|
GUARD_AGENTS_TEMPLATE = [
|
|
295
295
|
"# AGENTS.md",
|
|
296
296
|
"",
|
|
@@ -345,7 +345,7 @@ var init_flow_enforcer = __esm({
|
|
|
345
345
|
// src/index.ts
|
|
346
346
|
init_flow_enforcer();
|
|
347
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
|
|
348
|
+
import { join as join16, dirname as dirname8, basename as basename9 } from "node:path";
|
|
349
349
|
|
|
350
350
|
// src/vibeOS-lib/session-metrics.js
|
|
351
351
|
function formatDuration(totalSeconds) {
|
|
@@ -3231,7 +3231,7 @@ function applySlot2(slot) {
|
|
|
3231
3231
|
|
|
3232
3232
|
// src/lib/turn-classify.js
|
|
3233
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
|
|
3234
|
+
import { join as join6, dirname as dirname5, basename as basename5 } from "node:path";
|
|
3235
3235
|
import { homedir as homedir6, tmpdir as tmpdir4 } from "node:os";
|
|
3236
3236
|
import { createHash as createHash3 } from "node:crypto";
|
|
3237
3237
|
|
|
@@ -3492,33 +3492,22 @@ var VibeOSNetworkError = class extends Error {
|
|
|
3492
3492
|
|
|
3493
3493
|
// src/lib/api-client.js
|
|
3494
3494
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
3495
|
-
import { join as join6 } from "node:path";
|
|
3496
3495
|
import { homedir as homedir5 } from "node:os";
|
|
3497
3496
|
var VIBEOS_API_URL = process.env.VIBEOS_API_URL || "https://api.vibetheog.com";
|
|
3498
|
-
var
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
3502
|
-
if (m) _envToken2 = m[1].trim();
|
|
3503
|
-
} catch {
|
|
3504
|
-
}
|
|
3505
|
-
if (!_envToken2) {
|
|
3497
|
+
var _envToken = "";
|
|
3498
|
+
var _searchDirs = [__dirname, homedir5() + "/.claude", homedir5(), process.cwd()];
|
|
3499
|
+
for (const dir of _searchDirs) {
|
|
3506
3500
|
try {
|
|
3507
|
-
const env = readFileSync5(
|
|
3501
|
+
const env = readFileSync5(dir + "/.env.production", "utf8");
|
|
3508
3502
|
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
3509
|
-
if (m)
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
}
|
|
3513
|
-
if (!_envToken2) {
|
|
3514
|
-
try {
|
|
3515
|
-
const env = readFileSync5(join6(homedir5(), ".claude", ".env.production"), "utf8");
|
|
3516
|
-
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
3517
|
-
if (m) _envToken2 = m[1].trim();
|
|
3503
|
+
if (m) {
|
|
3504
|
+
_envToken = m[1].trim();
|
|
3505
|
+
break;
|
|
3506
|
+
}
|
|
3518
3507
|
} catch {
|
|
3519
3508
|
}
|
|
3520
3509
|
}
|
|
3521
|
-
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN ||
|
|
3510
|
+
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN || _envToken || "";
|
|
3522
3511
|
var VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
3523
3512
|
var _apiClient = null;
|
|
3524
3513
|
var _apiFallbackMode = false;
|
|
@@ -3538,15 +3527,13 @@ function isApiFallback() {
|
|
|
3538
3527
|
}
|
|
3539
3528
|
async function remoteCall(method, args, fallbackFn) {
|
|
3540
3529
|
if (!VIBEOS_API_ENABLED || _apiFallbackMode) {
|
|
3541
|
-
if (fallbackFn)
|
|
3542
|
-
return fallbackFn();
|
|
3530
|
+
if (fallbackFn) return fallbackFn();
|
|
3543
3531
|
return null;
|
|
3544
3532
|
}
|
|
3545
3533
|
try {
|
|
3546
3534
|
const client2 = getApiClient();
|
|
3547
3535
|
if (!client2) {
|
|
3548
|
-
if (fallbackFn)
|
|
3549
|
-
return fallbackFn();
|
|
3536
|
+
if (fallbackFn) return fallbackFn();
|
|
3550
3537
|
return null;
|
|
3551
3538
|
}
|
|
3552
3539
|
const result = await client2[method](...args);
|
|
@@ -3557,13 +3544,13 @@ async function remoteCall(method, args, fallbackFn) {
|
|
|
3557
3544
|
if (!_apiFallbackMode) {
|
|
3558
3545
|
_apiFallbackMode = true;
|
|
3559
3546
|
_apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
3560
|
-
console.error(
|
|
3547
|
+
console.error("[vibeOS] API fallback activated: " + err.message);
|
|
3561
3548
|
}
|
|
3562
3549
|
if (fallbackFn) {
|
|
3563
3550
|
try {
|
|
3564
3551
|
return fallbackFn();
|
|
3565
3552
|
} catch (fe) {
|
|
3566
|
-
console.error(
|
|
3553
|
+
console.error("[vibeOS] fallback also failed: " + fe.message);
|
|
3567
3554
|
}
|
|
3568
3555
|
}
|
|
3569
3556
|
return null;
|
|
@@ -3775,11 +3762,11 @@ var USER_HOME4 = (() => {
|
|
|
3775
3762
|
return tmpdir4();
|
|
3776
3763
|
}
|
|
3777
3764
|
})();
|
|
3778
|
-
var FILE_LOCK_DIR3 =
|
|
3779
|
-
var BLACKBOX_STATE_FILE2 =
|
|
3780
|
-
var GLOBAL_LEARNING_FILE2 =
|
|
3781
|
-
var STATE_FILE3 =
|
|
3782
|
-
var PROJECT_STATE_FILE2 =
|
|
3765
|
+
var FILE_LOCK_DIR3 = join6(USER_HOME4, ".claude/.vibeOS-locks");
|
|
3766
|
+
var BLACKBOX_STATE_FILE2 = join6(USER_HOME4, ".claude/blackbox-state.json");
|
|
3767
|
+
var GLOBAL_LEARNING_FILE2 = join6(USER_HOME4, ".claude/global-learning.json");
|
|
3768
|
+
var STATE_FILE3 = join6(USER_HOME4, ".claude/delegation-state.json");
|
|
3769
|
+
var PROJECT_STATE_FILE2 = join6(USER_HOME4, ".claude/project-states.json");
|
|
3783
3770
|
var DFLT_GL2 = { exploratory_words: {}, task_first_words: {}, updatedAt: null };
|
|
3784
3771
|
var _blackboxTracker = null;
|
|
3785
3772
|
var _OC_SID2 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
@@ -3794,14 +3781,14 @@ var WARN_MAX_PER_SESSION = 3;
|
|
|
3794
3781
|
var WARN_COALESCE_THRESHOLD = 10;
|
|
3795
3782
|
var warnCoalesceCounters = /* @__PURE__ */ new Map();
|
|
3796
3783
|
function _handleStateCorruption4(path) {
|
|
3797
|
-
const backupDir =
|
|
3784
|
+
const backupDir = join6(USER_HOME4, ".claude", ".backups");
|
|
3798
3785
|
mkdirSync5(backupDir, { recursive: true });
|
|
3799
|
-
const backupPath =
|
|
3786
|
+
const backupPath = join6(backupDir, basename5(path) + ".corrupted." + Date.now());
|
|
3800
3787
|
try {
|
|
3801
3788
|
copyFileSync4(path, backupPath);
|
|
3802
3789
|
} catch {
|
|
3803
3790
|
}
|
|
3804
|
-
const logPath =
|
|
3791
|
+
const logPath = join6(USER_HOME4, ".claude", ".state-corruption-log.jsonl");
|
|
3805
3792
|
try {
|
|
3806
3793
|
appendFileSync5(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
3807
3794
|
} catch {
|
|
@@ -3809,7 +3796,7 @@ function _handleStateCorruption4(path) {
|
|
|
3809
3796
|
}
|
|
3810
3797
|
function _lockPathFor3(filePath) {
|
|
3811
3798
|
const hash = createHash3("sha1").update(String(filePath || "")).digest("hex");
|
|
3812
|
-
return
|
|
3799
|
+
return join6(FILE_LOCK_DIR3, `${hash}.lock`);
|
|
3813
3800
|
}
|
|
3814
3801
|
function withFileLock3(filePath, fn, opts = {}) {
|
|
3815
3802
|
const staleMs = Number(opts.staleMs || 3e4);
|
|
@@ -3872,7 +3859,7 @@ function readJsonOrEmpty2(filePath) {
|
|
|
3872
3859
|
}
|
|
3873
3860
|
function loadTrinityModels() {
|
|
3874
3861
|
try {
|
|
3875
|
-
const p =
|
|
3862
|
+
const p = join6(USER_HOME4, ".claude/model-tiers.json");
|
|
3876
3863
|
if (!existsSync6(p))
|
|
3877
3864
|
return { brain: "", cheap: "", medium: "" };
|
|
3878
3865
|
const j = safeJsonParse3(readFileSync6(p, "utf-8"));
|
|
@@ -4116,9 +4103,9 @@ function saveProjectState2(state) {
|
|
|
4116
4103
|
function detectTechStack2(dir) {
|
|
4117
4104
|
const stacks = [];
|
|
4118
4105
|
try {
|
|
4119
|
-
const pkg = safeJsonParse3(readFileSync6(
|
|
4106
|
+
const pkg = safeJsonParse3(readFileSync6(join6(dir, "package.json"), "utf-8"));
|
|
4120
4107
|
if (pkg) {
|
|
4121
|
-
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(
|
|
4108
|
+
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(join6(dir, "tsconfig.json")))
|
|
4122
4109
|
stacks.push("typescript");
|
|
4123
4110
|
if (pkg.dependencies?.react || pkg.devDependencies?.react)
|
|
4124
4111
|
stacks.push("react");
|
|
@@ -4127,21 +4114,21 @@ function detectTechStack2(dir) {
|
|
|
4127
4114
|
} catch {
|
|
4128
4115
|
}
|
|
4129
4116
|
try {
|
|
4130
|
-
if (existsSync6(
|
|
4117
|
+
if (existsSync6(join6(dir, "Cargo.toml")))
|
|
4131
4118
|
stacks.push("rust");
|
|
4132
4119
|
} catch {
|
|
4133
4120
|
}
|
|
4134
4121
|
try {
|
|
4135
|
-
if (existsSync6(
|
|
4122
|
+
if (existsSync6(join6(dir, "go.mod")))
|
|
4136
4123
|
stacks.push("go");
|
|
4137
4124
|
} catch {
|
|
4138
4125
|
}
|
|
4139
4126
|
try {
|
|
4140
|
-
if (existsSync6(
|
|
4127
|
+
if (existsSync6(join6(dir, "requirements.txt")))
|
|
4141
4128
|
stacks.push("python");
|
|
4142
|
-
if (existsSync6(
|
|
4129
|
+
if (existsSync6(join6(dir, "setup.py")))
|
|
4143
4130
|
stacks.push("python");
|
|
4144
|
-
if (existsSync6(
|
|
4131
|
+
if (existsSync6(join6(dir, "pyproject.toml")))
|
|
4145
4132
|
stacks.push("python");
|
|
4146
4133
|
} catch {
|
|
4147
4134
|
}
|
|
@@ -4250,7 +4237,7 @@ function saveOptimizationMode(mode) {
|
|
|
4250
4237
|
|
|
4251
4238
|
// src/lib/research-audit.js
|
|
4252
4239
|
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "node:fs";
|
|
4253
|
-
import { join as
|
|
4240
|
+
import { join as join7 } from "node:path";
|
|
4254
4241
|
import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
|
|
4255
4242
|
var USER_HOME5 = (() => {
|
|
4256
4243
|
try {
|
|
@@ -4260,19 +4247,19 @@ var USER_HOME5 = (() => {
|
|
|
4260
4247
|
}
|
|
4261
4248
|
})();
|
|
4262
4249
|
var _OC_SID3 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4263
|
-
var SCRATCHPAD_ROOT2 =
|
|
4264
|
-
var SCRATCHPAD_GLOBAL_DIR2 =
|
|
4265
|
-
var SCRATCHPAD_SESSIONS_DIR2 =
|
|
4266
|
-
var STATE_FILE4 =
|
|
4250
|
+
var SCRATCHPAD_ROOT2 = join7(USER_HOME5, ".claude/scratch");
|
|
4251
|
+
var SCRATCHPAD_GLOBAL_DIR2 = join7(SCRATCHPAD_ROOT2, "by-hash");
|
|
4252
|
+
var SCRATCHPAD_SESSIONS_DIR2 = join7(SCRATCHPAD_ROOT2, "sessions");
|
|
4253
|
+
var STATE_FILE4 = join7(USER_HOME5, ".claude/delegation-state.json");
|
|
4267
4254
|
var currentModel2 = null;
|
|
4268
4255
|
function getSessionRoot2() {
|
|
4269
|
-
return
|
|
4256
|
+
return join7(SCRATCHPAD_SESSIONS_DIR2, _OC_SID3);
|
|
4270
4257
|
}
|
|
4271
4258
|
function getSessionScratchpadDir2() {
|
|
4272
|
-
return
|
|
4259
|
+
return join7(getSessionRoot2(), "by-hash");
|
|
4273
4260
|
}
|
|
4274
4261
|
function getGlobalIndexPath2() {
|
|
4275
|
-
return
|
|
4262
|
+
return join7(SCRATCHPAD_ROOT2, "index.jsonl");
|
|
4276
4263
|
}
|
|
4277
4264
|
var FETCH_TOOLS = /* @__PURE__ */ new Set(["WebFetch", "WebSearch", "webfetch", "websearch"]);
|
|
4278
4265
|
function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
@@ -4295,8 +4282,8 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4295
4282
|
report.totalFetches++;
|
|
4296
4283
|
report.totalBytes += e.size || 0;
|
|
4297
4284
|
const hash = e.hash;
|
|
4298
|
-
const summaryPathSession =
|
|
4299
|
-
const summaryPathGlobal =
|
|
4285
|
+
const summaryPathSession = join7(getSessionScratchpadDir2(), hash + ".summary.txt");
|
|
4286
|
+
const summaryPathGlobal = join7(SCRATCHPAD_GLOBAL_DIR2, hash + ".summary.txt");
|
|
4300
4287
|
const summaryPath = existsSync7(summaryPathSession) ? summaryPathSession : summaryPathGlobal;
|
|
4301
4288
|
if (existsSync7(summaryPath)) {
|
|
4302
4289
|
const summary = readFileSync7(summaryPath, "utf-8").slice(0, 200);
|
|
@@ -4370,7 +4357,7 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4370
4357
|
|
|
4371
4358
|
// src/lib/reporting.js
|
|
4372
4359
|
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";
|
|
4373
|
-
import { join as
|
|
4360
|
+
import { join as join8, basename as basename6 } from "node:path";
|
|
4374
4361
|
import { homedir as homedir8, tmpdir as tmpdir6 } from "node:os";
|
|
4375
4362
|
var USER_HOME6 = (() => {
|
|
4376
4363
|
try {
|
|
@@ -4379,15 +4366,15 @@ var USER_HOME6 = (() => {
|
|
|
4379
4366
|
return tmpdir6();
|
|
4380
4367
|
}
|
|
4381
4368
|
})();
|
|
4382
|
-
var REPORTS_DIR2 =
|
|
4383
|
-
var REPORTS_INDEX =
|
|
4369
|
+
var REPORTS_DIR2 = join8(USER_HOME6, ".claude/reports");
|
|
4370
|
+
var REPORTS_INDEX = join8(REPORTS_DIR2, "index.json");
|
|
4384
4371
|
var _OC_SID4 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4385
4372
|
var currentProjectFingerprint3 = "";
|
|
4386
4373
|
var currentProjectName2 = "";
|
|
4387
4374
|
function _handleStateCorruption5(path) {
|
|
4388
|
-
const backupDir =
|
|
4375
|
+
const backupDir = join8(USER_HOME6, ".claude", ".backups");
|
|
4389
4376
|
mkdirSync6(backupDir, { recursive: true });
|
|
4390
|
-
const backupPath =
|
|
4377
|
+
const backupPath = join8(backupDir, basename6(path) + ".corrupted." + Date.now());
|
|
4391
4378
|
try {
|
|
4392
4379
|
copyFileSync5(path, backupPath);
|
|
4393
4380
|
} catch {
|
|
@@ -4457,7 +4444,7 @@ function _pruneReports() {
|
|
|
4457
4444
|
continue;
|
|
4458
4445
|
if (now - created > 90 * 24 * 3600 * 1e3) {
|
|
4459
4446
|
try {
|
|
4460
|
-
rmSync4(
|
|
4447
|
+
rmSync4(join8(REPORTS_DIR2, `${r.id}.json`));
|
|
4461
4448
|
} catch {
|
|
4462
4449
|
}
|
|
4463
4450
|
continue;
|
|
@@ -4528,7 +4515,7 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
4528
4515
|
try {
|
|
4529
4516
|
withFileLock(REPORTS_INDEX, () => {
|
|
4530
4517
|
mkdirSync6(REPORTS_DIR2, { recursive: true });
|
|
4531
|
-
writeFileSync6(
|
|
4518
|
+
writeFileSync6(join8(REPORTS_DIR2, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
4532
4519
|
const idx = reportsIndex();
|
|
4533
4520
|
const _sum = (summary || "").slice(0, 80);
|
|
4534
4521
|
idx.reports.push({ id: id2, type, project: report.meta.project, fingerprint: fp3, created: report.meta.created, summary: _sum });
|
|
@@ -4562,7 +4549,7 @@ function readReport(id2) {
|
|
|
4562
4549
|
return null;
|
|
4563
4550
|
if (!/^[\w-]+$/.test(String(id2)))
|
|
4564
4551
|
return null;
|
|
4565
|
-
const path =
|
|
4552
|
+
const path = join8(REPORTS_DIR2, `${id2}.json`);
|
|
4566
4553
|
try {
|
|
4567
4554
|
if (!existsSync8(path))
|
|
4568
4555
|
return null;
|
|
@@ -4574,7 +4561,7 @@ function readReport(id2) {
|
|
|
4574
4561
|
|
|
4575
4562
|
// src/lib/credit-api.js
|
|
4576
4563
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "node:fs";
|
|
4577
|
-
import { join as
|
|
4564
|
+
import { join as join9 } from "node:path";
|
|
4578
4565
|
function safeJsonParse4(raw) {
|
|
4579
4566
|
try {
|
|
4580
4567
|
return JSON.parse(raw);
|
|
@@ -4653,7 +4640,7 @@ function _cachedPct() {
|
|
|
4653
4640
|
return null;
|
|
4654
4641
|
let budget = 50;
|
|
4655
4642
|
try {
|
|
4656
|
-
const p =
|
|
4643
|
+
const p = join9(USER_HOME2, ".claude/model-tiers.json");
|
|
4657
4644
|
if (existsSync9(p)) {
|
|
4658
4645
|
const j = safeJsonParse4(readFileSync9(p, "utf-8"));
|
|
4659
4646
|
if (j?.selection?.monthly_budget_usd)
|
|
@@ -4686,7 +4673,7 @@ function loadCredit() {
|
|
|
4686
4673
|
return n;
|
|
4687
4674
|
}
|
|
4688
4675
|
try {
|
|
4689
|
-
const f =
|
|
4676
|
+
const f = join9(USER_HOME2, ".claude/credit-percent");
|
|
4690
4677
|
if (existsSync9(f)) {
|
|
4691
4678
|
const n = parseInt(readFileSync9(f, "utf-8").trim(), 10);
|
|
4692
4679
|
if (!isNaN(n))
|
|
@@ -4705,7 +4692,7 @@ function thinkingLevel(credit) {
|
|
|
4705
4692
|
}
|
|
4706
4693
|
|
|
4707
4694
|
// src/lib/trinity-tool.js
|
|
4708
|
-
import { join as
|
|
4695
|
+
import { join as join10 } from "node:path";
|
|
4709
4696
|
function createTrinityTool(deps) {
|
|
4710
4697
|
return {
|
|
4711
4698
|
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'.",
|
|
@@ -4960,7 +4947,7 @@ Lock is per-session (resets on restart).`;
|
|
|
4960
4947
|
const ok = deps.writeSelection("tdd_enforce", slot === "on");
|
|
4961
4948
|
return ok ? `\u2705 TDD enforcement ${slot === "on" ? "ENABLED (auto-create skeletons)" : "DISABLED (nudge only)"}` : `\u274C Failed to write model-tiers.json`;
|
|
4962
4949
|
}
|
|
4963
|
-
const stateFile =
|
|
4950
|
+
const stateFile = join10(deps.USER_HOME, ".claude/delegation-state.json");
|
|
4964
4951
|
let enforced = 0;
|
|
4965
4952
|
try {
|
|
4966
4953
|
if (deps.existsSync(stateFile)) {
|
|
@@ -5340,7 +5327,7 @@ ${L.repeat(40)}`);
|
|
|
5340
5327
|
}
|
|
5341
5328
|
if (action === "diagnose") {
|
|
5342
5329
|
const results = [];
|
|
5343
|
-
const ocConfig =
|
|
5330
|
+
const ocConfig = join10(deps.USER_HOME, ".config/opencode/opencode.json");
|
|
5344
5331
|
const checks = [
|
|
5345
5332
|
{ path: deps.TIERS_FILE, label: "model-tiers.json" },
|
|
5346
5333
|
{ path: ocConfig, label: "opencode.json" },
|
|
@@ -5512,7 +5499,7 @@ ${L.repeat(40)}`);
|
|
|
5512
5499
|
for (const r of idx.reports || []) {
|
|
5513
5500
|
if (r.project !== name || r.fingerprint !== dstFp)
|
|
5514
5501
|
continue;
|
|
5515
|
-
const rf =
|
|
5502
|
+
const rf = join10(deps.REPORTS_DIR, `${r.id}.json`);
|
|
5516
5503
|
try {
|
|
5517
5504
|
if (!deps.existsSync(rf))
|
|
5518
5505
|
continue;
|
|
@@ -5632,7 +5619,7 @@ ${L.repeat(40)}`);
|
|
|
5632
5619
|
|
|
5633
5620
|
// src/lib/trinity-rebuild.js
|
|
5634
5621
|
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "node:fs";
|
|
5635
|
-
import { join as
|
|
5622
|
+
import { join as join11 } from "node:path";
|
|
5636
5623
|
var MODEL_RANK = { high: 3, mid: 2, budget: 1 };
|
|
5637
5624
|
var OPENCODE_GO_CATALOG = [
|
|
5638
5625
|
"deepseek/deepseek-v4-flash",
|
|
@@ -5836,16 +5823,16 @@ async function probeModel(modelId, auth) {
|
|
|
5836
5823
|
|
|
5837
5824
|
// src/lib/hooks/footer.js
|
|
5838
5825
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
5839
|
-
import { join as
|
|
5826
|
+
import { join as join14 } from "node:path";
|
|
5840
5827
|
import { homedir as homedir9, tmpdir as tmpdir7 } from "node:os";
|
|
5841
5828
|
|
|
5842
5829
|
// src/lib/hooks/chat-transform.js
|
|
5843
5830
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5844
|
-
import { join as
|
|
5831
|
+
import { join as join13, basename as basename7 } from "node:path";
|
|
5845
5832
|
import { createHash as createHash4 } from "node:crypto";
|
|
5846
5833
|
|
|
5847
5834
|
// src/lib/index-helpers.js
|
|
5848
|
-
import { join as
|
|
5835
|
+
import { join as join12 } from "node:path";
|
|
5849
5836
|
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
5850
5837
|
|
|
5851
5838
|
// src/lib/text-compress.js
|
|
@@ -6180,7 +6167,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
6180
6167
|
try {
|
|
6181
6168
|
const sd = getSessionScratchpadDir();
|
|
6182
6169
|
if (sd) {
|
|
6183
|
-
const sp =
|
|
6170
|
+
const sp = join12(sd, "delegation-state-hint.txt");
|
|
6184
6171
|
try {
|
|
6185
6172
|
writeFileSync8(sp, JSON.stringify({ sid, total_savings: s.lifetime.total_savings_usd, last_reason: reason }), "utf8");
|
|
6186
6173
|
} catch {
|
|
@@ -6309,10 +6296,10 @@ function buildProjectBriefing(directory3) {
|
|
|
6309
6296
|
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
6310
6297
|
}
|
|
6311
6298
|
function ensureProjectSkill(dir, fp3) {
|
|
6312
|
-
const skillsDir =
|
|
6299
|
+
const skillsDir = join13(dir, ".opencode", "skills");
|
|
6313
6300
|
const projectName = basename7(dir);
|
|
6314
|
-
const skillDir =
|
|
6315
|
-
const skillPath =
|
|
6301
|
+
const skillDir = join13(skillsDir, projectName);
|
|
6302
|
+
const skillPath = join13(skillDir, "SKILL.md");
|
|
6316
6303
|
if (existsSync11(skillPath)) {
|
|
6317
6304
|
return { created: false, skipped: true, path: skillPath };
|
|
6318
6305
|
}
|
|
@@ -6469,7 +6456,7 @@ var onMessagesTransform = async (_input, output) => {
|
|
|
6469
6456
|
const hash = createHash4("sha256").update(`tool_result
|
|
6470
6457
|
${raw}
|
|
6471
6458
|
`).digest("hex").slice(0, 16);
|
|
6472
|
-
const fullPath =
|
|
6459
|
+
const fullPath = join13(getSessionScratchpadDir(), `${hash}.txt`);
|
|
6473
6460
|
try {
|
|
6474
6461
|
ensureSessionScratchpadDirs();
|
|
6475
6462
|
if (!existsSync11(fullPath)) {
|
|
@@ -6741,14 +6728,14 @@ var USER_HOME7 = (() => {
|
|
|
6741
6728
|
return tmpdir7();
|
|
6742
6729
|
}
|
|
6743
6730
|
})();
|
|
6744
|
-
var STATE_FILE5 =
|
|
6745
|
-
var SAVINGS_LEDGER_FILE2 =
|
|
6731
|
+
var STATE_FILE5 = join14(USER_HOME7, ".claude/delegation-state.json");
|
|
6732
|
+
var SAVINGS_LEDGER_FILE2 = join14(USER_HOME7, ".claude/savings-ledger.jsonl");
|
|
6746
6733
|
var _prevOutputText = "";
|
|
6747
6734
|
var _autoReportCount = 0;
|
|
6748
6735
|
var textCompletePainted = /* @__PURE__ */ new Set();
|
|
6749
6736
|
function loadSelection3() {
|
|
6750
6737
|
try {
|
|
6751
|
-
const raw = readFileSync12(
|
|
6738
|
+
const raw = readFileSync12(join14(USER_HOME7, ".claude/model-tiers.json"), "utf-8");
|
|
6752
6739
|
return safeJsonParse3(raw)?.selection || { active_slot: "medium", enabled: true, delegation_enforce: false, flow_enabled: false, flow_enforce: false, tdd_enforce: false, tdd_strict: false };
|
|
6753
6740
|
} catch {
|
|
6754
6741
|
return { active_slot: "medium", enabled: true, delegation_enforce: false, flow_enabled: false, flow_enforce: false, tdd_enforce: false, tdd_strict: false };
|
|
@@ -6826,6 +6813,10 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6826
6813
|
if (messageID && textCompletePainted.has(messageID))
|
|
6827
6814
|
return;
|
|
6828
6815
|
const text = typeof output?.text === "string" ? output.text : typeof output?.result === "string" ? output.result : typeof output?.content === "string" ? output.content : "";
|
|
6816
|
+
if (!text || text.length < 50) {
|
|
6817
|
+
if (messageID) textCompletePainted.add(messageID);
|
|
6818
|
+
return;
|
|
6819
|
+
}
|
|
6829
6820
|
const { ltTasks, ltCache, ltCost, count, sesTasks, sesEdit, sesCredit, sesC7, sesQuota, sesCache, sesTaskDelegations, sesDuration, sesRatePerHour, sesTrend, sesToolBreakdown, sesModelTurns, quality_avg } = readLifetimeSavings2();
|
|
6830
6821
|
const sessionSlot = loadSessionSlot(_OC_SID6);
|
|
6831
6822
|
const slot = sessionSlot || loadSelection3().active_slot || "brain";
|
|
@@ -6988,7 +6979,7 @@ init_flow_enforcer();
|
|
|
6988
6979
|
|
|
6989
6980
|
// src/lib/tdd-enforcer.js
|
|
6990
6981
|
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";
|
|
6991
|
-
import { join as
|
|
6982
|
+
import { join as join15, dirname as dirname6 } from "node:path";
|
|
6992
6983
|
import { createHash as createHash5 } from "node:crypto";
|
|
6993
6984
|
|
|
6994
6985
|
// src/utils/tdd-helpers.js
|
|
@@ -8027,7 +8018,7 @@ function _detectTestFramework() {
|
|
|
8027
8018
|
let testExt = null;
|
|
8028
8019
|
try {
|
|
8029
8020
|
const root = directory || process.cwd();
|
|
8030
|
-
const pkgPath =
|
|
8021
|
+
const pkgPath = join15(root, "package.json");
|
|
8031
8022
|
if (existsSync12(pkgPath)) {
|
|
8032
8023
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
8033
8024
|
const testScript = String(pkg?.scripts?.test || "");
|
|
@@ -8049,12 +8040,12 @@ function _detectTestFramework() {
|
|
|
8049
8040
|
if (!framework) {
|
|
8050
8041
|
const testDirs = ["src/tests", "tests", "test", "__tests__"];
|
|
8051
8042
|
for (const td of testDirs) {
|
|
8052
|
-
const dirPath =
|
|
8043
|
+
const dirPath = join15(root, td);
|
|
8053
8044
|
if (!existsSync12(dirPath))
|
|
8054
8045
|
continue;
|
|
8055
8046
|
const files = readdirSync2(dirPath).filter((f) => /\.test\./.test(f) || /\.spec\./.test(f));
|
|
8056
8047
|
if (files.length > 0) {
|
|
8057
|
-
const content = readFileSync13(
|
|
8048
|
+
const content = readFileSync13(join15(dirPath, files[0]), "utf-8");
|
|
8058
8049
|
if (/from\s+['"]node:test['"]/.test(content)) {
|
|
8059
8050
|
framework = "node-test";
|
|
8060
8051
|
testExt = files[0].split(".").pop();
|
|
@@ -8080,16 +8071,16 @@ function _detectTestFramework() {
|
|
|
8080
8071
|
console.error(`[vibeOS] [tdd] detected test framework: ${framework || "default"} (ext: ${testExt || "match source"})`);
|
|
8081
8072
|
return _detectedFramework;
|
|
8082
8073
|
}
|
|
8083
|
-
var ENFORCEMENT_LOCK_DIR =
|
|
8074
|
+
var ENFORCEMENT_LOCK_DIR = join15(USER_HOME2, ".claude/.enforcement-lock");
|
|
8084
8075
|
var LOCK_EXPIRE_MS = 3e4;
|
|
8085
|
-
var ENFORCEMENT_COOLDOWN_FILE2 =
|
|
8076
|
+
var ENFORCEMENT_COOLDOWN_FILE2 = join15(USER_HOME2, ".claude/.enforcement-cooldown.jsonl");
|
|
8086
8077
|
var COOLDOWN_MS = 6e4;
|
|
8087
8078
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
8088
8079
|
function _acquireLock(testPath) {
|
|
8089
8080
|
try {
|
|
8090
8081
|
mkdirSync8(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
8091
8082
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8092
|
-
const lockPath =
|
|
8083
|
+
const lockPath = join15(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8093
8084
|
try {
|
|
8094
8085
|
openSync4(lockPath, "wx");
|
|
8095
8086
|
return true;
|
|
@@ -8117,7 +8108,7 @@ function _acquireLock(testPath) {
|
|
|
8117
8108
|
function _releaseLock(testPath) {
|
|
8118
8109
|
try {
|
|
8119
8110
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8120
|
-
const lockPath =
|
|
8111
|
+
const lockPath = join15(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8121
8112
|
rmSync5(lockPath);
|
|
8122
8113
|
} catch {
|
|
8123
8114
|
}
|
|
@@ -8903,15 +8894,15 @@ var _mcpServerRuntime = null;
|
|
|
8903
8894
|
var _mcpServerHooked = false;
|
|
8904
8895
|
function _loadOpenCodeProviders() {
|
|
8905
8896
|
try {
|
|
8906
|
-
const cfg = _readOpenCodeConfigObject(
|
|
8897
|
+
const cfg = _readOpenCodeConfigObject(join16(USER_HOME2, ".config", "opencode"));
|
|
8907
8898
|
return cfg?.provider || {};
|
|
8908
8899
|
} catch {
|
|
8909
8900
|
return {};
|
|
8910
8901
|
}
|
|
8911
8902
|
}
|
|
8912
8903
|
function _readOpenCodeConfigObject(dir) {
|
|
8913
|
-
const jsonPath =
|
|
8914
|
-
const jsoncPath =
|
|
8904
|
+
const jsonPath = join16(dir, "opencode.json");
|
|
8905
|
+
const jsoncPath = join16(dir, "opencode.jsonc");
|
|
8915
8906
|
if (existsSync15(jsonPath)) return safeJsonParse3(readFileSync15(jsonPath, "utf-8"));
|
|
8916
8907
|
if (existsSync15(jsoncPath)) return _parseJsonc(readFileSync15(jsoncPath, "utf-8"));
|
|
8917
8908
|
return {};
|
|
@@ -8939,9 +8930,9 @@ function _modelTier2(id2) {
|
|
|
8939
8930
|
function backupFile(path, label) {
|
|
8940
8931
|
try {
|
|
8941
8932
|
if (!existsSync15(path)) return null;
|
|
8942
|
-
const bkDir =
|
|
8933
|
+
const bkDir = join16(USER_HOME2, ".claude", ".backups");
|
|
8943
8934
|
mkdirSync10(bkDir, { recursive: true });
|
|
8944
|
-
const bk =
|
|
8935
|
+
const bk = join16(bkDir, `${basename9(path)}.${label}.${Date.now()}.bak`);
|
|
8945
8936
|
copyFileSync6(path, bk);
|
|
8946
8937
|
return bk;
|
|
8947
8938
|
} catch {
|
|
@@ -8950,7 +8941,7 @@ function backupFile(path, label) {
|
|
|
8950
8941
|
}
|
|
8951
8942
|
function readPackageVersion() {
|
|
8952
8943
|
try {
|
|
8953
|
-
const pkg = safeJsonParse3(readFileSync15(
|
|
8944
|
+
const pkg = safeJsonParse3(readFileSync15(join16(process.cwd(), "package.json"), "utf-8"));
|
|
8954
8945
|
return String(pkg?.version || "");
|
|
8955
8946
|
} catch {
|
|
8956
8947
|
return "";
|
|
@@ -9146,7 +9137,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9146
9137
|
setCurrentModel(readConfig(directory3));
|
|
9147
9138
|
if (!currentModel) {
|
|
9148
9139
|
const home = process.env.HOME || "";
|
|
9149
|
-
if (home) setCurrentModel(readConfig(
|
|
9140
|
+
if (home) setCurrentModel(readConfig(join16(home, ".config/opencode")));
|
|
9150
9141
|
}
|
|
9151
9142
|
if (!currentModel) setCurrentModel(process?.env?.OPENCODE_MODEL || "");
|
|
9152
9143
|
if (currentModel) {
|