vibeostheog 0.25.13 → 0.25.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/bin/setup.js +5 -18
- package/dist/assets/dashboard/vibeos-dashboard-config.js +1 -1
- package/dist/vibeOS.js +218 -42
- package/package.json +1 -1
- package/scripts/deploy.mjs +57 -40
package/CHANGELOG.md
CHANGED
package/bin/setup.js
CHANGED
|
@@ -5,30 +5,17 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
|
5
5
|
import { dirname, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
|
-
import readline from "node:readline";
|
|
9
8
|
|
|
10
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
10
|
const root = resolve(__dirname, "..");
|
|
12
11
|
const args = process.argv.slice(2);
|
|
12
|
+
const command = args[0] ?? "setup";
|
|
13
|
+
const isInstallCommand = command === "setup" || command === "set";
|
|
13
14
|
const isProject = args.includes("--project");
|
|
14
|
-
const autoYes = args.includes("--yes") || args.includes("-y");
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const prompt = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
20
|
-
const answer = await new Promise((resolveAnswer) => {
|
|
21
|
-
prompt.question("Install vibeOS into OpenCode? [y/N] ", (response) => {
|
|
22
|
-
resolveAnswer(String(response || "").trim().toLowerCase());
|
|
23
|
-
});
|
|
24
|
-
});
|
|
25
|
-
prompt.close();
|
|
26
|
-
return answer === "y" || answer === "yes";
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!(await confirmInstall())) {
|
|
30
|
-
console.log("Install cancelled.");
|
|
31
|
-
process.exit(0);
|
|
16
|
+
if (!isInstallCommand) {
|
|
17
|
+
console.error("Usage: vibeostheog set [--project] | vibeostheog setup [--project]");
|
|
18
|
+
process.exit(1);
|
|
32
19
|
}
|
|
33
20
|
|
|
34
21
|
// Deploy plugin files to ~/.config/opencode/plugins/ and register globally
|
|
@@ -1 +1 @@
|
|
|
1
|
-
window.__VIBEOS_DASHBOARD_BASE__ = "
|
|
1
|
+
window.__VIBEOS_DASHBOARD_BASE__ = "";
|
package/dist/vibeOS.js
CHANGED
|
@@ -3416,7 +3416,7 @@ function autoSelectMode(subRegime, stressMultiplier) {
|
|
|
3416
3416
|
if (regime === "AUDIT" || regime === "FORENSIC")
|
|
3417
3417
|
return regime.toLowerCase();
|
|
3418
3418
|
if (regime === "LOOPING")
|
|
3419
|
-
return "
|
|
3419
|
+
return "quality";
|
|
3420
3420
|
if (regime === "CONVERGING" || regime === "CLOSED")
|
|
3421
3421
|
return "quality";
|
|
3422
3422
|
if (regime === "IMPLEMENTING")
|
|
@@ -3552,16 +3552,16 @@ var init_meta_controller = __esm({
|
|
|
3552
3552
|
wbp_verbosity: "minimal"
|
|
3553
3553
|
},
|
|
3554
3554
|
LOOPING: {
|
|
3555
|
-
enforcement_mode: "
|
|
3556
|
-
enforcement_reason: "user stuck \u2014
|
|
3557
|
-
flow_mode: "
|
|
3558
|
-
flow_focus: ["suggest-alternative"],
|
|
3559
|
-
tdd_mode: "
|
|
3560
|
-
tdd_focus: [],
|
|
3561
|
-
tier_bias: "
|
|
3562
|
-
thinking_mode: "
|
|
3563
|
-
stress_multiplier:
|
|
3564
|
-
context7_urgency: "
|
|
3555
|
+
enforcement_mode: "strict",
|
|
3556
|
+
enforcement_reason: "user stuck \u2014 tighten enforcement and switch to recovery posture",
|
|
3557
|
+
flow_mode: "strict",
|
|
3558
|
+
flow_focus: ["write-edit-check", "no-untouched-files", "suggest-alternative"],
|
|
3559
|
+
tdd_mode: "strict",
|
|
3560
|
+
tdd_focus: ["skeleton-on-write", "assertion-check"],
|
|
3561
|
+
tier_bias: "brain",
|
|
3562
|
+
thinking_mode: "brief",
|
|
3563
|
+
stress_multiplier: 2,
|
|
3564
|
+
context7_urgency: "required",
|
|
3565
3565
|
wbp_verbosity: "detailed"
|
|
3566
3566
|
},
|
|
3567
3567
|
CLOSED: {
|
|
@@ -3824,7 +3824,7 @@ import { resolve as resolve2, dirname as dirname7 } from "node:path";
|
|
|
3824
3824
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
3825
3825
|
function fallback(sr, text) {
|
|
3826
3826
|
if (sr === "LOOPING")
|
|
3827
|
-
return "
|
|
3827
|
+
return "quality";
|
|
3828
3828
|
const t = String(text || "").toLowerCase();
|
|
3829
3829
|
if (sr === "INIT" && t.length <= 42 && !/[\.\/\\]/.test(t))
|
|
3830
3830
|
return "budget";
|
|
@@ -4476,10 +4476,8 @@ var DASHBOARD_DIR = resolveDashboardDir();
|
|
|
4476
4476
|
var DASHBOARD_CONFIG_PATH = join4(DASHBOARD_DIR, "vibeos-dashboard-config.js");
|
|
4477
4477
|
function writeDashboardBaseConfig(baseUrl) {
|
|
4478
4478
|
try {
|
|
4479
|
-
if (!baseUrl)
|
|
4480
|
-
return null;
|
|
4481
4479
|
mkdirSync3(DASHBOARD_DIR, { recursive: true });
|
|
4482
|
-
const payload = `window.__VIBEOS_DASHBOARD_BASE__ = ${JSON.stringify(baseUrl.replace(/\/$/, ""))};
|
|
4480
|
+
const payload = `window.__VIBEOS_DASHBOARD_BASE__ = ${JSON.stringify((baseUrl || "").replace(/\/$/, ""))};
|
|
4483
4481
|
`;
|
|
4484
4482
|
writeFileSync4(DASHBOARD_CONFIG_PATH, payload, "utf-8");
|
|
4485
4483
|
return DASHBOARD_CONFIG_PATH;
|
|
@@ -6874,6 +6872,42 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6874
6872
|
normalizeText(text) {
|
|
6875
6873
|
return (text || "").toLowerCase().replace(/[^a-z0-9\s]+/g, " ").replace(/\s+/g, " ").trim();
|
|
6876
6874
|
}
|
|
6875
|
+
normalizeActivity(activity, action, text) {
|
|
6876
|
+
const fallbackSignature = this.normalizeText(action || text || "");
|
|
6877
|
+
if (!activity) {
|
|
6878
|
+
return {
|
|
6879
|
+
signature: fallbackSignature || "",
|
|
6880
|
+
tool: null,
|
|
6881
|
+
target: null,
|
|
6882
|
+
action: action || null,
|
|
6883
|
+
repeat_count: 1,
|
|
6884
|
+
outcome: null
|
|
6885
|
+
};
|
|
6886
|
+
}
|
|
6887
|
+
if (typeof activity === "string") {
|
|
6888
|
+
const sig = this.normalizeText(activity);
|
|
6889
|
+
return {
|
|
6890
|
+
signature: sig || fallbackSignature || "",
|
|
6891
|
+
tool: null,
|
|
6892
|
+
target: null,
|
|
6893
|
+
action: action || null,
|
|
6894
|
+
repeat_count: 1,
|
|
6895
|
+
outcome: null
|
|
6896
|
+
};
|
|
6897
|
+
}
|
|
6898
|
+
const tool2 = this.normalizeText(activity.tool || activity.toolName || activity.kind || "");
|
|
6899
|
+
const target = this.normalizeText(activity.target || activity.filePath || activity.file_path || activity.path || activity.command || "");
|
|
6900
|
+
const normalizedAction = this.normalizeText(activity.action || activity.kind || action || "");
|
|
6901
|
+
const signature = this.normalizeText(activity.signature || [tool2, target, normalizedAction, activity.outcome || ""].filter(Boolean).join(" "));
|
|
6902
|
+
return {
|
|
6903
|
+
signature: signature || fallbackSignature || "",
|
|
6904
|
+
tool: tool2 || null,
|
|
6905
|
+
target: target || null,
|
|
6906
|
+
action: normalizedAction || action || null,
|
|
6907
|
+
repeat_count: Number(activity.repeat_count || activity.repeatCount || 1) || 1,
|
|
6908
|
+
outcome: typeof activity.outcome === "string" ? activity.outcome : activity.outcome ?? null
|
|
6909
|
+
};
|
|
6910
|
+
}
|
|
6877
6911
|
getRepeatStreak() {
|
|
6878
6912
|
if (this.history.length < 2)
|
|
6879
6913
|
return 0;
|
|
@@ -6889,7 +6923,38 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6889
6923
|
}
|
|
6890
6924
|
return streak;
|
|
6891
6925
|
}
|
|
6892
|
-
|
|
6926
|
+
getActivityRepeatStreak() {
|
|
6927
|
+
if (this.history.length < 2)
|
|
6928
|
+
return 0;
|
|
6929
|
+
const normalizedLast = this.normalizeActivity(this.history[this.history.length - 1].activity, this.history[this.history.length - 1].action, this.history[this.history.length - 1].text).signature;
|
|
6930
|
+
if (!normalizedLast)
|
|
6931
|
+
return 0;
|
|
6932
|
+
let streak = 1;
|
|
6933
|
+
for (let i = this.history.length - 2; i >= 0; i--) {
|
|
6934
|
+
const normalized = this.normalizeActivity(this.history[i].activity, this.history[i].action, this.history[i].text).signature;
|
|
6935
|
+
if (!normalized || normalized !== normalizedLast)
|
|
6936
|
+
break;
|
|
6937
|
+
streak++;
|
|
6938
|
+
}
|
|
6939
|
+
return streak;
|
|
6940
|
+
}
|
|
6941
|
+
getTargetRepeatStreak() {
|
|
6942
|
+
if (this.history.length < 2)
|
|
6943
|
+
return 0;
|
|
6944
|
+
const normalizedLast = this.normalizeActivity(this.history[this.history.length - 1].activity, this.history[this.history.length - 1].action, this.history[this.history.length - 1].text).target;
|
|
6945
|
+
if (!normalizedLast)
|
|
6946
|
+
return 0;
|
|
6947
|
+
let streak = 1;
|
|
6948
|
+
for (let i = this.history.length - 2; i >= 0; i--) {
|
|
6949
|
+
const normalized = this.normalizeActivity(this.history[i].activity, this.history[i].action, this.history[i].text).target;
|
|
6950
|
+
if (!normalized || normalized !== normalizedLast)
|
|
6951
|
+
break;
|
|
6952
|
+
streak++;
|
|
6953
|
+
}
|
|
6954
|
+
return streak;
|
|
6955
|
+
}
|
|
6956
|
+
update(userText, features, action, entropy, uncertainty, embedding = null, activity = null) {
|
|
6957
|
+
const normalizedActivity = this.normalizeActivity(activity, action, userText);
|
|
6893
6958
|
const entry = {
|
|
6894
6959
|
text: userText,
|
|
6895
6960
|
features: { ...features },
|
|
@@ -6897,6 +6962,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6897
6962
|
entropy,
|
|
6898
6963
|
uncertainty,
|
|
6899
6964
|
embedding: embedding ? [...embedding] : null,
|
|
6965
|
+
activity: normalizedActivity,
|
|
6900
6966
|
timestamp: Date.now() / 1e3
|
|
6901
6967
|
};
|
|
6902
6968
|
if (this.history.length >= 2) {
|
|
@@ -6965,6 +7031,8 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
6965
7031
|
const featureContradiction = this.calcFeatureContradiction();
|
|
6966
7032
|
const embeddingDelta = this.calcEmbeddingDelta();
|
|
6967
7033
|
const repeatStreak = this.getRepeatStreak();
|
|
7034
|
+
const activityRepeatStreak = this.getActivityRepeatStreak();
|
|
7035
|
+
const targetRepeatStreak = this.getTargetRepeatStreak();
|
|
6968
7036
|
const isLooping = this.detectLoop();
|
|
6969
7037
|
const intentState = this.computeIntentState();
|
|
6970
7038
|
const continuityState = this.continuityState(intentState);
|
|
@@ -7000,9 +7068,10 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7000
7068
|
const momentum = this.calcMomentum(entropyTrend, actionConsistency, embeddingDelta, isLooping, lastEntry.action, lastEntry.entropy);
|
|
7001
7069
|
let loopLevel = "none";
|
|
7002
7070
|
if (isLooping) {
|
|
7003
|
-
|
|
7071
|
+
const repeatSignal = Math.max(repeatStreak, activityRepeatStreak, targetRepeatStreak);
|
|
7072
|
+
if (repeatSignal >= 3 || this.loopCount >= 4)
|
|
7004
7073
|
loopLevel = "escalated";
|
|
7005
|
-
else if (
|
|
7074
|
+
else if (repeatSignal >= 2 || this.loopCount >= 3)
|
|
7006
7075
|
loopLevel = "assertive";
|
|
7007
7076
|
else if (this.loopCount >= 2)
|
|
7008
7077
|
loopLevel = "suggestive";
|
|
@@ -7019,7 +7088,9 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7019
7088
|
action_consistency: Math.round(actionConsistency * 1e4) / 1e4,
|
|
7020
7089
|
entropy_trend: Math.round(entropyTrend * 1e4) / 1e4,
|
|
7021
7090
|
feature_contradiction: Math.round(featureContradiction * 1e4) / 1e4,
|
|
7022
|
-
embedding_delta: Math.round(embeddingDelta * 1e4) / 1e4
|
|
7091
|
+
embedding_delta: Math.round(embeddingDelta * 1e4) / 1e4,
|
|
7092
|
+
activity_repeat_streak: Math.round(activityRepeatStreak * 1e4) / 1e4,
|
|
7093
|
+
target_repeat_streak: Math.round(targetRepeatStreak * 1e4) / 1e4
|
|
7023
7094
|
},
|
|
7024
7095
|
intent_state: {
|
|
7025
7096
|
volatility_score: Math.round(intentState.volatility_score * 1e4) / 1e4,
|
|
@@ -7030,6 +7101,8 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7030
7101
|
is_looping: isLooping,
|
|
7031
7102
|
loop_consecutive: this.loopCount,
|
|
7032
7103
|
repeat_streak: repeatStreak,
|
|
7104
|
+
activity_repeat_streak: activityRepeatStreak,
|
|
7105
|
+
target_repeat_streak: targetRepeatStreak,
|
|
7033
7106
|
loop_intervention_level: loopLevel,
|
|
7034
7107
|
pivot_detected: pivotDetected,
|
|
7035
7108
|
pivot_score: Math.round(pivotScore * 1e4) / 1e4,
|
|
@@ -7083,7 +7156,7 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7083
7156
|
return 1 - cosineSimilarity2(a, b);
|
|
7084
7157
|
}
|
|
7085
7158
|
detectLoop() {
|
|
7086
|
-
return this.loopCount >= 2 || this.getRepeatStreak() >= 2;
|
|
7159
|
+
return this.loopCount >= 2 || this.getRepeatStreak() >= 2 || this.getActivityRepeatStreak() >= 2 || this.getTargetRepeatStreak() >= 2;
|
|
7087
7160
|
}
|
|
7088
7161
|
computeIntentState() {
|
|
7089
7162
|
const last = this.history[this.history.length - 1];
|
|
@@ -7197,7 +7270,10 @@ var ResolutionTracker = class _ResolutionTracker {
|
|
|
7197
7270
|
}
|
|
7198
7271
|
static deserialize(data) {
|
|
7199
7272
|
const tracker = new _ResolutionTracker(data.sessionId || "session", data.maxHistory || 10);
|
|
7200
|
-
tracker.history = Array.isArray(data.history) ? data.history
|
|
7273
|
+
tracker.history = Array.isArray(data.history) ? data.history.map((entry) => ({
|
|
7274
|
+
...entry,
|
|
7275
|
+
activity: entry?.activity || null
|
|
7276
|
+
})) : [];
|
|
7201
7277
|
tracker.loopCount = Number(data.loopCount || 0);
|
|
7202
7278
|
tracker.pivotHistory = Array.isArray(data.pivotHistory) ? data.pivotHistory : [];
|
|
7203
7279
|
tracker.outcomeHistory = Array.isArray(data.outcomeHistory) ? data.outcomeHistory : [];
|
|
@@ -7330,6 +7406,7 @@ init_state();
|
|
|
7330
7406
|
init_selection_manager();
|
|
7331
7407
|
|
|
7332
7408
|
// src/lib/classifiers.js
|
|
7409
|
+
init_state();
|
|
7333
7410
|
function detectOutcomeSignal(text) {
|
|
7334
7411
|
if (!text)
|
|
7335
7412
|
return null;
|
|
@@ -7339,7 +7416,29 @@ function detectOutcomeSignal(text) {
|
|
|
7339
7416
|
return "negative";
|
|
7340
7417
|
return null;
|
|
7341
7418
|
}
|
|
7342
|
-
function
|
|
7419
|
+
function countTrailingRepeat(items, signatureOf) {
|
|
7420
|
+
if (!Array.isArray(items) || items.length === 0)
|
|
7421
|
+
return 0;
|
|
7422
|
+
const last = signatureOf(items[items.length - 1]);
|
|
7423
|
+
if (!last)
|
|
7424
|
+
return 0;
|
|
7425
|
+
let streak = 0;
|
|
7426
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
7427
|
+
if (signatureOf(items[i]) !== last)
|
|
7428
|
+
break;
|
|
7429
|
+
streak++;
|
|
7430
|
+
}
|
|
7431
|
+
return streak;
|
|
7432
|
+
}
|
|
7433
|
+
function normalizeActivitySignature(event) {
|
|
7434
|
+
if (!event || typeof event !== "object")
|
|
7435
|
+
return "";
|
|
7436
|
+
const tool2 = String(event.tool || "").trim().toLowerCase();
|
|
7437
|
+
const target = String(event.target || "").trim().toLowerCase();
|
|
7438
|
+
const action = String(event.action || event.kind || "").trim().toLowerCase();
|
|
7439
|
+
return [tool2, target, action].filter(Boolean).join(":");
|
|
7440
|
+
}
|
|
7441
|
+
function scoreStress(text, context = {}) {
|
|
7343
7442
|
if (!text || typeof text !== "string")
|
|
7344
7443
|
return 0;
|
|
7345
7444
|
const t = text.toLowerCase();
|
|
@@ -7378,6 +7477,48 @@ function scoreStress(text) {
|
|
|
7378
7477
|
const qeCombos = text.match(/\?!|!\?/g);
|
|
7379
7478
|
if (qeCombos)
|
|
7380
7479
|
score += qeCombos.length * 0.1;
|
|
7480
|
+
const behavioralPhrases = [
|
|
7481
|
+
{ 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 },
|
|
7482
|
+
{ 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 },
|
|
7483
|
+
{ re: /\b(blocked again|stuck again|failed again|fails again|this is not working|nothing changed|no change)\b/gi, weight: 0.1 }
|
|
7484
|
+
];
|
|
7485
|
+
for (const { re, weight } of behavioralPhrases) {
|
|
7486
|
+
const hits = (t.match(re) || []).length;
|
|
7487
|
+
score += hits * weight;
|
|
7488
|
+
}
|
|
7489
|
+
const sessionId = String(_OC_SID || "");
|
|
7490
|
+
let blackboxState = context?.blackboxState || null;
|
|
7491
|
+
if (!blackboxState) {
|
|
7492
|
+
try {
|
|
7493
|
+
const raw = loadBlackboxState();
|
|
7494
|
+
blackboxState = raw?.sessions?.[sessionId] || null;
|
|
7495
|
+
} catch {
|
|
7496
|
+
}
|
|
7497
|
+
}
|
|
7498
|
+
const recentEvents = Array.isArray(context?.recentToolEvents) ? context.recentToolEvents : Array.isArray(recentToolEvents) ? recentToolEvents : [];
|
|
7499
|
+
const recentWindow = recentEvents.slice(-8);
|
|
7500
|
+
const toolRepeatStreak = countTrailingRepeat(recentWindow, normalizeActivitySignature);
|
|
7501
|
+
if (toolRepeatStreak >= 2) {
|
|
7502
|
+
score += 0.05 + Math.min(0.2, (toolRepeatStreak - 1) * 0.04);
|
|
7503
|
+
}
|
|
7504
|
+
const repeatedTargets = countTrailingRepeat(recentWindow, (event) => String(event?.target || "").trim().toLowerCase());
|
|
7505
|
+
if (repeatedTargets >= 2) {
|
|
7506
|
+
score += 0.04 + Math.min(0.12, (repeatedTargets - 1) * 0.03);
|
|
7507
|
+
}
|
|
7508
|
+
const outcomeHistory = Array.isArray(context?.outcomeHistory) ? context.outcomeHistory : Array.isArray(blackboxState?.outcomeHistory) ? blackboxState.outcomeHistory : [];
|
|
7509
|
+
const recentOutcomes = outcomeHistory.slice(-5);
|
|
7510
|
+
const negativeOutcomes = recentOutcomes.filter((o) => /negative|failed|unresolved|loop_detected/i.test(String(o?.outcome || ""))).length;
|
|
7511
|
+
if (negativeOutcomes >= 1) {
|
|
7512
|
+
score += 0.03 * negativeOutcomes + Math.min(0.12, negativeOutcomes * 0.02);
|
|
7513
|
+
}
|
|
7514
|
+
const loopCount = Number(blackboxState?.loop_count ?? blackboxState?.loopConsecutive ?? blackboxState?.loop_consecutive ?? 0);
|
|
7515
|
+
if (blackboxState?.is_looping || loopCount >= 2) {
|
|
7516
|
+
score += 0.08 + Math.min(0.15, loopCount * 0.02);
|
|
7517
|
+
}
|
|
7518
|
+
const repeatStreak = Number(blackboxState?.repeat_streak ?? 0);
|
|
7519
|
+
if (repeatStreak >= 2) {
|
|
7520
|
+
score += 0.05 + Math.min(0.08, repeatStreak * 0.02);
|
|
7521
|
+
}
|
|
7381
7522
|
if (text.length < 30)
|
|
7382
7523
|
score += 0.06;
|
|
7383
7524
|
else if (text.length < 80)
|
|
@@ -7537,7 +7678,7 @@ function autoSelectMode2(subRegime, stressMultiplier) {
|
|
|
7537
7678
|
if (regime === "AUDIT" || regime === "FORENSIC")
|
|
7538
7679
|
return regime.toLowerCase();
|
|
7539
7680
|
if (regime === "LOOPING")
|
|
7540
|
-
return "
|
|
7681
|
+
return "quality";
|
|
7541
7682
|
if (regime === "CONVERGING" || regime === "CLOSED")
|
|
7542
7683
|
return "quality";
|
|
7543
7684
|
if (regime === "IMPLEMENTING")
|
|
@@ -7658,22 +7799,27 @@ function computeControlVector2(_state, _action, _optimizationMode) {
|
|
|
7658
7799
|
const subRegime = _state?.sub_regime || "INIT";
|
|
7659
7800
|
const stress = Number(_state?.latest_stress_multiplier ?? 0);
|
|
7660
7801
|
const tierBias = stress > QUALITY_STRESS_THRESHOLD2 ? "brain" : subRegime === "CONVERGING" || subRegime === "CLOSED" ? "brain" : subRegime === "REFINING" || subRegime === "LOOPING" ? "medium" : mode === "quality" || mode === "longrun" || mode === "vibeultrax" || mode === "vibeqmax" || mode === "forensic" || mode === "audit" ? "brain" : mode === "speed" || mode === "vibemax" || mode === "vibelitex" ? "medium" : mode === "balanced" ? "auto" : "cheap";
|
|
7802
|
+
const loopingHardening = String(subRegime).toUpperCase() === "LOOPING";
|
|
7803
|
+
const hardenedTierBias = loopingHardening ? "brain" : tierBias;
|
|
7804
|
+
const hardenedMode = loopingHardening ? "quality" : mode;
|
|
7805
|
+
const hardenedModeRoot = loopingHardening ? { mode_root: "quality", mode_family: "brain-runtime", cascade_depth: 1, pipeline_root: ["brain"] } : modeRoot;
|
|
7661
7806
|
return {
|
|
7662
|
-
enforcement_mode: isStrict ? "strict" : isRelaxed ? "relaxed" : "normal",
|
|
7663
|
-
enforcement_reason: `[optimize: ${mode}] using safe offline defaults`,
|
|
7664
|
-
flow_mode: isStrict ? "strict" : isRelaxed ? "audit" : "normal",
|
|
7807
|
+
enforcement_mode: loopingHardening ? "strict" : isStrict ? "strict" : isRelaxed ? "relaxed" : "normal",
|
|
7808
|
+
enforcement_reason: loopingHardening ? "[optimize: LOOPING] recovery posture \u2014 tighten enforcement and preserve outcome detection" : `[optimize: ${mode}] using safe offline defaults`,
|
|
7809
|
+
flow_mode: loopingHardening ? "strict" : isStrict ? "strict" : isRelaxed ? "audit" : "normal",
|
|
7665
7810
|
flow_focus: [],
|
|
7666
|
-
tdd_mode: isStrict ? "strict" : isRelaxed ? "lazy" : "normal",
|
|
7811
|
+
tdd_mode: loopingHardening ? "strict" : isStrict ? "strict" : isRelaxed ? "lazy" : "normal",
|
|
7667
7812
|
tdd_focus: [],
|
|
7668
|
-
tier_bias:
|
|
7669
|
-
thinking_mode: isStrict ? "full" : mode === "longrun" ? "brief" : isRelaxed ? "off" : "auto",
|
|
7670
|
-
stress_multiplier: 1,
|
|
7671
|
-
context7_urgency: isStrict ? "required" : "preferred",
|
|
7672
|
-
wbp_verbosity: isStrict ? "verbose" : isRelaxed ? "minimal" : "normal",
|
|
7813
|
+
tier_bias: hardenedTierBias,
|
|
7814
|
+
thinking_mode: loopingHardening ? "brief" : isStrict ? "full" : mode === "longrun" ? "brief" : isRelaxed ? "off" : "auto",
|
|
7815
|
+
stress_multiplier: loopingHardening ? Math.max(1.5, stress) : 1,
|
|
7816
|
+
context7_urgency: loopingHardening ? "required" : isStrict ? "required" : "preferred",
|
|
7817
|
+
wbp_verbosity: loopingHardening ? "detailed" : isStrict ? "verbose" : isRelaxed ? "minimal" : "normal",
|
|
7673
7818
|
agent_mode: (subRegime === "REFINING" || subRegime === "CONVERGING" || subRegime === "CLOSED") && stress <= QUALITY_STRESS_THRESHOLD2 ? "plan" : void 0,
|
|
7674
|
-
optimization_mode:
|
|
7675
|
-
...
|
|
7676
|
-
|
|
7819
|
+
optimization_mode: hardenedMode,
|
|
7820
|
+
...hardenedModeRoot,
|
|
7821
|
+
outcome_detection: true,
|
|
7822
|
+
directives: isRelaxed && !loopingHardening && (subRegime === "EXPLORING" || subRegime === "INIT" || subRegime === "AUDIT" || subRegime === "FORENSIC" || subRegime === "LOOPING") ? [
|
|
7677
7823
|
`[speed guard] VERIFY BEFORE ACT - Speed-oriented mode "${mode}" is active and user intent is ${subRegime}. Before modifying files or executing commands, first verify the current state. When a request is ambiguous between "check and report" vs "fix", always choose CHECK FIRST. Treat "look at", "check", "investigate", "tell me about" as requests for information, not action items.`
|
|
7678
7824
|
] : []
|
|
7679
7825
|
};
|
|
@@ -7731,6 +7877,29 @@ function normalizeBlackboxFeatures(text) {
|
|
|
7731
7877
|
uncertainty: computeBlackboxUncertainty(features)
|
|
7732
7878
|
};
|
|
7733
7879
|
}
|
|
7880
|
+
function summarizeRecentToolActivity(limit = 5) {
|
|
7881
|
+
const events = Array.isArray(recentToolEvents) ? recentToolEvents.slice(-limit) : [];
|
|
7882
|
+
if (events.length === 0)
|
|
7883
|
+
return null;
|
|
7884
|
+
const last = events[events.length - 1] || {};
|
|
7885
|
+
const signature = `${String(last.tool || "").trim().toLowerCase()}:${String(last.target || "").trim().toLowerCase()}`;
|
|
7886
|
+
let repeatCount = 0;
|
|
7887
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
7888
|
+
const cur = events[i] || {};
|
|
7889
|
+
const curSignature = `${String(cur.tool || "").trim().toLowerCase()}:${String(cur.target || "").trim().toLowerCase()}`;
|
|
7890
|
+
if (curSignature !== signature)
|
|
7891
|
+
break;
|
|
7892
|
+
repeatCount++;
|
|
7893
|
+
}
|
|
7894
|
+
return {
|
|
7895
|
+
tool: String(last.tool || "").toLowerCase(),
|
|
7896
|
+
target: String(last.target || "").toLowerCase(),
|
|
7897
|
+
action: String(last.action || last.kind || "").toLowerCase(),
|
|
7898
|
+
signature,
|
|
7899
|
+
repeat_count: repeatCount,
|
|
7900
|
+
recent_count: events.length
|
|
7901
|
+
};
|
|
7902
|
+
}
|
|
7734
7903
|
function normalizeBlackboxHistoryEntry(entry) {
|
|
7735
7904
|
const text = typeof entry?.text === "string" ? entry.text : "";
|
|
7736
7905
|
const fallback2 = normalizeBlackboxFeatures(text);
|
|
@@ -7744,7 +7913,8 @@ function normalizeBlackboxHistoryEntry(entry) {
|
|
|
7744
7913
|
embedding: Array.isArray(entry?.embedding) ? [...entry.embedding] : null,
|
|
7745
7914
|
timestamp: Number.isFinite(Number(entry?.timestamp)) ? Number(entry.timestamp) : Date.now() / 1e3,
|
|
7746
7915
|
is_pivot: Boolean(entry?.is_pivot),
|
|
7747
|
-
outcome: typeof entry?.outcome === "string" ? entry.outcome : entry?.outcome ?? null
|
|
7916
|
+
outcome: typeof entry?.outcome === "string" ? entry.outcome : entry?.outcome ?? null,
|
|
7917
|
+
activity: entry?.activity && typeof entry.activity === "object" ? { ...entry.activity } : null
|
|
7748
7918
|
};
|
|
7749
7919
|
}
|
|
7750
7920
|
function normalizeBlackboxHistory(history) {
|
|
@@ -7771,7 +7941,8 @@ var _BlackboxStub = class __BlackboxStub {
|
|
|
7771
7941
|
}
|
|
7772
7942
|
update(text) {
|
|
7773
7943
|
const normalized = normalizeBlackboxFeatures(text);
|
|
7774
|
-
const
|
|
7944
|
+
const recentActivity = summarizeRecentToolActivity();
|
|
7945
|
+
const state = this.tracker.update(text, normalized.features, normalized.action, normalized.entropy, normalized.uncertainty, null, recentActivity);
|
|
7775
7946
|
return { ...state, ...normalized };
|
|
7776
7947
|
}
|
|
7777
7948
|
snapshot() {
|
|
@@ -7896,8 +8067,10 @@ function computeLocalCalibration() {
|
|
|
7896
8067
|
}
|
|
7897
8068
|
function resolveEnforcementMode() {
|
|
7898
8069
|
const sub = _latestBlackboxState2?.sub_regime || "INIT";
|
|
7899
|
-
if (sub === "EXPLORING" || sub === "DIVERGENT"
|
|
8070
|
+
if (sub === "EXPLORING" || sub === "DIVERGENT")
|
|
7900
8071
|
return "relaxed";
|
|
8072
|
+
if (sub === "LOOPING")
|
|
8073
|
+
return "strict";
|
|
7901
8074
|
if (sub === "CONVERGING" || sub === "CLOSED")
|
|
7902
8075
|
return "strict";
|
|
7903
8076
|
return "normal";
|
|
@@ -10791,7 +10964,11 @@ function isManualOverride(mode) {
|
|
|
10791
10964
|
function chooseEpisodeMode(regime, suggestedMode, stress) {
|
|
10792
10965
|
if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax" || suggestedMode === "audit" || suggestedMode === "forensic")
|
|
10793
10966
|
return suggestedMode;
|
|
10794
|
-
if (
|
|
10967
|
+
if (regime === "LOOPING")
|
|
10968
|
+
return "quality";
|
|
10969
|
+
if (suggestedMode === "speed")
|
|
10970
|
+
return "speed";
|
|
10971
|
+
if (LOOP_REGIMES.has(regime))
|
|
10795
10972
|
return "speed";
|
|
10796
10973
|
if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality")
|
|
10797
10974
|
return "quality";
|
|
@@ -11454,7 +11631,7 @@ function resolveTemplate(prevTemplate, stressScore, userText, creditPercent, sub
|
|
|
11454
11631
|
if (detectBudgetSignal(creditPercent)) {
|
|
11455
11632
|
const regime = String(subRegime || "").toUpperCase();
|
|
11456
11633
|
if (regime === "LOOPING" || regime === "DIVERGENT")
|
|
11457
|
-
return "
|
|
11634
|
+
return "quality";
|
|
11458
11635
|
return "save";
|
|
11459
11636
|
}
|
|
11460
11637
|
if (detectStressSpike(stressScore))
|
|
@@ -15753,8 +15930,7 @@ async function ensureMcpServerRunning() {
|
|
|
15753
15930
|
const actualPort = Number(mcpServer?.address?.()?.port || requestedPort);
|
|
15754
15931
|
if (actualPort && actualPort !== requestedPort)
|
|
15755
15932
|
persistMcpPort(actualPort);
|
|
15756
|
-
|
|
15757
|
-
writeDashboardBaseConfig(`http://127.0.0.1:${actualPort}`);
|
|
15933
|
+
writeDashboardBaseConfig(process.env.VIBEOS_DASHBOARD_BASE_URL?.trim() || "");
|
|
15758
15934
|
console.error(`[vibeOS] MCP server on http://127.0.0.1:${actualPort}`);
|
|
15759
15935
|
if (actualPort)
|
|
15760
15936
|
console.error(`[vibeOS] Dashboard at http://127.0.0.1:${actualPort}/`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.15",
|
|
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/scripts/deploy.mjs
CHANGED
|
@@ -10,9 +10,15 @@ const ROOT = join(__dirname, "..")
|
|
|
10
10
|
|
|
11
11
|
const bundlePath = join(ROOT, "dist", "vibeOS.js")
|
|
12
12
|
const assetsPath = join(ROOT, "dist", "assets")
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
13
|
+
|
|
14
|
+
function resolveOpenCodeHomes() {
|
|
15
|
+
const override = process.env.VIBEOS_OPENCODE_HOME
|
|
16
|
+
if (override) return [override]
|
|
17
|
+
const base = homedir()
|
|
18
|
+
const configHome = join(base, ".config", "opencode")
|
|
19
|
+
const dotHome = join(base, ".opencode")
|
|
20
|
+
return [configHome, dotHome]
|
|
21
|
+
}
|
|
16
22
|
|
|
17
23
|
if (!existsSync(bundlePath)) {
|
|
18
24
|
process.stderr.write("[vibeOS deploy] ERROR: dist/vibeOS.js not found\n")
|
|
@@ -20,38 +26,47 @@ if (!existsSync(bundlePath)) {
|
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
try {
|
|
23
|
-
if (!existsSync(pluginDir)) {
|
|
24
|
-
mkdirSync(pluginDir, { recursive: true })
|
|
25
|
-
}
|
|
26
29
|
const bundle = readFileSync(bundlePath)
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
for (const home of resolveOpenCodeHomes()) {
|
|
31
|
+
const pluginDir = join(home, "plugins")
|
|
32
|
+
const destPath = join(pluginDir, "vibeOS.js")
|
|
33
|
+
const destAssets = join(pluginDir, "assets")
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
if (!existsSync(pluginDir)) {
|
|
36
|
+
mkdirSync(pluginDir, { recursive: true })
|
|
37
|
+
}
|
|
38
|
+
writeFileSync(destPath, bundle)
|
|
39
|
+
process.stderr.write(`[vibeOS deploy] dist/vibeOS.js -> ${home}/plugins/vibeOS.js (${bundle.length} bytes)\n`)
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
if (existsSync(assetsPath)) {
|
|
42
|
+
cpSync(assetsPath, destAssets, { recursive: true, force: true })
|
|
43
|
+
process.stderr.write(`[vibeOS deploy] dist/assets/ -> ${home}/plugins/assets/\n`)
|
|
38
44
|
}
|
|
45
|
+
|
|
46
|
+
for (const staleDir of [join(pluginDir, "lib"), join(pluginDir, "utils"), join(pluginDir, "vibeOS-lib"), join(pluginDir, "vibeOS-api-server"), join(pluginDir, "dashboard", "dist")]) {
|
|
47
|
+
if (existsSync(staleDir)) {
|
|
48
|
+
rmSync(staleDir, { recursive: true, force: true })
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const rmTsRecursive = (d) => { for (const e of readdirSync(d)) { const f = join(d, e); if (statSync(f).isDirectory()) rmTsRecursive(f); else if (e.endsWith('.ts')) { rmSync(f); } } }
|
|
52
|
+
rmTsRecursive(pluginDir)
|
|
53
|
+
process.stderr.write(`[vibeOS deploy] Stripped .ts files from ${home}/plugins\n`)
|
|
39
54
|
}
|
|
40
|
-
const rmTsRecursive = (d) => { for (const e of readdirSync(d)) { const f = join(d, e); if (statSync(f).isDirectory()) rmTsRecursive(f); else if (e.endsWith('.ts')) { rmSync(f); } } }
|
|
41
|
-
rmTsRecursive(pluginDir)
|
|
42
|
-
process.stderr.write(`[vibeOS deploy] Stripped .ts files from plugin dir\n`)
|
|
43
55
|
|
|
44
56
|
const envSrc = join(ROOT, ".env.production")
|
|
45
57
|
if (existsSync(envSrc)) {
|
|
46
58
|
const envContent = readFileSync(envSrc)
|
|
47
|
-
const pluginEnvDest = join(pluginDir, ".env.production")
|
|
48
59
|
const homeEnvDir = join(homedir(), ".claude")
|
|
49
60
|
const homeEnvDest = join(homeEnvDir, ".env.production")
|
|
50
61
|
|
|
51
62
|
mkdirSync(homeEnvDir, { recursive: true })
|
|
52
|
-
writeFileSync(pluginEnvDest, envContent)
|
|
53
63
|
writeFileSync(homeEnvDest, envContent)
|
|
54
|
-
|
|
64
|
+
for (const home of resolveOpenCodeHomes()) {
|
|
65
|
+
const pluginEnvDir = join(home, "plugins")
|
|
66
|
+
mkdirSync(pluginEnvDir, { recursive: true })
|
|
67
|
+
writeFileSync(join(pluginEnvDir, ".env.production"), envContent)
|
|
68
|
+
}
|
|
69
|
+
process.stderr.write(`[vibeOS deploy] Synced .env.production to plugin dirs and ~/.claude\n`)
|
|
55
70
|
}
|
|
56
71
|
|
|
57
72
|
// ── Install nightly pricing sync cron if not already present ──
|
|
@@ -85,26 +100,28 @@ try {
|
|
|
85
100
|
|
|
86
101
|
// Auto-register in opencode.json so OpenCode loads the plugin
|
|
87
102
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
103
|
+
for (const home of resolveOpenCodeHomes()) {
|
|
104
|
+
const ocConfigPath = join(home, "opencode.json")
|
|
105
|
+
mkdirSync(dirname(ocConfigPath), { recursive: true })
|
|
106
|
+
let config = {}
|
|
107
|
+
if (existsSync(ocConfigPath)) {
|
|
108
|
+
const raw = readFileSync(ocConfigPath, "utf-8")
|
|
109
|
+
try {
|
|
110
|
+
const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "")
|
|
111
|
+
config = JSON.parse(cleaned)
|
|
112
|
+
} catch {
|
|
113
|
+
config = {}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) config = {}
|
|
117
|
+
if (!Array.isArray(config.plugin)) config.plugin = []
|
|
118
|
+
const hasVibeOs = config.plugin.some(p => typeof p === "string" && p.includes("vibeOS"))
|
|
119
|
+
if (!hasVibeOs) {
|
|
120
|
+
config.$schema ||= "https://opencode.ai/config.json"
|
|
121
|
+
config.plugin.push("./plugins/vibeOS.js")
|
|
122
|
+
writeFileSync(ocConfigPath, JSON.stringify(config, null, 2) + "\n")
|
|
123
|
+
process.stderr.write(`[vibeOS deploy] Registered vibeOS in ${home}/opencode.json\n`)
|
|
98
124
|
}
|
|
99
|
-
}
|
|
100
|
-
if (!config || typeof config !== "object" || Array.isArray(config)) config = {}
|
|
101
|
-
if (!Array.isArray(config.plugin)) config.plugin = []
|
|
102
|
-
const hasVibeOs = config.plugin.some(p => typeof p === "string" && p.includes("vibeOS"))
|
|
103
|
-
if (!hasVibeOs) {
|
|
104
|
-
config.$schema ||= "https://opencode.ai/config.json"
|
|
105
|
-
config.plugin.push("./plugins/vibeOS.js")
|
|
106
|
-
writeFileSync(ocConfigPath, JSON.stringify(config, null, 2) + "\n")
|
|
107
|
-
process.stderr.write("[vibeOS deploy] Registered vibeOS in opencode.json\n")
|
|
108
125
|
}
|
|
109
126
|
} catch {
|
|
110
127
|
process.stderr.write("[vibeOS deploy] Could not auto-register in opencode.json (plugin may need manual config)\n")
|