vibeostheog 0.15.8 → 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 +10 -0
- package/package.json +1 -1
- package/src/index.js +91 -92
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
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
|
+
|
|
7
|
+
## 0.15.9
|
|
8
|
+
- fix: VIBEOS_API_TOKEN lookup from __dirname, ~/.claude/, ~/, cwd/
|
|
9
|
+
|
|
10
|
+
|
|
1
11
|
## 0.15.8
|
|
2
12
|
- fix: load VIBEOS_API_TOKEN from .env.production if env var not set
|
|
3
13
|
|
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,25 +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)
|
|
3503
|
+
if (m) {
|
|
3504
|
+
_envToken = m[1].trim();
|
|
3505
|
+
break;
|
|
3506
|
+
}
|
|
3510
3507
|
} catch {
|
|
3511
3508
|
}
|
|
3512
3509
|
}
|
|
3513
|
-
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN ||
|
|
3510
|
+
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN || _envToken || "";
|
|
3514
3511
|
var VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
3515
3512
|
var _apiClient = null;
|
|
3516
3513
|
var _apiFallbackMode = false;
|
|
@@ -3530,15 +3527,13 @@ function isApiFallback() {
|
|
|
3530
3527
|
}
|
|
3531
3528
|
async function remoteCall(method, args, fallbackFn) {
|
|
3532
3529
|
if (!VIBEOS_API_ENABLED || _apiFallbackMode) {
|
|
3533
|
-
if (fallbackFn)
|
|
3534
|
-
return fallbackFn();
|
|
3530
|
+
if (fallbackFn) return fallbackFn();
|
|
3535
3531
|
return null;
|
|
3536
3532
|
}
|
|
3537
3533
|
try {
|
|
3538
3534
|
const client2 = getApiClient();
|
|
3539
3535
|
if (!client2) {
|
|
3540
|
-
if (fallbackFn)
|
|
3541
|
-
return fallbackFn();
|
|
3536
|
+
if (fallbackFn) return fallbackFn();
|
|
3542
3537
|
return null;
|
|
3543
3538
|
}
|
|
3544
3539
|
const result = await client2[method](...args);
|
|
@@ -3549,13 +3544,13 @@ async function remoteCall(method, args, fallbackFn) {
|
|
|
3549
3544
|
if (!_apiFallbackMode) {
|
|
3550
3545
|
_apiFallbackMode = true;
|
|
3551
3546
|
_apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
3552
|
-
console.error(
|
|
3547
|
+
console.error("[vibeOS] API fallback activated: " + err.message);
|
|
3553
3548
|
}
|
|
3554
3549
|
if (fallbackFn) {
|
|
3555
3550
|
try {
|
|
3556
3551
|
return fallbackFn();
|
|
3557
3552
|
} catch (fe) {
|
|
3558
|
-
console.error(
|
|
3553
|
+
console.error("[vibeOS] fallback also failed: " + fe.message);
|
|
3559
3554
|
}
|
|
3560
3555
|
}
|
|
3561
3556
|
return null;
|
|
@@ -3767,11 +3762,11 @@ var USER_HOME4 = (() => {
|
|
|
3767
3762
|
return tmpdir4();
|
|
3768
3763
|
}
|
|
3769
3764
|
})();
|
|
3770
|
-
var FILE_LOCK_DIR3 =
|
|
3771
|
-
var BLACKBOX_STATE_FILE2 =
|
|
3772
|
-
var GLOBAL_LEARNING_FILE2 =
|
|
3773
|
-
var STATE_FILE3 =
|
|
3774
|
-
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");
|
|
3775
3770
|
var DFLT_GL2 = { exploratory_words: {}, task_first_words: {}, updatedAt: null };
|
|
3776
3771
|
var _blackboxTracker = null;
|
|
3777
3772
|
var _OC_SID2 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
@@ -3786,14 +3781,14 @@ var WARN_MAX_PER_SESSION = 3;
|
|
|
3786
3781
|
var WARN_COALESCE_THRESHOLD = 10;
|
|
3787
3782
|
var warnCoalesceCounters = /* @__PURE__ */ new Map();
|
|
3788
3783
|
function _handleStateCorruption4(path) {
|
|
3789
|
-
const backupDir =
|
|
3784
|
+
const backupDir = join6(USER_HOME4, ".claude", ".backups");
|
|
3790
3785
|
mkdirSync5(backupDir, { recursive: true });
|
|
3791
|
-
const backupPath =
|
|
3786
|
+
const backupPath = join6(backupDir, basename5(path) + ".corrupted." + Date.now());
|
|
3792
3787
|
try {
|
|
3793
3788
|
copyFileSync4(path, backupPath);
|
|
3794
3789
|
} catch {
|
|
3795
3790
|
}
|
|
3796
|
-
const logPath =
|
|
3791
|
+
const logPath = join6(USER_HOME4, ".claude", ".state-corruption-log.jsonl");
|
|
3797
3792
|
try {
|
|
3798
3793
|
appendFileSync5(logPath, JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), path, backup: backupPath }) + "\n");
|
|
3799
3794
|
} catch {
|
|
@@ -3801,7 +3796,7 @@ function _handleStateCorruption4(path) {
|
|
|
3801
3796
|
}
|
|
3802
3797
|
function _lockPathFor3(filePath) {
|
|
3803
3798
|
const hash = createHash3("sha1").update(String(filePath || "")).digest("hex");
|
|
3804
|
-
return
|
|
3799
|
+
return join6(FILE_LOCK_DIR3, `${hash}.lock`);
|
|
3805
3800
|
}
|
|
3806
3801
|
function withFileLock3(filePath, fn, opts = {}) {
|
|
3807
3802
|
const staleMs = Number(opts.staleMs || 3e4);
|
|
@@ -3864,7 +3859,7 @@ function readJsonOrEmpty2(filePath) {
|
|
|
3864
3859
|
}
|
|
3865
3860
|
function loadTrinityModels() {
|
|
3866
3861
|
try {
|
|
3867
|
-
const p =
|
|
3862
|
+
const p = join6(USER_HOME4, ".claude/model-tiers.json");
|
|
3868
3863
|
if (!existsSync6(p))
|
|
3869
3864
|
return { brain: "", cheap: "", medium: "" };
|
|
3870
3865
|
const j = safeJsonParse3(readFileSync6(p, "utf-8"));
|
|
@@ -4108,9 +4103,9 @@ function saveProjectState2(state) {
|
|
|
4108
4103
|
function detectTechStack2(dir) {
|
|
4109
4104
|
const stacks = [];
|
|
4110
4105
|
try {
|
|
4111
|
-
const pkg = safeJsonParse3(readFileSync6(
|
|
4106
|
+
const pkg = safeJsonParse3(readFileSync6(join6(dir, "package.json"), "utf-8"));
|
|
4112
4107
|
if (pkg) {
|
|
4113
|
-
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(
|
|
4108
|
+
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync6(join6(dir, "tsconfig.json")))
|
|
4114
4109
|
stacks.push("typescript");
|
|
4115
4110
|
if (pkg.dependencies?.react || pkg.devDependencies?.react)
|
|
4116
4111
|
stacks.push("react");
|
|
@@ -4119,21 +4114,21 @@ function detectTechStack2(dir) {
|
|
|
4119
4114
|
} catch {
|
|
4120
4115
|
}
|
|
4121
4116
|
try {
|
|
4122
|
-
if (existsSync6(
|
|
4117
|
+
if (existsSync6(join6(dir, "Cargo.toml")))
|
|
4123
4118
|
stacks.push("rust");
|
|
4124
4119
|
} catch {
|
|
4125
4120
|
}
|
|
4126
4121
|
try {
|
|
4127
|
-
if (existsSync6(
|
|
4122
|
+
if (existsSync6(join6(dir, "go.mod")))
|
|
4128
4123
|
stacks.push("go");
|
|
4129
4124
|
} catch {
|
|
4130
4125
|
}
|
|
4131
4126
|
try {
|
|
4132
|
-
if (existsSync6(
|
|
4127
|
+
if (existsSync6(join6(dir, "requirements.txt")))
|
|
4133
4128
|
stacks.push("python");
|
|
4134
|
-
if (existsSync6(
|
|
4129
|
+
if (existsSync6(join6(dir, "setup.py")))
|
|
4135
4130
|
stacks.push("python");
|
|
4136
|
-
if (existsSync6(
|
|
4131
|
+
if (existsSync6(join6(dir, "pyproject.toml")))
|
|
4137
4132
|
stacks.push("python");
|
|
4138
4133
|
} catch {
|
|
4139
4134
|
}
|
|
@@ -4242,7 +4237,7 @@ function saveOptimizationMode(mode) {
|
|
|
4242
4237
|
|
|
4243
4238
|
// src/lib/research-audit.js
|
|
4244
4239
|
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "node:fs";
|
|
4245
|
-
import { join as
|
|
4240
|
+
import { join as join7 } from "node:path";
|
|
4246
4241
|
import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
|
|
4247
4242
|
var USER_HOME5 = (() => {
|
|
4248
4243
|
try {
|
|
@@ -4252,19 +4247,19 @@ var USER_HOME5 = (() => {
|
|
|
4252
4247
|
}
|
|
4253
4248
|
})();
|
|
4254
4249
|
var _OC_SID3 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4255
|
-
var SCRATCHPAD_ROOT2 =
|
|
4256
|
-
var SCRATCHPAD_GLOBAL_DIR2 =
|
|
4257
|
-
var SCRATCHPAD_SESSIONS_DIR2 =
|
|
4258
|
-
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");
|
|
4259
4254
|
var currentModel2 = null;
|
|
4260
4255
|
function getSessionRoot2() {
|
|
4261
|
-
return
|
|
4256
|
+
return join7(SCRATCHPAD_SESSIONS_DIR2, _OC_SID3);
|
|
4262
4257
|
}
|
|
4263
4258
|
function getSessionScratchpadDir2() {
|
|
4264
|
-
return
|
|
4259
|
+
return join7(getSessionRoot2(), "by-hash");
|
|
4265
4260
|
}
|
|
4266
4261
|
function getGlobalIndexPath2() {
|
|
4267
|
-
return
|
|
4262
|
+
return join7(SCRATCHPAD_ROOT2, "index.jsonl");
|
|
4268
4263
|
}
|
|
4269
4264
|
var FETCH_TOOLS = /* @__PURE__ */ new Set(["WebFetch", "WebSearch", "webfetch", "websearch"]);
|
|
4270
4265
|
function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
@@ -4287,8 +4282,8 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4287
4282
|
report.totalFetches++;
|
|
4288
4283
|
report.totalBytes += e.size || 0;
|
|
4289
4284
|
const hash = e.hash;
|
|
4290
|
-
const summaryPathSession =
|
|
4291
|
-
const summaryPathGlobal =
|
|
4285
|
+
const summaryPathSession = join7(getSessionScratchpadDir2(), hash + ".summary.txt");
|
|
4286
|
+
const summaryPathGlobal = join7(SCRATCHPAD_GLOBAL_DIR2, hash + ".summary.txt");
|
|
4292
4287
|
const summaryPath = existsSync7(summaryPathSession) ? summaryPathSession : summaryPathGlobal;
|
|
4293
4288
|
if (existsSync7(summaryPath)) {
|
|
4294
4289
|
const summary = readFileSync7(summaryPath, "utf-8").slice(0, 200);
|
|
@@ -4362,7 +4357,7 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
4362
4357
|
|
|
4363
4358
|
// src/lib/reporting.js
|
|
4364
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";
|
|
4365
|
-
import { join as
|
|
4360
|
+
import { join as join8, basename as basename6 } from "node:path";
|
|
4366
4361
|
import { homedir as homedir8, tmpdir as tmpdir6 } from "node:os";
|
|
4367
4362
|
var USER_HOME6 = (() => {
|
|
4368
4363
|
try {
|
|
@@ -4371,15 +4366,15 @@ var USER_HOME6 = (() => {
|
|
|
4371
4366
|
return tmpdir6();
|
|
4372
4367
|
}
|
|
4373
4368
|
})();
|
|
4374
|
-
var REPORTS_DIR2 =
|
|
4375
|
-
var REPORTS_INDEX =
|
|
4369
|
+
var REPORTS_DIR2 = join8(USER_HOME6, ".claude/reports");
|
|
4370
|
+
var REPORTS_INDEX = join8(REPORTS_DIR2, "index.json");
|
|
4376
4371
|
var _OC_SID4 = "opencode-" + (process.pid || "x") + "-" + Date.now();
|
|
4377
4372
|
var currentProjectFingerprint3 = "";
|
|
4378
4373
|
var currentProjectName2 = "";
|
|
4379
4374
|
function _handleStateCorruption5(path) {
|
|
4380
|
-
const backupDir =
|
|
4375
|
+
const backupDir = join8(USER_HOME6, ".claude", ".backups");
|
|
4381
4376
|
mkdirSync6(backupDir, { recursive: true });
|
|
4382
|
-
const backupPath =
|
|
4377
|
+
const backupPath = join8(backupDir, basename6(path) + ".corrupted." + Date.now());
|
|
4383
4378
|
try {
|
|
4384
4379
|
copyFileSync5(path, backupPath);
|
|
4385
4380
|
} catch {
|
|
@@ -4449,7 +4444,7 @@ function _pruneReports() {
|
|
|
4449
4444
|
continue;
|
|
4450
4445
|
if (now - created > 90 * 24 * 3600 * 1e3) {
|
|
4451
4446
|
try {
|
|
4452
|
-
rmSync4(
|
|
4447
|
+
rmSync4(join8(REPORTS_DIR2, `${r.id}.json`));
|
|
4453
4448
|
} catch {
|
|
4454
4449
|
}
|
|
4455
4450
|
continue;
|
|
@@ -4520,7 +4515,7 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
4520
4515
|
try {
|
|
4521
4516
|
withFileLock(REPORTS_INDEX, () => {
|
|
4522
4517
|
mkdirSync6(REPORTS_DIR2, { recursive: true });
|
|
4523
|
-
writeFileSync6(
|
|
4518
|
+
writeFileSync6(join8(REPORTS_DIR2, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
4524
4519
|
const idx = reportsIndex();
|
|
4525
4520
|
const _sum = (summary || "").slice(0, 80);
|
|
4526
4521
|
idx.reports.push({ id: id2, type, project: report.meta.project, fingerprint: fp3, created: report.meta.created, summary: _sum });
|
|
@@ -4554,7 +4549,7 @@ function readReport(id2) {
|
|
|
4554
4549
|
return null;
|
|
4555
4550
|
if (!/^[\w-]+$/.test(String(id2)))
|
|
4556
4551
|
return null;
|
|
4557
|
-
const path =
|
|
4552
|
+
const path = join8(REPORTS_DIR2, `${id2}.json`);
|
|
4558
4553
|
try {
|
|
4559
4554
|
if (!existsSync8(path))
|
|
4560
4555
|
return null;
|
|
@@ -4566,7 +4561,7 @@ function readReport(id2) {
|
|
|
4566
4561
|
|
|
4567
4562
|
// src/lib/credit-api.js
|
|
4568
4563
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync9 } from "node:fs";
|
|
4569
|
-
import { join as
|
|
4564
|
+
import { join as join9 } from "node:path";
|
|
4570
4565
|
function safeJsonParse4(raw) {
|
|
4571
4566
|
try {
|
|
4572
4567
|
return JSON.parse(raw);
|
|
@@ -4645,7 +4640,7 @@ function _cachedPct() {
|
|
|
4645
4640
|
return null;
|
|
4646
4641
|
let budget = 50;
|
|
4647
4642
|
try {
|
|
4648
|
-
const p =
|
|
4643
|
+
const p = join9(USER_HOME2, ".claude/model-tiers.json");
|
|
4649
4644
|
if (existsSync9(p)) {
|
|
4650
4645
|
const j = safeJsonParse4(readFileSync9(p, "utf-8"));
|
|
4651
4646
|
if (j?.selection?.monthly_budget_usd)
|
|
@@ -4678,7 +4673,7 @@ function loadCredit() {
|
|
|
4678
4673
|
return n;
|
|
4679
4674
|
}
|
|
4680
4675
|
try {
|
|
4681
|
-
const f =
|
|
4676
|
+
const f = join9(USER_HOME2, ".claude/credit-percent");
|
|
4682
4677
|
if (existsSync9(f)) {
|
|
4683
4678
|
const n = parseInt(readFileSync9(f, "utf-8").trim(), 10);
|
|
4684
4679
|
if (!isNaN(n))
|
|
@@ -4697,7 +4692,7 @@ function thinkingLevel(credit) {
|
|
|
4697
4692
|
}
|
|
4698
4693
|
|
|
4699
4694
|
// src/lib/trinity-tool.js
|
|
4700
|
-
import { join as
|
|
4695
|
+
import { join as join10 } from "node:path";
|
|
4701
4696
|
function createTrinityTool(deps) {
|
|
4702
4697
|
return {
|
|
4703
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'.",
|
|
@@ -4952,7 +4947,7 @@ Lock is per-session (resets on restart).`;
|
|
|
4952
4947
|
const ok = deps.writeSelection("tdd_enforce", slot === "on");
|
|
4953
4948
|
return ok ? `\u2705 TDD enforcement ${slot === "on" ? "ENABLED (auto-create skeletons)" : "DISABLED (nudge only)"}` : `\u274C Failed to write model-tiers.json`;
|
|
4954
4949
|
}
|
|
4955
|
-
const stateFile =
|
|
4950
|
+
const stateFile = join10(deps.USER_HOME, ".claude/delegation-state.json");
|
|
4956
4951
|
let enforced = 0;
|
|
4957
4952
|
try {
|
|
4958
4953
|
if (deps.existsSync(stateFile)) {
|
|
@@ -5332,7 +5327,7 @@ ${L.repeat(40)}`);
|
|
|
5332
5327
|
}
|
|
5333
5328
|
if (action === "diagnose") {
|
|
5334
5329
|
const results = [];
|
|
5335
|
-
const ocConfig =
|
|
5330
|
+
const ocConfig = join10(deps.USER_HOME, ".config/opencode/opencode.json");
|
|
5336
5331
|
const checks = [
|
|
5337
5332
|
{ path: deps.TIERS_FILE, label: "model-tiers.json" },
|
|
5338
5333
|
{ path: ocConfig, label: "opencode.json" },
|
|
@@ -5504,7 +5499,7 @@ ${L.repeat(40)}`);
|
|
|
5504
5499
|
for (const r of idx.reports || []) {
|
|
5505
5500
|
if (r.project !== name || r.fingerprint !== dstFp)
|
|
5506
5501
|
continue;
|
|
5507
|
-
const rf =
|
|
5502
|
+
const rf = join10(deps.REPORTS_DIR, `${r.id}.json`);
|
|
5508
5503
|
try {
|
|
5509
5504
|
if (!deps.existsSync(rf))
|
|
5510
5505
|
continue;
|
|
@@ -5624,7 +5619,7 @@ ${L.repeat(40)}`);
|
|
|
5624
5619
|
|
|
5625
5620
|
// src/lib/trinity-rebuild.js
|
|
5626
5621
|
import { readFileSync as readFileSync10, existsSync as existsSync10 } from "node:fs";
|
|
5627
|
-
import { join as
|
|
5622
|
+
import { join as join11 } from "node:path";
|
|
5628
5623
|
var MODEL_RANK = { high: 3, mid: 2, budget: 1 };
|
|
5629
5624
|
var OPENCODE_GO_CATALOG = [
|
|
5630
5625
|
"deepseek/deepseek-v4-flash",
|
|
@@ -5828,16 +5823,16 @@ async function probeModel(modelId, auth) {
|
|
|
5828
5823
|
|
|
5829
5824
|
// src/lib/hooks/footer.js
|
|
5830
5825
|
import { readFileSync as readFileSync12 } from "node:fs";
|
|
5831
|
-
import { join as
|
|
5826
|
+
import { join as join14 } from "node:path";
|
|
5832
5827
|
import { homedir as homedir9, tmpdir as tmpdir7 } from "node:os";
|
|
5833
5828
|
|
|
5834
5829
|
// src/lib/hooks/chat-transform.js
|
|
5835
5830
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, existsSync as existsSync11, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5836
|
-
import { join as
|
|
5831
|
+
import { join as join13, basename as basename7 } from "node:path";
|
|
5837
5832
|
import { createHash as createHash4 } from "node:crypto";
|
|
5838
5833
|
|
|
5839
5834
|
// src/lib/index-helpers.js
|
|
5840
|
-
import { join as
|
|
5835
|
+
import { join as join12 } from "node:path";
|
|
5841
5836
|
import { writeFileSync as writeFileSync8 } from "node:fs";
|
|
5842
5837
|
|
|
5843
5838
|
// src/lib/text-compress.js
|
|
@@ -6172,7 +6167,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
6172
6167
|
try {
|
|
6173
6168
|
const sd = getSessionScratchpadDir();
|
|
6174
6169
|
if (sd) {
|
|
6175
|
-
const sp =
|
|
6170
|
+
const sp = join12(sd, "delegation-state-hint.txt");
|
|
6176
6171
|
try {
|
|
6177
6172
|
writeFileSync8(sp, JSON.stringify({ sid, total_savings: s.lifetime.total_savings_usd, last_reason: reason }), "utf8");
|
|
6178
6173
|
} catch {
|
|
@@ -6301,10 +6296,10 @@ function buildProjectBriefing(directory3) {
|
|
|
6301
6296
|
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
6302
6297
|
}
|
|
6303
6298
|
function ensureProjectSkill(dir, fp3) {
|
|
6304
|
-
const skillsDir =
|
|
6299
|
+
const skillsDir = join13(dir, ".opencode", "skills");
|
|
6305
6300
|
const projectName = basename7(dir);
|
|
6306
|
-
const skillDir =
|
|
6307
|
-
const skillPath =
|
|
6301
|
+
const skillDir = join13(skillsDir, projectName);
|
|
6302
|
+
const skillPath = join13(skillDir, "SKILL.md");
|
|
6308
6303
|
if (existsSync11(skillPath)) {
|
|
6309
6304
|
return { created: false, skipped: true, path: skillPath };
|
|
6310
6305
|
}
|
|
@@ -6461,7 +6456,7 @@ var onMessagesTransform = async (_input, output) => {
|
|
|
6461
6456
|
const hash = createHash4("sha256").update(`tool_result
|
|
6462
6457
|
${raw}
|
|
6463
6458
|
`).digest("hex").slice(0, 16);
|
|
6464
|
-
const fullPath =
|
|
6459
|
+
const fullPath = join13(getSessionScratchpadDir(), `${hash}.txt`);
|
|
6465
6460
|
try {
|
|
6466
6461
|
ensureSessionScratchpadDirs();
|
|
6467
6462
|
if (!existsSync11(fullPath)) {
|
|
@@ -6733,14 +6728,14 @@ var USER_HOME7 = (() => {
|
|
|
6733
6728
|
return tmpdir7();
|
|
6734
6729
|
}
|
|
6735
6730
|
})();
|
|
6736
|
-
var STATE_FILE5 =
|
|
6737
|
-
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");
|
|
6738
6733
|
var _prevOutputText = "";
|
|
6739
6734
|
var _autoReportCount = 0;
|
|
6740
6735
|
var textCompletePainted = /* @__PURE__ */ new Set();
|
|
6741
6736
|
function loadSelection3() {
|
|
6742
6737
|
try {
|
|
6743
|
-
const raw = readFileSync12(
|
|
6738
|
+
const raw = readFileSync12(join14(USER_HOME7, ".claude/model-tiers.json"), "utf-8");
|
|
6744
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 };
|
|
6745
6740
|
} catch {
|
|
6746
6741
|
return { active_slot: "medium", enabled: true, delegation_enforce: false, flow_enabled: false, flow_enforce: false, tdd_enforce: false, tdd_strict: false };
|
|
@@ -6818,6 +6813,10 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6818
6813
|
if (messageID && textCompletePainted.has(messageID))
|
|
6819
6814
|
return;
|
|
6820
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
|
+
}
|
|
6821
6820
|
const { ltTasks, ltCache, ltCost, count, sesTasks, sesEdit, sesCredit, sesC7, sesQuota, sesCache, sesTaskDelegations, sesDuration, sesRatePerHour, sesTrend, sesToolBreakdown, sesModelTurns, quality_avg } = readLifetimeSavings2();
|
|
6822
6821
|
const sessionSlot = loadSessionSlot(_OC_SID6);
|
|
6823
6822
|
const slot = sessionSlot || loadSelection3().active_slot || "brain";
|
|
@@ -6980,7 +6979,7 @@ init_flow_enforcer();
|
|
|
6980
6979
|
|
|
6981
6980
|
// src/lib/tdd-enforcer.js
|
|
6982
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";
|
|
6983
|
-
import { join as
|
|
6982
|
+
import { join as join15, dirname as dirname6 } from "node:path";
|
|
6984
6983
|
import { createHash as createHash5 } from "node:crypto";
|
|
6985
6984
|
|
|
6986
6985
|
// src/utils/tdd-helpers.js
|
|
@@ -8019,7 +8018,7 @@ function _detectTestFramework() {
|
|
|
8019
8018
|
let testExt = null;
|
|
8020
8019
|
try {
|
|
8021
8020
|
const root = directory || process.cwd();
|
|
8022
|
-
const pkgPath =
|
|
8021
|
+
const pkgPath = join15(root, "package.json");
|
|
8023
8022
|
if (existsSync12(pkgPath)) {
|
|
8024
8023
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
8025
8024
|
const testScript = String(pkg?.scripts?.test || "");
|
|
@@ -8041,12 +8040,12 @@ function _detectTestFramework() {
|
|
|
8041
8040
|
if (!framework) {
|
|
8042
8041
|
const testDirs = ["src/tests", "tests", "test", "__tests__"];
|
|
8043
8042
|
for (const td of testDirs) {
|
|
8044
|
-
const dirPath =
|
|
8043
|
+
const dirPath = join15(root, td);
|
|
8045
8044
|
if (!existsSync12(dirPath))
|
|
8046
8045
|
continue;
|
|
8047
8046
|
const files = readdirSync2(dirPath).filter((f) => /\.test\./.test(f) || /\.spec\./.test(f));
|
|
8048
8047
|
if (files.length > 0) {
|
|
8049
|
-
const content = readFileSync13(
|
|
8048
|
+
const content = readFileSync13(join15(dirPath, files[0]), "utf-8");
|
|
8050
8049
|
if (/from\s+['"]node:test['"]/.test(content)) {
|
|
8051
8050
|
framework = "node-test";
|
|
8052
8051
|
testExt = files[0].split(".").pop();
|
|
@@ -8072,16 +8071,16 @@ function _detectTestFramework() {
|
|
|
8072
8071
|
console.error(`[vibeOS] [tdd] detected test framework: ${framework || "default"} (ext: ${testExt || "match source"})`);
|
|
8073
8072
|
return _detectedFramework;
|
|
8074
8073
|
}
|
|
8075
|
-
var ENFORCEMENT_LOCK_DIR =
|
|
8074
|
+
var ENFORCEMENT_LOCK_DIR = join15(USER_HOME2, ".claude/.enforcement-lock");
|
|
8076
8075
|
var LOCK_EXPIRE_MS = 3e4;
|
|
8077
|
-
var ENFORCEMENT_COOLDOWN_FILE2 =
|
|
8076
|
+
var ENFORCEMENT_COOLDOWN_FILE2 = join15(USER_HOME2, ".claude/.enforcement-cooldown.jsonl");
|
|
8078
8077
|
var COOLDOWN_MS = 6e4;
|
|
8079
8078
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
8080
8079
|
function _acquireLock(testPath) {
|
|
8081
8080
|
try {
|
|
8082
8081
|
mkdirSync8(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
8083
8082
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8084
|
-
const lockPath =
|
|
8083
|
+
const lockPath = join15(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8085
8084
|
try {
|
|
8086
8085
|
openSync4(lockPath, "wx");
|
|
8087
8086
|
return true;
|
|
@@ -8109,7 +8108,7 @@ function _acquireLock(testPath) {
|
|
|
8109
8108
|
function _releaseLock(testPath) {
|
|
8110
8109
|
try {
|
|
8111
8110
|
const hash = createHash5("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
8112
|
-
const lockPath =
|
|
8111
|
+
const lockPath = join15(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
8113
8112
|
rmSync5(lockPath);
|
|
8114
8113
|
} catch {
|
|
8115
8114
|
}
|
|
@@ -8895,15 +8894,15 @@ var _mcpServerRuntime = null;
|
|
|
8895
8894
|
var _mcpServerHooked = false;
|
|
8896
8895
|
function _loadOpenCodeProviders() {
|
|
8897
8896
|
try {
|
|
8898
|
-
const cfg = _readOpenCodeConfigObject(
|
|
8897
|
+
const cfg = _readOpenCodeConfigObject(join16(USER_HOME2, ".config", "opencode"));
|
|
8899
8898
|
return cfg?.provider || {};
|
|
8900
8899
|
} catch {
|
|
8901
8900
|
return {};
|
|
8902
8901
|
}
|
|
8903
8902
|
}
|
|
8904
8903
|
function _readOpenCodeConfigObject(dir) {
|
|
8905
|
-
const jsonPath =
|
|
8906
|
-
const jsoncPath =
|
|
8904
|
+
const jsonPath = join16(dir, "opencode.json");
|
|
8905
|
+
const jsoncPath = join16(dir, "opencode.jsonc");
|
|
8907
8906
|
if (existsSync15(jsonPath)) return safeJsonParse3(readFileSync15(jsonPath, "utf-8"));
|
|
8908
8907
|
if (existsSync15(jsoncPath)) return _parseJsonc(readFileSync15(jsoncPath, "utf-8"));
|
|
8909
8908
|
return {};
|
|
@@ -8931,9 +8930,9 @@ function _modelTier2(id2) {
|
|
|
8931
8930
|
function backupFile(path, label) {
|
|
8932
8931
|
try {
|
|
8933
8932
|
if (!existsSync15(path)) return null;
|
|
8934
|
-
const bkDir =
|
|
8933
|
+
const bkDir = join16(USER_HOME2, ".claude", ".backups");
|
|
8935
8934
|
mkdirSync10(bkDir, { recursive: true });
|
|
8936
|
-
const bk =
|
|
8935
|
+
const bk = join16(bkDir, `${basename9(path)}.${label}.${Date.now()}.bak`);
|
|
8937
8936
|
copyFileSync6(path, bk);
|
|
8938
8937
|
return bk;
|
|
8939
8938
|
} catch {
|
|
@@ -8942,7 +8941,7 @@ function backupFile(path, label) {
|
|
|
8942
8941
|
}
|
|
8943
8942
|
function readPackageVersion() {
|
|
8944
8943
|
try {
|
|
8945
|
-
const pkg = safeJsonParse3(readFileSync15(
|
|
8944
|
+
const pkg = safeJsonParse3(readFileSync15(join16(process.cwd(), "package.json"), "utf-8"));
|
|
8946
8945
|
return String(pkg?.version || "");
|
|
8947
8946
|
} catch {
|
|
8948
8947
|
return "";
|
|
@@ -9138,7 +9137,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
9138
9137
|
setCurrentModel(readConfig(directory3));
|
|
9139
9138
|
if (!currentModel) {
|
|
9140
9139
|
const home = process.env.HOME || "";
|
|
9141
|
-
if (home) setCurrentModel(readConfig(
|
|
9140
|
+
if (home) setCurrentModel(readConfig(join16(home, ".config/opencode")));
|
|
9142
9141
|
}
|
|
9143
9142
|
if (!currentModel) setCurrentModel(process?.env?.OPENCODE_MODEL || "");
|
|
9144
9143
|
if (currentModel) {
|