vibeostheog 0.23.7 → 0.23.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.23.7",
3
+ "version": "0.23.12",
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",
@@ -14,8 +14,8 @@
14
14
  "checkpoint:validate": "node scripts/checkpoint-validate.mjs",
15
15
  "test:scripts": "node --test scripts/tests/checkpoint-validate.test.mjs tests/release-pack.test.mjs",
16
16
  "ts:audit": "node scripts/ts-audit.mjs",
17
- "test": "VIBEOS_MCP_PORT=0 node --test --test-timeout=240000 tests/deep_integration.test.mjs tests/production_regressions.test.mjs tests/release_hardening_tigerteam.test.mjs tests/test_api_migration.neutral.test.mjs tests/test_const_assignment_regression.test.mjs tests/test_delegation_enforcer.test.mjs tests/test_diagnose_cmd.test.mjs tests/test_install_and_recovery.test.mjs tests/test_internals_stress_patterns_offtopic.test.mjs tests/test_saveos_e2e_cleanup.test.mjs tests/test_tdd_enforcer.test.mjs tests/test_10fixes_regression.test.mjs tests/test_cross_session_regression.test.mjs tests/test_mega_all_fixes.test.mjs tests/test_smart_cache_regression.test.mjs src/tests/*.test.js src/utils/tests/*.test.mjs \"src/vibeOS-lib/tests/auto-select-mode.test.mjs\" \"src/vibeOS-lib/tests/blackbox-regression.test.mjs\" \"src/vibeOS-lib/tests/blackbox-smoke.test.mjs\" \"src/vibeOS-lib/tests/budget-first-mode.test.mjs\" \"src/vibeOS-lib/tests/flow-enforcer.test.mjs\" \"src/vibeOS-lib/tests/flow-secrets.test.mjs\" \"src/vibeOS-lib/tests/session-metrics.test.mjs\" \"src/vibeOS-lib/tests/test_stress.test.mjs\" tests/test_trinity_mega_regression.test.mjs tests/test_multisession_mega.test.mjs",
18
- "test:ci": "VIBEOS_MCP_PORT=0 node --test --test-timeout=30000 tests/production_regressions.test.mjs tests/release_hardening_tigerteam.test.mjs tests/test_const_assignment_regression.test.mjs tests/test_diagnose_cmd.test.mjs tests/test_install_and_recovery.test.mjs tests/test_saveos_e2e_cleanup.test.mjs tests/test_tdd_enforcer.test.mjs tests/test_10fixes_regression.test.mjs tests/test_cross_session_regression.test.mjs tests/test_mega_all_fixes.test.mjs tests/test_smart_cache_regression.test.mjs src/tests/*.test.js src/utils/tests/*.test.mjs \"src/vibeOS-lib/tests/auto-select-mode.test.mjs\" \"src/vibeOS-lib/tests/blackbox-regression.test.mjs\" \"src/vibeOS-lib/tests/blackbox-smoke.test.mjs\" \"src/vibeOS-lib/tests/budget-first-mode.test.mjs\" \"src/vibeOS-lib/tests/flow-enforcer.test.mjs\" \"src/vibeOS-lib/tests/flow-secrets.test.mjs\" \"src/vibeOS-lib/tests/session-metrics.test.mjs\" \"src/vibeOS-lib/tests/test_stress.test.mjs\"",
17
+ "test": "VIBEOS_MCP_PORT=0 node --test --test-timeout=240000 tests/deep_integration.test.mjs tests/production_regressions.test.mjs tests/release_hardening_tigerteam.test.mjs tests/test_api_migration.neutral.test.mjs tests/test_const_assignment_regression.test.mjs tests/test_delegation_enforcer.test.mjs tests/test_diagnose_cmd.test.mjs tests/test_install_and_recovery.test.mjs tests/test_internals_stress_patterns_offtopic.test.mjs tests/test_saveos_e2e_cleanup.test.mjs tests/test_tdd_enforcer.test.mjs tests/test_10fixes_regression.test.mjs tests/test_cross_session_regression.test.mjs tests/test_mega_all_fixes.test.mjs tests/test_smart_cache_regression.test.mjs src/tests/*.test.js src/utils/tests/*.test.mjs \"src/vibeOS-lib/tests/auto-select-mode.test.mjs\" \"src/vibeOS-lib/tests/blackbox-regression.test.mjs\" \"src/vibeOS-lib/tests/blackbox-smoke.test.mjs\" \"src/vibeOS-lib/tests/budget-first-mode.test.mjs\" \"src/vibeOS-lib/tests/flow-enforcer.test.mjs\" \"src/vibeOS-lib/tests/flow-secrets.test.mjs\" \"src/vibeOS-lib/tests/session-metrics.test.mjs\" \"src/vibeOS-lib/tests/test_stress.test.mjs\" tests/test_trinity_mega_regression.test.mjs tests/test_multisession_mega.test.mjs tests/test_blackbox_default_enabled.test.mjs tests/test_mega_regressions.test.mjs",
18
+ "test:ci": "VIBEOS_MCP_PORT=0 node --test --test-timeout=120000 tests/production_regressions.test.mjs tests/release_hardening_tigerteam.test.mjs tests/test_const_assignment_regression.test.mjs tests/test_diagnose_cmd.test.mjs tests/test_install_and_recovery.test.mjs tests/test_saveos_e2e_cleanup.test.mjs tests/test_tdd_enforcer.test.mjs tests/test_10fixes_regression.test.mjs tests/test_cross_session_regression.test.mjs tests/test_mega_all_fixes.test.mjs tests/test_smart_cache_regression.test.mjs src/tests/*.test.js src/utils/tests/*.test.mjs \"src/vibeOS-lib/tests/auto-select-mode.test.mjs\" \"src/vibeOS-lib/tests/blackbox-regression.test.mjs\" \"src/vibeOS-lib/tests/blackbox-smoke.test.mjs\" \"src/vibeOS-lib/tests/budget-first-mode.test.mjs\" \"src/vibeOS-lib/tests/flow-enforcer.test.mjs\" \"src/vibeOS-lib/tests/flow-secrets.test.mjs\" \"src/vibeOS-lib/tests/session-metrics.test.mjs\" \"src/vibeOS-lib/tests/test_stress.test.mjs\" tests/test_blackbox_default_enabled.test.mjs tests/test_mega_regressions.test.mjs tests/test_delegation_enforcer.test.mjs tests/test_first_install_autoconfig.mjs tests/deep_integration.test.mjs tests/e2e_workflows.test.mjs tests/integration_cross_module.test.mjs tests/privacy_telemetry.test.mjs tests/release-pack.test.mjs tests/test_api_migration.neutral.test.mjs tests/test_internals_stress_patterns_offtopic.test.mjs tests/test_ml_cache_mega.test.mjs tests/test_mode_brand.test.mjs tests/test_multisession_mega.test.mjs tests/test_trinity_mega_regression.test.mjs",
19
19
  "guard": "bash plugins/vibetheog-guard/scripts/run-guard.sh",
20
20
  "guard:full": "VIBETHEOG_GUARD_FULL=1 bash plugins/vibetheog-guard/scripts/run-guard.sh",
21
21
  "hook:precommit": "bash plugins/vibetheog-guard/hooks/pre-commit.sh",
package/src/index.js CHANGED
@@ -19,7 +19,7 @@ import { safeJsonParse, readFullState, loadSelection, writeSelection, readLifeti
19
19
  import { researchAudit } from "./lib/research-audit.js";
20
20
  import { buildStatusPayload, buildSavingsPayload, buildSessionCheckout, diagnoseStructuredFromText, projectStructuredFromText, } from "./lib/runtime-surface.js";
21
21
  import { saveReport, listReports, readReport } from "./lib/reporting.js";
22
- import { writeSessionSlot } from "./lib/selection-manager.js";
22
+ import { writeSessionSlot, writeSessionOptMode } from "./lib/selection-manager.js";
23
23
  import { loadCredit, thinkingLevel, _lazyRefresh, _readAuth } from "./lib/credit-api.js";
24
24
  import { createTrinityTool } from "./lib/trinity-tool.js";
25
25
  import { classifyAndRankModels, modelToCcAlias, discoverAvailableModels, probeModel } from "./lib/trinity-rebuild.js";
@@ -286,7 +286,7 @@ export async function DelegationEnforcer({ client, directory } = {}) {
286
286
  console.error(`[vibeOS] LOADED cwd=${directory}`);
287
287
  const hookHome = process.env.HOME || USER_HOME;
288
288
  const hookFp = projectFingerprint(directory || "");
289
- const hookSessionId = `opencode-${process.pid || "x"}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
289
+ if (!globalThis.__vibeOS_sessionId) { globalThis.__vibeOS_sessionId = `opencode-${process.pid || "x"}-${Date.now()}`; } const hookSessionId = globalThis.__vibeOS_sessionId;
290
290
  setVibeOSHomeContext(join(hookHome, ".claude"));
291
291
  setCurrentSessionId(hookSessionId);
292
292
  if (hookFp) {
@@ -434,7 +434,7 @@ export async function DelegationEnforcer({ client, directory } = {}) {
434
434
  projectPatternRows, promotedProjectPatterns, detectTechStack, ensureProjectDocs,
435
435
  discoverAvailableModels, classifyAndRankModels, modelToCcAlias, probeModel,
436
436
  setBlackboxEnabled, loadBlackboxState, saveBlackboxState,
437
- reportsIndex: reportsIndexStable, saveReportsIndex: saveReportsIndexStable, backupFile: backupFileStable, writeSessionSlot, _refreshModel,
437
+ reportsIndex: reportsIndexStable, saveReportsIndex: saveReportsIndexStable, backupFile: backupFileStable, writeSessionSlot, writeSessionOptMode, _refreshModel,
438
438
  setApiToken,
439
439
  setApiBootstrapToken,
440
440
  ensureBootstrapExchange,
@@ -790,7 +790,7 @@ export default { id: "vibeOS", server: DelegationEnforcer };
790
790
  export { researchAudit } from "./lib/research-audit.js";
791
791
  export { saveReport, listReports, readReport } from "./lib/reporting.js";
792
792
  export { applySlot, modelCostPerTurn, isModelFree, isDocsTarget, detectContext7, loadTierRegexes, classify, _refreshModel, HIGH_TIER_RE, MID_TIER_RE, PLACEHOLDER_RE, TRINITY_BRAIN, TRINITY_MEDIUM, TRINITY_CHEAP, setTrinityBrain, setTrinityMedium, setTrinityCheap, trendDisplay, } from "./lib/pricing.js";
793
- export { getScratchpadHit, getSessionScratchpadDir, getSessionIndexPath } from "./lib/state.js";
793
+ export { getScratchpadHit, getSessionScratchpadDir, getSessionIndexPath, setCurrentModel, setCurrentTier } from "./lib/state.js";
794
794
  export { extractExports, buildTestSkeleton, enforceTestFile, buildTestReminder } from "./lib/tdd-enforcer.js";
795
795
  export { classifyAndRankModels, modelToCcAlias } from "./lib/trinity-rebuild.js";
796
796
  export { scoreStress, detectTechStack, loadBlackboxState, saveBlackboxState, getBlackboxResolution, } from "./lib/turn-classify.js";
@@ -4,10 +4,11 @@ import { join, basename } from "node:path";
4
4
  import { createHash } from "node:crypto";
5
5
  import { currentModel, currentProjectFingerprint, currentProjectName, _blackboxEnabled, loadSelection, writeSelection, safeJsonParse, applyDecadence, getSessionScratchpadDir, ensureSessionScratchpadDirs, indexAppend, briefedProjects, getActiveJobForProject, loadTodos, promotedProjectPatterns, detectTechStack, projectFingerprint, SCRATCHPAD_ROOT, TRINITY_OPENCODE_CONFIG, TIERS_FILE, loadGlobalLearning, setCurrentProjectFingerprint, setCurrentProjectName, stableJson, TOOL_NAME_NORMALIZE, _cacheDb, recordCacheSaving, } from "../state.js";
6
6
  import { applySlot, TRINITY_CHEAP, TRINITY_MEDIUM, cacheSavePer1MInputTokens, } from "../pricing.js";
7
- import { scoreStress, classifyTurnSimple, loadOptimizationMode, saveOptimizationMode, selectOptimizationModeRemote, computeControlVector, getBlackboxTracker, loadBlackboxState as loadBlackboxStateFromCtx, saveBlackboxState as saveBlackboxStateToCtx, extractLastUserText, isLikelyOffTopic, fetchBlackboxEnrichment, estimateContextBudget, buildControlHistoryEntry, } from "../turn-classify.js";
7
+ import { scoreStress, classifyTurnSimple, loadOptimizationMode, saveOptimizationMode, selectOptimizationModeRemote, computeControlVector, getBlackboxTracker, loadBlackboxState as loadBlackboxStateFromCtx, saveBlackboxState as saveBlackboxStateToCtx, extractLastUserText, isLikelyOffTopic, fetchBlackboxEnrichment, estimateContextBudget, buildControlHistoryEntry, setBlackboxEnabled, } from "../turn-classify.js";
8
8
  import { applyBudgetFirstMode, peekBudgetFirstMode } from "../mode-policy.js";
9
+ import { BRANDED_MODES, RUNTIME_MODES } from "../mode-router.js";
9
10
  import { addCacheEntry, extractRecentCacheOutputs } from "../../vibeOS-lib/smart-cache.js";
10
- import { remoteCall } from "../api-client.js";
11
+ import { remoteCall, isApiConnected } from "../api-client.js";
11
12
  import { loadCredit } from "../credit-api.js";
12
13
  import { loadSessionOptMode, loadSessionSlot, writeSessionSlot } from "../selection-manager.js";
13
14
  import { noteProjectPattern } from "../index-helpers.js";
@@ -160,12 +161,34 @@ export function syncControlSettings(cv, options = {}) {
160
161
  const sid = _OC_SID;
161
162
  const persistOptimizationMode = options.persistOptimizationMode !== false;
162
163
  const currentSel = loadSelection();
163
- const compatibilityMode = currentSel.onboarding_mode === "assist";
164
+ const userSetMode = loadSessionOptMode(sid + "_opt");
165
+ const userOptMode = userSetMode || loadOptimizationMode();
166
+ const isManualMode = userSetMode && userOptMode !== "auto";
164
167
  const writeIf = (key, val) => {
165
168
  const sel = loadSelection();
166
169
  if (sel[key] !== val)
167
170
  writeSelection(key, val);
168
171
  };
172
+ if (isManualMode) {
173
+ const allEntries = [...BRANDED_MODES, ...RUNTIME_MODES];
174
+ const modeEntry = allEntries.find((e) => e.id === userOptMode);
175
+ if (modeEntry) {
176
+ writeIf("delegation_enforce", modeEntry.enforcement === "strict" || modeEntry.enforcement === "on");
177
+ writeIf("flow_enabled", modeEntry.flow === "strict" || modeEntry.flow === "on" || modeEntry.flow === "audit");
178
+ writeIf("flow_enforce", modeEntry.flow === "strict" || modeEntry.flow === "on");
179
+ writeIf("tdd_enforce", modeEntry.tdd === "quality" || modeEntry.tdd === "on" || modeEntry.tdd === "strict");
180
+ writeIf("tdd_strict", modeEntry.tdd === "strict");
181
+ if (modeEntry.thinking)
182
+ writeIf("thinking_level", modeEntry.thinking);
183
+ const rawTier = modeEntry.pipeline[0] || "cheap";
184
+ const allowedTiers = new Set(["brain", "medium", "cheap"]);
185
+ const slot = allowedTiers.has(rawTier) ? rawTier : "cheap";
186
+ writeIf("active_slot", slot);
187
+ writeIf("active_pipeline", JSON.stringify(modeEntry.pipeline));
188
+ return;
189
+ }
190
+ }
191
+ const compatibilityMode = currentSel.onboarding_mode === "assist";
169
192
  writeIf("delegation_enforce", compatibilityMode ? cv.enforcement_mode === "strict" : true);
170
193
  if (compatibilityMode) {
171
194
  writeIf("flow_enabled", cv.flow_mode === "strict");
@@ -193,8 +216,6 @@ export function syncControlSettings(cv, options = {}) {
193
216
  }
194
217
  if (cv.thinking_mode && currentSel.thinking_level !== "full")
195
218
  writeIf("thinking_level", cv.thinking_mode);
196
- const userSetMode = loadSessionOptMode(sid + "_opt");
197
- const userOptMode = userSetMode || loadOptimizationMode();
198
219
  if (persistOptimizationMode && cv.optimization_mode && userOptMode !== "auto") {
199
220
  if (userOptMode !== cv.optimization_mode && !userSetMode) {
200
221
  writeSessionSlot(sid + "_opt", cv.optimization_mode);
@@ -592,6 +613,19 @@ export const onSystemTransform = async (_input, output) => {
592
613
  const system = output?.system;
593
614
  if (!Array.isArray(system))
594
615
  return;
616
+ if (isApiConnected()) {
617
+ try {
618
+ const bb = loadBlackboxStateFromCtx();
619
+ if (!bb.enabled || _blackboxEnabled === false) {
620
+ setBlackboxEnabled(true);
621
+ if (!bb.enabled) {
622
+ bb.enabled = true;
623
+ saveBlackboxStateToCtx(bb);
624
+ }
625
+ }
626
+ }
627
+ catch { }
628
+ }
595
629
  const sel = loadSelection();
596
630
  syncControlSettings(_controlVector, { persistOptimizationMode: optimizationDecision.shouldPersistRequestedMode });
597
631
  const fp = ensureProjectContext(hookDirectory);
@@ -283,8 +283,10 @@ async function _appendFooter(input, output, directory) {
283
283
  const ltTotal = ltTasks + ltCache;
284
284
  const modeCapitalized = (mode) => mode.charAt(0).toUpperCase() + mode.slice(1);
285
285
  const optMode = (resolvedMode || "budget").toLowerCase();
286
- const vibeBrand = optModeFooter === "vibeultrax" ? "VibeUltraX" : (optModeFooter === "vibeqmax" || optModeFooter === "quality") ? "VibeQMaX" : "VibeMaX";
287
- const modeLabel = modeCapitalized(optMode);
286
+ const brandMap = { vibeultrax: "VibeUltraX", vibeqmax: "VibeQMaX", vibemax: "VibeMaX" };
287
+ const brandedToRuntime = { vibeultrax: "Quality", vibeqmax: "Quality", vibemax: "Speed" };
288
+ const vibeBrand = brandMap[optModeFooter] || (execution.quality === "brain" ? "VibeQMaX" : "VibeMaX");
289
+ const modeLabel = modeCapitalized(brandedToRuntime[optMode] || optMode);
288
290
  const qualityIcon = execution.quality === "brain" ? "🧠" : execution.quality === "medium" ? "⚙" : execution.quality === "free" ? "🎁" : "⚡";
289
291
  const flashIcon = isApiConnected() ? " ⚡" : "";
290
292
  let vibeLine = `— ${qualityIcon} ${execution.quality} | ${execution.provider_label} | ${modelDisplayName(execution.model)}`;
@@ -292,7 +294,7 @@ async function _appendFooter(input, output, directory) {
292
294
  vibeLine += ` | $${formatUsd(ltTotal)}`;
293
295
  }
294
296
  if (isApiConnected()) {
295
- vibeLine += ` | ${vibeBrand}${flashIcon} ${modeLabel}`;
297
+ vibeLine += ` | ${vibeBrand}${flashIcon}`;
296
298
  }
297
299
  const footerText = stripped + `\n\n${vibeLine} —`;
298
300
  if (_blackboxEnabled) {
@@ -3,15 +3,22 @@ import { writeFileSync, appendFileSync, existsSync, mkdirSync } from "node:fs";
3
3
  import { join, dirname, basename } from "node:path";
4
4
  import { createHash } from "node:crypto";
5
5
  import { currentTier, currentModel, setCurrentModel, setCurrentTier, _OC_SID, _modelLocked, loadSelection, readLifetimeSavings, recordCacheSaving, recordMissedContext7, getScratchpadHit, recordScratchpadObservation, recordPrivacyTelemetry, updateState, getSessionScratchpadDir, ensureSessionScratchpadDirs, SAVINGS_LEDGER_FILE, CONTEXT7_INSTALL_FLAG, SOFT_QUOTA_LIMIT, upsertTodo, ML_ENABLED, _mlGraph, _cacheDb, _mlSavePending, ML_CONFIDENCE_THRESHOLD, setMlSavePending, saveMLState, SCRATCHPAD_TOOLS, SCRATCHPAD_GLOBAL_DIR, TOOL_NAME_NORMALIZE, stableJson, applyDecadence, } from "../state.js";
6
- import { classify, modelCostPerTurn, isModelFree, detectContext7, isDocsTarget, shortModelName, formatUsd, _refreshModel, readConfig, resolveDisplayModelId, TRINITY_CHEAP, TRINITY_MEDIUM, cacheSavePer1MInputTokens, trendDisplay, modelToSlotLabel, resolveExecutionIdentity, formatProviderName, formatQualityName, } from "../pricing.js";
6
+ import { classify, modelCostPerTurn, isModelFree, detectContext7, isDocsTarget, shortModelName, formatUsd, _refreshModel, readConfig, resolveDisplayModelId, TRINITY_CHEAP, TRINITY_MEDIUM, TRINITY_BRAIN, cacheSavePer1MInputTokens, trendDisplay, modelToSlotLabel, resolveExecutionIdentity, modelDisplayName, } from "../pricing.js";
7
7
  import { latestUserIntent } from "./chat-transform.js";
8
+ import { loadSessionOptMode } from "../selection-manager.js";
9
+ import { loadOptimizationMode } from "../turn-classify.js";
10
+ function modeCapitalized(mode) {
11
+ if (!mode)
12
+ return "Budget";
13
+ return mode.charAt(0).toUpperCase() + mode.slice(1);
14
+ }
8
15
  import { scoreStress, extractFirstWordFromArgs, shouldLogWarn, isUserAskingForTests, resolveEnforcementMode, getLearnedExploratoryWords, noteTaskRoutingLearning, incrementTurnCounter, } from "../turn-classify.js";
9
16
  import { saveReport } from "../reporting.js";
10
17
  import { loadCredit } from "../credit-api.js";
11
18
  import { remoteCall, VIBEOS_API_ENABLED } from "../api-client.js";
12
19
  import { getCostAnomalyDetector } from "../cost-anomaly.js";
13
20
  import { checkFlowRules } from "../../vibeOS-lib/flow-enforcer.js";
14
- import { computeDifficulty, addRouteEdge, predictBestModel, hashQuery } from "../../vibeOS-lib/ml-router.js";
21
+ import { computeDifficulty, cascadeDecide, addRouteEdge, predictBestModel, hashQuery } from "../../vibeOS-lib/ml-router.js";
15
22
  import { addCacheEntry, recordCacheStats, predictCacheHit } from "../../vibeOS-lib/smart-cache.js";
16
23
  import { buildTestReminder, enforceTestFile } from "../tdd-enforcer.js";
17
24
  import { setActiveJobFromTaskPrompt, observeToolPattern, compressText, recordSaving } from "../index-helpers.js";
@@ -412,6 +419,33 @@ export const onToolExecuteBefore = async (input, output) => {
412
419
  console.error(`[vibeOS] ML router error: ${mlErr.message}`);
413
420
  }
414
421
  }
422
+ const activePipeline = loadSelection().active_pipeline;
423
+ if (activePipeline && Array.isArray(activePipeline) && activePipeline.length > 1 && TRINITY_CHEAP && TRINITY_MEDIUM) {
424
+ try {
425
+ const cheapCost = 0.001;
426
+ const mediumCost = 0.005;
427
+ const brainCost = 0.02;
428
+ const cascadeResult = cascadeDecide(_prompt, cheapCost, mediumCost, brainCost, 0.85);
429
+ const tierMap = { cheap: TRINITY_CHEAP, medium: TRINITY_MEDIUM, brain: TRINITY_BRAIN || TRINITY_MEDIUM, local: TRINITY_CHEAP };
430
+ const pipelineModels = activePipeline.map(t => tierMap[t] || TRINITY_CHEAP);
431
+ if (cascadeResult.escalate && pipelineModels.length > 1) {
432
+ const escalated = pipelineModels[1];
433
+ if (escalated && escalated !== currentModel && (!_target || escalated !== _target)) {
434
+ _target = escalated;
435
+ console.error(`[vibeOS] 🔀 Cascade escalate: ${cascadeResult.reason} → ${escalated}`);
436
+ }
437
+ }
438
+ else if (cascadeResult.useCheap && !_target) {
439
+ _target = pipelineModels[0];
440
+ if (_target && _target !== currentModel) {
441
+ console.error(`[vibeOS] 🔀 Cascade cheap: ${cascadeResult.reason} → ${_target}`);
442
+ }
443
+ }
444
+ }
445
+ catch (cascadeErr) {
446
+ console.error(`[vibeOS] Cascade router error: ${cascadeErr.message}`);
447
+ }
448
+ }
415
449
  if (_target)
416
450
  noteTaskRoutingLearning(_firstWord, _target, _exploratoryTarget ? "exploratory" : `tier:${currentTier}`);
417
451
  if (_target && targetArgs?.model !== _target) {
@@ -690,11 +724,20 @@ export const onToolExecuteAfter = async (input, output) => {
690
724
  setCurrentTier(classify(resolvedModel));
691
725
  }
692
726
  const execution = resolveExecutionIdentity(input?.args?.model || resolvedModel || "", projectDirectory);
693
- _footerText = `— ${flashIcon ? `${flashIcon} ` : ""}Quality: ${formatQualityName(execution.quality)} | Provider: ${formatProviderName(execution.provider)} | Model: ${execution.model}`;
727
+ const { BRANDED_MODES, RUNTIME_MODES } = await import("../mode-router.js");
728
+ const brandMap = { vibeultrax: "VibeUltraX", vibeqmax: "VibeQMaX", vibemax: "VibeMaX" };
729
+ const brandedToRuntime = { vibeultrax: "Quality", vibeqmax: "Quality", vibemax: "Speed" };
730
+ const currentSel = loadSelection();
731
+ const currentSid = _OC_SID;
732
+ const optModeFooter = loadSessionOptMode(currentSid + "_opt") || loadOptimizationMode() || "budget";
733
+ const vibeBrand = brandMap[optModeFooter] || (execution.quality === "brain" ? "VibeQMaX" : "VibeMaX");
734
+ const qualityIcon = execution.quality === "brain" ? "\u{1F9E0}" : execution.quality === "medium" ? "\u2699" : execution.quality === "free" ? "\u{1F381}" : "\u26A1";
735
+ const modeLabel = modeCapitalized(brandedToRuntime[optModeFooter] || optModeFooter);
736
+ _footerText = `— ${qualityIcon} ${execution.quality} | ${execution.provider_label} | ${modelDisplayName(execution.model)}`;
694
737
  if (ltTotal > 0) {
695
- _footerText += ` | $${formatUsd(ltTotal)} saved`;
738
+ _footerText += ` | $${formatUsd(ltTotal)}`;
696
739
  }
697
- _footerText += ` | VIBE${flashIcon ? " ⚡" : ""} —\n\n`;
740
+ _footerText += ` | ${vibeBrand}${flashIcon} —\n\n`;
698
741
  output.title = _footerText.trim();
699
742
  if (typeof output?.output === "string")
700
743
  output.output = _footerText + output.output;
@@ -67,11 +67,18 @@ export const RUNTIME_MODES = [
67
67
  desc: "Brain tier security audit. OWASP validation.",
68
68
  },
69
69
  {
70
- id: "longrun", index: 9, name: "Longrun", icon: "\u{1F3C3}",
70
+ id: "longrun", index: 6, name: "Longrun", icon: "\u{1F4C8}",
71
+ pipeline: ["cheap"],
72
+ thinking: "off", tdd: "off", enforcement: "off", flow: "off",
73
+ qualityVsBrain: 15, costVsBrain: 100,
74
+ desc: "Extended sessions. Cheap tier only.",
75
+ },
76
+ {
77
+ id: "forensic", index: 7, name: "Forensic", icon: "\u{1F52C}",
71
78
  pipeline: ["brain"],
72
79
  thinking: "full", tdd: "quality", enforcement: "strict", flow: "strict",
73
- qualityVsBrain: 100, costVsBrain: 70,
74
- desc: "Brain tier extended session. Full context.",
80
+ qualityVsBrain: 100, costVsBrain: 65,
81
+ desc: "Deep analysis and web research. Full audit trail.",
75
82
  },
76
83
  ];
77
84
  export const RAW_MODE = {
@@ -57,6 +57,8 @@ export function loadSelection() {
57
57
  return {
58
58
  enabled: j?.selection?.enabled !== false,
59
59
  active_slot: j?.selection?.active_slot || null,
60
+ active_pipeline: j?.selection?.active_pipeline || null,
61
+ optimization_mode: j?.selection?.optimization_mode || null,
60
62
  thinking_level: j?.selection?.thinking_level || "off",
61
63
  flow_enabled: j?.selection?.flow_enabled === true,
62
64
  tdd_enforce: j?.selection?.tdd_enforce === true,
@@ -140,6 +142,18 @@ export function loadSessionOptMode(sid) {
140
142
  return null;
141
143
  }
142
144
  }
145
+ export function loadGlobalOptMode() {
146
+ try {
147
+ const sel = loadSelection();
148
+ return sel.optimization_mode || null;
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ export function saveGlobalOptMode(mode) {
155
+ return writeSelection("optimization_mode", mode);
156
+ }
143
157
  export function writeSessionOptMode(sid, mode) {
144
158
  const BLACKBOX_FILE = join(getVibeOSHome(), "blackbox-state.json");
145
159
  try {
package/src/lib/state.js CHANGED
@@ -113,6 +113,14 @@ const warnCoalesceCounters = new Map();
113
113
  let _savingsCache = null;
114
114
  let _savingsCacheMtime = 0;
115
115
  let _ledgerReconciledMtime = 0;
116
+ let _ledgerTotalsCache = {
117
+ mtime: 0,
118
+ size: 0,
119
+ delegation: 0,
120
+ cache: 0,
121
+ context7: 0,
122
+ entries: 0,
123
+ };
116
124
  function invalidateSavingsCache() {
117
125
  _savingsCache = null;
118
126
  _savingsCacheMtime = 0;
@@ -1617,16 +1625,82 @@ function getTodos() {
1617
1625
  function readLedgerTotals() {
1618
1626
  const empty = { delegation: 0, cache: 0, context7: 0, total: 0, entries: 0 };
1619
1627
  try {
1620
- if (!existsSync(SAVINGS_LEDGER_FILE))
1628
+ if (!existsSync(SAVINGS_LEDGER_FILE)) {
1629
+ _ledgerTotalsCache = { mtime: 0, size: 0, delegation: 0, cache: 0, context7: 0, entries: 0 };
1621
1630
  return empty;
1622
- const raw = readFileSync(SAVINGS_LEDGER_FILE, "utf-8");
1623
- if (!raw.trim())
1631
+ }
1632
+ const st = statSync(SAVINGS_LEDGER_FILE);
1633
+ if (st.size > 10485760) {
1634
+ _handleStateCorruption(SAVINGS_LEDGER_FILE);
1624
1635
  return empty;
1636
+ }
1637
+ if (st.size === 0) {
1638
+ _ledgerTotalsCache = { mtime: st.mtimeMs, size: 0, delegation: 0, cache: 0, context7: 0, entries: 0 };
1639
+ return empty;
1640
+ }
1641
+ if (_ledgerTotalsCache.mtime === st.mtimeMs && _ledgerTotalsCache.size === st.size) {
1642
+ return {
1643
+ delegation: Math.round(_ledgerTotalsCache.delegation * 1000) / 1000,
1644
+ cache: Math.round(_ledgerTotalsCache.cache * 1000) / 1000,
1645
+ context7: Math.round(_ledgerTotalsCache.context7 * 1000) / 1000,
1646
+ total: Math.round((_ledgerTotalsCache.delegation + _ledgerTotalsCache.cache) * 1000) / 1000,
1647
+ entries: _ledgerTotalsCache.entries,
1648
+ };
1649
+ }
1625
1650
  let delegation = 0;
1626
1651
  let cache = 0;
1627
1652
  let context7 = 0;
1628
1653
  let entries = 0;
1629
- for (const line of raw.split("\n")) {
1654
+ let raw = "";
1655
+ let incremental = _ledgerTotalsCache.size > 0 && st.size >= _ledgerTotalsCache.size && _ledgerTotalsCache.mtime > 0;
1656
+ if (incremental) {
1657
+ const deltaSize = st.size - _ledgerTotalsCache.size;
1658
+ if (deltaSize > 0) {
1659
+ const fd = openSync(SAVINGS_LEDGER_FILE, "r");
1660
+ try {
1661
+ const buf = Buffer.allocUnsafe(deltaSize);
1662
+ const bytesRead = readSync(fd, buf, 0, deltaSize, _ledgerTotalsCache.size);
1663
+ raw = buf.toString("utf-8", 0, bytesRead);
1664
+ }
1665
+ finally {
1666
+ try {
1667
+ closeSync(fd);
1668
+ }
1669
+ catch { }
1670
+ }
1671
+ }
1672
+ else {
1673
+ incremental = false;
1674
+ }
1675
+ delegation = _ledgerTotalsCache.delegation;
1676
+ cache = _ledgerTotalsCache.cache;
1677
+ context7 = _ledgerTotalsCache.context7;
1678
+ entries = _ledgerTotalsCache.entries;
1679
+ }
1680
+ if (!incremental) {
1681
+ raw = readFileSync(SAVINGS_LEDGER_FILE, "utf-8");
1682
+ }
1683
+ if (!raw.trim()) {
1684
+ _ledgerTotalsCache = {
1685
+ mtime: st.mtimeMs,
1686
+ size: st.size,
1687
+ delegation,
1688
+ cache,
1689
+ context7,
1690
+ entries,
1691
+ };
1692
+ return {
1693
+ delegation: Math.round(delegation * 1000) / 1000,
1694
+ cache: Math.round(cache * 1000) / 1000,
1695
+ context7: Math.round(context7 * 1000) / 1000,
1696
+ total: Math.round((delegation + cache) * 1000) / 1000,
1697
+ entries,
1698
+ };
1699
+ }
1700
+ const lines = raw.split("\n");
1701
+ if (raw.endsWith("\n"))
1702
+ lines.pop();
1703
+ for (const line of lines) {
1630
1704
  const ln = line.trim();
1631
1705
  if (!ln)
1632
1706
  continue;
@@ -1653,6 +1727,7 @@ function readLedgerTotals() {
1653
1727
  else
1654
1728
  delegation += amt;
1655
1729
  }
1730
+ _ledgerTotalsCache = { mtime: st.mtimeMs, size: st.size, delegation, cache, context7, entries };
1656
1731
  const total = delegation + cache;
1657
1732
  return {
1658
1733
  delegation: Math.round(delegation * 1000) / 1000,
@@ -1668,8 +1743,10 @@ function readLedgerTotals() {
1668
1743
  }
1669
1744
  function reconcileStateFromLedger() {
1670
1745
  try {
1671
- const ledgerMtime = existsSync(SAVINGS_LEDGER_FILE) ? statSync(SAVINGS_LEDGER_FILE).mtimeMs : 0;
1672
- if (ledgerMtime === _ledgerReconciledMtime)
1746
+ const ledgerStat = existsSync(SAVINGS_LEDGER_FILE) ? statSync(SAVINGS_LEDGER_FILE) : null;
1747
+ const ledgerMtime = ledgerStat?.mtimeMs || 0;
1748
+ const ledgerSize = ledgerStat?.size || 0;
1749
+ if (ledgerMtime === _ledgerReconciledMtime && ledgerSize === (_savingsCache?._ledgerSize || 0))
1673
1750
  return;
1674
1751
  _ledgerReconciledMtime = ledgerMtime;
1675
1752
  _flushLedgerBuffer();
@@ -1694,6 +1771,8 @@ function reconcileStateFromLedger() {
1694
1771
  s.lifetime.ledger_entries_reconciled = l.entries;
1695
1772
  return s;
1696
1773
  });
1774
+ _savingsCache = null;
1775
+ _savingsCacheMtime = 0;
1697
1776
  invalidateSavingsCache();
1698
1777
  }
1699
1778
  catch { }
@@ -1709,7 +1788,8 @@ function readLifetimeSavings() {
1709
1788
  if (_savingsCache && mtime === _savingsCacheMtime)
1710
1789
  return _savingsCache;
1711
1790
  const s = safeJsonParse(readFileSync(delegationStateFile, "utf-8"));
1712
- _savingsCache = { ..._computeSessionMetrics(s, _OC_SID), telemetry: readTelemetrySummary(s, _OC_SID) };
1791
+ const ledgerSize = existsSync(SAVINGS_LEDGER_FILE) ? statSync(SAVINGS_LEDGER_FILE).size : 0;
1792
+ _savingsCache = { ..._computeSessionMetrics(s, _OC_SID), telemetry: readTelemetrySummary(s, _OC_SID), _ledgerSize: ledgerSize };
1713
1793
  _savingsCacheMtime = mtime;
1714
1794
  return _savingsCache;
1715
1795
  }
@@ -1,5 +1,5 @@
1
1
  // @ts-nocheck
2
- import { join } from "node:path";
2
+ import { join, dirname } from "node:path";
3
3
  import { LABEL_MODES, buildDeterministicTrinity, resolveExecutionIdentity } from "./pricing.js";
4
4
  import { BRANDED_MODES, RUNTIME_MODES } from "./mode-router.js";
5
5
  import { invalidateApiToken } from "./api-client.js";
@@ -20,6 +20,8 @@ export function createTrinityTool(deps) {
20
20
  "Use action='enable' or 'disable' to toggle the plugin (takes effect immediately, no restart needed). " +
21
21
  "Use action='set' with slot='brain'|'medium'|'cheap' to switch model tiers " +
22
22
  "(writes opencode.json — active immediately). " +
23
+ "Use action='mode' with slot='vibeultrax'|'vibeqmax'|'vibemax'|'budget'|'quality'|'speed'|'longrun'|'auto'|'balanced'|'audit'|'forensic' to switch optimization mode. " +
24
+ "Use action='thinking' with level='full'|'brief'|'off'. " +
23
25
  "Use action='rebuild' to auto-detect available models from all configured providers and reassign brain/medium/cheap slots. " +
24
26
  "Use action='flow' with slot='on'|'off' to toggle flow enforcer, or action='flow' alone for audit. " +
25
27
  "Use action='flow' with slot='enforce' and level='on'|'off' to toggle auto-extract TODOs. " +
@@ -48,6 +50,20 @@ export function createTrinityTool(deps) {
48
50
  slot = action;
49
51
  action = "set";
50
52
  }
53
+ const _brandedModeIds = ["vibeultrax", "vibeqmax", "vibemax"];
54
+ const _builtInModeIds = ["budget", "quality", "speed", "longrun", "auto", "balanced", "audit", "forensic"];
55
+ if (!action || action === "status") { }
56
+ else if (_brandedModeIds.includes(action) || _builtInModeIds.includes(action)) {
57
+ slot = action;
58
+ action = "mode";
59
+ }
60
+ else if (["full", "brief", "off"].includes(action)) {
61
+ level = action;
62
+ action = "thinking";
63
+ }
64
+ else if (["on", "off"].includes(action) && !slot) {
65
+ slot = action;
66
+ }
51
67
  if (action === "status") {
52
68
  const sel = deps.loadSelection();
53
69
  let tiers = {};
@@ -58,6 +74,41 @@ export function createTrinityTool(deps) {
58
74
  let cheapModel = "(unset)";
59
75
  const credit = deps.loadCredit();
60
76
  const effectiveLevel = sel.thinking_level || deps.thinkingLevel(credit);
77
+ if (deps.currentModel && sel.selected_model && deps.currentModel !== sel.selected_model) {
78
+ try {
79
+ const providers = deps._loadOpenCodeProviders();
80
+ const auth = deps._readAuth();
81
+ const models = await deps.discoverAvailableModels(providers, auth);
82
+ const trinity = buildDeterministicTrinity(models, { selectedModelId: deps.currentModel, selectedTier: sel.active_slot || "brain" });
83
+ if (trinity && trinity.brain) {
84
+ const probed = {
85
+ brain: models.find(m => m.id === trinity.brain) || { id: trinity.brain, cost: deps._modelCost(trinity.brain), tier: deps._modelTier(trinity.brain) },
86
+ medium: models.find(m => m.id === trinity.medium) || { id: trinity.medium, cost: deps._modelCost(trinity.medium), tier: deps._modelTier(trinity.medium) },
87
+ cheap: models.find(m => m.id === trinity.cheap) || { id: trinity.cheap, cost: deps._modelCost(trinity.cheap), tier: deps._modelTier(trinity.cheap) },
88
+ };
89
+ const tiersData = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
90
+ tiersData.trinity = {
91
+ brain: { oc: probed.brain.id, cc: deps.modelToCcAlias(probed.brain.id) },
92
+ medium: { oc: probed.medium.id, cc: deps.modelToCcAlias(probed.medium.id) },
93
+ cheap: { oc: probed.cheap.id, cc: deps.modelToCcAlias(probed.cheap.id) },
94
+ };
95
+ tiersData.selection ??= {};
96
+ tiersData.selection.selected_provider = trinity.provider || resolveExecutionIdentity(deps.currentModel, deps.directory)?.provider || "";
97
+ tiersData.selection.selected_model = deps.currentModel;
98
+ tiersData.selection.executed_provider = tiersData.selection.selected_provider;
99
+ tiersData.selection.executed_model = deps.currentModel;
100
+ const _tmp = deps.TIERS_FILE + ".tmp." + Date.now();
101
+ deps.writeFileSync(_tmp, JSON.stringify(tiersData, null, 2) + "\n", "utf-8");
102
+ deps.renameSync(_tmp, deps.TIERS_FILE);
103
+ tiers = tiersData.trinity;
104
+ sel.selected_provider = tiersData.selection.selected_provider;
105
+ sel.selected_model = deps.currentModel;
106
+ }
107
+ }
108
+ catch (e) {
109
+ console.error("[vibeOS] auto-rebuild on model change failed:", e.message);
110
+ }
111
+ }
61
112
  const sv = deps.readLifetimeSavings();
62
113
  const ltTotal = (sv.ltTasks || 0) + (sv.ltCache || 0);
63
114
  const sesTasks = sv.sesTasks || 0;
@@ -202,20 +253,22 @@ export function createTrinityTool(deps) {
202
253
  const ok = deps.saveOptimizationMode(resolvedSlot);
203
254
  if (!ok)
204
255
  return `Failed to write mode`;
205
- deps.writeSessionSlot(deps._OC_SID + "_opt", resolvedSlot);
256
+ deps.writeSessionOptMode(deps._OC_SID + "_opt", resolvedSlot);
206
257
  const allEntries = [...BRANDED_MODES, ...RUNTIME_MODES];
207
258
  const modeEntry = allEntries.find(e => e.id === slot);
208
259
  if (modeEntry) {
209
260
  const rawTier = modeEntry.pipeline[0] || "cheap";
210
261
  const tierSlot = new Set(["brain", "medium", "cheap"]).has(rawTier) ? rawTier : "cheap";
211
262
  deps.writeSelection("active_slot", tierSlot);
263
+ deps.writeSelection("active_pipeline", modeEntry.pipeline);
212
264
  deps.writeSelection("onboarding_mode", modeEntry.tdd === "quality" || modeEntry.enforcement === "strict" ? "strict" : "assist");
213
265
  deps.writeSelection("delegation_enforce", modeEntry.enforcement === "strict" || modeEntry.enforcement === "on");
214
266
  deps.writeSelection("flow_enabled", modeEntry.flow === "strict" || modeEntry.flow === "on" || modeEntry.flow === "audit");
215
267
  deps.writeSelection("flow_enforce", modeEntry.flow === "strict" || modeEntry.flow === "on");
216
268
  deps.writeSelection("tdd_enforce", modeEntry.tdd === "quality" || modeEntry.tdd === "on" || modeEntry.tdd === "strict");
217
269
  deps.writeSelection("thinking_level", modeEntry.thinking);
218
- return `Mode set to ${slot.toUpperCase()}. Tier: ${tierSlot}.`;
270
+ const pipelineStr = modeEntry.pipeline.join(" ");
271
+ return `Mode set to ${slot.toUpperCase()}. Tier: ${tierSlot}. Pipeline: ${pipelineStr}`;
219
272
  }
220
273
  return `Mode set to ${slot.toUpperCase()}.`;
221
274
  }
@@ -408,16 +461,6 @@ export function createTrinityTool(deps) {
408
461
  tiers.trinity.cheap = { oc: cheap, cc: deps.modelToCcAlias(cheap) };
409
462
  deps.mkdirSync(dirname(deps.TIERS_FILE), { recursive: true });
410
463
  deps.writeFileSync(deps.TIERS_FILE, JSON.stringify(tiers, null, 2) + "\n");
411
- try {
412
- const bbState = deps.loadBlackboxState();
413
- bbState.enabled = false;
414
- deps.saveBlackboxState(bbState);
415
- if (typeof deps.setBlackboxEnabled === "function")
416
- deps.setBlackboxEnabled(false);
417
- else
418
- deps._blackboxEnabled = false;
419
- }
420
- catch { }
421
464
  if (typeof deps._refreshModel === "function")
422
465
  deps._refreshModel(deps.directory);
423
466
  const lines = [
@@ -428,7 +471,7 @@ export function createTrinityTool(deps) {
428
471
  ` Delegation: off`,
429
472
  ` Flow: off`,
430
473
  ` TDD: off`,
431
- ` Blackbox: off`,
474
+ ` Blackbox: on`,
432
475
  ];
433
476
  if (discovered.length > 0)
434
477
  lines.push(` Discovered models: ${discovered.length}`);
@@ -3,7 +3,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, renameSync } from "
3
3
  import { join, dirname } from "node:path";
4
4
  import { ResolutionTracker } from "../vibeOS-lib/blackbox/index.js";
5
5
  import { safeJsonParse, _blackboxEnabled, setBlackboxEnabled as _setGlobalBlackboxEnabled, _OC_SID, currentProjectFingerprint, setCurrentProjectFingerprint, withFileLock, readJsonOrEmpty, validateState, loadBlackboxState, saveBlackboxState, loadGlobalLearning, updateGlobalLearning, getLearnedExploratoryWords, projectFingerprint, loadProjectState, saveProjectState, detectTechStack, ensureProjectBucket, recordMissedContext7 } from "./state.js";
6
- import { loadSessionOptMode, writeSessionOptMode } from "./selection-manager.js";
6
+ import { loadSessionOptMode, loadGlobalOptMode, saveGlobalOptMode, writeSessionOptMode } from "./selection-manager.js";
7
7
  import { getApiClient, isApiFallback } from "./api-client.js";
8
8
  export { scoreStress, estimateContextBudget, classifyTurnSimple, tokenizeWords, topKeywords, extractLastUserText, isUserAskingForTests, isLikelyOffTopic, detectOutcomeSignal } from "./classifiers.js";
9
9
  function getVibeOSHome() {
@@ -557,7 +557,12 @@ const DFLT_OPTIMIZATION_MODE = "budget";
557
557
  export function loadOptimizationMode() {
558
558
  try {
559
559
  const mode = loadSessionOptMode(_OC_SID);
560
- return mode && mode !== "auto" ? mode : DFLT_OPTIMIZATION_MODE;
560
+ if (mode && mode !== "auto")
561
+ return mode;
562
+ const global = loadGlobalOptMode();
563
+ if (global && global !== "auto")
564
+ return global;
565
+ return DFLT_OPTIMIZATION_MODE;
561
566
  }
562
567
  catch {
563
568
  return DFLT_OPTIMIZATION_MODE;
@@ -565,7 +570,10 @@ export function loadOptimizationMode() {
565
570
  }
566
571
  export function saveOptimizationMode(mode) {
567
572
  try {
568
- return writeSessionOptMode(_OC_SID, mode);
573
+ writeSessionOptMode(_OC_SID, mode);
574
+ if (mode && mode !== "auto")
575
+ saveGlobalOptMode(mode);
576
+ return true;
569
577
  }
570
578
  catch (err) {
571
579
  console.error("[vibeOS] saveOptimizationMode failed: " + err.message);