vibeostheog 0.25.35 → 0.25.37

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 CHANGED
@@ -1,8 +1,11 @@
1
+ ## 0.25.37
2
+ - fix: add permission prompt to setup.js + contract tests for install flow (#251) (#251)
3
+
4
+
1
5
  ## 0.25.34
2
6
  - feat: holistic semantic observer replacing pattern learner (#245)
3
- - fix: use .js imports for CI compatibility
4
- - fix: rewrite cascade contract tests to match actual cascadeDecide/computeDifficulty behavior
5
- - fix: replace cascade source-code regex toy test with real behavioral contract tests
7
+ - fix: re-establish npm link after publish + contract test for bin symlink (#248) (#249)
8
+ - fix: replace cascade source-code regex toy test with real behavioral contract tests (#248)
6
9
  - fix: anti-lie path resolution — verify-claims respects $VIBEOS_HOME, no double .claude nesting (#247)
7
10
  - fix: persist slot_locked on lock on/off, remove duplicate loadSelection in pricing (#246)
8
11
  - fix: remove hardcoded model names from fallback
package/bin/setup.js CHANGED
@@ -4,20 +4,41 @@ import { execSync } from "node:child_process";
4
4
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
5
5
  import { dirname, resolve } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
- import { resolveOpenCodeHome } from "../scripts/lib/opencode-homes.mjs";
7
+ import { createInterface } from "node:readline";
8
+ import { resolveOpenCodeHome, resolveOpenCodeHomes } from "../scripts/lib/opencode-homes.mjs";
8
9
 
9
10
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
11
  const root = resolve(__dirname, "..");
11
12
  const args = process.argv.slice(2);
12
- const command = args[0] ?? "setup";
13
+ const command = args.find(a => !a.startsWith("-")) ?? "setup";
13
14
  const isInstallCommand = command === "setup" || command === "set";
14
15
  const isProject = args.includes("--project");
16
+ const isYes = args.includes("--yes") || args.includes("-y");
15
17
 
16
- if (!isInstallCommand) {
17
- console.error("Usage: vibeostheog set [--project] | vibeostheog setup [--project]");
18
+ if (!isInstallCommand || args.includes("--help") || args.includes("-h")) {
19
+ console.error("Usage: vibeostheog set [--yes] [--project] | vibeostheog setup [--yes] [--project]");
18
20
  process.exit(1);
19
21
  }
20
22
 
23
+ // Permission prompt
24
+ const homes = resolveOpenCodeHomes({ cwd: process.cwd() });
25
+ console.log("");
26
+ console.log("vibeOS — cost-aware delegation enforcer for OpenCode");
27
+ console.log("");
28
+ console.log("This will install vibeOS plugin to the following directories:");
29
+ for (const h of homes) console.log(" " + h);
30
+ console.log("");
31
+
32
+ if (!isYes && process.stdin.isTTY && process.stderr.isTTY) {
33
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
34
+ const answer = await new Promise((resolve) => rl.question("Install vibeOS into OpenCode? [y/N] ", resolve));
35
+ rl.close();
36
+ if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
37
+ console.log("Installation cancelled.");
38
+ process.exit(0);
39
+ }
40
+ }
41
+
21
42
  // Deploy plugin files to ~/.config/opencode/plugins/ and register globally
22
43
  const deployScript = resolve(root, "scripts", "deploy.mjs");
23
44
  if (!existsSync(deployScript)) {
@@ -51,4 +72,5 @@ if (isProject) {
51
72
  console.log(`vibeOS registered in ${configPath}`);
52
73
  }
53
74
 
75
+ console.log("");
54
76
  console.log("Done. Restart OpenCode to activate the plugin.");
@@ -1 +1 @@
1
- window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:53086";
1
+ window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:55491";
package/dist/vibeOS.js CHANGED
@@ -5114,7 +5114,7 @@ var init_vibeultrax = __esm({
5114
5114
 
5115
5115
  // src/index.ts
5116
5116
  init_flow_enforcer();
5117
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync17, existsSync as existsSync20, mkdirSync as mkdirSync15, copyFileSync as copyFileSync2, renameSync as renameSync6, statSync as statSync10 } from "node:fs";
5117
+ import { readFileSync as readFileSync18, writeFileSync as writeFileSync17, existsSync as existsSync19, mkdirSync as mkdirSync15, copyFileSync as copyFileSync2, renameSync as renameSync6, statSync as statSync9 } from "node:fs";
5118
5118
  import { join as join19, dirname as dirname13, basename as basename5 } from "node:path";
5119
5119
 
5120
5120
  // src/vibeOS-lib/session-metrics.js
@@ -11236,7 +11236,7 @@ async function probeModel(modelId, auth, providers = null) {
11236
11236
  }
11237
11237
 
11238
11238
  // src/lib/hooks/footer.js
11239
- import { readFileSync as readFileSync15, appendFileSync as appendFileSync5, existsSync as existsSync16, mkdirSync as mkdirSync12, statSync as statSync8 } from "node:fs";
11239
+ import { readFileSync as readFileSync15, appendFileSync as appendFileSync5, mkdirSync as mkdirSync12 } from "node:fs";
11240
11240
  import { join as join16 } from "node:path";
11241
11241
 
11242
11242
  // src/lib/hooks/chat-transform.js
@@ -13429,52 +13429,14 @@ async function _appendFooter(input, output, directory3) {
13429
13429
  const rawMode = (typeof loadSelection2 === "function" ? loadSelection2()?.requested_optimization_mode || loadSelection2()?.optimization_mode : null) || displayMode;
13430
13430
  const cv = computeControlVector2({ sub_regime: currentSubRegime, latest_stress_multiplier: _footerStress, user_text: latestUserIntent || "" }, void 0, rawMode);
13431
13431
  const vibeBrand = resolveBrand(loadOptimizationMode() || displayMode, activeSlot);
13432
- let _claimTag = "\u2713";
13433
- const claimAuditFile = join16(VIBEOS_HOME, "cascade-audit", "claim-audit.jsonl");
13434
- const cascadeAuditFile = join16(VIBEOS_HOME, "cascade-audit", "cascade-audit.jsonl");
13435
- if (existsSync16(claimAuditFile) && statSync8(claimAuditFile).size > 0) {
13436
- try {
13437
- const claimLines = readFileSync15(claimAuditFile, "utf-8").trim().split("\n").slice(-10);
13438
- const cascadeLines = readFileSync15(cascadeAuditFile, "utf-8").trim().split("\n").slice(-30);
13439
- const cascadeRuns = cascadeLines.filter(Boolean).map((l) => {
13440
- try {
13441
- return JSON.parse(l);
13442
- } catch {
13443
- }
13444
- }).filter(Boolean);
13445
- let unsub = false;
13446
- for (const cl of claimLines) {
13447
- if (!cl.trim())
13448
- continue;
13449
- let entry;
13450
- try {
13451
- entry = JSON.parse(cl);
13452
- } catch {
13453
- continue;
13454
- }
13455
- if (!entry)
13456
- continue;
13457
- const claimTexts = (entry.claims || []).map((c) => c.text).join(" | ");
13458
- if (!/(?:done|fixed|validated|works|score|%|passed|verified|solved|resolved)/i.test(claimTexts))
13459
- continue;
13460
- let cascadeMatch = false;
13461
- for (const cr of cascadeRuns) {
13462
- const cTs = cr._ts || "";
13463
- if (cTs && entry.ts) {
13464
- if (Math.abs(new Date(cTs).getTime() - new Date(entry.ts).getTime()) < 12e4) {
13465
- cascadeMatch = true;
13466
- break;
13467
- }
13468
- }
13469
- }
13470
- if (!cascadeMatch) {
13471
- unsub = true;
13472
- break;
13473
- }
13432
+ const _cp = [/(?:\u005c|['"](?:done|fixed|validated|works|verified|solved|resolved)['"]|\d+%|score|passed)/i];
13433
+ let _claimTag = "";
13434
+ if (text) {
13435
+ for (const _p of _cp) {
13436
+ if (_p.test(text)) {
13437
+ _claimTag = "[CLAIMS]";
13438
+ break;
13474
13439
  }
13475
- _claimTag = unsub ? "\u26A0" : "\u2713";
13476
- } catch {
13477
- _claimTag = "\u26A0";
13478
13440
  }
13479
13441
  }
13480
13442
  const vibeLine = buildFooterLine({
@@ -13551,7 +13513,7 @@ ${vibeLine} \u2014`);
13551
13513
 
13552
13514
  // src/lib/hooks/tool-execute.js
13553
13515
  init_state();
13554
- import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync7, existsSync as existsSync18, mkdirSync as mkdirSync14 } from "node:fs";
13516
+ import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync7, existsSync as existsSync17, mkdirSync as mkdirSync14 } from "node:fs";
13555
13517
  import { join as join18, dirname as dirname12, basename as basename4 } from "node:path";
13556
13518
  import { createHash as createHash5 } from "node:crypto";
13557
13519
  init_selection_manager();
@@ -13621,7 +13583,7 @@ init_smart_cache();
13621
13583
 
13622
13584
  // src/lib/tdd-enforcer.js
13623
13585
  init_state();
13624
- import { readFileSync as readFileSync16, writeFileSync as writeFileSync15, appendFileSync as appendFileSync6, existsSync as existsSync17, mkdirSync as mkdirSync13, statSync as statSync9, readdirSync as readdirSync4, rmSync as rmSync6, openSync as openSync3 } from "node:fs";
13586
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync15, appendFileSync as appendFileSync6, existsSync as existsSync16, mkdirSync as mkdirSync13, statSync as statSync8, readdirSync as readdirSync4, rmSync as rmSync6, openSync as openSync3 } from "node:fs";
13625
13587
  import { join as join17, dirname as dirname11 } from "node:path";
13626
13588
  import { createHash as createHash4 } from "node:crypto";
13627
13589
 
@@ -14765,7 +14727,7 @@ function _detectTestFramework() {
14765
14727
  try {
14766
14728
  const root = directory || process.cwd();
14767
14729
  const pkgPath = join17(root, "package.json");
14768
- if (existsSync17(pkgPath)) {
14730
+ if (existsSync16(pkgPath)) {
14769
14731
  const pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
14770
14732
  const testScript = String(pkg?.scripts?.test || "");
14771
14733
  const deps = { ...pkg?.devDependencies, ...pkg?.dependencies };
@@ -14787,7 +14749,7 @@ function _detectTestFramework() {
14787
14749
  const testDirs = ["src/tests", "tests", "test", "__tests__"];
14788
14750
  for (const td of testDirs) {
14789
14751
  const dirPath = join17(root, td);
14790
- if (!existsSync17(dirPath))
14752
+ if (!existsSync16(dirPath))
14791
14753
  continue;
14792
14754
  const files = readdirSync4(dirPath).filter((f) => /\.test\./.test(f) || /\.spec\./.test(f));
14793
14755
  if (files.length > 0) {
@@ -14834,7 +14796,7 @@ function _acquireLock(testPath) {
14834
14796
  if (err.code !== "EEXIST")
14835
14797
  return false;
14836
14798
  try {
14837
- const st = statSync9(lockPath);
14799
+ const st = statSync8(lockPath);
14838
14800
  if (Date.now() - st.mtimeMs >= LOCK_EXPIRE_MS) {
14839
14801
  rmSync6(lockPath, { force: true });
14840
14802
  try {
@@ -14861,7 +14823,7 @@ function _releaseLock(testPath) {
14861
14823
  }
14862
14824
  function _isInCooldown(testPath) {
14863
14825
  try {
14864
- if (!existsSync17(ENFORCEMENT_COOLDOWN_FILE2))
14826
+ if (!existsSync16(ENFORCEMENT_COOLDOWN_FILE2))
14865
14827
  return false;
14866
14828
  const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
14867
14829
  const lines = readFileSync16(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
@@ -14955,7 +14917,7 @@ function enforceTestFile(filePath) {
14955
14917
  console.error(`[vibeOS] [tdd-enforce] enforceTestFile called for ${filePath}`);
14956
14918
  let sourceContent = "";
14957
14919
  try {
14958
- if (existsSync17(filePath)) {
14920
+ if (existsSync16(filePath)) {
14959
14921
  sourceContent = readFileSync16(filePath, "utf-8");
14960
14922
  }
14961
14923
  } catch {
@@ -14964,7 +14926,7 @@ function enforceTestFile(filePath) {
14964
14926
  const skeleton = buildTestSkeleton(filePath, sourceContent, { strict: sel.tdd_strict !== false, quality: sel.tdd_quality !== false });
14965
14927
  if (!skeleton)
14966
14928
  return null;
14967
- if (existsSync17(skeleton.path))
14929
+ if (existsSync16(skeleton.path))
14968
14930
  return null;
14969
14931
  if (_enforcementCooldown.has(skeleton.path))
14970
14932
  return null;
@@ -15316,14 +15278,14 @@ ${argsJson}
15316
15278
  const sessionDir = getSessionScratchpadDir();
15317
15279
  const globalDir = SCRATCHPAD_GLOBAL_DIR;
15318
15280
  const ptrPath = join18(sessionDir, `${curHash}.ptr`);
15319
- if (!existsSync18(ptrPath)) {
15281
+ if (!existsSync17(ptrPath)) {
15320
15282
  for (const similar of prediction.similarEntries) {
15321
15283
  const targetHash = similar.entry.hash;
15322
15284
  if (targetHash.length < 16)
15323
15285
  continue;
15324
15286
  const cachedFile = join18(sessionDir, `${targetHash}.txt`);
15325
15287
  const globalFile = join18(globalDir, `${targetHash}.txt`);
15326
- if (existsSync18(cachedFile) || existsSync18(globalFile)) {
15288
+ if (existsSync17(cachedFile) || existsSync17(globalFile)) {
15327
15289
  ensureSessionScratchpadDirs();
15328
15290
  writeFileSync16(ptrPath, JSON.stringify({
15329
15291
  contentHash: targetHash,
@@ -15632,7 +15594,7 @@ ${argsJson}
15632
15594
  }
15633
15595
  } else {
15634
15596
  const missed = recordMissedContext7(_estC7);
15635
- if (!existsSync18(CONTEXT7_INSTALL_FLAG)) {
15597
+ if (!existsSync17(CONTEXT7_INSTALL_FLAG)) {
15636
15598
  try {
15637
15599
  mkdirSync14(dirname12(CONTEXT7_INSTALL_FLAG), { recursive: true });
15638
15600
  writeFileSync16(CONTEXT7_INSTALL_FLAG, "");
@@ -16075,7 +16037,7 @@ ${pendingUiNote}`;
16075
16037
 
16076
16038
  // src/lib/hooks/session-compact.js
16077
16039
  init_state();
16078
- import { readFileSync as readFileSync17, existsSync as existsSync19 } from "node:fs";
16040
+ import { readFileSync as readFileSync17, existsSync as existsSync18 } from "node:fs";
16079
16041
  var onSessionCompacting = async (_input, output) => {
16080
16042
  if (!loadSelection().enabled)
16081
16043
  return;
@@ -16084,7 +16046,7 @@ var onSessionCompacting = async (_input, output) => {
16084
16046
  const needsCompact = turnCount >= 7;
16085
16047
  const indexPath = getSessionIndexPath();
16086
16048
  let recent = "";
16087
- if (existsSync19(indexPath)) {
16049
+ if (existsSync18(indexPath)) {
16088
16050
  try {
16089
16051
  const lines = readFileSync17(indexPath, "utf-8").trim().split("\n").slice(-30);
16090
16052
  recent = lines.map((l) => {
@@ -16236,9 +16198,9 @@ var _runDeferredStartupBootstrap = null;
16236
16198
  function _readOpenCodeConfigObject(dir) {
16237
16199
  const jsonPath = join19(dir, "opencode.json");
16238
16200
  const jsoncPath = join19(dir, "opencode.jsonc");
16239
- if (existsSync20(jsonPath))
16201
+ if (existsSync19(jsonPath))
16240
16202
  return safeJsonParse2(readFileSync18(jsonPath, "utf-8"));
16241
- if (existsSync20(jsoncPath))
16203
+ if (existsSync19(jsoncPath))
16242
16204
  return _parseJsonc(readFileSync18(jsoncPath, "utf-8"));
16243
16205
  return {};
16244
16206
  }
@@ -16291,7 +16253,7 @@ function _loadActiveJobForProject(directory3, fp2 = "") {
16291
16253
  for (const base of candidates) {
16292
16254
  try {
16293
16255
  const activeJobsPath = join19(String(base), "active-jobs.json");
16294
- if (!existsSync20(activeJobsPath))
16256
+ if (!existsSync19(activeJobsPath))
16295
16257
  continue;
16296
16258
  const jobs = safeJsonParse2(readFileSync18(activeJobsPath, "utf-8")) || {};
16297
16259
  const job = fp2 ? jobs?.[fp2] : null;
@@ -16313,9 +16275,9 @@ function _tiersNeedRepair(tiers) {
16313
16275
  async function _seedOrRepairModelTiers(directory3) {
16314
16276
  const TIERS_FILE3 = getTiersFile();
16315
16277
  let existing = null;
16316
- if (existsSync20(TIERS_FILE3)) {
16278
+ if (existsSync19(TIERS_FILE3)) {
16317
16279
  try {
16318
- const st = statSync10(TIERS_FILE3);
16280
+ const st = statSync9(TIERS_FILE3);
16319
16281
  if (st.size > 10485760) {
16320
16282
  _handleStateCorruption(TIERS_FILE3);
16321
16283
  return false;
@@ -16426,7 +16388,7 @@ function loadMcpPort() {
16426
16388
  return n;
16427
16389
  }
16428
16390
  try {
16429
- if (existsSync20(getTiersFile())) {
16391
+ if (existsSync19(getTiersFile())) {
16430
16392
  const tiers = safeJsonParse2(readFileSync18(getTiersFile(), "utf-8"));
16431
16393
  const cfg = tiers?.selection?.mcp_port;
16432
16394
  if (cfg === false || cfg === "disabled" || cfg === 0)
@@ -16441,7 +16403,7 @@ function loadMcpPort() {
16441
16403
  }
16442
16404
  function persistMcpPort(port) {
16443
16405
  try {
16444
- if (!existsSync20(getTiersFile()))
16406
+ if (!existsSync19(getTiersFile()))
16445
16407
  return;
16446
16408
  const tiers = safeJsonParse2(readFileSync18(getTiersFile(), "utf-8"));
16447
16409
  tiers.selection ??= {};
@@ -16543,7 +16505,7 @@ async function ensureMcpServerRunning() {
16543
16505
  getSessionMetrics: () => computeSessionMetrics(readFullState(), _OC_SID),
16544
16506
  getTodos: () => loadTodos(),
16545
16507
  listReports: (filter) => {
16546
- if (!existsSync20(getReportsDir2())) {
16508
+ if (!existsSync19(getReportsDir2())) {
16547
16509
  const e = new Error("reports dir not found");
16548
16510
  e.status = 404;
16549
16511
  throw e;
@@ -16756,9 +16718,9 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
16756
16718
  }
16757
16719
  } catch {
16758
16720
  }
16759
- console.error(`[vibeOS] auto-config guard: currentModel=${currentModel ? "SET" : "NONE"}, TIERS_FILE=${getTiersFile()}, exists=${existsSync20(getTiersFile())}`);
16721
+ console.error(`[vibeOS] auto-config guard: currentModel=${currentModel ? "SET" : "NONE"}, TIERS_FILE=${getTiersFile()}, exists=${existsSync19(getTiersFile())}`);
16760
16722
  try {
16761
- if (!existsSync20(getTiersFile())) {
16723
+ if (!existsSync19(getTiersFile())) {
16762
16724
  console.error(`[vibeOS] model-tiers.json missing at load; will seed on first hook`);
16763
16725
  }
16764
16726
  await _seedOrRepairModelTiers(directory3);
@@ -16818,7 +16780,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
16818
16780
  };
16819
16781
  const backupFileStable = (path, label) => {
16820
16782
  try {
16821
- if (!existsSync20(path))
16783
+ if (!existsSync19(path))
16822
16784
  return null;
16823
16785
  const bkDir = join19(hookVibeHome, ".backups");
16824
16786
  mkdirSync15(bkDir, { recursive: true });
@@ -16858,7 +16820,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
16858
16820
  safeJsonParse: safeJsonParse2,
16859
16821
  readFileSync: readFileSync18,
16860
16822
  writeFileSync: writeFileSync17,
16861
- existsSync: existsSync20,
16823
+ existsSync: existsSync19,
16862
16824
  renameSync: renameSync6,
16863
16825
  mkdirSync: mkdirSync15,
16864
16826
  get TIERS_FILE() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.25.35",
3
+ "version": "0.25.37",
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",
@@ -27,7 +27,8 @@
27
27
  "lint": "eslint src/",
28
28
  "lint:fix": "eslint src/ --fix",
29
29
  "test:coverage": "c8 --reporter=text --reporter=html npm test",
30
- "typecheck:strict": "tsc -p tsconfig.strict.json --noEmit"
30
+ "typecheck:strict": "tsc -p tsconfig.strict.json --noEmit",
31
+ "postpublish": "npm link --force"
31
32
  },
32
33
  "type": "module",
33
34
  "main": "./dist/vibeOS.js",