vibeostheog 0.24.5 → 0.24.7

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/vibeOS.js +341 -183
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -175,7 +175,7 @@ Local dev checkout:
175
175
  | Command | Effect |
176
176
  |---------|--------|
177
177
  | `trinity status` | Tier, enforcement, savings, stress, lock state |
178
- | `trinity set brain\|medium\|cheap` | Switch active model tier |
178
+ | `trinity set brain\|medium\|cheap [model=<model_id>]` | Switch active model tier or override the slot model |
179
179
  | `trinity brain\|medium\|cheap` | Shorthand tier switch |
180
180
  | `trinity enable\|disable` | Toggle plugin on/off |
181
181
  | `trinity mode budget\|quality\|speed\|longrun\|auto` | Set optimization mode |
package/dist/vibeOS.js CHANGED
@@ -1532,7 +1532,7 @@ import { dirname as dirname3 } from "node:path";
1532
1532
  import { fileURLToPath as fileURLToPath3 } from "node:url";
1533
1533
  import { homedir } from "node:os";
1534
1534
 
1535
- // src/lib/runtime-state.ts
1535
+ // src/lib/runtime-state.js
1536
1536
  var RUNTIME_KEY = "__vibeOSRuntimeState";
1537
1537
  function getRuntimeState() {
1538
1538
  const g = globalThis;
@@ -1559,7 +1559,8 @@ function markApiDisconnected() {
1559
1559
  const state = getRuntimeState();
1560
1560
  state.apiConnected = false;
1561
1561
  state.apiFallbackMode = true;
1562
- if (!state.apiFallbackSince) state.apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
1562
+ if (!state.apiFallbackSince)
1563
+ state.apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
1563
1564
  }
1564
1565
  function resetApiConnection() {
1565
1566
  const state = getRuntimeState();
@@ -2424,42 +2425,56 @@ function writeSessionOptMode(sid, mode) {
2424
2425
  }
2425
2426
  }
2426
2427
 
2427
- // src/lib/pattern-helpers.ts
2428
+ // src/lib/pattern-helpers.js
2428
2429
  import { relative, basename as basename2 } from "node:path";
2429
2430
  function normalizeObservedPath(filePath, directory3) {
2430
- if (!filePath || typeof filePath !== "string") return "unknown";
2431
+ if (!filePath || typeof filePath !== "string")
2432
+ return "unknown";
2431
2433
  let p = filePath;
2432
2434
  try {
2433
2435
  if (directory3 && p.startsWith("/")) {
2434
2436
  const rel = relative(directory3, p);
2435
- if (rel && !rel.startsWith("..") && !rel.startsWith("/")) p = rel;
2437
+ if (rel && !rel.startsWith("..") && !rel.startsWith("/"))
2438
+ p = rel;
2436
2439
  }
2437
2440
  } catch {
2438
2441
  }
2439
2442
  p = p.replace(/\\/g, "/").replace(/^\.\/+/, "");
2440
- if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p)) return p;
2443
+ if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p))
2444
+ return p;
2441
2445
  const m = p.match(/\.([a-z0-9]+)$/i);
2442
- if (p.startsWith("src/") && m) return `src/*.${m[1].toLowerCase()}`;
2443
- if (p.startsWith("tests/") && m) return `tests/*.${m[1].toLowerCase()}`;
2446
+ if (p.startsWith("src/") && m)
2447
+ return `src/*.${m[1].toLowerCase()}`;
2448
+ if (p.startsWith("tests/") && m)
2449
+ return `tests/*.${m[1].toLowerCase()}`;
2444
2450
  return basename2(p) || "unknown";
2445
2451
  }
2446
2452
  function commandFamily(command) {
2447
2453
  const c = String(command || "").trim().toLowerCase();
2448
- if (!c) return "unknown";
2449
- if (/\bnode\s+--check\b/.test(c)) return "syntax-check";
2450
- if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c)) return "typecheck";
2451
- if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c)) return "test";
2452
- if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c)) return "build";
2453
- if (/\bgit\s+status\b/.test(c)) return "git-status";
2454
- if (/\bgit\s+commit\b/.test(c)) return "git-commit";
2454
+ if (!c)
2455
+ return "unknown";
2456
+ if (/\bnode\s+--check\b/.test(c))
2457
+ return "syntax-check";
2458
+ if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c))
2459
+ return "typecheck";
2460
+ if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c))
2461
+ return "test";
2462
+ if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c))
2463
+ return "build";
2464
+ if (/\bgit\s+status\b/.test(c))
2465
+ return "git-status";
2466
+ if (/\bgit\s+commit\b/.test(c))
2467
+ return "git-commit";
2455
2468
  const first = c.replace(/^[a-z_][a-z0-9_]*=\S+\s+/g, "").split(/\s+/)[0];
2456
2469
  return /^[a-z0-9._/-]{1,30}$/.test(first) ? first : "command";
2457
2470
  }
2458
2471
  function commandFailed(output) {
2459
2472
  const code = output?.exitCode ?? output?.statusCode ?? output?.code;
2460
- if (Number.isFinite(Number(code)) && Number(code) !== 0) return true;
2473
+ if (Number.isFinite(Number(code)) && Number(code) !== 0)
2474
+ return true;
2461
2475
  const raw = output?.result ?? output?.text ?? output?.content ?? output?.data ?? "";
2462
- if (typeof raw !== "string") return false;
2476
+ if (typeof raw !== "string")
2477
+ return false;
2463
2478
  return /\b(exit code|exited with code)\s*[:=]?\s*[1-9]\b|\b(assertionerror|syntaxerror|typeerror|referenceerror)\b|\b(failed|error:|err!)\b/i.test(raw);
2464
2479
  }
2465
2480
  function mergeProjectBucket(dst, src) {
@@ -2476,7 +2491,8 @@ function mergeProjectBucket(dst, src) {
2476
2491
  row.sessions = [.../* @__PURE__ */ new Set([...row.sessions || [], ...v?.sessions || []])].slice(-10);
2477
2492
  row.lastSeen = [row.lastSeen, v?.lastSeen].filter(Boolean).sort().slice(-1)[0] || null;
2478
2493
  row.summary = row.summary || v?.summary || "";
2479
- if (v?.kind) row.kind = v.kind;
2494
+ if (v?.kind)
2495
+ row.kind = v.kind;
2480
2496
  out[key] = row;
2481
2497
  }
2482
2498
  }
@@ -2495,9 +2511,11 @@ function mergeProjectBucket(dst, src) {
2495
2511
  };
2496
2512
  }
2497
2513
  function _pruneOldSessions(state) {
2498
- if (!state?.sessions) return;
2514
+ if (!state?.sessions)
2515
+ return;
2499
2516
  const entries = Object.entries(state.sessions);
2500
- if (entries.length <= 30) return;
2517
+ if (entries.length <= 30)
2518
+ return;
2501
2519
  entries.sort((a, b) => {
2502
2520
  const da = a[1]?.started || a[1]?.last_costed || "";
2503
2521
  const db = b[1]?.started || b[1]?.last_costed || "";
@@ -4662,7 +4680,6 @@ function _sortByCostAsc(models = []) {
4662
4680
  function buildDeterministicTrinity(models, options = {}) {
4663
4681
  const list = Array.isArray(models) ? models.filter((m) => m && typeof m === "object" && String(m.id || "").trim()) : [];
4664
4682
  if (list.length === 0) return null;
4665
- const selectedTier = String(options.selectedTier || "brain").toLowerCase();
4666
4683
  const selectedModelId = String(options.selectedModelId || "").trim();
4667
4684
  const providerHint = String(options.provider || "").trim();
4668
4685
  const selectedModel = selectedModelId ? list.find((m) => m.id === selectedModelId || normalizeModelId(m.id) === normalizeModelId(selectedModelId)) || null : null;
@@ -4671,14 +4688,15 @@ function buildDeterministicTrinity(models, options = {}) {
4671
4688
  const scoped = providerModels.length > 0 ? providerModels : list;
4672
4689
  const qualityRanked = _sortByQualityDesc(scoped);
4673
4690
  const costRanked = _sortByCostAsc(scoped);
4674
- const selected = selectedModel || qualityRanked[0] || costRanked[0] || scoped[0] || list[0];
4675
- const brain = selectedTier === "medium" || selectedTier === "cheap" || selectedTier === "free" ? selected : qualityRanked[0] || selected;
4676
- const medium = selectedTier === "brain" ? qualityRanked.find((m) => m.id !== brain?.id) || brain || selected : selected;
4677
- const cheap = costRanked[0] || selected;
4691
+ const brain = selectedModel || qualityRanked[0] || costRanked[0] || scoped[0] || list[0];
4692
+ const medium = qualityRanked.find((m) => m.id !== brain?.id) || brain;
4693
+ const freeModel = scoped.find((m) => isModelFree(m.id));
4694
+ const cheap = freeModel || costRanked[0] || medium;
4695
+ const brainClass = isModelFree(brain?.id) ? "free" : classify(brain?.id);
4678
4696
  return {
4679
4697
  provider,
4680
- selected_tier: selectedTier,
4681
- selected_model: selected?.id || selectedModelId || "",
4698
+ selected_tier: brainClass,
4699
+ selected_model: brain?.id || selectedModelId || "",
4682
4700
  brain: brain?.id || "",
4683
4701
  medium: medium?.id || "",
4684
4702
  cheap: cheap?.id || "",
@@ -5527,7 +5545,8 @@ function _refreshModel(directory3) {
5527
5545
  }
5528
5546
  }
5529
5547
  if (!_modelLocked) {
5530
- const cfgModel = readConfig(directory3) || readConfig(getOpenCodeHome()) || "";
5548
+ const activeIsManual = tiersData?.trinity?.[activeSlot]?.manual === true;
5549
+ const cfgModel = activeIsManual ? "" : readConfig(directory3) || readConfig(getOpenCodeHome()) || "";
5531
5550
  if (cfgModel && cfgModel.includes("/") && cfgModel !== currentModel) {
5532
5551
  const oldModel = currentModel;
5533
5552
  const oldTier = currentTier;
@@ -5574,7 +5593,7 @@ function applySlot2(slot, projectDir = "") {
5574
5593
  writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
5575
5594
  }
5576
5595
  clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
5577
- _refreshModel(process.cwd());
5596
+ _refreshModel(dir);
5578
5597
  return { ok: true, ocModel };
5579
5598
  } catch (err) {
5580
5599
  return { ok: false, reason: err.message };
@@ -7480,6 +7499,15 @@ function createTrinityTool(deps) {
7480
7499
  const _brandedModeIds = ["vibeultrax", "vibeqmax", "vibemax", "vibelitex"];
7481
7500
  const _builtInModeIds = ["budget", "quality", "speed", "longrun", "auto", "balanced", "audit", "forensic"];
7482
7501
  if (!action || action === "status") {
7502
+ if (slot && (_brandedModeIds.includes(slot) || _builtInModeIds.includes(slot))) {
7503
+ action = "mode";
7504
+ } else if (["brain", "medium", "cheap"].includes(slot)) {
7505
+ action = "set";
7506
+ } else if (["full", "brief", "off"].includes(slot)) {
7507
+ action = "thinking";
7508
+ level = slot;
7509
+ slot = void 0;
7510
+ }
7483
7511
  } else if (_brandedModeIds.includes(action) || _builtInModeIds.includes(action)) {
7484
7512
  slot = action;
7485
7513
  action = "mode";
@@ -7504,7 +7532,7 @@ function createTrinityTool(deps) {
7504
7532
  const providers = deps._loadOpenCodeProviders();
7505
7533
  const auth = deps._readAuth();
7506
7534
  const models = await deps.discoverAvailableModels(providers, auth);
7507
- const trinity = buildDeterministicTrinity(models, { selectedModelId: deps.currentModel, selectedTier: sel.active_slot || "brain" });
7535
+ const trinity = buildDeterministicTrinity(models, { selectedModelId: deps.currentModel });
7508
7536
  if (trinity && trinity.brain) {
7509
7537
  const probed = {
7510
7538
  brain: models.find((m) => m.id === trinity.brain) || { id: trinity.brain, cost: deps._modelCost(trinity.brain), tier: deps._modelTier(trinity.brain) },
@@ -7640,12 +7668,24 @@ function createTrinityTool(deps) {
7640
7668
  if (!tiers.trinity[slot]) tiers.trinity[slot] = {};
7641
7669
  tiers.trinity[slot].oc = model;
7642
7670
  tiers.trinity[slot].cc = model;
7671
+ tiers.trinity[slot].manual = true;
7643
7672
  const _tmp = deps.TIERS_FILE + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
7644
7673
  deps.writeFileSync(_tmp, JSON.stringify(tiers, null, 2) + "\n");
7645
7674
  deps.renameSync(_tmp, deps.TIERS_FILE);
7646
7675
  } catch (e) {
7647
7676
  return `\u274C Failed to write model to tiers: ${e.message}`;
7648
7677
  }
7678
+ } else {
7679
+ try {
7680
+ const tiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
7681
+ if (tiers?.trinity?.[slot]?.manual) {
7682
+ delete tiers.trinity[slot].manual;
7683
+ const _tmp = deps.TIERS_FILE + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
7684
+ deps.writeFileSync(_tmp, JSON.stringify(tiers, null, 2) + "\n");
7685
+ deps.renameSync(_tmp, deps.TIERS_FILE);
7686
+ }
7687
+ } catch {
7688
+ }
7649
7689
  }
7650
7690
  let targetModel = "";
7651
7691
  try {
@@ -7664,10 +7704,10 @@ function createTrinityTool(deps) {
7664
7704
  console.error("[vibeOS] WARN: probe error for " + targetModel + ": " + e.message + " - switching anyway");
7665
7705
  }
7666
7706
  deps.writeSessionSlot(deps._OC_SID, slot);
7667
- const result = deps.applySlot(slot);
7707
+ const result = deps.applySlot(slot, deps.directory);
7668
7708
  if (!result.ok) return `\u274C Failed to set slot: ${result.reason}`;
7669
7709
  try {
7670
- const selected = typeof deps.resolveExecutionIdentity === "function" ? deps.resolveExecutionIdentity(result.ocModel, deps.directory) : null;
7710
+ const selected = resolveExecutionIdentity(result.ocModel, deps.directory);
7671
7711
  if (selected) {
7672
7712
  deps.writeSelection("selected_provider", selected.provider || "");
7673
7713
  deps.writeSelection("selected_quality_tier", selected.quality || slot);
@@ -7862,8 +7902,7 @@ Lock is per-session (resets on restart).`;
7862
7902
  } catch {
7863
7903
  }
7864
7904
  const selectedModel = deps.currentModel || existing?.selection?.selected_model || existing?.selection?.executed_model || "";
7865
- const selectedTier = existing?.selection?.active_slot || "brain";
7866
- const trinity = buildDeterministicTrinity(discovered, { selectedModelId: selectedModel, selectedTier });
7905
+ const trinity = buildDeterministicTrinity(discovered, { selectedModelId: selectedModel });
7867
7906
  const brain = trinity?.brain || existing?.trinity?.brain?.oc || selectedModel || "";
7868
7907
  const medium = trinity?.medium || existing?.trinity?.medium?.oc || brain;
7869
7908
  const cheap = trinity?.cheap || existing?.trinity?.cheap?.oc || medium || brain;
@@ -7882,14 +7921,14 @@ Lock is per-session (resets on restart).`;
7882
7921
  tiers.selection.thinking_level = "off";
7883
7922
  tiers.selection.setup_completed_at = now;
7884
7923
  tiers.selection.selected_provider = trinity?.provider || resolveExecutionIdentity(selectedModel, deps.directory)?.provider || "";
7885
- tiers.selection.selected_quality_tier = trinity?.selected_tier || selectedTier || "brain";
7924
+ tiers.selection.selected_quality_tier = trinity?.selected_tier || "brain";
7886
7925
  tiers.selection.selected_model = trinity?.selected_model || selectedModel || "";
7887
7926
  tiers.selection.executed_provider = tiers.selection.selected_provider;
7888
7927
  tiers.selection.executed_quality_tier = tiers.selection.selected_quality_tier;
7889
7928
  tiers.selection.executed_model = tiers.selection.selected_model;
7890
- if (brain) tiers.trinity.brain = { oc: brain, cc: deps.modelToCcAlias(brain) };
7891
- if (medium) tiers.trinity.medium = { oc: medium, cc: deps.modelToCcAlias(medium) };
7892
- if (cheap) tiers.trinity.cheap = { oc: cheap, cc: deps.modelToCcAlias(cheap) };
7929
+ if (brain && existing?.trinity?.brain?.manual !== true) tiers.trinity.brain = { oc: brain, cc: deps.modelToCcAlias(brain) };
7930
+ if (medium && existing?.trinity?.medium?.manual !== true) tiers.trinity.medium = { oc: medium, cc: deps.modelToCcAlias(medium) };
7931
+ if (cheap && existing?.trinity?.cheap?.manual !== true) tiers.trinity.cheap = { oc: cheap, cc: deps.modelToCcAlias(cheap) };
7893
7932
  deps.mkdirSync(dirname9(deps.TIERS_FILE), { recursive: true });
7894
7933
  deps.writeFileSync(deps.TIERS_FILE, JSON.stringify(tiers, null, 2) + "\n");
7895
7934
  if (typeof deps._refreshModel === "function") deps._refreshModel(deps.directory);
@@ -8222,8 +8261,7 @@ ${L.repeat(40)}`);
8222
8261
  const auth = deps._readAuth();
8223
8262
  const models = await deps.discoverAvailableModels(providers, auth);
8224
8263
  const selectedModel = deps.currentModel || deps.loadSelection?.().selected_model || deps.loadSelection?.().executed_model || "";
8225
- const selectedTier = deps.loadSelection?.().active_slot || "brain";
8226
- const trinity = buildDeterministicTrinity(models, { selectedModelId: selectedModel, selectedTier });
8264
+ const trinity = buildDeterministicTrinity(models, { selectedModelId: selectedModel });
8227
8265
  if (!trinity) {
8228
8266
  return "\u274C No models discovered from any configured provider.";
8229
8267
  }
@@ -8244,14 +8282,15 @@ ${L.repeat(40)}`);
8244
8282
  }
8245
8283
  try {
8246
8284
  const tiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
8285
+ const existing = tiers.trinity || {};
8247
8286
  tiers.trinity = {
8248
- brain: { oc: probed.brain.id, cc: deps.modelToCcAlias(probed.brain.id) },
8249
- medium: { oc: probed.medium.id, cc: deps.modelToCcAlias(probed.medium.id) },
8250
- cheap: { oc: probed.cheap.id, cc: deps.modelToCcAlias(probed.cheap.id) }
8287
+ brain: existing.brain?.manual === true ? { ...existing.brain } : { oc: probed.brain.id, cc: deps.modelToCcAlias(probed.brain.id) },
8288
+ medium: existing.medium?.manual === true ? { ...existing.medium } : { oc: probed.medium.id, cc: deps.modelToCcAlias(probed.medium.id) },
8289
+ cheap: existing.cheap?.manual === true ? { ...existing.cheap } : { oc: probed.cheap.id, cc: deps.modelToCcAlias(probed.cheap.id) }
8251
8290
  };
8252
8291
  tiers.selection ??= {};
8253
8292
  tiers.selection.selected_provider = trinity.provider || resolveExecutionIdentity(selectedModel, deps.directory)?.provider || "";
8254
- tiers.selection.selected_quality_tier = trinity.selected_tier || selectedTier || "brain";
8293
+ tiers.selection.selected_quality_tier = trinity.selected_tier || "brain";
8255
8294
  tiers.selection.selected_model = trinity.selected_model || selectedModel || "";
8256
8295
  tiers.selection.executed_provider = tiers.selection.selected_provider;
8257
8296
  tiers.selection.executed_quality_tier = tiers.selection.selected_quality_tier;
@@ -8267,11 +8306,14 @@ ${L.repeat(40)}`);
8267
8306
  } catch (e) {
8268
8307
  console.error("[vibeOS] auto-activate brain failed:", e.message);
8269
8308
  }
8309
+ const _finalTiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
8310
+ const _trinity = _finalTiers?.trinity || {};
8311
+ const _pMan = (s) => _trinity[s]?.manual === true ? " [manual, preserved]" : "";
8270
8312
  const lines = [
8271
8313
  `\u{1F50D} Auto-detected models from provider: ${trinity.provider || "unknown"}`,
8272
- " \u{1F9E0} brain \u2192 " + probed.brain.id + " (tier: " + probed.brain.tier + ", $" + probed.brain.cost.toFixed(4) + "/turn) \u2705",
8273
- " \u2699 medium \u2192 " + probed.medium.id + " (tier: " + probed.medium.tier + ", $" + probed.medium.cost.toFixed(4) + "/turn) \u2705",
8274
- " \u26A1 cheap \u2192 " + probed.cheap.id + " (tier: " + probed.cheap.tier + ", $" + probed.cheap.cost.toFixed(4) + "/turn) \u2705"
8314
+ " \u{1F9E0} brain \u2192 " + probed.brain.id + " (tier: " + probed.brain.tier + ", $" + probed.brain.cost.toFixed(4) + "/turn) \u2705" + _pMan("brain"),
8315
+ " \u2699 medium \u2192 " + probed.medium.id + " (tier: " + probed.medium.tier + ", $" + probed.medium.cost.toFixed(4) + "/turn) \u2705" + _pMan("medium"),
8316
+ " \u26A1 cheap \u2192 " + probed.cheap.id + " (tier: " + probed.cheap.tier + ", $" + probed.cheap.cost.toFixed(4) + "/turn) \u2705" + _pMan("cheap")
8275
8317
  ];
8276
8318
  if (failed.length > 0) {
8277
8319
  lines.push("", "Probe failures (skipped):");
@@ -8922,7 +8964,7 @@ import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, appen
8922
8964
  import { join as join14, dirname as dirname11, basename as basename7 } from "node:path";
8923
8965
  import { createHash as createHash3 } from "node:crypto";
8924
8966
 
8925
- // src/lib/mode-policy.ts
8967
+ // src/lib/mode-policy.js
8926
8968
  var STRESS_QUALITY_THRESHOLD = 1.5;
8927
8969
  var BASELINE_MODE = "budget";
8928
8970
  var LOOP_REGIMES = /* @__PURE__ */ new Set(["LOOPING", "DIVERGENT"]);
@@ -8930,7 +8972,8 @@ var QUALITY_REGIMES = /* @__PURE__ */ new Set(["CONVERGING", "CLOSED"]);
8930
8972
  var MANUAL_MODES = /* @__PURE__ */ new Set(["balanced", "quality", "speed", "longrun", "vibemax", "vibeqmax", "vibeultrax"]);
8931
8973
  function normalizeMode(mode) {
8932
8974
  const normalized = String(mode || BASELINE_MODE).toLowerCase();
8933
- if (normalized === "auto" || normalized === "") return BASELINE_MODE;
8975
+ if (normalized === "auto" || normalized === "")
8976
+ return BASELINE_MODE;
8934
8977
  if (normalized === "budget" || normalized === "quality" || normalized === "speed" || normalized === "longrun" || normalized === "balanced" || normalized === "vibemax" || normalized === "vibeqmax" || normalized === "vibeultrax") {
8935
8978
  return normalized;
8936
8979
  }
@@ -8943,9 +8986,12 @@ function isManualOverride(mode) {
8943
8986
  return MANUAL_MODES.has(normalizeMode(mode));
8944
8987
  }
8945
8988
  function chooseEpisodeMode(regime, suggestedMode, stress) {
8946
- if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax") return suggestedMode;
8947
- if (LOOP_REGIMES.has(regime) || suggestedMode === "speed") return "speed";
8948
- if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality") return "quality";
8989
+ if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax")
8990
+ return suggestedMode;
8991
+ if (LOOP_REGIMES.has(regime) || suggestedMode === "speed")
8992
+ return "speed";
8993
+ if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality")
8994
+ return "quality";
8949
8995
  return stress > STRESS_QUALITY_THRESHOLD ? "quality" : "budget";
8950
8996
  }
8951
8997
  function defaultPolicy() {
@@ -8966,15 +9012,19 @@ function defaultPolicy() {
8966
9012
  }
8967
9013
  function modeToSlot(mode) {
8968
9014
  const normalized = normalizeMode(mode);
8969
- if (normalized === "speed") return "medium";
8970
- if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax") return "brain";
9015
+ if (normalized === "speed")
9016
+ return "medium";
9017
+ if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax")
9018
+ return "brain";
8971
9019
  return "cheap";
8972
9020
  }
8973
9021
  function loadSessionPolicy() {
8974
9022
  const state = loadBlackboxState();
8975
- if (!state.sessions || typeof state.sessions !== "object") state.sessions = {};
9023
+ if (!state.sessions || typeof state.sessions !== "object")
9024
+ state.sessions = {};
8976
9025
  const sid = _OC_SID;
8977
- if (!state.sessions[sid] || typeof state.sessions[sid] !== "object") state.sessions[sid] = {};
9026
+ if (!state.sessions[sid] || typeof state.sessions[sid] !== "object")
9027
+ state.sessions[sid] = {};
8978
9028
  const session = state.sessions[sid];
8979
9029
  if (!session.mode_policy || typeof session.mode_policy !== "object") {
8980
9030
  session.mode_policy = defaultPolicy();
@@ -9102,7 +9152,7 @@ function recordBudgetFirstOutcome(input = {}) {
9102
9152
  import { join as join13 } from "node:path";
9103
9153
  import { writeFileSync as writeFileSync12 } from "node:fs";
9104
9154
 
9105
- // src/lib/text-compress.ts
9155
+ // src/lib/text-compress.js
9106
9156
  var VERBOSE_LINE_RE = [
9107
9157
  /^[\s#*/\\\-_=+|~:;'"`@\$%^&<>{}\[\]()!?.,0-9]+$/,
9108
9158
  /^(Filed|Created|Modified|Deleted|Updated|Renamed|Copied|Moved|Changed):/,
@@ -9119,12 +9169,15 @@ function extractBulletLines(lines, targetChars, minLines) {
9119
9169
  const keyLines = [];
9120
9170
  const otherLines = [];
9121
9171
  for (const line of lines) {
9122
- if (BULLET_PATTERNS.some((re) => re.test(line))) keyLines.push(line);
9123
- else otherLines.push(line);
9172
+ if (BULLET_PATTERNS.some((re) => re.test(line)))
9173
+ keyLines.push(line);
9174
+ else
9175
+ otherLines.push(line);
9124
9176
  }
9125
9177
  const selected = [...keyLines];
9126
9178
  for (const line of otherLines) {
9127
- if (selected.length >= minLines && selected.join("\n").length >= targetChars) break;
9179
+ if (selected.length >= minLines && selected.join("\n").length >= targetChars)
9180
+ break;
9128
9181
  selected.push(line);
9129
9182
  }
9130
9183
  while (selected.length > minLines && selected.join("\n").length > targetChars * 2) {
@@ -9133,7 +9186,8 @@ function extractBulletLines(lines, targetChars, minLines) {
9133
9186
  return selected;
9134
9187
  }
9135
9188
  function compressText(text) {
9136
- if (!text || typeof text !== "string") return text;
9189
+ if (!text || typeof text !== "string")
9190
+ return text;
9137
9191
  let lines = text.split("\n");
9138
9192
  let removed = 0;
9139
9193
  const out = [];
@@ -9146,14 +9200,16 @@ function compressText(text) {
9146
9200
  break;
9147
9201
  }
9148
9202
  }
9149
- if (!skip) out.push(line);
9203
+ if (!skip)
9204
+ out.push(line);
9150
9205
  }
9151
9206
  const collapsed = [];
9152
9207
  let blanks = 0;
9153
9208
  for (const line of out) {
9154
9209
  if (line.trim() === "") {
9155
9210
  blanks++;
9156
- if (blanks <= 2) collapsed.push(line);
9211
+ if (blanks <= 2)
9212
+ collapsed.push(line);
9157
9213
  } else {
9158
9214
  blanks = 0;
9159
9215
  collapsed.push(line);
@@ -9161,10 +9217,7 @@ function compressText(text) {
9161
9217
  }
9162
9218
  let result = collapsed.join("\n").trim();
9163
9219
  if (result.length > COMPRESS_THRESHOLD) {
9164
- const targetChars = Math.max(
9165
- Math.round(result.length * COMPRESS_RATIO),
9166
- COMPRESS_THRESHOLD
9167
- );
9220
+ const targetChars = Math.max(Math.round(result.length * COMPRESS_RATIO), COMPRESS_THRESHOLD);
9168
9221
  const minLines = Math.max(1, Math.round(collapsed.length * MIN_KEPT_LINES_RATIO));
9169
9222
  const bulletLines = extractBulletLines(collapsed, targetChars, minLines);
9170
9223
  result = bulletLines.join("\n").trim();
@@ -9463,7 +9516,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
9463
9516
  }
9464
9517
  }
9465
9518
 
9466
- // src/lib/constants.ts
9519
+ // src/lib/constants.js
9467
9520
  var SAVE_EST = {
9468
9521
  // Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
9469
9522
  WRITE_EDIT: 4e-4,
@@ -9481,7 +9534,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
9481
9534
  var PROTOCOL_MARKER = "[wbp-v1]";
9482
9535
  var PROTOCOL_TEXT = PROTOCOL_MARKER + " [Worker-to-Brain Report Protocol] When synthesizing the preceding Task output: 1) EXTRACT core findings/data. 2) REFORMAT into bullet points. 3) VERIFY against the original ask. 4) SYNTHESIZE into final response.";
9483
9536
 
9484
- // src/lib/templates.ts
9537
+ // src/lib/templates.js
9485
9538
  var TEMPLATES = {
9486
9539
  save: {
9487
9540
  tier_bias: "cheap",
@@ -9520,7 +9573,8 @@ var TEMPLATES = {
9520
9573
  var DEFAULT_TEMPLATE = "save";
9521
9574
  var SEC_KEYWORDS = /\b(security|vuln|exploit|injection|xss|csrf|secret|credential|token leak|auth bypass|privacy|breach|backdoor|sql injection|cve)\b/i;
9522
9575
  function detectSecuritySignal(text) {
9523
- if (!text || typeof text !== "string") return false;
9576
+ if (!text || typeof text !== "string")
9577
+ return false;
9524
9578
  return SEC_KEYWORDS.test(text);
9525
9579
  }
9526
9580
  function detectBudgetSignal(creditPercent) {
@@ -9533,16 +9587,21 @@ function detectStressSpike(stressScore) {
9533
9587
  return delta > 0.3 && stressScore > 0.5;
9534
9588
  }
9535
9589
  function resolveTemplate(prevTemplate, stressScore, userText, creditPercent) {
9536
- if (detectSecuritySignal(userText)) return "security";
9537
- if (detectBudgetSignal(creditPercent)) return "save";
9538
- if (detectStressSpike(stressScore)) return "quality";
9590
+ if (detectSecuritySignal(userText))
9591
+ return "security";
9592
+ if (detectBudgetSignal(creditPercent))
9593
+ return "save";
9594
+ if (detectStressSpike(stressScore))
9595
+ return "quality";
9539
9596
  return prevTemplate || DEFAULT_TEMPLATE;
9540
9597
  }
9541
9598
  var _turnCount = 0;
9542
9599
  function shouldInjectTemplate(template, prevTemplate) {
9543
9600
  _turnCount++;
9544
- if (template !== prevTemplate) return true;
9545
- if (_turnCount % 10 === 0) return true;
9601
+ if (template !== prevTemplate)
9602
+ return true;
9603
+ if (_turnCount % 10 === 0)
9604
+ return true;
9546
9605
  return false;
9547
9606
  }
9548
9607
 
@@ -10649,7 +10708,7 @@ import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync9, ex
10649
10708
  import { join as join17, dirname as dirname14, basename as basename9 } from "node:path";
10650
10709
  import { createHash as createHash5 } from "node:crypto";
10651
10710
 
10652
- // src/lib/cost-anomaly.ts
10711
+ // src/lib/cost-anomaly.js
10653
10712
  var COST_WINDOW_SIZE = 20;
10654
10713
  var COST_ANOMALY_THRESHOLD = 3;
10655
10714
  var COST_WARMUP_SAMPLES = 5;
@@ -10660,21 +10719,26 @@ var CostAnomalyDetector = class {
10660
10719
  currentAnomalyCost = 0;
10661
10720
  currentAnomalyMean = 0;
10662
10721
  record(cost) {
10663
- if (this.disabled) return;
10722
+ if (this.disabled)
10723
+ return;
10664
10724
  this.costHistory.push(cost);
10665
10725
  if (this.costHistory.length > COST_WINDOW_SIZE) {
10666
10726
  this.costHistory.shift();
10667
10727
  }
10668
10728
  }
10669
10729
  get mean() {
10670
- if (this.costHistory.length === 0) return 0;
10730
+ if (this.costHistory.length === 0)
10731
+ return 0;
10671
10732
  return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
10672
10733
  }
10673
10734
  checkAnomaly(model, cost) {
10674
- if (this.disabled) return false;
10675
- if (this.costHistory.length < COST_WARMUP_SAMPLES) return false;
10735
+ if (this.disabled)
10736
+ return false;
10737
+ if (this.costHistory.length < COST_WARMUP_SAMPLES)
10738
+ return false;
10676
10739
  const avg = this.mean;
10677
- if (avg <= 0 || cost <= avg) return false;
10740
+ if (avg <= 0 || cost <= avg)
10741
+ return false;
10678
10742
  const ratio = cost / avg;
10679
10743
  if (ratio > COST_ANOMALY_THRESHOLD) {
10680
10744
  this.currentAnomalyModel = model;
@@ -10696,7 +10760,8 @@ var CostAnomalyDetector = class {
10696
10760
  };
10697
10761
  var _costDetector = null;
10698
10762
  function getCostAnomalyDetector() {
10699
- if (!_costDetector) _costDetector = new CostAnomalyDetector();
10763
+ if (!_costDetector)
10764
+ _costDetector = new CostAnomalyDetector();
10700
10765
  return _costDetector;
10701
10766
  }
10702
10767
 
@@ -10708,9 +10773,10 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync15, appen
10708
10773
  import { join as join16, dirname as dirname13 } from "node:path";
10709
10774
  import { createHash as createHash4 } from "node:crypto";
10710
10775
 
10711
- // src/utils/tdd-helpers.ts
10776
+ // src/utils/tdd-helpers.js
10712
10777
  function extractExports(sourceContent, ext) {
10713
- if (!sourceContent || typeof sourceContent !== "string") return [];
10778
+ if (!sourceContent || typeof sourceContent !== "string")
10779
+ return [];
10714
10780
  const exports = [];
10715
10781
  const seen = /* @__PURE__ */ new Set();
10716
10782
  const add = (name, type = "function") => {
@@ -10721,51 +10787,69 @@ function extractExports(sourceContent, ext) {
10721
10787
  };
10722
10788
  switch (ext) {
10723
10789
  case "py": {
10724
- for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm)) add(m[1]);
10725
- for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm)) add(m[1], "class");
10790
+ for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
10791
+ add(m[1]);
10792
+ for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm))
10793
+ add(m[1], "class");
10726
10794
  break;
10727
10795
  }
10728
10796
  case "js":
10729
10797
  case "mjs":
10730
10798
  case "jsx": {
10731
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10732
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g)) add(m[1]);
10799
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
10800
+ add(m[1]);
10801
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g))
10802
+ add(m[1]);
10733
10803
  if (exports.length === 0) {
10734
- for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm)) add(m[1]);
10804
+ for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
10805
+ add(m[1]);
10735
10806
  }
10736
10807
  break;
10737
10808
  }
10738
10809
  case "ts":
10739
10810
  case "tsx": {
10740
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10741
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g)) add(m[1]);
10742
- for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g)) add(m[1], "class");
10811
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
10812
+ add(m[1]);
10813
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g))
10814
+ add(m[1]);
10815
+ for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g))
10816
+ add(m[1], "class");
10743
10817
  break;
10744
10818
  }
10745
10819
  case "go": {
10746
- for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g)) add(m[1]);
10820
+ for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
10821
+ add(m[1]);
10747
10822
  break;
10748
10823
  }
10749
10824
  case "rs": {
10750
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g)) add(m[1]);
10751
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g)) add(m[1]);
10752
- for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g)) add(m[1], "struct");
10825
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
10826
+ add(m[1]);
10827
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g))
10828
+ add(m[1]);
10829
+ for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g))
10830
+ add(m[1], "struct");
10753
10831
  break;
10754
10832
  }
10755
10833
  case "rb": {
10756
- for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g)) add(m[1]);
10757
- for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g)) add(m[1], "class");
10834
+ for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
10835
+ add(m[1]);
10836
+ for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g))
10837
+ add(m[1], "class");
10758
10838
  break;
10759
10839
  }
10760
10840
  case "java":
10761
10841
  case "kt": {
10762
- for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10763
- for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10842
+ for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
10843
+ add(m[1]);
10844
+ for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g))
10845
+ add(m[1]);
10764
10846
  break;
10765
10847
  }
10766
10848
  case "sh": {
10767
- for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm)) add(m[1]);
10768
- for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm)) add(m[1]);
10849
+ for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
10850
+ add(m[1]);
10851
+ for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm))
10852
+ add(m[1]);
10769
10853
  break;
10770
10854
  }
10771
10855
  }
@@ -10787,7 +10871,8 @@ function generateTestCaseNames(funcName, _type, quality = false) {
10787
10871
  ];
10788
10872
  }
10789
10873
  function inferFunctionParams(sourceContent, funcName) {
10790
- if (!sourceContent || !funcName) return [];
10874
+ if (!sourceContent || !funcName)
10875
+ return [];
10791
10876
  const patterns = [
10792
10877
  new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
10793
10878
  new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
@@ -10800,7 +10885,8 @@ function inferFunctionParams(sourceContent, funcName) {
10800
10885
  if (m) {
10801
10886
  return m[1].split(",").map((s) => {
10802
10887
  const trimmed = s.trim();
10803
- if (!trimmed) return null;
10888
+ if (!trimmed)
10889
+ return null;
10804
10890
  const nameMatch = trimmed.match(/^\s*((?:public|protected)|static|final|val|var|let|const)?\s*(?:readonly\s+)?(?:[_$a-zA-Z][_$a-zA-Z0-9]*)\s*(?::|(?=\s*=)|(?=\s*[,)]))/);
10805
10891
  const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
10806
10892
  const defaultMatch = trimmed.match(/=\s*(.+)$/);
@@ -10816,22 +10902,35 @@ function inferFunctionParams(sourceContent, funcName) {
10816
10902
  return [];
10817
10903
  }
10818
10904
  function inferTypeFromName(paramName, defaultValue) {
10819
- if (!paramName) return "any";
10905
+ if (!paramName)
10906
+ return "any";
10820
10907
  const name = paramName.toLowerCase();
10821
10908
  if (defaultValue !== null && defaultValue !== void 0) {
10822
- if (/^["']/.test(defaultValue)) return "string";
10823
- if (/^\d+\.?\d*$/.test(defaultValue)) return "number";
10824
- if (/^(true|false)$/i.test(defaultValue)) return "boolean";
10825
- if (/^\[/.test(defaultValue)) return "array";
10826
- if (/^\{/.test(defaultValue)) return "object";
10827
- if (/^null$/i.test(defaultValue)) return "null";
10828
- }
10829
- if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name)) return "boolean";
10830
- if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name)) return "number";
10831
- if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name)) return "string";
10832
- if (/^(items|list|arr|entries|data|values|args)_?/.test(name)) return "array";
10833
- if (/^(obj|config|opts|options|settings|params|props)_?/.test(name)) return "object";
10834
- if (/^(fn|cb|callback|handler|on[A-Z])/.test(name)) return "function";
10909
+ if (/^["']/.test(defaultValue))
10910
+ return "string";
10911
+ if (/^\d+\.?\d*$/.test(defaultValue))
10912
+ return "number";
10913
+ if (/^(true|false)$/i.test(defaultValue))
10914
+ return "boolean";
10915
+ if (/^\[/.test(defaultValue))
10916
+ return "array";
10917
+ if (/^\{/.test(defaultValue))
10918
+ return "object";
10919
+ if (/^null$/i.test(defaultValue))
10920
+ return "null";
10921
+ }
10922
+ if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name))
10923
+ return "boolean";
10924
+ if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name))
10925
+ return "number";
10926
+ if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name))
10927
+ return "string";
10928
+ if (/^(items|list|arr|entries|data|values|args)_?/.test(name))
10929
+ return "array";
10930
+ if (/^(obj|config|opts|options|settings|params|props)_?/.test(name))
10931
+ return "object";
10932
+ if (/^(fn|cb|callback|handler|on[A-Z])/.test(name))
10933
+ return "function";
10835
10934
  return "any";
10836
10935
  }
10837
10936
  function _langComment(lang) {
@@ -10844,14 +10943,22 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10844
10943
  let block = "";
10845
10944
  const testValues = params.map((p) => {
10846
10945
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10847
- if (t === "string" || t === "String") return '"sample_input"';
10848
- if (t === "number" || t === "int" || t === "float" || t === "Number") return "42";
10849
- if (t === "boolean" || t === "bool" || t === "Boolean") return "true";
10850
- if (t === "array" || t === "Array" || t === "list" || t === "List") return "[]";
10851
- if (t === "object" || t === "Object" || t === "dict" || t === "Dict") return "{}";
10852
- if (t === "function" || t === "Function") return "() => {}";
10853
- if (t === "any") return '"test"';
10854
- if (t === "null") return "null";
10946
+ if (t === "string" || t === "String")
10947
+ return '"sample_input"';
10948
+ if (t === "number" || t === "int" || t === "float" || t === "Number")
10949
+ return "42";
10950
+ if (t === "boolean" || t === "bool" || t === "Boolean")
10951
+ return "true";
10952
+ if (t === "array" || t === "Array" || t === "list" || t === "List")
10953
+ return "[]";
10954
+ if (t === "object" || t === "Object" || t === "dict" || t === "Dict")
10955
+ return "{}";
10956
+ if (t === "function" || t === "Function")
10957
+ return "() => {}";
10958
+ if (t === "any")
10959
+ return '"test"';
10960
+ if (t === "null")
10961
+ return "null";
10855
10962
  return '"test"';
10856
10963
  });
10857
10964
  const args = testValues.join(", ");
@@ -10881,8 +10988,10 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10881
10988
  `;
10882
10989
  const ecArgs = params.map((p) => {
10883
10990
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10884
- if (t === "string") return '""';
10885
- if (t === "number" || t === "int" || t === "float") return "0";
10991
+ if (t === "string")
10992
+ return '""';
10993
+ if (t === "number" || t === "int" || t === "float")
10994
+ return "0";
10886
10995
  return '"edge"';
10887
10996
  }).join(", ");
10888
10997
  block += `${indent} result = ${funcName}(${ecArgs})
@@ -10920,11 +11029,16 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10920
11029
  `;
10921
11030
  const ecArgsJS = params.map((p) => {
10922
11031
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10923
- if (t === "string") return '""';
10924
- if (t === "number" || t === "int" || t === "float") return "0";
10925
- if (t === "boolean") return "false";
10926
- if (t === "array") return "[]";
10927
- if (t === "object") return "{}";
11032
+ if (t === "string")
11033
+ return '""';
11034
+ if (t === "number" || t === "int" || t === "float")
11035
+ return "0";
11036
+ if (t === "boolean")
11037
+ return "false";
11038
+ if (t === "array")
11039
+ return "[]";
11040
+ if (t === "object")
11041
+ return "{}";
10928
11042
  return "undefined";
10929
11043
  }).join(", ");
10930
11044
  block += `${indent} const result = mod.${funcName}(${ecArgsJS});
@@ -10957,14 +11071,15 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10957
11071
  return block;
10958
11072
  }
10959
11073
  function isSkeletonUseless(content) {
10960
- if (!content) return true;
11074
+ if (!content)
11075
+ return true;
10961
11076
  const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
10962
11077
  const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
10963
11078
  const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
10964
11079
  return meaningfulLines.length < 2;
10965
11080
  }
10966
11081
 
10967
- // src/lib/test-skeletons.ts
11082
+ // src/lib/test-skeletons.js
10968
11083
  var TEST_SKELETONS = {
10969
11084
  py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
10970
11085
  const moduleImport = name.replace(/-/g, "_");
@@ -10992,7 +11107,8 @@ var TEST_SKELETONS = {
10992
11107
 
10993
11108
  `;
10994
11109
  for (const exp of exports) {
10995
- if (exp.type === "class") continue;
11110
+ if (exp.type === "class")
11111
+ continue;
10996
11112
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
10997
11113
  content += `# TODO: implement tests for ${exp.name}
10998
11114
  `;
@@ -11000,10 +11116,12 @@ var TEST_SKELETONS = {
11000
11116
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11001
11117
  content += `def test_${caseFunc}():
11002
11118
  `;
11003
- if (strict) content += ` raise AssertionError("TODO: implement ${caseName}")
11119
+ if (strict)
11120
+ content += ` raise AssertionError("TODO: implement ${caseName}")
11004
11121
 
11005
11122
  `;
11006
- else content += ` pytest.skip("TODO: implement ${caseName}")
11123
+ else
11124
+ content += ` pytest.skip("TODO: implement ${caseName}")
11007
11125
 
11008
11126
  `;
11009
11127
  }
@@ -11015,10 +11133,12 @@ var TEST_SKELETONS = {
11015
11133
  if (exports.length === 0) {
11016
11134
  content += `def test_${name}_placeholder():
11017
11135
  `;
11018
- if (strict) content += ` raise AssertionError("TODO: implement tests for ${name}")
11136
+ if (strict)
11137
+ content += ` raise AssertionError("TODO: implement tests for ${name}")
11019
11138
 
11020
11139
  `;
11021
- else content += ` pytest.skip("TODO: implement tests for ${name}")
11140
+ else
11141
+ content += ` pytest.skip("TODO: implement tests for ${name}")
11022
11142
 
11023
11143
  `;
11024
11144
  }
@@ -11052,7 +11172,8 @@ var TEST_SKELETONS = {
11052
11172
 
11053
11173
  `;
11054
11174
  for (const exp of exports) {
11055
- if (exp.type === "class") continue;
11175
+ if (exp.type === "class")
11176
+ continue;
11056
11177
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11057
11178
  content += ` // TODO: implement tests for ${exp.name}
11058
11179
  `;
@@ -11068,9 +11189,11 @@ var TEST_SKELETONS = {
11068
11189
  `;
11069
11190
  content += ` // TODO: implement ${caseName}
11070
11191
  `;
11071
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11192
+ if (strict)
11193
+ content += ` throw new Error('TODO: implement ${caseName}');
11072
11194
  `;
11073
- else content += ` expect(true).toBe(true);
11195
+ else
11196
+ content += ` expect(true).toBe(true);
11074
11197
  `;
11075
11198
  content += ` });
11076
11199
 
@@ -11123,7 +11246,8 @@ var TEST_SKELETONS = {
11123
11246
 
11124
11247
  `;
11125
11248
  for (const exp of exports) {
11126
- if (exp.type === "class") continue;
11249
+ if (exp.type === "class")
11250
+ continue;
11127
11251
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11128
11252
  content += ` // TODO: implement tests for ${exp.name}
11129
11253
  `;
@@ -11139,9 +11263,11 @@ var TEST_SKELETONS = {
11139
11263
  `;
11140
11264
  content += ` // TODO: implement ${caseName}
11141
11265
  `;
11142
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11266
+ if (strict)
11267
+ content += ` throw new Error('TODO: implement ${caseName}');
11143
11268
  `;
11144
- else content += ` expect(true).toBe(true);
11269
+ else
11270
+ content += ` expect(true).toBe(true);
11145
11271
  `;
11146
11272
  content += ` });
11147
11273
 
@@ -11194,7 +11320,8 @@ var TEST_SKELETONS = {
11194
11320
 
11195
11321
  `;
11196
11322
  for (const exp of exports) {
11197
- if (exp.type === "class") continue;
11323
+ if (exp.type === "class")
11324
+ continue;
11198
11325
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11199
11326
  content += ` // TODO: implement tests for ${exp.name}
11200
11327
  `;
@@ -11210,9 +11337,11 @@ var TEST_SKELETONS = {
11210
11337
  `;
11211
11338
  content += ` // TODO: implement ${caseName}
11212
11339
  `;
11213
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11340
+ if (strict)
11341
+ content += ` throw new Error('TODO: implement ${caseName}');
11214
11342
  `;
11215
- else content += ` expect(true).toBe(true);
11343
+ else
11344
+ content += ` expect(true).toBe(true);
11216
11345
  `;
11217
11346
  content += ` });
11218
11347
 
@@ -11272,7 +11401,8 @@ var TEST_SKELETONS = {
11272
11401
 
11273
11402
  `;
11274
11403
  for (const exp of exports) {
11275
- if (exp.type === "class") continue;
11404
+ if (exp.type === "class")
11405
+ continue;
11276
11406
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11277
11407
  const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
11278
11408
  content += `// TODO: implement tests for ${exp.name}
@@ -11281,9 +11411,11 @@ var TEST_SKELETONS = {
11281
11411
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11282
11412
  content += `func Test${cap}_${caseFunc}(t *testing.T) {
11283
11413
  `;
11284
- if (strict) content += ` t.Error("TODO: implement ${caseName}")
11414
+ if (strict)
11415
+ content += ` t.Error("TODO: implement ${caseName}")
11285
11416
  `;
11286
- else content += ` t.Skip("TODO: implement ${caseName}")
11417
+ else
11418
+ content += ` t.Skip("TODO: implement ${caseName}")
11287
11419
  `;
11288
11420
  content += `}
11289
11421
 
@@ -11303,9 +11435,11 @@ var TEST_SKELETONS = {
11303
11435
  if (exports.length === 0) {
11304
11436
  content += `func Test${cap}_Placeholder(t *testing.T) {
11305
11437
  `;
11306
- if (strict) content += ` t.Error("TODO: implement tests for ${name}")
11438
+ if (strict)
11439
+ content += ` t.Error("TODO: implement tests for ${name}")
11307
11440
  `;
11308
- else content += ` t.Skip("TODO: implement tests for ${name}")
11441
+ else
11442
+ content += ` t.Skip("TODO: implement tests for ${name}")
11309
11443
  `;
11310
11444
  content += `}
11311
11445
  `;
@@ -11338,9 +11472,11 @@ var TEST_SKELETONS = {
11338
11472
  `;
11339
11473
  content += ` echo "TODO: implement ${caseName}"
11340
11474
  `;
11341
- if (strict) content += ` exit 1
11475
+ if (strict)
11476
+ content += ` exit 1
11342
11477
  `;
11343
- else content += ` echo "SKIP: ${caseName}"
11478
+ else
11479
+ content += ` echo "SKIP: ${caseName}"
11344
11480
  `;
11345
11481
  content += `}
11346
11482
 
@@ -11354,9 +11490,11 @@ var TEST_SKELETONS = {
11354
11490
  if (exports.length === 0) {
11355
11491
  content += `function test_smoke {
11356
11492
  `;
11357
- if (strict) content += ` echo "TODO: implement tests for ${name}" && exit 1
11493
+ if (strict)
11494
+ content += ` echo "TODO: implement tests for ${name}" && exit 1
11358
11495
  `;
11359
- else content += ` echo "TODO: implement tests for ${name}"
11496
+ else
11497
+ content += ` echo "TODO: implement tests for ${name}"
11360
11498
  `;
11361
11499
  content += `}
11362
11500
  `;
@@ -11396,7 +11534,8 @@ mod tests {
11396
11534
 
11397
11535
  `;
11398
11536
  for (const exp of exports) {
11399
- if (exp.type === "class") continue;
11537
+ if (exp.type === "class")
11538
+ continue;
11400
11539
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11401
11540
  content += ` // TODO: implement tests for ${exp.name}
11402
11541
  `;
@@ -11405,9 +11544,11 @@ mod tests {
11405
11544
  content += ` #[test]
11406
11545
  fn test_${caseFunc}() {
11407
11546
  `;
11408
- if (strict) content += ` panic!("TODO: implement ${caseName}");
11547
+ if (strict)
11548
+ content += ` panic!("TODO: implement ${caseName}");
11409
11549
  `;
11410
- else content += ` // TODO: implement ${caseName}
11550
+ else
11551
+ content += ` // TODO: implement ${caseName}
11411
11552
  `;
11412
11553
  content += ` }
11413
11554
 
@@ -11422,9 +11563,11 @@ mod tests {
11422
11563
  content += ` #[test]
11423
11564
  fn ${name}_placeholder() {
11424
11565
  `;
11425
- if (strict) content += ` panic!("TODO: implement tests for ${name}");
11566
+ if (strict)
11567
+ content += ` panic!("TODO: implement tests for ${name}");
11426
11568
  `;
11427
- else content += ` // TODO: implement tests for ${name}
11569
+ else
11570
+ content += ` // TODO: implement tests for ${name}
11428
11571
  `;
11429
11572
  content += ` }
11430
11573
  `;
@@ -11464,7 +11607,8 @@ mod tests {
11464
11607
 
11465
11608
  `;
11466
11609
  for (const exp of exports) {
11467
- if (exp.type === "class") continue;
11610
+ if (exp.type === "class")
11611
+ continue;
11468
11612
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11469
11613
  content += ` # TODO: implement tests for ${exp.name}
11470
11614
  `;
@@ -11472,9 +11616,11 @@ mod tests {
11472
11616
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11473
11617
  content += ` def test_${caseFunc}
11474
11618
  `;
11475
- if (strict) content += ` flunk "TODO: implement ${caseName}"
11619
+ if (strict)
11620
+ content += ` flunk "TODO: implement ${caseName}"
11476
11621
  `;
11477
- else content += ` # TODO: implement ${caseName}
11622
+ else
11623
+ content += ` # TODO: implement ${caseName}
11478
11624
  `;
11479
11625
  content += ` end
11480
11626
 
@@ -11488,9 +11634,11 @@ mod tests {
11488
11634
  if (exports.length === 0) {
11489
11635
  content += ` def test_placeholder
11490
11636
  `;
11491
- if (strict) content += ` flunk "TODO: implement tests for ${name}"
11637
+ if (strict)
11638
+ content += ` flunk "TODO: implement tests for ${name}"
11492
11639
  `;
11493
- else content += ` # TODO: implement tests for ${name}
11640
+ else
11641
+ content += ` # TODO: implement tests for ${name}
11494
11642
  `;
11495
11643
  content += ` end
11496
11644
  `;
@@ -11536,15 +11684,18 @@ mod tests {
11536
11684
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11537
11685
  for (const caseName of cases) {
11538
11686
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11539
- if (!strict) content += ` // @Disabled("TODO")
11687
+ if (!strict)
11688
+ content += ` // @Disabled("TODO")
11540
11689
  `;
11541
11690
  content += ` @Test
11542
11691
  `;
11543
11692
  content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11544
11693
  `;
11545
- if (strict) content += ` fail("TODO: implement ${caseName}");
11694
+ if (strict)
11695
+ content += ` fail("TODO: implement ${caseName}");
11546
11696
  `;
11547
- else content += ` assertTrue(true); // TODO: implement ${caseName}
11697
+ else
11698
+ content += ` assertTrue(true); // TODO: implement ${caseName}
11548
11699
  `;
11549
11700
  content += ` }
11550
11701
 
@@ -11606,15 +11757,18 @@ mod tests {
11606
11757
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11607
11758
  for (const caseName of cases) {
11608
11759
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11609
- if (!strict) content += ` // @Disabled("TODO")
11760
+ if (!strict)
11761
+ content += ` // @Disabled("TODO")
11610
11762
  `;
11611
11763
  content += ` @Test
11612
11764
  `;
11613
11765
  content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11614
11766
  `;
11615
- if (strict) content += ` fail("TODO: implement ${caseName}")
11767
+ if (strict)
11768
+ content += ` fail("TODO: implement ${caseName}")
11616
11769
  `;
11617
- else content += ` assertTrue(true) // TODO: implement ${caseName}
11770
+ else
11771
+ content += ` assertTrue(true) // TODO: implement ${caseName}
11618
11772
  `;
11619
11773
  content += ` }
11620
11774
 
@@ -12492,7 +12646,10 @@ var onToolExecuteAfter = async (input, output) => {
12492
12646
  const optModeFooter = loadSessionOptMode(currentSid + "_opt") || loadOptimizationMode() || "budget";
12493
12647
  const activeSlot = selNow.active_slot || (execution.quality === "brain" ? "brain" : execution.quality === "medium" ? "medium" : "cheap");
12494
12648
  const vibeBrand = resolveBrand(optModeFooter, activeSlot);
12495
- const flashIcon = VIBEOS_API_ENABLED ? " \u26A1" : "";
12649
+ const sessionSlot = loadSessionSlot(currentSid);
12650
+ const displayMode = selNow.optimization_mode || optModeFooter || "auto";
12651
+ const currentSubRegime = loadBlackboxState()?.sessions?.[currentSid]?.sub_regime || classifyTurnSimple2(latestUserIntent || "");
12652
+ const flashIcon = isApiConnected2() ? " \u26A1" : "";
12496
12653
  _footerText = buildFooterLine({
12497
12654
  activeSlot,
12498
12655
  providerLabel: execution.provider_label,
@@ -12500,10 +12657,12 @@ var onToolExecuteAfter = async (input, output) => {
12500
12657
  ltTotal,
12501
12658
  ltTrend: sesTrend || "",
12502
12659
  vibeBrand,
12503
- optMode: optModeFooter,
12660
+ optMode: displayMode,
12504
12661
  flashIcon,
12505
12662
  enfTags,
12506
- vectorChangedSlot: selNow.vector_changed_slot
12663
+ sessionSlot,
12664
+ vectorChangedSlot: selNow.vector_changed_slot,
12665
+ subRegime: currentSubRegime
12507
12666
  }) + "\n\n";
12508
12667
  const footerTarget = _payload(output);
12509
12668
  output.title = _footerText.trim();
@@ -12982,15 +13141,14 @@ async function _seedModelTiersIfMissing(directory3) {
12982
13141
  discovered = await discoverAvailableModels(providers, auth);
12983
13142
  } catch {
12984
13143
  }
12985
- let ranked = null;
13144
+ let trinity = null;
12986
13145
  try {
12987
- ranked = classifyAndRankModels(discovered);
13146
+ trinity = buildDeterministicTrinity(discovered, { selectedModelId: currentModel });
12988
13147
  } catch {
12989
13148
  }
12990
- const fallbackModel = currentModel || readConfig(directory3) || readConfig(getOpenCodeHome3()) || process?.env?.OPENCODE_MODEL || "";
12991
- let brain = ranked?.brain?.id || fallbackModel;
12992
- let medium = ranked?.medium?.id || brain;
12993
- let cheap = ranked?.cheap?.id || medium || brain;
13149
+ let brain = trinity?.brain || currentModel || readConfig(directory3) || readConfig(getOpenCodeHome3()) || process?.env?.OPENCODE_MODEL || "";
13150
+ let medium = trinity?.medium || brain;
13151
+ let cheap = trinity?.cheap || medium || brain;
12994
13152
  if (!brain) {
12995
13153
  brain = "deepseek/deepseek-v4-pro";
12996
13154
  medium = "deepseek/deepseek-v4-flash";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.24.5",
3
+ "version": "0.24.7",
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",
@@ -32,7 +32,7 @@
32
32
  "type": "module",
33
33
  "main": "./dist/vibeOS.js",
34
34
  "bin": {
35
- "vibeostheog": "./bin/setup.js"
35
+ "vibeostheog": "bin/setup.js"
36
36
  },
37
37
  "exports": {
38
38
  ".": "./dist/vibeOS.js",
@@ -71,7 +71,7 @@
71
71
  ],
72
72
  "repository": {
73
73
  "type": "git",
74
- "url": "https://github.com/DrunkkToys/vibeOS.git"
74
+ "url": "git+https://github.com/DrunkkToys/vibeOS.git"
75
75
  },
76
76
  "homepage": "https://github.com/DrunkkToys/vibeOS#readme",
77
77
  "bugs": {