vibeostheog 0.15.22 → 0.15.23
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 +4 -0
- package/package.json +1 -1
- package/src/index.js +194 -166
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.23",
|
|
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
|
@@ -291,12 +291,12 @@ function recordFlowTodo({ filePath, content }) {
|
|
|
291
291
|
return 0;
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
-
var
|
|
294
|
+
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;
|
|
295
295
|
var init_flow_enforcer = __esm({
|
|
296
296
|
"src/vibeOS-lib/flow-enforcer.js"() {
|
|
297
297
|
"use strict";
|
|
298
|
-
|
|
299
|
-
RULES_PATH = join(
|
|
298
|
+
__dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
299
|
+
RULES_PATH = join(__dirname2, "flow-rules.json");
|
|
300
300
|
GUARD_AGENTS_TEMPLATE = [
|
|
301
301
|
"# AGENTS.md",
|
|
302
302
|
"",
|
|
@@ -350,7 +350,7 @@ var init_flow_enforcer = __esm({
|
|
|
350
350
|
|
|
351
351
|
// src/index.ts
|
|
352
352
|
init_flow_enforcer();
|
|
353
|
-
import { readFileSync as readFileSync15, writeFileSync as
|
|
353
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, existsSync as existsSync14, mkdirSync as mkdirSync10, copyFileSync as copyFileSync6, renameSync as renameSync6 } from "node:fs";
|
|
354
354
|
import { join as join15, dirname as dirname7, basename as basename9 } from "node:path";
|
|
355
355
|
|
|
356
356
|
// src/vibeOS-lib/session-metrics.js
|
|
@@ -496,26 +496,123 @@ function computeSessionMetrics(state, sessionId) {
|
|
|
496
496
|
// src/index.ts
|
|
497
497
|
import { createMcpServer } from "vibeOScore/mcp-server";
|
|
498
498
|
|
|
499
|
+
// src/lib/api-client.js
|
|
500
|
+
import { VibeOSApiClient, VibeOSAuthError, VibeOSTimeoutError, VibeOSNetworkError } from "vibeOScore/client";
|
|
501
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
502
|
+
import { homedir as homedir2 } from "node:os";
|
|
503
|
+
var VIBEOS_API_URL = process.env.VIBEOS_API_URL || "https://api.vibetheog.com";
|
|
504
|
+
var _envTk = "";
|
|
505
|
+
var _envPaths = [
|
|
506
|
+
process.cwd() + "/.env.production",
|
|
507
|
+
homedir2() + "/.claude/.env.production",
|
|
508
|
+
homedir2() + "/.env.production",
|
|
509
|
+
process.cwd() + "/.env.production"
|
|
510
|
+
];
|
|
511
|
+
for (const dir of _envPaths) {
|
|
512
|
+
try {
|
|
513
|
+
const env = readFileSync2(dir + "/.env.production", "utf8");
|
|
514
|
+
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
515
|
+
if (m) {
|
|
516
|
+
_envTk = m[1].trim();
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
} catch {
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN || _envTk || "";
|
|
523
|
+
var VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
524
|
+
var _apiClient = null;
|
|
525
|
+
var _apiFallbackMode = false;
|
|
526
|
+
var _apiFallbackSince = null;
|
|
527
|
+
function setApiToken(newToken) {
|
|
528
|
+
VIBEOS_API_TOKEN = newToken;
|
|
529
|
+
VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
530
|
+
_apiClient = null;
|
|
531
|
+
_apiFallbackMode = false;
|
|
532
|
+
_apiFallbackSince = null;
|
|
533
|
+
const paths = [__dirname, homedir2() + "/.claude", homedir2(), process.cwd()];
|
|
534
|
+
for (const dir of paths) {
|
|
535
|
+
try {
|
|
536
|
+
const filePath = dir + "/.env.production";
|
|
537
|
+
let env = "";
|
|
538
|
+
try {
|
|
539
|
+
env = readFileSync2(filePath, "utf8");
|
|
540
|
+
} catch {
|
|
541
|
+
}
|
|
542
|
+
const lines = env.split("\n");
|
|
543
|
+
const filtered = lines.filter((l) => !l.startsWith("VIBEOS_API_TOKEN="));
|
|
544
|
+
filtered.push("VIBEOS_API_TOKEN=" + newToken);
|
|
545
|
+
writeFileSync2(filePath, filtered.join("\n") + "\n", "utf8");
|
|
546
|
+
} catch {
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
console.error("[vibeOS] API token updated via setApiToken");
|
|
550
|
+
}
|
|
551
|
+
function getApiClient() {
|
|
552
|
+
if (!_apiClient && VIBEOS_API_ENABLED) {
|
|
553
|
+
_apiClient = new VibeOSApiClient({
|
|
554
|
+
baseUrl: VIBEOS_API_URL,
|
|
555
|
+
apiToken: VIBEOS_API_TOKEN,
|
|
556
|
+
timeout: 5e3
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
return _apiClient;
|
|
560
|
+
}
|
|
561
|
+
function isApiFallback() {
|
|
562
|
+
return _apiFallbackMode || !VIBEOS_API_ENABLED;
|
|
563
|
+
}
|
|
564
|
+
async function remoteCall(method, args, fallbackFn) {
|
|
565
|
+
if (!VIBEOS_API_ENABLED || _apiFallbackMode) {
|
|
566
|
+
if (fallbackFn) return fallbackFn();
|
|
567
|
+
return null;
|
|
568
|
+
}
|
|
569
|
+
try {
|
|
570
|
+
const client2 = getApiClient();
|
|
571
|
+
if (!client2) {
|
|
572
|
+
if (fallbackFn) return fallbackFn();
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
const result = await client2[method](...args);
|
|
576
|
+
_apiFallbackMode = false;
|
|
577
|
+
_apiFallbackSince = null;
|
|
578
|
+
return result;
|
|
579
|
+
} catch (err) {
|
|
580
|
+
if (!_apiFallbackMode) {
|
|
581
|
+
_apiFallbackMode = true;
|
|
582
|
+
_apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
583
|
+
console.error(`[vibeOS] API fallback activated: ${err.message}`);
|
|
584
|
+
}
|
|
585
|
+
if (fallbackFn) {
|
|
586
|
+
try {
|
|
587
|
+
return fallbackFn();
|
|
588
|
+
} catch (fe) {
|
|
589
|
+
console.error(`[vibeOS] fallback also failed: ${fe.message}`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
499
596
|
// src/lib/pricing.js
|
|
500
|
-
import { readFileSync as
|
|
597
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, appendFileSync as appendFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync4, statSync as statSync4, copyFileSync as copyFileSync3, renameSync as renameSync4, openSync as openSync2, closeSync as closeSync2, rmSync as rmSync2 } from "node:fs";
|
|
501
598
|
import { join as join4, dirname as dirname3, basename as basename4 } from "node:path";
|
|
502
|
-
import { homedir as
|
|
599
|
+
import { homedir as homedir5, tmpdir as tmpdir3 } from "node:os";
|
|
503
600
|
import { createHash as createHash2 } from "node:crypto";
|
|
504
601
|
|
|
505
602
|
// src/lib/state.js
|
|
506
|
-
import { readFileSync as
|
|
603
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, appendFileSync as appendFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3, statSync as statSync3, readdirSync, openSync, readSync, closeSync, rmSync, copyFileSync as copyFileSync2, renameSync as renameSync3 } from "node:fs";
|
|
507
604
|
import { join as join3, dirname as dirname2, basename as basename3 } from "node:path";
|
|
508
605
|
import { spawn } from "node:child_process";
|
|
509
|
-
import { homedir as
|
|
606
|
+
import { homedir as homedir4, tmpdir as tmpdir2 } from "node:os";
|
|
510
607
|
import { createHash } from "node:crypto";
|
|
511
608
|
|
|
512
609
|
// src/lib/selection-manager.js
|
|
513
|
-
import { readFileSync as
|
|
610
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, appendFileSync as appendFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, statSync as statSync2, copyFileSync, renameSync as renameSync2 } from "node:fs";
|
|
514
611
|
import { join as join2, basename } from "node:path";
|
|
515
|
-
import { homedir as
|
|
612
|
+
import { homedir as homedir3, tmpdir } from "node:os";
|
|
516
613
|
var USER_HOME = (() => {
|
|
517
614
|
try {
|
|
518
|
-
return
|
|
615
|
+
return homedir3();
|
|
519
616
|
} catch {
|
|
520
617
|
return tmpdir();
|
|
521
618
|
}
|
|
@@ -559,7 +656,7 @@ function loadSelection() {
|
|
|
559
656
|
_handleStateCorruption(TIERS_FILE);
|
|
560
657
|
return DFLT_SEL;
|
|
561
658
|
}
|
|
562
|
-
const j = safeJsonParse2(
|
|
659
|
+
const j = safeJsonParse2(readFileSync3(TIERS_FILE, "utf-8"));
|
|
563
660
|
return {
|
|
564
661
|
enabled: j?.selection?.enabled !== false,
|
|
565
662
|
active_slot: j?.selection?.active_slot || null,
|
|
@@ -578,10 +675,10 @@ function loadSelection() {
|
|
|
578
675
|
}
|
|
579
676
|
function writeSelection(key, value) {
|
|
580
677
|
try {
|
|
581
|
-
const j = safeJsonParse2(
|
|
678
|
+
const j = safeJsonParse2(readFileSync3(TIERS_FILE, "utf-8"));
|
|
582
679
|
j.selection[key] = value;
|
|
583
680
|
const tmp = TIERS_FILE + ".tmp";
|
|
584
|
-
|
|
681
|
+
writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
|
|
585
682
|
renameSync2(tmp, TIERS_FILE);
|
|
586
683
|
return true;
|
|
587
684
|
} catch (err) {
|
|
@@ -594,7 +691,7 @@ function loadSessionSlot(sid) {
|
|
|
594
691
|
try {
|
|
595
692
|
if (!existsSync2(BLACKBOX_FILE))
|
|
596
693
|
return null;
|
|
597
|
-
const j = safeJsonParse2(
|
|
694
|
+
const j = safeJsonParse2(readFileSync3(BLACKBOX_FILE, "utf-8"));
|
|
598
695
|
return j?.sessions?.[sid]?.active_slot || null;
|
|
599
696
|
} catch {
|
|
600
697
|
return null;
|
|
@@ -602,14 +699,14 @@ function loadSessionSlot(sid) {
|
|
|
602
699
|
}
|
|
603
700
|
function writeSessionSlot(sid, slot) {
|
|
604
701
|
try {
|
|
605
|
-
const j = existsSync2(BLACKBOX_FILE) ? safeJsonParse2(
|
|
702
|
+
const j = existsSync2(BLACKBOX_FILE) ? safeJsonParse2(readFileSync3(BLACKBOX_FILE, "utf-8")) : {};
|
|
606
703
|
if (!j.sessions)
|
|
607
704
|
j.sessions = {};
|
|
608
705
|
if (!j.sessions[sid])
|
|
609
706
|
j.sessions[sid] = {};
|
|
610
707
|
j.sessions[sid].active_slot = slot;
|
|
611
708
|
const tmp = BLACKBOX_FILE + ".tmp";
|
|
612
|
-
|
|
709
|
+
writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
|
|
613
710
|
renameSync2(tmp, BLACKBOX_FILE);
|
|
614
711
|
return true;
|
|
615
712
|
} catch (err) {
|
|
@@ -621,7 +718,7 @@ function loadSessionOptMode(sid) {
|
|
|
621
718
|
try {
|
|
622
719
|
if (!existsSync2(BLACKBOX_FILE))
|
|
623
720
|
return null;
|
|
624
|
-
const j = safeJsonParse2(
|
|
721
|
+
const j = safeJsonParse2(readFileSync3(BLACKBOX_FILE, "utf-8"));
|
|
625
722
|
return j?.sessions?.[sid]?.optimization_mode || null;
|
|
626
723
|
} catch {
|
|
627
724
|
return null;
|
|
@@ -629,14 +726,14 @@ function loadSessionOptMode(sid) {
|
|
|
629
726
|
}
|
|
630
727
|
function writeSessionOptMode(sid, mode) {
|
|
631
728
|
try {
|
|
632
|
-
const j = existsSync2(BLACKBOX_FILE) ? safeJsonParse2(
|
|
729
|
+
const j = existsSync2(BLACKBOX_FILE) ? safeJsonParse2(readFileSync3(BLACKBOX_FILE, "utf-8")) : {};
|
|
633
730
|
if (!j.sessions)
|
|
634
731
|
j.sessions = {};
|
|
635
732
|
if (!j.sessions[sid])
|
|
636
733
|
j.sessions[sid] = {};
|
|
637
734
|
j.sessions[sid].optimization_mode = mode;
|
|
638
735
|
const tmp = BLACKBOX_FILE + ".tmp";
|
|
639
|
-
|
|
736
|
+
writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
|
|
640
737
|
renameSync2(tmp, BLACKBOX_FILE);
|
|
641
738
|
return true;
|
|
642
739
|
} catch (err) {
|
|
@@ -1310,7 +1407,7 @@ function deserializeCacheDb(raw) {
|
|
|
1310
1407
|
// src/lib/state.js
|
|
1311
1408
|
var USER_HOME2 = (() => {
|
|
1312
1409
|
try {
|
|
1313
|
-
return
|
|
1410
|
+
return homedir4();
|
|
1314
1411
|
} catch {
|
|
1315
1412
|
return tmpdir2();
|
|
1316
1413
|
}
|
|
@@ -1461,7 +1558,7 @@ function withFileLock(filePath, fn, opts = {}) {
|
|
|
1461
1558
|
mkdirSync3(FILE_LOCK_DIR, { recursive: true });
|
|
1462
1559
|
const fd = openSync(lockPath, "wx");
|
|
1463
1560
|
try {
|
|
1464
|
-
|
|
1561
|
+
writeFileSync4(fd, `${process.pid}
|
|
1465
1562
|
${Date.now()}
|
|
1466
1563
|
`);
|
|
1467
1564
|
} catch {
|
|
@@ -1539,7 +1636,7 @@ function readJsonOrEmpty(filePath) {
|
|
|
1539
1636
|
_handleStateCorruption2(filePath);
|
|
1540
1637
|
return {};
|
|
1541
1638
|
}
|
|
1542
|
-
return safeJsonParse3(
|
|
1639
|
+
return safeJsonParse3(readFileSync4(filePath, "utf-8"));
|
|
1543
1640
|
} catch {
|
|
1544
1641
|
_handleStateCorruption2(filePath);
|
|
1545
1642
|
return {};
|
|
@@ -1567,7 +1664,7 @@ function updateState(mutator) {
|
|
|
1567
1664
|
validateState(next, DELEGATION_STATE_FILE);
|
|
1568
1665
|
mkdirSync3(dirname2(DELEGATION_STATE_FILE), { recursive: true });
|
|
1569
1666
|
const tmp = DELEGATION_STATE_FILE + ".tmp";
|
|
1570
|
-
|
|
1667
|
+
writeFileSync4(tmp, JSON.stringify(next, null, 2) + "\n");
|
|
1571
1668
|
renameSync3(tmp, DELEGATION_STATE_FILE);
|
|
1572
1669
|
return next;
|
|
1573
1670
|
});
|
|
@@ -1590,7 +1687,7 @@ function readFullState() {
|
|
|
1590
1687
|
_handleStateCorruption2(DELEGATION_STATE_FILE);
|
|
1591
1688
|
return {};
|
|
1592
1689
|
}
|
|
1593
|
-
return safeJsonParse3(
|
|
1690
|
+
return safeJsonParse3(readFileSync4(DELEGATION_STATE_FILE, "utf-8"));
|
|
1594
1691
|
} catch {
|
|
1595
1692
|
_handleStateCorruption2(DELEGATION_STATE_FILE);
|
|
1596
1693
|
return {};
|
|
@@ -1616,7 +1713,7 @@ function loadTierRegexes() {
|
|
|
1616
1713
|
const p = join3(USER_HOME2, ".claude/model-tiers.json");
|
|
1617
1714
|
if (!existsSync3(p))
|
|
1618
1715
|
return { high: FALLBACK_HIGH, mid: FALLBACK_MID };
|
|
1619
|
-
const j = safeJsonParse3(
|
|
1716
|
+
const j = safeJsonParse3(readFileSync4(p, "utf-8"));
|
|
1620
1717
|
const highRe = _safeRegex(j?.tiers?.high?.regex, FALLBACK_HIGH, "high");
|
|
1621
1718
|
const midRe = _safeRegex(j?.tiers?.mid?.regex, FALLBACK_MID, "mid");
|
|
1622
1719
|
return { high: highRe, mid: midRe };
|
|
@@ -1634,7 +1731,7 @@ function loadGlobalLearning() {
|
|
|
1634
1731
|
_handleStateCorruption2(GLOBAL_LEARNING_FILE);
|
|
1635
1732
|
return DFLT_GL;
|
|
1636
1733
|
}
|
|
1637
|
-
const j = safeJsonParse3(
|
|
1734
|
+
const j = safeJsonParse3(readFileSync4(GLOBAL_LEARNING_FILE, "utf-8"));
|
|
1638
1735
|
if (!j || typeof j !== "object")
|
|
1639
1736
|
return DFLT_GL;
|
|
1640
1737
|
j.exploratory_words ??= {};
|
|
@@ -1652,7 +1749,7 @@ function updateGlobalLearning(mutator) {
|
|
|
1652
1749
|
next.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1653
1750
|
mkdirSync3(dirname2(GLOBAL_LEARNING_FILE), { recursive: true });
|
|
1654
1751
|
const tmp = GLOBAL_LEARNING_FILE + ".tmp";
|
|
1655
|
-
|
|
1752
|
+
writeFileSync4(tmp, JSON.stringify(next, null, 2));
|
|
1656
1753
|
renameSync3(tmp, GLOBAL_LEARNING_FILE);
|
|
1657
1754
|
return next;
|
|
1658
1755
|
});
|
|
@@ -1926,14 +2023,14 @@ function _pruneScratchpadDir(targetDir, opts = {}) {
|
|
|
1926
2023
|
const summaryPath = join3(targetDir, hash + ".summary.txt");
|
|
1927
2024
|
if (!existsSync3(summaryPath))
|
|
1928
2025
|
try {
|
|
1929
|
-
const content =
|
|
1930
|
-
|
|
2026
|
+
const content = readFileSync4(fullPath, "utf-8");
|
|
2027
|
+
writeFileSync4(summaryPath, content.slice(0, 200).replace(/\n+/g, " ").trim() + (content.length > 200 ? "\u2026" : ""));
|
|
1931
2028
|
} catch {
|
|
1932
2029
|
}
|
|
1933
2030
|
const head = _readHead(fullPath);
|
|
1934
2031
|
if (!head.includes("[cold-storage]"))
|
|
1935
2032
|
try {
|
|
1936
|
-
|
|
2033
|
+
writeFileSync4(fullPath, `[cold-storage] ${st.size}B original \u2192 ${hash}.summary.txt`);
|
|
1937
2034
|
rotated++;
|
|
1938
2035
|
} catch {
|
|
1939
2036
|
}
|
|
@@ -1943,14 +2040,14 @@ function _pruneScratchpadDir(targetDir, opts = {}) {
|
|
|
1943
2040
|
const summaryPath = join3(targetDir, hash + ".summary.txt");
|
|
1944
2041
|
if (!existsSync3(summaryPath))
|
|
1945
2042
|
try {
|
|
1946
|
-
const content =
|
|
1947
|
-
|
|
2043
|
+
const content = readFileSync4(fullPath, "utf-8");
|
|
2044
|
+
writeFileSync4(summaryPath, content.slice(0, 500).replace(/\n+/g, " ").trim() + (content.length > 500 ? "\u2026" : ""));
|
|
1948
2045
|
} catch {
|
|
1949
2046
|
}
|
|
1950
2047
|
const head = _readHead(fullPath);
|
|
1951
2048
|
if (!head.includes("[warm-storage]") && !head.includes("[cold-storage]"))
|
|
1952
2049
|
try {
|
|
1953
|
-
|
|
2050
|
+
writeFileSync4(fullPath, `[warm-storage] ${st.size}B original at ${hash}.summary.txt`);
|
|
1954
2051
|
rotated++;
|
|
1955
2052
|
} catch {
|
|
1956
2053
|
}
|
|
@@ -2018,7 +2115,7 @@ function loadActiveJobs() {
|
|
|
2018
2115
|
_handleStateCorruption2(ACTIVE_JOBS_FILE);
|
|
2019
2116
|
return {};
|
|
2020
2117
|
}
|
|
2021
|
-
const raw = safeJsonParse3(
|
|
2118
|
+
const raw = safeJsonParse3(readFileSync4(ACTIVE_JOBS_FILE, "utf-8"));
|
|
2022
2119
|
if (!raw || typeof raw !== "object")
|
|
2023
2120
|
return {};
|
|
2024
2121
|
return raw;
|
|
@@ -2044,7 +2141,7 @@ function saveActiveJobForProject(job, fp3 = currentProjectFingerprint) {
|
|
|
2044
2141
|
jobs[fp3] = job;
|
|
2045
2142
|
mkdirSync3(dirname2(ACTIVE_JOBS_FILE), { recursive: true });
|
|
2046
2143
|
const tmp = ACTIVE_JOBS_FILE + ".tmp";
|
|
2047
|
-
|
|
2144
|
+
writeFileSync4(tmp, JSON.stringify(jobs, null, 2));
|
|
2048
2145
|
renameSync3(tmp, ACTIVE_JOBS_FILE);
|
|
2049
2146
|
} catch {
|
|
2050
2147
|
}
|
|
@@ -2070,7 +2167,7 @@ function saveProjectState(state) {
|
|
|
2070
2167
|
withFileLock(PROJECT_STATE_FILE, () => {
|
|
2071
2168
|
mkdirSync3(dirname2(PROJECT_STATE_FILE), { recursive: true });
|
|
2072
2169
|
const _tmp = PROJECT_STATE_FILE + ".tmp." + Date.now();
|
|
2073
|
-
|
|
2170
|
+
writeFileSync4(_tmp, JSON.stringify(state, null, 2) + "\n", "utf-8");
|
|
2074
2171
|
renameSync3(_tmp, PROJECT_STATE_FILE);
|
|
2075
2172
|
});
|
|
2076
2173
|
} catch (err) {
|
|
@@ -2093,7 +2190,7 @@ function ensureProjectBucket(state, fp3) {
|
|
|
2093
2190
|
function detectTechStack(dir) {
|
|
2094
2191
|
const stacks = [];
|
|
2095
2192
|
try {
|
|
2096
|
-
const pkg = safeJsonParse3(
|
|
2193
|
+
const pkg = safeJsonParse3(readFileSync4(join3(dir, "package.json"), "utf-8"));
|
|
2097
2194
|
if (pkg) {
|
|
2098
2195
|
if (pkg.devDependencies?.typescript || pkg.dependencies?.typescript || existsSync3(join3(dir, "tsconfig.json")))
|
|
2099
2196
|
stacks.push("typescript");
|
|
@@ -2264,7 +2361,7 @@ function readLedgerTotals() {
|
|
|
2264
2361
|
try {
|
|
2265
2362
|
if (!existsSync3(SAVINGS_LEDGER_FILE))
|
|
2266
2363
|
return empty;
|
|
2267
|
-
const raw =
|
|
2364
|
+
const raw = readFileSync4(SAVINGS_LEDGER_FILE, "utf-8");
|
|
2268
2365
|
if (!raw.trim())
|
|
2269
2366
|
return empty;
|
|
2270
2367
|
let delegation = 0;
|
|
@@ -2341,7 +2438,7 @@ function readLifetimeSavings() {
|
|
|
2341
2438
|
const mtime = statSync3(DELEGATION_STATE_FILE).mtimeMs;
|
|
2342
2439
|
if (_savingsCache && mtime === _savingsCacheMtime)
|
|
2343
2440
|
return _savingsCache;
|
|
2344
|
-
const s = safeJsonParse3(
|
|
2441
|
+
const s = safeJsonParse3(readFileSync4(DELEGATION_STATE_FILE, "utf-8"));
|
|
2345
2442
|
_savingsCache = _computeSessionMetrics(s, _OC_SID);
|
|
2346
2443
|
_savingsCacheMtime = mtime;
|
|
2347
2444
|
return _savingsCache;
|
|
@@ -2368,7 +2465,7 @@ function saveSessionCheckpoint() {
|
|
|
2368
2465
|
const cpPath = join3(getSessionRoot(), "checkpoint.json");
|
|
2369
2466
|
mkdirSync3(dirname2(cpPath), { recursive: true });
|
|
2370
2467
|
const tmp = cpPath + ".tmp";
|
|
2371
|
-
|
|
2468
|
+
writeFileSync4(tmp, JSON.stringify(cp, null, 2) + "\n");
|
|
2372
2469
|
renameSync3(tmp, cpPath);
|
|
2373
2470
|
} catch {
|
|
2374
2471
|
}
|
|
@@ -2389,7 +2486,7 @@ function setTrinityCheap(v) {
|
|
|
2389
2486
|
}
|
|
2390
2487
|
var USER_HOME3 = (() => {
|
|
2391
2488
|
try {
|
|
2392
|
-
return
|
|
2489
|
+
return homedir5();
|
|
2393
2490
|
} catch {
|
|
2394
2491
|
return tmpdir3();
|
|
2395
2492
|
}
|
|
@@ -2424,7 +2521,7 @@ function withFileLock2(filePath, fn, opts = {}) {
|
|
|
2424
2521
|
mkdirSync4(FILE_LOCK_DIR2, { recursive: true });
|
|
2425
2522
|
const fd = openSync2(lockPath, "wx");
|
|
2426
2523
|
try {
|
|
2427
|
-
|
|
2524
|
+
writeFileSync5(fd, `${process.pid}
|
|
2428
2525
|
${Date.now()}
|
|
2429
2526
|
`);
|
|
2430
2527
|
} catch {
|
|
@@ -2464,7 +2561,7 @@ function loadTierRegexes2() {
|
|
|
2464
2561
|
const p = join4(USER_HOME3, ".claude/model-tiers.json");
|
|
2465
2562
|
if (!existsSync4(p))
|
|
2466
2563
|
return { high: FALLBACK_HIGH, mid: FALLBACK_MID };
|
|
2467
|
-
const j = safeJsonParse3(
|
|
2564
|
+
const j = safeJsonParse3(readFileSync5(p, "utf-8"));
|
|
2468
2565
|
const highRe = _safeRegex(j?.tiers?.high?.regex, FALLBACK_HIGH, "high");
|
|
2469
2566
|
const midRe = _safeRegex(j?.tiers?.mid?.regex, FALLBACK_MID, "mid");
|
|
2470
2567
|
return { high: highRe, mid: midRe };
|
|
@@ -2533,7 +2630,7 @@ var MODEL_USD_PER_TURN = {
|
|
|
2533
2630
|
"haiku": 22e-4,
|
|
2534
2631
|
// ── DeepSeek (OC platform + OpenRouter) ──────────────────
|
|
2535
2632
|
"deepseek/deepseek-v4-pro": 57e-5,
|
|
2536
|
-
"deepseek/deepseek-v4-flash": 0.
|
|
2633
|
+
"deepseek/deepseek-v4-flash": 0.00013,
|
|
2537
2634
|
"deepseek/deepseek-chat": 0,
|
|
2538
2635
|
"deepseek-chat": 0,
|
|
2539
2636
|
"deepseek/deepseek-v3": 0,
|
|
@@ -2570,7 +2667,7 @@ function _loadDynamicPricingCache() {
|
|
|
2570
2667
|
_dynamicPricingCache = {};
|
|
2571
2668
|
return {};
|
|
2572
2669
|
}
|
|
2573
|
-
const raw = safeJsonParse3(
|
|
2670
|
+
const raw = safeJsonParse3(readFileSync5(PRICING_CACHE_FILE2, "utf-8"));
|
|
2574
2671
|
const map = raw?.models && typeof raw.models === "object" ? raw.models : {};
|
|
2575
2672
|
_dynamicPricingCache = map;
|
|
2576
2673
|
} catch {
|
|
@@ -2612,7 +2709,7 @@ function _writeDynamicPricingCache(modelsMap) {
|
|
|
2612
2709
|
withFileLock2(PRICING_CACHE_FILE2, () => {
|
|
2613
2710
|
mkdirSync4(dirname3(PRICING_CACHE_FILE2), { recursive: true });
|
|
2614
2711
|
const tmp = PRICING_CACHE_FILE2 + ".tmp";
|
|
2615
|
-
|
|
2712
|
+
writeFileSync5(tmp, JSON.stringify({
|
|
2616
2713
|
ts: Date.now(),
|
|
2617
2714
|
source: "openrouter-models",
|
|
2618
2715
|
models: modelsMap
|
|
@@ -2682,7 +2779,7 @@ function detectContext7(files = CONTEXT7_CONFIG_FILES) {
|
|
|
2682
2779
|
return true;
|
|
2683
2780
|
for (const f of files) {
|
|
2684
2781
|
try {
|
|
2685
|
-
if (existsSync4(f) && /context7/i.test(
|
|
2782
|
+
if (existsSync4(f) && /context7/i.test(readFileSync5(f, "utf-8")))
|
|
2686
2783
|
return true;
|
|
2687
2784
|
} catch {
|
|
2688
2785
|
}
|
|
@@ -2703,7 +2800,7 @@ function loadSelection2() {
|
|
|
2703
2800
|
_handleStateCorruption3(TIERS_FILE3);
|
|
2704
2801
|
return DFLT_SEL2;
|
|
2705
2802
|
}
|
|
2706
|
-
const j = safeJsonParse3(
|
|
2803
|
+
const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
2707
2804
|
return {
|
|
2708
2805
|
enabled: j?.selection?.enabled !== false,
|
|
2709
2806
|
active_slot: j?.selection?.active_slot || null,
|
|
@@ -2739,10 +2836,10 @@ function readOpenCodeConfigObject(dir) {
|
|
|
2739
2836
|
const jsonPath = join4(dir, "opencode.json");
|
|
2740
2837
|
const jsoncPath = join4(dir, "opencode.jsonc");
|
|
2741
2838
|
if (existsSync4(jsonPath)) {
|
|
2742
|
-
return safeJsonParse3(
|
|
2839
|
+
return safeJsonParse3(readFileSync5(jsonPath, "utf-8"));
|
|
2743
2840
|
}
|
|
2744
2841
|
if (existsSync4(jsoncPath)) {
|
|
2745
|
-
return parseJsonc(
|
|
2842
|
+
return parseJsonc(readFileSync5(jsoncPath, "utf-8"));
|
|
2746
2843
|
}
|
|
2747
2844
|
return {};
|
|
2748
2845
|
}
|
|
@@ -2752,7 +2849,7 @@ function _refreshModel(directory3) {
|
|
|
2752
2849
|
const sel = loadSelection2();
|
|
2753
2850
|
if (!sel.enabled)
|
|
2754
2851
|
return;
|
|
2755
|
-
const tiersData = safeJsonParse3(
|
|
2852
|
+
const tiersData = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
2756
2853
|
const activeSlot = sel.active_slot || "brain";
|
|
2757
2854
|
let slotOcModel = tiersData?.trinity?.[activeSlot]?.oc || "";
|
|
2758
2855
|
if (slotOcModel && PLACEHOLDER_RE.test(slotOcModel)) {
|
|
@@ -2789,12 +2886,12 @@ function _refreshModel(directory3) {
|
|
|
2789
2886
|
console.error(`[vibeOS] model refresh (config): ${oldModel}(${oldTier}) \u2192 ${currentModel}(${currentTier})`);
|
|
2790
2887
|
try {
|
|
2791
2888
|
if (existsSync4(TIERS_FILE3)) {
|
|
2792
|
-
const t = safeJsonParse3(
|
|
2889
|
+
const t = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
2793
2890
|
for (const s of ["brain", "medium", "cheap"]) {
|
|
2794
2891
|
if (t?.trinity?.[s]?.oc === cfgModel) {
|
|
2795
2892
|
t.selection.active_slot = s;
|
|
2796
2893
|
const _tmp = TIERS_FILE3 + ".tmp." + Date.now();
|
|
2797
|
-
|
|
2894
|
+
writeFileSync5(_tmp, JSON.stringify(t, null, 2) + "\n", "utf-8");
|
|
2798
2895
|
renameSync4(_tmp, TIERS_FILE3);
|
|
2799
2896
|
console.error(`[vibeOS] model refresh (config): synced active_slot \u2192 ${s}`);
|
|
2800
2897
|
break;
|
|
@@ -2810,20 +2907,20 @@ function _refreshModel(directory3) {
|
|
|
2810
2907
|
}
|
|
2811
2908
|
function applySlot2(slot) {
|
|
2812
2909
|
try {
|
|
2813
|
-
const j = safeJsonParse3(
|
|
2910
|
+
const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
|
|
2814
2911
|
const ocModel = j?.trinity?.[slot]?.oc;
|
|
2815
2912
|
if (!ocModel)
|
|
2816
2913
|
return { ok: false, reason: `slot '${slot}' has no oc model` };
|
|
2817
2914
|
j.selection.active_slot = slot;
|
|
2818
2915
|
const _tmp = TIERS_FILE3 + ".tmp." + Date.now();
|
|
2819
|
-
|
|
2916
|
+
writeFileSync5(_tmp, JSON.stringify(j, null, 2) + "\n", "utf-8");
|
|
2820
2917
|
renameSync4(_tmp, TIERS_FILE3);
|
|
2821
2918
|
const localOcConfig = join4(process.cwd(), "opencode.json");
|
|
2822
2919
|
const ocConfig = existsSync4(localOcConfig) ? localOcConfig : join4(USER_HOME3, ".config/opencode/opencode.json");
|
|
2823
2920
|
if (existsSync4(ocConfig)) {
|
|
2824
|
-
const oc = safeJsonParse3(
|
|
2921
|
+
const oc = safeJsonParse3(readFileSync5(ocConfig, "utf-8"));
|
|
2825
2922
|
oc.model = ocModel;
|
|
2826
|
-
|
|
2923
|
+
writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
|
|
2827
2924
|
}
|
|
2828
2925
|
_refreshModel(process.cwd());
|
|
2829
2926
|
return { ok: true, ocModel };
|
|
@@ -2833,86 +2930,11 @@ function applySlot2(slot) {
|
|
|
2833
2930
|
}
|
|
2834
2931
|
|
|
2835
2932
|
// src/lib/turn-classify.js
|
|
2836
|
-
import { readFileSync as readFileSync6, writeFileSync as
|
|
2933
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, appendFileSync as appendFileSync5, existsSync as existsSync5, mkdirSync as mkdirSync5, statSync as statSync5, copyFileSync as copyFileSync4, renameSync as renameSync5, openSync as openSync3, closeSync as closeSync3, rmSync as rmSync3 } from "node:fs";
|
|
2837
2934
|
import { join as join5, dirname as dirname4, basename as basename5 } from "node:path";
|
|
2838
2935
|
import { homedir as homedir6, tmpdir as tmpdir4 } from "node:os";
|
|
2839
2936
|
import { createHash as createHash3 } from "node:crypto";
|
|
2840
2937
|
|
|
2841
|
-
// src/lib/api-client.js
|
|
2842
|
-
import { VibeOSApiClient } from "vibeOScore/client";
|
|
2843
|
-
import { readFileSync as readFileSync5 } from "node:fs";
|
|
2844
|
-
import { homedir as homedir5 } from "node:os";
|
|
2845
|
-
var VIBEOS_API_URL = process.env.VIBEOS_API_URL || "https://api.vibetheog.com";
|
|
2846
|
-
var _envTk = "";
|
|
2847
|
-
var _envPaths = [
|
|
2848
|
-
process.cwd() + "/.env.production",
|
|
2849
|
-
homedir5() + "/.claude/.env.production",
|
|
2850
|
-
homedir5() + "/.env.production",
|
|
2851
|
-
process.cwd() + "/.env.production"
|
|
2852
|
-
];
|
|
2853
|
-
for (const dir of _envPaths) {
|
|
2854
|
-
try {
|
|
2855
|
-
const env = readFileSync5(dir + "/.env.production", "utf8");
|
|
2856
|
-
const m = env.match(/^VIBEOS_API_TOKEN=(.+)$/m);
|
|
2857
|
-
if (m) {
|
|
2858
|
-
_envTk = m[1].trim();
|
|
2859
|
-
break;
|
|
2860
|
-
}
|
|
2861
|
-
} catch {
|
|
2862
|
-
}
|
|
2863
|
-
}
|
|
2864
|
-
var VIBEOS_API_TOKEN = process.env.VIBEOS_API_TOKEN || _envTk || "";
|
|
2865
|
-
var VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && !!VIBEOS_API_TOKEN;
|
|
2866
|
-
var _apiClient = null;
|
|
2867
|
-
var _apiFallbackMode = false;
|
|
2868
|
-
var _apiFallbackSince = null;
|
|
2869
|
-
function getApiClient() {
|
|
2870
|
-
if (!_apiClient && VIBEOS_API_ENABLED) {
|
|
2871
|
-
_apiClient = new VibeOSApiClient({
|
|
2872
|
-
baseUrl: VIBEOS_API_URL,
|
|
2873
|
-
apiToken: VIBEOS_API_TOKEN,
|
|
2874
|
-
timeout: 5e3
|
|
2875
|
-
});
|
|
2876
|
-
}
|
|
2877
|
-
return _apiClient;
|
|
2878
|
-
}
|
|
2879
|
-
function isApiFallback() {
|
|
2880
|
-
return _apiFallbackMode || !VIBEOS_API_ENABLED;
|
|
2881
|
-
}
|
|
2882
|
-
async function remoteCall(method, args, fallbackFn) {
|
|
2883
|
-
if (!VIBEOS_API_ENABLED || _apiFallbackMode) {
|
|
2884
|
-
if (fallbackFn)
|
|
2885
|
-
return fallbackFn();
|
|
2886
|
-
return null;
|
|
2887
|
-
}
|
|
2888
|
-
try {
|
|
2889
|
-
const client2 = getApiClient();
|
|
2890
|
-
if (!client2) {
|
|
2891
|
-
if (fallbackFn)
|
|
2892
|
-
return fallbackFn();
|
|
2893
|
-
return null;
|
|
2894
|
-
}
|
|
2895
|
-
const result = await client2[method](...args);
|
|
2896
|
-
_apiFallbackMode = false;
|
|
2897
|
-
_apiFallbackSince = null;
|
|
2898
|
-
return result;
|
|
2899
|
-
} catch (err) {
|
|
2900
|
-
if (!_apiFallbackMode) {
|
|
2901
|
-
_apiFallbackMode = true;
|
|
2902
|
-
_apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
2903
|
-
console.error(`[vibeOS] API fallback activated: ${err.message}`);
|
|
2904
|
-
}
|
|
2905
|
-
if (fallbackFn) {
|
|
2906
|
-
try {
|
|
2907
|
-
return fallbackFn();
|
|
2908
|
-
} catch (fe) {
|
|
2909
|
-
console.error(`[vibeOS] fallback also failed: ${fe.message}`);
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
return null;
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
|
|
2916
2938
|
// src/lib/classifiers.js
|
|
2917
2939
|
function detectOutcomeSignal(text) {
|
|
2918
2940
|
if (!text)
|
|
@@ -3164,7 +3186,7 @@ function withFileLock3(filePath, fn, opts = {}) {
|
|
|
3164
3186
|
mkdirSync5(FILE_LOCK_DIR3, { recursive: true });
|
|
3165
3187
|
const fd = openSync3(lockPath, "wx");
|
|
3166
3188
|
try {
|
|
3167
|
-
|
|
3189
|
+
writeFileSync6(fd, `${process.pid}
|
|
3168
3190
|
${Date.now()}
|
|
3169
3191
|
`);
|
|
3170
3192
|
} catch {
|
|
@@ -3250,7 +3272,7 @@ function saveBlackboxState(state) {
|
|
|
3250
3272
|
try {
|
|
3251
3273
|
mkdirSync5(dirname4(BLACKBOX_STATE_FILE2), { recursive: true });
|
|
3252
3274
|
const tmp = BLACKBOX_STATE_FILE2 + ".tmp";
|
|
3253
|
-
|
|
3275
|
+
writeFileSync6(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
3254
3276
|
renameSync5(tmp, BLACKBOX_STATE_FILE2);
|
|
3255
3277
|
} catch (err) {
|
|
3256
3278
|
console.error("[vibeOS] saveBlackboxState failed: " + err.message);
|
|
@@ -3411,7 +3433,7 @@ function updateGlobalLearning2(mutator) {
|
|
|
3411
3433
|
next.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3412
3434
|
mkdirSync5(dirname4(GLOBAL_LEARNING_FILE2), { recursive: true });
|
|
3413
3435
|
const tmp = GLOBAL_LEARNING_FILE2 + ".tmp";
|
|
3414
|
-
|
|
3436
|
+
writeFileSync6(tmp, JSON.stringify(next, null, 2));
|
|
3415
3437
|
renameSync5(tmp, GLOBAL_LEARNING_FILE2);
|
|
3416
3438
|
return next;
|
|
3417
3439
|
});
|
|
@@ -3449,7 +3471,7 @@ function saveProjectState2(state) {
|
|
|
3449
3471
|
withFileLock3(PROJECT_STATE_FILE2, () => {
|
|
3450
3472
|
mkdirSync5(dirname4(PROJECT_STATE_FILE2), { recursive: true });
|
|
3451
3473
|
const _tmp = PROJECT_STATE_FILE2 + ".tmp." + Date.now();
|
|
3452
|
-
|
|
3474
|
+
writeFileSync6(_tmp, JSON.stringify(state, null, 2) + "\n", "utf-8");
|
|
3453
3475
|
renameSync5(_tmp, PROJECT_STATE_FILE2);
|
|
3454
3476
|
});
|
|
3455
3477
|
} catch (err) {
|
|
@@ -3712,7 +3734,7 @@ function researchAudit({ hours = 24, session: sessionFilter } = {}) {
|
|
|
3712
3734
|
}
|
|
3713
3735
|
|
|
3714
3736
|
// src/lib/reporting.js
|
|
3715
|
-
import { readFileSync as readFileSync8, writeFileSync as
|
|
3737
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync7, mkdirSync as mkdirSync6, statSync as statSync6, copyFileSync as copyFileSync5, rmSync as rmSync4 } from "node:fs";
|
|
3716
3738
|
import { join as join7, basename as basename6 } from "node:path";
|
|
3717
3739
|
import { homedir as homedir8, tmpdir as tmpdir6 } from "node:os";
|
|
3718
3740
|
var USER_HOME6 = (() => {
|
|
@@ -3761,7 +3783,7 @@ function saveReportsIndex(idx) {
|
|
|
3761
3783
|
try {
|
|
3762
3784
|
withFileLock(REPORTS_INDEX, () => {
|
|
3763
3785
|
mkdirSync6(REPORTS_DIR2, { recursive: true });
|
|
3764
|
-
|
|
3786
|
+
writeFileSync7(REPORTS_INDEX, JSON.stringify(idx, null, 2) + "\n");
|
|
3765
3787
|
});
|
|
3766
3788
|
} catch (err) {
|
|
3767
3789
|
console.error(`[vibeOS] reports index write failed: ${err.message}`);
|
|
@@ -3871,11 +3893,11 @@ function saveReport({ type = "manual", summary = "", findings = null, metrics =
|
|
|
3871
3893
|
try {
|
|
3872
3894
|
withFileLock(REPORTS_INDEX, () => {
|
|
3873
3895
|
mkdirSync6(REPORTS_DIR2, { recursive: true });
|
|
3874
|
-
|
|
3896
|
+
writeFileSync7(join7(REPORTS_DIR2, `${id2}.json`), JSON.stringify(report, null, 2) + "\n");
|
|
3875
3897
|
const idx = reportsIndex();
|
|
3876
3898
|
const _sum = (summary || "").slice(0, 80);
|
|
3877
3899
|
idx.reports.push({ id: id2, type, project: report.meta.project, fingerprint: fp3, created: report.meta.created, summary: _sum });
|
|
3878
|
-
|
|
3900
|
+
writeFileSync7(REPORTS_INDEX, JSON.stringify(idx, null, 2) + "\n");
|
|
3879
3901
|
});
|
|
3880
3902
|
} catch (err) {
|
|
3881
3903
|
console.error(`[vibeOS] report/index write failed: ${err.message}`);
|
|
@@ -3916,7 +3938,7 @@ function readReport(id2) {
|
|
|
3916
3938
|
}
|
|
3917
3939
|
|
|
3918
3940
|
// src/lib/credit-api.js
|
|
3919
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
3941
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, existsSync as existsSync8 } from "node:fs";
|
|
3920
3942
|
import { join as join8 } from "node:path";
|
|
3921
3943
|
function safeJsonParse4(raw) {
|
|
3922
3944
|
try {
|
|
@@ -3983,7 +4005,7 @@ async function _snapshot() {
|
|
|
3983
4005
|
}
|
|
3984
4006
|
}
|
|
3985
4007
|
try {
|
|
3986
|
-
|
|
4008
|
+
writeFileSync8(CREDIT_CACHE_F, JSON.stringify({ total, providers: provs, ts: Date.now() }));
|
|
3987
4009
|
} catch {
|
|
3988
4010
|
}
|
|
3989
4011
|
}
|
|
@@ -4051,13 +4073,14 @@ function thinkingLevel(credit) {
|
|
|
4051
4073
|
import { join as join9 } from "node:path";
|
|
4052
4074
|
function createTrinityTool(deps) {
|
|
4053
4075
|
return {
|
|
4054
|
-
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'.",
|
|
4076
|
+
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. Use action='api-token' with token='<new_token>' to update the API token and re-enable remote control-vector. Call this when the user says things like 'switch to medium', 'use cheap model', 'disable plugin', 'trinity status'.",
|
|
4055
4077
|
args: {
|
|
4056
|
-
action: deps.tool.schema.enum(["status", "enable", "disable", "set", "mode", "thinking", "flow", "tdd", "project", "patterns", "rebuild", "diagnose", "help", "enforce", "repair-state", "blackbox", "report", "target", "guard"]).optional(),
|
|
4078
|
+
action: deps.tool.schema.enum(["status", "enable", "disable", "set", "mode", "thinking", "flow", "tdd", "project", "patterns", "rebuild", "diagnose", "help", "enforce", "repair-state", "blackbox", "report", "target", "guard", "api-token"]).optional(),
|
|
4057
4079
|
slot: deps.tool.schema.enum(["brain", "medium", "cheap", "budget", "quality", "speed", "longrun", "auto", "on", "off", "enforce", "strict", "preview", "apply", "clear", "savings"]).optional(),
|
|
4058
|
-
level: deps.tool.schema.enum(["full", "brief", "off", "on"]).optional()
|
|
4080
|
+
level: deps.tool.schema.enum(["full", "brief", "off", "on"]).optional(),
|
|
4081
|
+
token: deps.tool.schema.string().optional()
|
|
4059
4082
|
},
|
|
4060
|
-
async execute({ action, slot, level } = {}) {
|
|
4083
|
+
async execute({ action, slot, level, token } = {}) {
|
|
4061
4084
|
if (typeof deps._lazyRefresh === "function")
|
|
4062
4085
|
deps._lazyRefresh();
|
|
4063
4086
|
if (!action)
|
|
@@ -4599,6 +4622,11 @@ ${L.repeat(40)}`);
|
|
|
4599
4622
|
lines.push("README.md: auto-maintained feature documentation \u2014 keep it updated.");
|
|
4600
4623
|
return lines.join("\n");
|
|
4601
4624
|
}
|
|
4625
|
+
if (action === "api-token") {
|
|
4626
|
+
if (!token) return "Usage: trinity api-token <token>\nProvide a valid VIBEOS_API_TOKEN to enable remote control-vector computation.";
|
|
4627
|
+
deps.setApiToken(token);
|
|
4628
|
+
return "[vibeOS] API token updated. Remote API re-enabled.";
|
|
4629
|
+
}
|
|
4602
4630
|
if (action === "rebuild") {
|
|
4603
4631
|
const providers = deps._loadOpenCodeProviders();
|
|
4604
4632
|
const auth = deps._readAuth();
|
|
@@ -4950,6 +4978,7 @@ ${L.repeat(40)}`);
|
|
|
4950
4978
|
" trinity flow on/off Toggle flow enforcer (code quality checks)",
|
|
4951
4979
|
" trinity tdd on/off Toggle auto test skeleton creation",
|
|
4952
4980
|
" trinity guard Ensure AGENTS.md/README.md exist and are current",
|
|
4981
|
+
" trinity api-token Update VIBEOS_API_TOKEN and re-enable remote API",
|
|
4953
4982
|
" trinity flow Show flow violations this session",
|
|
4954
4983
|
"",
|
|
4955
4984
|
"DIAGNOSTICS:",
|
|
@@ -5183,14 +5212,14 @@ import { join as join13 } from "node:path";
|
|
|
5183
5212
|
import { homedir as homedir10, tmpdir as tmpdir7 } from "node:os";
|
|
5184
5213
|
|
|
5185
5214
|
// src/lib/hooks/chat-transform.js
|
|
5186
|
-
import { readFileSync as readFileSync11, writeFileSync as
|
|
5215
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10, existsSync as existsSync10, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5187
5216
|
import { join as join12, basename as basename7 } from "node:path";
|
|
5188
5217
|
import { homedir as homedir9 } from "node:os";
|
|
5189
5218
|
import { createHash as createHash4 } from "node:crypto";
|
|
5190
5219
|
|
|
5191
5220
|
// src/lib/index-helpers.js
|
|
5192
5221
|
import { join as join11 } from "node:path";
|
|
5193
|
-
import { writeFileSync as
|
|
5222
|
+
import { writeFileSync as writeFileSync9 } from "node:fs";
|
|
5194
5223
|
|
|
5195
5224
|
// src/lib/text-compress.js
|
|
5196
5225
|
var VERBOSE_LINE_RE = [
|
|
@@ -5526,7 +5555,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
5526
5555
|
if (sd) {
|
|
5527
5556
|
const sp = join11(sd, "delegation-state-hint.txt");
|
|
5528
5557
|
try {
|
|
5529
|
-
|
|
5558
|
+
writeFileSync9(sp, JSON.stringify({ sid, total_savings: s.lifetime.total_savings_usd, last_reason: reason }), "utf8");
|
|
5530
5559
|
} catch {
|
|
5531
5560
|
}
|
|
5532
5561
|
}
|
|
@@ -5714,7 +5743,7 @@ function ensureProjectSkill(dir, fp22) {
|
|
|
5714
5743
|
}
|
|
5715
5744
|
try {
|
|
5716
5745
|
mkdirSync7(skillDir, { recursive: true });
|
|
5717
|
-
|
|
5746
|
+
writeFileSync10(skillPath, content, "utf-8");
|
|
5718
5747
|
console.error(`[vibeOS] Project Guard: created .opencode/skills/${projectName}/SKILL.md`);
|
|
5719
5748
|
return { created: true, path: skillPath, skipped: false };
|
|
5720
5749
|
} catch (err) {
|
|
@@ -5778,7 +5807,7 @@ function syncControlSettings(cv) {
|
|
|
5778
5807
|
const oc = safeJsonParse3(readFileSync11(OC_CONFIG, "utf-8"));
|
|
5779
5808
|
if (oc.default_agent !== cv.agent_mode) {
|
|
5780
5809
|
oc.default_agent = cv.agent_mode;
|
|
5781
|
-
|
|
5810
|
+
writeFileSync10(OC_CONFIG, JSON.stringify(oc, null, 2) + "\n");
|
|
5782
5811
|
}
|
|
5783
5812
|
}
|
|
5784
5813
|
} catch {
|
|
@@ -5793,7 +5822,7 @@ function syncControlSettings(cv) {
|
|
|
5793
5822
|
const oc = safeJsonParse3(readFileSync11(OC_CONFIG, "utf-8"));
|
|
5794
5823
|
if (oc.default_agent === "plan") {
|
|
5795
5824
|
oc.default_agent = "orchestrator";
|
|
5796
|
-
|
|
5825
|
+
writeFileSync10(OC_CONFIG, JSON.stringify(oc, null, 2) + "\n");
|
|
5797
5826
|
}
|
|
5798
5827
|
}
|
|
5799
5828
|
} catch {
|
|
@@ -5828,7 +5857,7 @@ ${raw}
|
|
|
5828
5857
|
try {
|
|
5829
5858
|
ensureSessionScratchpadDirs();
|
|
5830
5859
|
if (!existsSync10(fullPath)) {
|
|
5831
|
-
|
|
5860
|
+
writeFileSync10(fullPath, raw);
|
|
5832
5861
|
indexAppend(hash, part.tool, raw.length);
|
|
5833
5862
|
}
|
|
5834
5863
|
} catch (err) {
|
|
@@ -6340,12 +6369,12 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6340
6369
|
}
|
|
6341
6370
|
|
|
6342
6371
|
// src/lib/hooks/tool-execute.js
|
|
6343
|
-
import { writeFileSync as
|
|
6372
|
+
import { writeFileSync as writeFileSync12, appendFileSync as appendFileSync7, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "node:fs";
|
|
6344
6373
|
import { dirname as dirname6, basename as basename8 } from "node:path";
|
|
6345
6374
|
init_flow_enforcer();
|
|
6346
6375
|
|
|
6347
6376
|
// src/lib/tdd-enforcer.js
|
|
6348
|
-
import { readFileSync as readFileSync13, writeFileSync as
|
|
6377
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, appendFileSync as appendFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync8, statSync as statSync7, readdirSync as readdirSync2, rmSync as rmSync5, openSync as openSync4 } from "node:fs";
|
|
6349
6378
|
import { join as join14, dirname as dirname5 } from "node:path";
|
|
6350
6379
|
import { createHash as createHash5 } from "node:crypto";
|
|
6351
6380
|
|
|
@@ -7508,7 +7537,7 @@ function _recordCooldown(testPath) {
|
|
|
7508
7537
|
appendFileSync6(ENFORCEMENT_COOLDOWN_FILE2, entry);
|
|
7509
7538
|
const lines = readFileSync13(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
7510
7539
|
if (lines.length > 500) {
|
|
7511
|
-
|
|
7540
|
+
writeFileSync11(ENFORCEMENT_COOLDOWN_FILE2, lines.slice(-200).join("\n") + "\n");
|
|
7512
7541
|
}
|
|
7513
7542
|
} catch {
|
|
7514
7543
|
}
|
|
@@ -7595,7 +7624,7 @@ function enforceTestFile(filePath) {
|
|
|
7595
7624
|
return null;
|
|
7596
7625
|
try {
|
|
7597
7626
|
mkdirSync8(skeleton.dir, { recursive: true });
|
|
7598
|
-
|
|
7627
|
+
writeFileSync11(skeleton.path, skeleton.content);
|
|
7599
7628
|
_enforcementCooldown.add(skeleton.path);
|
|
7600
7629
|
_recordCooldown(skeleton.path);
|
|
7601
7630
|
try {
|
|
@@ -7884,7 +7913,7 @@ var onToolExecuteBefore = async (input, output) => {
|
|
|
7884
7913
|
if (!existsSync12(CONTEXT7_INSTALL_FLAG)) {
|
|
7885
7914
|
try {
|
|
7886
7915
|
mkdirSync9(dirname6(CONTEXT7_INSTALL_FLAG), { recursive: true });
|
|
7887
|
-
|
|
7916
|
+
writeFileSync12(CONTEXT7_INSTALL_FLAG, "");
|
|
7888
7917
|
} catch {
|
|
7889
7918
|
}
|
|
7890
7919
|
console.error(`[vibeOS] \u{1F4A1} Install context7 MCP to save ~$0.06/turn on docs: \`claude mcp add context7 npx @upstash/context7-mcp\``);
|
|
@@ -8340,7 +8369,7 @@ function persistMcpPort(port) {
|
|
|
8340
8369
|
tiers.selection.mcp_port = port;
|
|
8341
8370
|
mkdirSync10(dirname7(TIERS_FILE2), { recursive: true });
|
|
8342
8371
|
const tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
8343
|
-
|
|
8372
|
+
writeFileSync13(tmp, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
8344
8373
|
renameSync6(tmp, TIERS_FILE2);
|
|
8345
8374
|
} catch {
|
|
8346
8375
|
}
|
|
@@ -8606,7 +8635,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8606
8635
|
if (_tiersData2.selection.mcp_port === void 0) _tiersData2.selection.mcp_port = 9578;
|
|
8607
8636
|
mkdirSync10(dirname7(TIERS_FILE2), { recursive: true });
|
|
8608
8637
|
const _tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
8609
|
-
|
|
8638
|
+
writeFileSync13(_tmp, JSON.stringify(_tiersData2, null, 2) + "\n", "utf-8");
|
|
8610
8639
|
renameSync6(_tmp, TIERS_FILE2);
|
|
8611
8640
|
console.error(`[vibeOS] auto-synced model-tiers.json: brain=${_brain.id} medium=${_tiersData2.trinity?.medium?.oc || ""} cheap=${_tiersData2.trinity?.cheap?.oc || ""}`);
|
|
8612
8641
|
const _tiersCfg = safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
@@ -8630,7 +8659,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8630
8659
|
if (_mt.selection && (_mt.selection.mcp_port === void 0 || _mt.selection.mcp_port === null)) {
|
|
8631
8660
|
_mt.selection.mcp_port = 9578;
|
|
8632
8661
|
const _tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
8633
|
-
|
|
8662
|
+
writeFileSync13(_tmp, JSON.stringify(_mt, null, 2) + "\n", "utf-8");
|
|
8634
8663
|
renameSync6(_tmp, TIERS_FILE2);
|
|
8635
8664
|
}
|
|
8636
8665
|
} catch {
|
|
@@ -8688,7 +8717,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8688
8717
|
directory: directory3,
|
|
8689
8718
|
safeJsonParse: safeJsonParse3,
|
|
8690
8719
|
readFileSync: readFileSync15,
|
|
8691
|
-
writeFileSync:
|
|
8720
|
+
writeFileSync: writeFileSync13,
|
|
8692
8721
|
existsSync: existsSync14,
|
|
8693
8722
|
renameSync: renameSync6,
|
|
8694
8723
|
TIERS_FILE: TIERS_FILE2,
|
|
@@ -8734,8 +8763,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8734
8763
|
backupFile,
|
|
8735
8764
|
writeSessionSlot,
|
|
8736
8765
|
_refreshModel,
|
|
8737
|
-
|
|
8738
|
-
_refreshModel,
|
|
8766
|
+
setApiToken,
|
|
8739
8767
|
get _blackboxTracker() {
|
|
8740
8768
|
return getBlackboxTracker();
|
|
8741
8769
|
},
|