vibeostheog 0.25.22 → 0.25.25

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,3 +1,11 @@
1
+ ## 0.25.25
2
+ - fix: make deploy install tests platform-aware (skip macOS path on Linux)
3
+ - fix: resolveOpenCodeHomes() merges workspace + desktop homes
4
+ - fix: resolveOpenCodeHomes() now merges workspace + desktop homes
5
+ - fix: use getVibeOSHome() for hookVibeHome instead of hardcoded join(home, .claude) (#202)
6
+ Merge branch 'origin/master' — incorporate upstream changes
7
+
8
+
1
9
  ## 0.25.22
2
10
  - fix: include installer helper in package
3
11
 
@@ -1 +1 @@
1
- window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:50016";
1
+ window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:37161";
package/dist/vibeOS.js CHANGED
@@ -6851,6 +6851,7 @@ var ResolutionTracker = class _ResolutionTracker {
6851
6851
  this.pivotHistory = [];
6852
6852
  this.outcomeHistory = [];
6853
6853
  this.calibratedWeights = null;
6854
+ this.recentMessageLengths = [];
6854
6855
  }
6855
6856
  static extractFeatures(text) {
6856
6857
  if (!text || typeof text !== "string")
@@ -6925,13 +6926,18 @@ var ResolutionTracker = class _ResolutionTracker {
6925
6926
  getRepeatStreak() {
6926
6927
  if (this.history.length < 2)
6927
6928
  return 0;
6928
- const normalizedLast = this.normalizeText(this.history[this.history.length - 1].text);
6929
- if (!normalizedLast)
6929
+ const lastWords = new Set(this.history[this.history.length - 1].text.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
6930
+ if (lastWords.size === 0)
6930
6931
  return 0;
6931
6932
  let streak = 1;
6932
6933
  for (let i = this.history.length - 2; i >= 0; i--) {
6933
- const normalized = this.normalizeText(this.history[i].text);
6934
- if (!normalized || normalized !== normalizedLast)
6934
+ const currWords = new Set(this.history[i].text.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
6935
+ if (currWords.size === 0)
6936
+ break;
6937
+ const intersection = new Set([...lastWords].filter((w) => currWords.has(w)));
6938
+ const union = /* @__PURE__ */ new Set([...lastWords, ...currWords]);
6939
+ const jaccard = intersection.size / Math.max(union.size, 1);
6940
+ if (jaccard < 0.7)
6935
6941
  break;
6936
6942
  streak++;
6937
6943
  }
@@ -6967,6 +6973,39 @@ var ResolutionTracker = class _ResolutionTracker {
6967
6973
  }
6968
6974
  return streak;
6969
6975
  }
6976
+ getRecentNegativeOutcomeStreak() {
6977
+ if (this.outcomeHistory.length < 1)
6978
+ return 0;
6979
+ let streak = 0;
6980
+ for (let i = this.outcomeHistory.length - 1; i >= 0; i--) {
6981
+ const o = this.outcomeHistory[i];
6982
+ if (/negative|failed|unresolved|loop_detected/i.test(String(o?.outcome || "")))
6983
+ streak++;
6984
+ else
6985
+ break;
6986
+ }
6987
+ return streak;
6988
+ }
6989
+ computeMessageLengthTrend() {
6990
+ const lengths = this.recentMessageLengths;
6991
+ if (lengths.length < 3)
6992
+ return { trend: "stable", slope: 0 };
6993
+ const pairs = lengths.slice(-4);
6994
+ let decreasingCount = 0;
6995
+ let totalSlope = 0;
6996
+ for (let i = 1; i < pairs.length; i++) {
6997
+ const diff = pairs[i] - pairs[i - 1];
6998
+ if (diff < 0)
6999
+ decreasingCount++;
7000
+ totalSlope += diff;
7001
+ }
7002
+ const ratio = decreasingCount / (pairs.length - 1);
7003
+ const avgSlope = pairs.length > 1 ? totalSlope / (pairs.length - 1) : 0;
7004
+ return {
7005
+ trend: ratio >= 0.6 && avgSlope < 0 ? "shortening" : "stable",
7006
+ slope: avgSlope
7007
+ };
7008
+ }
6970
7009
  update(userText, features, action, entropy, uncertainty, embedding = null, activity = null) {
6971
7010
  const normalizedActivity = this.normalizeActivity(activity, action, userText);
6972
7011
  const entry = {
@@ -6986,6 +7025,9 @@ var ResolutionTracker = class _ResolutionTracker {
6986
7025
  }
6987
7026
  }
6988
7027
  this.history.push(entry);
7028
+ this.recentMessageLengths.push((userText || "").length);
7029
+ if (this.recentMessageLengths.length > 6)
7030
+ this.recentMessageLengths.shift();
6989
7031
  if (this.history.length > this.maxHistory) {
6990
7032
  this.history.shift();
6991
7033
  }
@@ -7121,6 +7163,9 @@ var ResolutionTracker = class _ResolutionTracker {
7121
7163
  pivot_detected: pivotDetected,
7122
7164
  pivot_score: Math.round(pivotScore * 1e4) / 1e4,
7123
7165
  outcome: lastEntry.outcome || null,
7166
+ outcome_negative_streak: this.getRecentNegativeOutcomeStreak(),
7167
+ message_length_trend: this.computeMessageLengthTrend().trend,
7168
+ message_length_slope: this.computeMessageLengthTrend().slope,
7124
7169
  n_interactions: n
7125
7170
  };
7126
7171
  }
@@ -7171,7 +7216,8 @@ var ResolutionTracker = class _ResolutionTracker {
7171
7216
  }
7172
7217
  detectLoop() {
7173
7218
  const repeatSignal = Math.max(this.getRepeatStreak(), this.getActivityRepeatStreak(), this.getTargetRepeatStreak());
7174
- return this.loopCount >= 2 || repeatSignal >= 2;
7219
+ const negativeOutcomeStreak = this.getRecentNegativeOutcomeStreak();
7220
+ return this.loopCount >= 2 || repeatSignal >= 2 || negativeOutcomeStreak >= 2;
7175
7221
  }
7176
7222
  computeIntentState() {
7177
7223
  const last = this.history[this.history.length - 1];
@@ -7215,6 +7261,7 @@ var ResolutionTracker = class _ResolutionTracker {
7215
7261
  this.loopCount = 0;
7216
7262
  this.pivotHistory = [];
7217
7263
  this.outcomeHistory = [];
7264
+ this.recentMessageLengths = [];
7218
7265
  }
7219
7266
  recordOutcome(outcome) {
7220
7267
  const entry = this.history[this.history.length - 1];
@@ -7280,6 +7327,7 @@ var ResolutionTracker = class _ResolutionTracker {
7280
7327
  loopCount: this.loopCount,
7281
7328
  pivotHistory: this.pivotHistory,
7282
7329
  outcomeHistory: this.outcomeHistory,
7330
+ recentMessageLengths: this.recentMessageLengths,
7283
7331
  calibratedWeights: this.calibratedWeights
7284
7332
  };
7285
7333
  }
@@ -7292,6 +7340,7 @@ var ResolutionTracker = class _ResolutionTracker {
7292
7340
  tracker.loopCount = Number(data.loopCount || 0);
7293
7341
  tracker.pivotHistory = Array.isArray(data.pivotHistory) ? data.pivotHistory : [];
7294
7342
  tracker.outcomeHistory = Array.isArray(data.outcomeHistory) ? data.outcomeHistory : [];
7343
+ tracker.recentMessageLengths = Array.isArray(data.recentMessageLengths) ? data.recentMessageLengths : [];
7295
7344
  tracker.calibratedWeights = data.calibratedWeights || null;
7296
7345
  return tracker;
7297
7346
  }
@@ -7425,9 +7474,9 @@ init_state();
7425
7474
  function detectOutcomeSignal(text) {
7426
7475
  if (!text)
7427
7476
  return null;
7428
- if (/thank|perfect|exactly|that.?s it|works great|works perfectly|solved|fixed|awesome|you rock/i.test(text))
7477
+ if (/thank|perfect|exactly|that.?s it|works great|works perfectly|solved|fixed|awesome|you rock|that works|finally|progress|much better|getting there|closer now/i.test(text))
7429
7478
  return "positive";
7430
- if (/doesn.?t work|still broken|not working|incorrect|wrong|failed|error|useless|stuck/i.test(text))
7479
+ if (/doesn.?t work|still broken|not working|incorrect|wrong|failed|error|useless|stuck|still failing|broke again|worse|regression|new (problem|bug|issue|error)|made it worse|every (fix|change|attempt) (broke|breaks|introduces)|went backwards|back to square|start over|same (issue|problem|error) (again|still)|(another|yet another|different) (error|problem|issue)|(still|again|still not) (the|at|same)|\d+\s*(times|attempts|tries) (and|but) (still|same|same result)/i.test(text))
7431
7480
  return "negative";
7432
7481
  return null;
7433
7482
  }
@@ -7464,6 +7513,8 @@ function getBehavioralStressSignals(context, blackboxState) {
7464
7513
  const repeatStreak = Number(blackboxState?.repeat_streak ?? 0);
7465
7514
  const activityRepeatStreak = Number(blackboxState?.activity_repeat_streak ?? 0);
7466
7515
  const targetRepeatStateStreak = Number(blackboxState?.target_repeat_streak ?? 0);
7516
+ const messageLengthTrend = String(blackboxState?.message_length_trend || "stable");
7517
+ const messageLengthSlope = Number(blackboxState?.message_length_slope ?? 0);
7467
7518
  return {
7468
7519
  toolRepeatStreak,
7469
7520
  targetRepeatStreak,
@@ -7471,10 +7522,13 @@ function getBehavioralStressSignals(context, blackboxState) {
7471
7522
  loopCount,
7472
7523
  repeatStreak,
7473
7524
  activityRepeatStreak,
7474
- targetRepeatStateStreak
7525
+ targetRepeatStateStreak,
7526
+ messageLengthTrend,
7527
+ messageLengthSlope
7475
7528
  };
7476
7529
  }
7477
7530
  function scoreStress(text, context = {}) {
7531
+ const blackboxState = loadBlackboxState();
7478
7532
  if (!text || typeof text !== "string")
7479
7533
  return 0;
7480
7534
  const t = text.toLowerCase();
@@ -7516,22 +7570,25 @@ function scoreStress(text, context = {}) {
7516
7570
  const behavioralPhrases = [
7517
7571
  { re: /\b(restart|restarts|restarted|restart again|restart it|retry|retries|retrial|rerun|redo|repeat the step|try again|another attempt|another pass)\b/gi, weight: 0.09 },
7518
7572
  { re: /\b(still failing|keeps failing|keeps breaking|still broken|same issue|same result|same error|new error|new issue|broke again|breaks again|every fix|every time|over and over|again and again)\b/gi, weight: 0.12 },
7519
- { re: /\b(blocked again|stuck again|failed again|fails again|this is not working|nothing changed|no change)\b/gi, weight: 0.1 }
7573
+ { re: /\b(blocked again|stuck again|failed again|fails again|this is not working|nothing changed|no change)\b/gi, weight: 0.1 },
7574
+ { re: /\b(start over|from scratch|back to square|back to the drawing board|reset|rethink|different approach)\b/gi, weight: 0.12 },
7575
+ { re: /\b(made it worse|went backwards|regression|introduced (a |a new |another )(problem|bug|issue)|worse than before|new (problem|bug|issue) (emerged|appeared|showed))\b/gi, weight: 0.15 },
7576
+ { re: /\b(\d+)\s*(times|attempts|tries)\b/gi, dynamic: true }
7520
7577
  ];
7521
- for (const { re, weight } of behavioralPhrases) {
7522
- const hits = (t.match(re) || []).length;
7523
- score += hits * weight;
7524
- }
7525
- const sessionId = String(_OC_SID || "");
7526
- let blackboxState = context?.blackboxState || null;
7527
- if (!blackboxState) {
7528
- try {
7529
- const raw = loadBlackboxState();
7530
- blackboxState = raw?.sessions?.[sessionId] || null;
7531
- } catch {
7578
+ for (const { re, weight, dynamic } of behavioralPhrases) {
7579
+ const matches = t.match(re);
7580
+ if (!matches)
7581
+ continue;
7582
+ if (dynamic) {
7583
+ for (const m of matches) {
7584
+ const num = parseInt(m, 10) || 0;
7585
+ score += Math.min(0.2, num * 0.04);
7586
+ }
7587
+ } else {
7588
+ score += matches.length * weight;
7532
7589
  }
7533
7590
  }
7534
- const { toolRepeatStreak, targetRepeatStreak, negativeOutcomes, loopCount, repeatStreak, activityRepeatStreak, targetRepeatStateStreak } = getBehavioralStressSignals(context, blackboxState);
7591
+ const { toolRepeatStreak, targetRepeatStreak, negativeOutcomes, loopCount, repeatStreak, activityRepeatStreak, targetRepeatStateStreak, messageLengthTrend, messageLengthSlope } = getBehavioralStressSignals(context, blackboxState);
7535
7592
  if (toolRepeatStreak >= 2) {
7536
7593
  score += 0.08 + Math.min(0.24, (toolRepeatStreak - 1) * 0.05);
7537
7594
  }
@@ -7553,6 +7610,9 @@ function scoreStress(text, context = {}) {
7553
7610
  if (targetRepeatStateStreak >= 2) {
7554
7611
  score += 0.04 + Math.min(0.08, targetRepeatStateStreak * 0.015);
7555
7612
  }
7613
+ if (messageLengthTrend === "shortening" && messageLengthSlope < -0.3) {
7614
+ score += 0.08;
7615
+ }
7556
7616
  if (text.length < 30)
7557
7617
  score += 0.06;
7558
7618
  else if (text.length < 80)
@@ -7916,19 +7976,22 @@ function summarizeRecentToolActivity(limit = 5) {
7916
7976
  if (events.length === 0)
7917
7977
  return null;
7918
7978
  const last = events[events.length - 1] || {};
7919
- const signature = `${String(last.tool || "").trim().toLowerCase()}:${String(last.target || "").trim().toLowerCase()}`;
7979
+ const actionType = String(last.action || last.kind || "").trim().toLowerCase();
7980
+ const toolTarget = `${String(last.tool || "").trim().toLowerCase()}:${String(last.target || "").trim().toLowerCase()}`;
7981
+ const signature = `${toolTarget}:${actionType}`;
7920
7982
  let repeatCount = 0;
7921
7983
  for (let i = events.length - 1; i >= 0; i--) {
7922
7984
  const cur = events[i] || {};
7923
- const curSignature = `${String(cur.tool || "").trim().toLowerCase()}:${String(cur.target || "").trim().toLowerCase()}`;
7924
- if (curSignature !== signature)
7985
+ const curAction = String(cur.action || cur.kind || "").trim().toLowerCase();
7986
+ const curSig = `${String(cur.tool || "").trim().toLowerCase()}:${String(cur.target || "").trim().toLowerCase()}:${curAction}`;
7987
+ if (curSig !== signature)
7925
7988
  break;
7926
7989
  repeatCount++;
7927
7990
  }
7928
7991
  return {
7929
7992
  tool: String(last.tool || "").toLowerCase(),
7930
7993
  target: String(last.target || "").toLowerCase(),
7931
- action: String(last.action || last.kind || "").toLowerCase(),
7994
+ action: actionType,
7932
7995
  signature,
7933
7996
  repeat_count: repeatCount,
7934
7997
  recent_count: events.length
@@ -16007,7 +16070,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
16007
16070
  globalThis.__vibeOS_sessionId = `opencode-${process.pid || "x"}-${Date.now()}`;
16008
16071
  }
16009
16072
  const hookSessionId = globalThis.__vibeOS_sessionId;
16010
- setVibeOSHomeContext(join18(hookHome, ".claude"));
16073
+ setVibeOSHomeContext(getVibeOSHome13());
16011
16074
  setCurrentSessionId(hookSessionId);
16012
16075
  if (hookFp) {
16013
16076
  setCurrentProjectFingerprint(hookFp);
@@ -16086,7 +16149,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
16086
16149
  briefedProjects.clear();
16087
16150
  activeJob2 = _loadActiveJobForProject(directory3, fp);
16088
16151
  const systemBriefedProjects = /* @__PURE__ */ new Set();
16089
- const hookVibeHome = join18(hookHome, ".claude");
16152
+ const hookVibeHome = getVibeOSHome13();
16090
16153
  const hookStateFile = join18(hookVibeHome, "delegation-state.json");
16091
16154
  const hookProjectStateFile = join18(hookVibeHome, "project-states.json");
16092
16155
  const hookReportsDir = join18(hookVibeHome, "reports");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.25.22",
3
+ "version": "0.25.25",
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",
@@ -35,12 +35,19 @@ function collectHomeOpenCodeHomes(baseHome) {
35
35
  export function resolveOpenCodeHomes({ cwd = process.cwd(), home = homedir() } = {}) {
36
36
  const override = process.env.VIBEOS_OPENCODE_HOME
37
37
  if (override) return [override]
38
+
38
39
  const workspaceHomes = collectWorkspaceOpenCodeHomes(cwd)
39
- if (workspaceHomes.length > 0) return workspaceHomes
40
40
  const homeHomes = collectHomeOpenCodeHomes(home)
41
41
  const activeHomeHomes = homeHomes.filter((dir) => existsSync(dir))
42
- if (activeHomeHomes.length > 0) return activeHomeHomes
43
- return homeHomes
42
+
43
+ const homeCandidates = activeHomeHomes.length > 0 ? activeHomeHomes : homeHomes
44
+ const seen = new Set()
45
+ return [...workspaceHomes, ...homeCandidates].filter((dir) => {
46
+ if (dir == null) return false
47
+ if (seen.has(dir)) return false
48
+ seen.add(dir)
49
+ return true
50
+ })
44
51
  }
45
52
 
46
53
  export function resolveOpenCodeHome(opts = {}) {