vibeostheog 0.25.22 → 0.25.26
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:
|
|
1
|
+
window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:56848";
|
package/dist/vibeOS.js
CHANGED
|
@@ -2697,7 +2697,7 @@ var init_state = __esm({
|
|
|
2697
2697
|
}
|
|
2698
2698
|
})();
|
|
2699
2699
|
VIBEOS_CONTEXT = new AsyncLocalStorage();
|
|
2700
|
-
VIBEOS_HOME = process.env.VIBEOS_HOME || join2(USER_HOME2, ".claude");
|
|
2700
|
+
VIBEOS_HOME = process.env.VIBEOS_HOME || join2(process.env.HOME || USER_HOME2, ".claude");
|
|
2701
2701
|
OPENCODE_HOME = resolveOpenCodeHome();
|
|
2702
2702
|
FILE_LOCK_DIR = join2(VIBEOS_HOME, ".vibeOS-locks");
|
|
2703
2703
|
DELEGATION_STATE_FILE = join2(VIBEOS_HOME, "delegation-state.json");
|
|
@@ -2817,8 +2817,8 @@ var init_state = __esm({
|
|
|
2817
2817
|
}
|
|
2818
2818
|
});
|
|
2819
2819
|
_startupMaintenanceHome = "";
|
|
2820
|
-
FALLBACK_HIGH = /opus|gemini-.*-pro|
|
|
2821
|
-
FALLBACK_MID = /
|
|
2820
|
+
FALLBACK_HIGH = /opus|gemini-.*-pro|gpt-5|(^|\/)o[134]($|-|\/)|claude.*opus|reasoner|r1/i;
|
|
2821
|
+
FALLBACK_MID = /sonnet|gemini-.*-flash|gpt-4o(?!-mini)|haiku|flash|4o/i;
|
|
2822
2822
|
({ high: HIGH_TIER_RE, mid: MID_TIER_RE } = loadTierRegexes());
|
|
2823
2823
|
loadMLState();
|
|
2824
2824
|
scratchpadHitsSeen = /* @__PURE__ */ new Set();
|
|
@@ -6820,7 +6820,6 @@ function applySlot2(slot, projectDir = "") {
|
|
|
6820
6820
|
oc.model = ocModel;
|
|
6821
6821
|
writeFileSync6(ocConfig, JSON.stringify(oc, null, 2) + "\n");
|
|
6822
6822
|
}
|
|
6823
|
-
clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
|
|
6824
6823
|
_refreshModel(dir);
|
|
6825
6824
|
return { ok: true, ocModel };
|
|
6826
6825
|
});
|
|
@@ -6851,6 +6850,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6851
6850
|
this.pivotHistory = [];
|
|
6852
6851
|
this.outcomeHistory = [];
|
|
6853
6852
|
this.calibratedWeights = null;
|
|
6853
|
+
this.recentMessageLengths = [];
|
|
6854
6854
|
}
|
|
6855
6855
|
static extractFeatures(text) {
|
|
6856
6856
|
if (!text || typeof text !== "string")
|
|
@@ -6925,13 +6925,18 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6925
6925
|
getRepeatStreak() {
|
|
6926
6926
|
if (this.history.length < 2)
|
|
6927
6927
|
return 0;
|
|
6928
|
-
const
|
|
6929
|
-
if (
|
|
6928
|
+
const lastWords = new Set(this.history[this.history.length - 1].text.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
|
|
6929
|
+
if (lastWords.size === 0)
|
|
6930
6930
|
return 0;
|
|
6931
6931
|
let streak = 1;
|
|
6932
6932
|
for (let i = this.history.length - 2; i >= 0; i--) {
|
|
6933
|
-
const
|
|
6934
|
-
if (
|
|
6933
|
+
const currWords = new Set(this.history[i].text.toLowerCase().split(/\s+/).filter((w) => w.length > 2));
|
|
6934
|
+
if (currWords.size === 0)
|
|
6935
|
+
break;
|
|
6936
|
+
const intersection = new Set([...lastWords].filter((w) => currWords.has(w)));
|
|
6937
|
+
const union = /* @__PURE__ */ new Set([...lastWords, ...currWords]);
|
|
6938
|
+
const jaccard = intersection.size / Math.max(union.size, 1);
|
|
6939
|
+
if (jaccard < 0.7)
|
|
6935
6940
|
break;
|
|
6936
6941
|
streak++;
|
|
6937
6942
|
}
|
|
@@ -6967,6 +6972,39 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6967
6972
|
}
|
|
6968
6973
|
return streak;
|
|
6969
6974
|
}
|
|
6975
|
+
getRecentNegativeOutcomeStreak() {
|
|
6976
|
+
if (this.outcomeHistory.length < 1)
|
|
6977
|
+
return 0;
|
|
6978
|
+
let streak = 0;
|
|
6979
|
+
for (let i = this.outcomeHistory.length - 1; i >= 0; i--) {
|
|
6980
|
+
const o = this.outcomeHistory[i];
|
|
6981
|
+
if (/negative|failed|unresolved|loop_detected/i.test(String(o?.outcome || "")))
|
|
6982
|
+
streak++;
|
|
6983
|
+
else
|
|
6984
|
+
break;
|
|
6985
|
+
}
|
|
6986
|
+
return streak;
|
|
6987
|
+
}
|
|
6988
|
+
computeMessageLengthTrend() {
|
|
6989
|
+
const lengths = this.recentMessageLengths;
|
|
6990
|
+
if (lengths.length < 3)
|
|
6991
|
+
return { trend: "stable", slope: 0 };
|
|
6992
|
+
const pairs = lengths.slice(-4);
|
|
6993
|
+
let decreasingCount = 0;
|
|
6994
|
+
let totalSlope = 0;
|
|
6995
|
+
for (let i = 1; i < pairs.length; i++) {
|
|
6996
|
+
const diff = pairs[i] - pairs[i - 1];
|
|
6997
|
+
if (diff < 0)
|
|
6998
|
+
decreasingCount++;
|
|
6999
|
+
totalSlope += diff;
|
|
7000
|
+
}
|
|
7001
|
+
const ratio = decreasingCount / (pairs.length - 1);
|
|
7002
|
+
const avgSlope = pairs.length > 1 ? totalSlope / (pairs.length - 1) : 0;
|
|
7003
|
+
return {
|
|
7004
|
+
trend: ratio >= 0.6 && avgSlope < 0 ? "shortening" : "stable",
|
|
7005
|
+
slope: avgSlope
|
|
7006
|
+
};
|
|
7007
|
+
}
|
|
6970
7008
|
update(userText, features, action, entropy, uncertainty, embedding = null, activity = null) {
|
|
6971
7009
|
const normalizedActivity = this.normalizeActivity(activity, action, userText);
|
|
6972
7010
|
const entry = {
|
|
@@ -6986,6 +7024,9 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6986
7024
|
}
|
|
6987
7025
|
}
|
|
6988
7026
|
this.history.push(entry);
|
|
7027
|
+
this.recentMessageLengths.push((userText || "").length);
|
|
7028
|
+
if (this.recentMessageLengths.length > 6)
|
|
7029
|
+
this.recentMessageLengths.shift();
|
|
6989
7030
|
if (this.history.length > this.maxHistory) {
|
|
6990
7031
|
this.history.shift();
|
|
6991
7032
|
}
|
|
@@ -7121,6 +7162,9 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7121
7162
|
pivot_detected: pivotDetected,
|
|
7122
7163
|
pivot_score: Math.round(pivotScore * 1e4) / 1e4,
|
|
7123
7164
|
outcome: lastEntry.outcome || null,
|
|
7165
|
+
outcome_negative_streak: this.getRecentNegativeOutcomeStreak(),
|
|
7166
|
+
message_length_trend: this.computeMessageLengthTrend().trend,
|
|
7167
|
+
message_length_slope: this.computeMessageLengthTrend().slope,
|
|
7124
7168
|
n_interactions: n
|
|
7125
7169
|
};
|
|
7126
7170
|
}
|
|
@@ -7171,7 +7215,8 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7171
7215
|
}
|
|
7172
7216
|
detectLoop() {
|
|
7173
7217
|
const repeatSignal = Math.max(this.getRepeatStreak(), this.getActivityRepeatStreak(), this.getTargetRepeatStreak());
|
|
7174
|
-
|
|
7218
|
+
const negativeOutcomeStreak = this.getRecentNegativeOutcomeStreak();
|
|
7219
|
+
return this.loopCount >= 2 || repeatSignal >= 2 || negativeOutcomeStreak >= 2;
|
|
7175
7220
|
}
|
|
7176
7221
|
computeIntentState() {
|
|
7177
7222
|
const last = this.history[this.history.length - 1];
|
|
@@ -7215,6 +7260,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7215
7260
|
this.loopCount = 0;
|
|
7216
7261
|
this.pivotHistory = [];
|
|
7217
7262
|
this.outcomeHistory = [];
|
|
7263
|
+
this.recentMessageLengths = [];
|
|
7218
7264
|
}
|
|
7219
7265
|
recordOutcome(outcome) {
|
|
7220
7266
|
const entry = this.history[this.history.length - 1];
|
|
@@ -7280,6 +7326,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7280
7326
|
loopCount: this.loopCount,
|
|
7281
7327
|
pivotHistory: this.pivotHistory,
|
|
7282
7328
|
outcomeHistory: this.outcomeHistory,
|
|
7329
|
+
recentMessageLengths: this.recentMessageLengths,
|
|
7283
7330
|
calibratedWeights: this.calibratedWeights
|
|
7284
7331
|
};
|
|
7285
7332
|
}
|
|
@@ -7292,6 +7339,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7292
7339
|
tracker.loopCount = Number(data.loopCount || 0);
|
|
7293
7340
|
tracker.pivotHistory = Array.isArray(data.pivotHistory) ? data.pivotHistory : [];
|
|
7294
7341
|
tracker.outcomeHistory = Array.isArray(data.outcomeHistory) ? data.outcomeHistory : [];
|
|
7342
|
+
tracker.recentMessageLengths = Array.isArray(data.recentMessageLengths) ? data.recentMessageLengths : [];
|
|
7295
7343
|
tracker.calibratedWeights = data.calibratedWeights || null;
|
|
7296
7344
|
return tracker;
|
|
7297
7345
|
}
|
|
@@ -7425,9 +7473,9 @@ init_state();
|
|
|
7425
7473
|
function detectOutcomeSignal(text) {
|
|
7426
7474
|
if (!text)
|
|
7427
7475
|
return null;
|
|
7428
|
-
if (/thank|perfect|exactly|that.?s it|works great|works perfectly|solved|fixed|awesome|you rock/i.test(text))
|
|
7476
|
+
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
7477
|
return "positive";
|
|
7430
|
-
if (/doesn.?t work|still broken|not working|incorrect|wrong|failed|error|useless|stuck/i.test(text))
|
|
7478
|
+
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
7479
|
return "negative";
|
|
7432
7480
|
return null;
|
|
7433
7481
|
}
|
|
@@ -7464,6 +7512,8 @@ function getBehavioralStressSignals(context, blackboxState) {
|
|
|
7464
7512
|
const repeatStreak = Number(blackboxState?.repeat_streak ?? 0);
|
|
7465
7513
|
const activityRepeatStreak = Number(blackboxState?.activity_repeat_streak ?? 0);
|
|
7466
7514
|
const targetRepeatStateStreak = Number(blackboxState?.target_repeat_streak ?? 0);
|
|
7515
|
+
const messageLengthTrend = String(blackboxState?.message_length_trend || "stable");
|
|
7516
|
+
const messageLengthSlope = Number(blackboxState?.message_length_slope ?? 0);
|
|
7467
7517
|
return {
|
|
7468
7518
|
toolRepeatStreak,
|
|
7469
7519
|
targetRepeatStreak,
|
|
@@ -7471,10 +7521,13 @@ function getBehavioralStressSignals(context, blackboxState) {
|
|
|
7471
7521
|
loopCount,
|
|
7472
7522
|
repeatStreak,
|
|
7473
7523
|
activityRepeatStreak,
|
|
7474
|
-
targetRepeatStateStreak
|
|
7524
|
+
targetRepeatStateStreak,
|
|
7525
|
+
messageLengthTrend,
|
|
7526
|
+
messageLengthSlope
|
|
7475
7527
|
};
|
|
7476
7528
|
}
|
|
7477
7529
|
function scoreStress(text, context = {}) {
|
|
7530
|
+
const blackboxState = loadBlackboxState();
|
|
7478
7531
|
if (!text || typeof text !== "string")
|
|
7479
7532
|
return 0;
|
|
7480
7533
|
const t = text.toLowerCase();
|
|
@@ -7516,22 +7569,25 @@ function scoreStress(text, context = {}) {
|
|
|
7516
7569
|
const behavioralPhrases = [
|
|
7517
7570
|
{ 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
7571
|
{ 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 }
|
|
7572
|
+
{ 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(start over|from scratch|back to square|back to the drawing board|reset|rethink|different approach)\b/gi, weight: 0.12 },
|
|
7574
|
+
{ 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 },
|
|
7575
|
+
{ re: /\b(\d+)\s*(times|attempts|tries)\b/gi, dynamic: true }
|
|
7520
7576
|
];
|
|
7521
|
-
for (const { re, weight } of behavioralPhrases) {
|
|
7522
|
-
const
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7577
|
+
for (const { re, weight, dynamic } of behavioralPhrases) {
|
|
7578
|
+
const matches = t.match(re);
|
|
7579
|
+
if (!matches)
|
|
7580
|
+
continue;
|
|
7581
|
+
if (dynamic) {
|
|
7582
|
+
for (const m of matches) {
|
|
7583
|
+
const num = parseInt(m, 10) || 0;
|
|
7584
|
+
score += Math.min(0.2, num * 0.04);
|
|
7585
|
+
}
|
|
7586
|
+
} else {
|
|
7587
|
+
score += matches.length * weight;
|
|
7532
7588
|
}
|
|
7533
7589
|
}
|
|
7534
|
-
const { toolRepeatStreak, targetRepeatStreak, negativeOutcomes, loopCount, repeatStreak, activityRepeatStreak, targetRepeatStateStreak } = getBehavioralStressSignals(context, blackboxState);
|
|
7590
|
+
const { toolRepeatStreak, targetRepeatStreak, negativeOutcomes, loopCount, repeatStreak, activityRepeatStreak, targetRepeatStateStreak, messageLengthTrend, messageLengthSlope } = getBehavioralStressSignals(context, blackboxState);
|
|
7535
7591
|
if (toolRepeatStreak >= 2) {
|
|
7536
7592
|
score += 0.08 + Math.min(0.24, (toolRepeatStreak - 1) * 0.05);
|
|
7537
7593
|
}
|
|
@@ -7553,6 +7609,9 @@ function scoreStress(text, context = {}) {
|
|
|
7553
7609
|
if (targetRepeatStateStreak >= 2) {
|
|
7554
7610
|
score += 0.04 + Math.min(0.08, targetRepeatStateStreak * 0.015);
|
|
7555
7611
|
}
|
|
7612
|
+
if (messageLengthTrend === "shortening" && messageLengthSlope < -0.3) {
|
|
7613
|
+
score += 0.08;
|
|
7614
|
+
}
|
|
7556
7615
|
if (text.length < 30)
|
|
7557
7616
|
score += 0.06;
|
|
7558
7617
|
else if (text.length < 80)
|
|
@@ -7686,20 +7745,34 @@ function isLikelyOffTopic(userText, job) {
|
|
|
7686
7745
|
|
|
7687
7746
|
// src/lib/turn-classify.js
|
|
7688
7747
|
init_vibeultrax();
|
|
7748
|
+
var _lastClassifiedByApi = false;
|
|
7689
7749
|
function classifyTurnSimple2(userText) {
|
|
7690
7750
|
return classifyTurnSimple(userText);
|
|
7691
7751
|
}
|
|
7692
7752
|
async function classifyTurnRemote(text) {
|
|
7693
7753
|
try {
|
|
7694
7754
|
const client2 = getApiClient2();
|
|
7695
|
-
if (!client2 || isApiFallback2())
|
|
7755
|
+
if (!client2 || isApiFallback2()) {
|
|
7756
|
+
_lastClassifiedByApi = false;
|
|
7696
7757
|
return classifyTurnSimple(text);
|
|
7697
|
-
|
|
7758
|
+
}
|
|
7759
|
+
const res = await client2.blackboxAnalyze(_OC_SID, {
|
|
7760
|
+
session_id: _OC_SID,
|
|
7761
|
+
project_id: currentProjectFingerprint || null,
|
|
7762
|
+
userText: text,
|
|
7763
|
+
lastRegime: null,
|
|
7764
|
+
lastIntent: "",
|
|
7765
|
+
lastAction: "",
|
|
7766
|
+
stress: 0,
|
|
7767
|
+
state: {}
|
|
7768
|
+
});
|
|
7698
7769
|
if (res && typeof res === "object" && "sub_regime" in res) {
|
|
7770
|
+
_lastClassifiedByApi = true;
|
|
7699
7771
|
return res.sub_regime;
|
|
7700
7772
|
}
|
|
7701
7773
|
} catch {
|
|
7702
7774
|
}
|
|
7775
|
+
_lastClassifiedByApi = false;
|
|
7703
7776
|
return classifyTurnSimple(text);
|
|
7704
7777
|
}
|
|
7705
7778
|
function getVibeOSHome5() {
|
|
@@ -7916,19 +7989,22 @@ function summarizeRecentToolActivity(limit = 5) {
|
|
|
7916
7989
|
if (events.length === 0)
|
|
7917
7990
|
return null;
|
|
7918
7991
|
const last = events[events.length - 1] || {};
|
|
7919
|
-
const
|
|
7992
|
+
const actionType = String(last.action || last.kind || "").trim().toLowerCase();
|
|
7993
|
+
const toolTarget = `${String(last.tool || "").trim().toLowerCase()}:${String(last.target || "").trim().toLowerCase()}`;
|
|
7994
|
+
const signature = `${toolTarget}:${actionType}`;
|
|
7920
7995
|
let repeatCount = 0;
|
|
7921
7996
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
7922
7997
|
const cur = events[i] || {};
|
|
7923
|
-
const
|
|
7924
|
-
|
|
7998
|
+
const curAction = String(cur.action || cur.kind || "").trim().toLowerCase();
|
|
7999
|
+
const curSig = `${String(cur.tool || "").trim().toLowerCase()}:${String(cur.target || "").trim().toLowerCase()}:${curAction}`;
|
|
8000
|
+
if (curSig !== signature)
|
|
7925
8001
|
break;
|
|
7926
8002
|
repeatCount++;
|
|
7927
8003
|
}
|
|
7928
8004
|
return {
|
|
7929
8005
|
tool: String(last.tool || "").toLowerCase(),
|
|
7930
8006
|
target: String(last.target || "").toLowerCase(),
|
|
7931
|
-
action:
|
|
8007
|
+
action: actionType,
|
|
7932
8008
|
signature,
|
|
7933
8009
|
repeat_count: repeatCount,
|
|
7934
8010
|
recent_count: events.length
|
|
@@ -16007,7 +16083,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
16007
16083
|
globalThis.__vibeOS_sessionId = `opencode-${process.pid || "x"}-${Date.now()}`;
|
|
16008
16084
|
}
|
|
16009
16085
|
const hookSessionId = globalThis.__vibeOS_sessionId;
|
|
16010
|
-
setVibeOSHomeContext(
|
|
16086
|
+
setVibeOSHomeContext(getVibeOSHome13());
|
|
16011
16087
|
setCurrentSessionId(hookSessionId);
|
|
16012
16088
|
if (hookFp) {
|
|
16013
16089
|
setCurrentProjectFingerprint(hookFp);
|
|
@@ -16086,7 +16162,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
16086
16162
|
briefedProjects.clear();
|
|
16087
16163
|
activeJob2 = _loadActiveJobForProject(directory3, fp);
|
|
16088
16164
|
const systemBriefedProjects = /* @__PURE__ */ new Set();
|
|
16089
|
-
const hookVibeHome =
|
|
16165
|
+
const hookVibeHome = getVibeOSHome13();
|
|
16090
16166
|
const hookStateFile = join18(hookVibeHome, "delegation-state.json");
|
|
16091
16167
|
const hookProjectStateFile = join18(hookVibeHome, "project-states.json");
|
|
16092
16168
|
const hookReportsDir = join18(hookVibeHome, "reports");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.26",
|
|
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
|
-
|
|
43
|
-
|
|
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 = {}) {
|