vibeostheog 0.24.3 → 0.24.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.24.5
2
+ - fix: cap saveEst at to prevent runaway pricing data corruption
3
+ - chore: v0.24.4
4
+
5
+
1
6
  ## 0.23.61
2
7
  - chore: clean TS source warnings and bump patch
3
8
 
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 || "";
@@ -5574,7 +5592,7 @@ function applySlot2(slot, projectDir = "") {
5574
5592
  writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
5575
5593
  }
5576
5594
  clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
5577
- _refreshModel(process.cwd());
5595
+ _refreshModel(dir);
5578
5596
  return { ok: true, ocModel };
5579
5597
  } catch (err) {
5580
5598
  return { ok: false, reason: err.message };
@@ -6081,7 +6099,7 @@ function classifyTurnSimple(userText) {
6081
6099
  if (new RegExp("^I (need|want|would like) to (" + IMPL_VERBS + ")\\b", "i").test(lower)) {
6082
6100
  return "REFINING";
6083
6101
  }
6084
- if (/^(the |there is |there are |i think |looks like |seems like |i see |why (is|are|does|did) )/.test(lower)) {
6102
+ if (/^(the |there is |there are |i think |looks like |seems like |i see |why (is|are|does|did) )/i.test(lower)) {
6085
6103
  return "EXPLORING";
6086
6104
  }
6087
6105
  if (/^(how|what|why|when|where|who|can you|could you|let me|tell me|explain|describe|show|list|check|is there|are there|does|do you|summarize|elaborate|clarify|inspect|trace|find|search|look|read|show me|dump|debug)/i.test(lower)) {
@@ -7480,6 +7498,15 @@ function createTrinityTool(deps) {
7480
7498
  const _brandedModeIds = ["vibeultrax", "vibeqmax", "vibemax", "vibelitex"];
7481
7499
  const _builtInModeIds = ["budget", "quality", "speed", "longrun", "auto", "balanced", "audit", "forensic"];
7482
7500
  if (!action || action === "status") {
7501
+ if (slot && (_brandedModeIds.includes(slot) || _builtInModeIds.includes(slot))) {
7502
+ action = "mode";
7503
+ } else if (["brain", "medium", "cheap"].includes(slot)) {
7504
+ action = "set";
7505
+ } else if (["full", "brief", "off"].includes(slot)) {
7506
+ action = "thinking";
7507
+ level = slot;
7508
+ slot = void 0;
7509
+ }
7483
7510
  } else if (_brandedModeIds.includes(action) || _builtInModeIds.includes(action)) {
7484
7511
  slot = action;
7485
7512
  action = "mode";
@@ -7664,10 +7691,10 @@ function createTrinityTool(deps) {
7664
7691
  console.error("[vibeOS] WARN: probe error for " + targetModel + ": " + e.message + " - switching anyway");
7665
7692
  }
7666
7693
  deps.writeSessionSlot(deps._OC_SID, slot);
7667
- const result = deps.applySlot(slot);
7694
+ const result = deps.applySlot(slot, deps.directory);
7668
7695
  if (!result.ok) return `\u274C Failed to set slot: ${result.reason}`;
7669
7696
  try {
7670
- const selected = typeof deps.resolveExecutionIdentity === "function" ? deps.resolveExecutionIdentity(result.ocModel, deps.directory) : null;
7697
+ const selected = resolveExecutionIdentity(result.ocModel, deps.directory);
7671
7698
  if (selected) {
7672
7699
  deps.writeSelection("selected_provider", selected.provider || "");
7673
7700
  deps.writeSelection("selected_quality_tier", selected.quality || slot);
@@ -8922,7 +8949,7 @@ import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, appen
8922
8949
  import { join as join14, dirname as dirname11, basename as basename7 } from "node:path";
8923
8950
  import { createHash as createHash3 } from "node:crypto";
8924
8951
 
8925
- // src/lib/mode-policy.ts
8952
+ // src/lib/mode-policy.js
8926
8953
  var STRESS_QUALITY_THRESHOLD = 1.5;
8927
8954
  var BASELINE_MODE = "budget";
8928
8955
  var LOOP_REGIMES = /* @__PURE__ */ new Set(["LOOPING", "DIVERGENT"]);
@@ -8930,7 +8957,8 @@ var QUALITY_REGIMES = /* @__PURE__ */ new Set(["CONVERGING", "CLOSED"]);
8930
8957
  var MANUAL_MODES = /* @__PURE__ */ new Set(["balanced", "quality", "speed", "longrun", "vibemax", "vibeqmax", "vibeultrax"]);
8931
8958
  function normalizeMode(mode) {
8932
8959
  const normalized = String(mode || BASELINE_MODE).toLowerCase();
8933
- if (normalized === "auto" || normalized === "") return BASELINE_MODE;
8960
+ if (normalized === "auto" || normalized === "")
8961
+ return BASELINE_MODE;
8934
8962
  if (normalized === "budget" || normalized === "quality" || normalized === "speed" || normalized === "longrun" || normalized === "balanced" || normalized === "vibemax" || normalized === "vibeqmax" || normalized === "vibeultrax") {
8935
8963
  return normalized;
8936
8964
  }
@@ -8943,9 +8971,12 @@ function isManualOverride(mode) {
8943
8971
  return MANUAL_MODES.has(normalizeMode(mode));
8944
8972
  }
8945
8973
  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";
8974
+ if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax")
8975
+ return suggestedMode;
8976
+ if (LOOP_REGIMES.has(regime) || suggestedMode === "speed")
8977
+ return "speed";
8978
+ if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality")
8979
+ return "quality";
8949
8980
  return stress > STRESS_QUALITY_THRESHOLD ? "quality" : "budget";
8950
8981
  }
8951
8982
  function defaultPolicy() {
@@ -8966,15 +8997,19 @@ function defaultPolicy() {
8966
8997
  }
8967
8998
  function modeToSlot(mode) {
8968
8999
  const normalized = normalizeMode(mode);
8969
- if (normalized === "speed") return "medium";
8970
- if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax") return "brain";
9000
+ if (normalized === "speed")
9001
+ return "medium";
9002
+ if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax")
9003
+ return "brain";
8971
9004
  return "cheap";
8972
9005
  }
8973
9006
  function loadSessionPolicy() {
8974
9007
  const state = loadBlackboxState();
8975
- if (!state.sessions || typeof state.sessions !== "object") state.sessions = {};
9008
+ if (!state.sessions || typeof state.sessions !== "object")
9009
+ state.sessions = {};
8976
9010
  const sid = _OC_SID;
8977
- if (!state.sessions[sid] || typeof state.sessions[sid] !== "object") state.sessions[sid] = {};
9011
+ if (!state.sessions[sid] || typeof state.sessions[sid] !== "object")
9012
+ state.sessions[sid] = {};
8978
9013
  const session = state.sessions[sid];
8979
9014
  if (!session.mode_policy || typeof session.mode_policy !== "object") {
8980
9015
  session.mode_policy = defaultPolicy();
@@ -9102,7 +9137,7 @@ function recordBudgetFirstOutcome(input = {}) {
9102
9137
  import { join as join13 } from "node:path";
9103
9138
  import { writeFileSync as writeFileSync12 } from "node:fs";
9104
9139
 
9105
- // src/lib/text-compress.ts
9140
+ // src/lib/text-compress.js
9106
9141
  var VERBOSE_LINE_RE = [
9107
9142
  /^[\s#*/\\\-_=+|~:;'"`@\$%^&<>{}\[\]()!?.,0-9]+$/,
9108
9143
  /^(Filed|Created|Modified|Deleted|Updated|Renamed|Copied|Moved|Changed):/,
@@ -9119,12 +9154,15 @@ function extractBulletLines(lines, targetChars, minLines) {
9119
9154
  const keyLines = [];
9120
9155
  const otherLines = [];
9121
9156
  for (const line of lines) {
9122
- if (BULLET_PATTERNS.some((re) => re.test(line))) keyLines.push(line);
9123
- else otherLines.push(line);
9157
+ if (BULLET_PATTERNS.some((re) => re.test(line)))
9158
+ keyLines.push(line);
9159
+ else
9160
+ otherLines.push(line);
9124
9161
  }
9125
9162
  const selected = [...keyLines];
9126
9163
  for (const line of otherLines) {
9127
- if (selected.length >= minLines && selected.join("\n").length >= targetChars) break;
9164
+ if (selected.length >= minLines && selected.join("\n").length >= targetChars)
9165
+ break;
9128
9166
  selected.push(line);
9129
9167
  }
9130
9168
  while (selected.length > minLines && selected.join("\n").length > targetChars * 2) {
@@ -9133,7 +9171,8 @@ function extractBulletLines(lines, targetChars, minLines) {
9133
9171
  return selected;
9134
9172
  }
9135
9173
  function compressText(text) {
9136
- if (!text || typeof text !== "string") return text;
9174
+ if (!text || typeof text !== "string")
9175
+ return text;
9137
9176
  let lines = text.split("\n");
9138
9177
  let removed = 0;
9139
9178
  const out = [];
@@ -9146,14 +9185,16 @@ function compressText(text) {
9146
9185
  break;
9147
9186
  }
9148
9187
  }
9149
- if (!skip) out.push(line);
9188
+ if (!skip)
9189
+ out.push(line);
9150
9190
  }
9151
9191
  const collapsed = [];
9152
9192
  let blanks = 0;
9153
9193
  for (const line of out) {
9154
9194
  if (line.trim() === "") {
9155
9195
  blanks++;
9156
- if (blanks <= 2) collapsed.push(line);
9196
+ if (blanks <= 2)
9197
+ collapsed.push(line);
9157
9198
  } else {
9158
9199
  blanks = 0;
9159
9200
  collapsed.push(line);
@@ -9161,10 +9202,7 @@ function compressText(text) {
9161
9202
  }
9162
9203
  let result = collapsed.join("\n").trim();
9163
9204
  if (result.length > COMPRESS_THRESHOLD) {
9164
- const targetChars = Math.max(
9165
- Math.round(result.length * COMPRESS_RATIO),
9166
- COMPRESS_THRESHOLD
9167
- );
9205
+ const targetChars = Math.max(Math.round(result.length * COMPRESS_RATIO), COMPRESS_THRESHOLD);
9168
9206
  const minLines = Math.max(1, Math.round(collapsed.length * MIN_KEPT_LINES_RATIO));
9169
9207
  const bulletLines = extractBulletLines(collapsed, targetChars, minLines);
9170
9208
  result = bulletLines.join("\n").trim();
@@ -9371,9 +9409,11 @@ function observeToolPattern(toolName, input, output, directory3) {
9371
9409
  } catch {
9372
9410
  }
9373
9411
  }
9412
+ var MAX_SAVE_EST_PER_WARN = 5;
9374
9413
  function recordSaving(tool2, reason, saveEst, meta = {}) {
9375
9414
  try {
9376
9415
  if (!saveEst || saveEst <= 0) return 0;
9416
+ if (saveEst > MAX_SAVE_EST_PER_WARN) saveEst = MAX_SAVE_EST_PER_WARN;
9377
9417
  const firstWord = meta?.firstWord || tool2 || "";
9378
9418
  updateState((s) => {
9379
9419
  s.lifetime ??= { total_savings_usd: 0, cache_savings_usd: 0, missed_context7_usd: 0, session_count: 0, warn_count: 0 };
@@ -9461,7 +9501,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
9461
9501
  }
9462
9502
  }
9463
9503
 
9464
- // src/lib/constants.ts
9504
+ // src/lib/constants.js
9465
9505
  var SAVE_EST = {
9466
9506
  // Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
9467
9507
  WRITE_EDIT: 4e-4,
@@ -9479,7 +9519,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
9479
9519
  var PROTOCOL_MARKER = "[wbp-v1]";
9480
9520
  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.";
9481
9521
 
9482
- // src/lib/templates.ts
9522
+ // src/lib/templates.js
9483
9523
  var TEMPLATES = {
9484
9524
  save: {
9485
9525
  tier_bias: "cheap",
@@ -9518,7 +9558,8 @@ var TEMPLATES = {
9518
9558
  var DEFAULT_TEMPLATE = "save";
9519
9559
  var SEC_KEYWORDS = /\b(security|vuln|exploit|injection|xss|csrf|secret|credential|token leak|auth bypass|privacy|breach|backdoor|sql injection|cve)\b/i;
9520
9560
  function detectSecuritySignal(text) {
9521
- if (!text || typeof text !== "string") return false;
9561
+ if (!text || typeof text !== "string")
9562
+ return false;
9522
9563
  return SEC_KEYWORDS.test(text);
9523
9564
  }
9524
9565
  function detectBudgetSignal(creditPercent) {
@@ -9531,16 +9572,21 @@ function detectStressSpike(stressScore) {
9531
9572
  return delta > 0.3 && stressScore > 0.5;
9532
9573
  }
9533
9574
  function resolveTemplate(prevTemplate, stressScore, userText, creditPercent) {
9534
- if (detectSecuritySignal(userText)) return "security";
9535
- if (detectBudgetSignal(creditPercent)) return "save";
9536
- if (detectStressSpike(stressScore)) return "quality";
9575
+ if (detectSecuritySignal(userText))
9576
+ return "security";
9577
+ if (detectBudgetSignal(creditPercent))
9578
+ return "save";
9579
+ if (detectStressSpike(stressScore))
9580
+ return "quality";
9537
9581
  return prevTemplate || DEFAULT_TEMPLATE;
9538
9582
  }
9539
9583
  var _turnCount = 0;
9540
9584
  function shouldInjectTemplate(template, prevTemplate) {
9541
9585
  _turnCount++;
9542
- if (template !== prevTemplate) return true;
9543
- if (_turnCount % 10 === 0) return true;
9586
+ if (template !== prevTemplate)
9587
+ return true;
9588
+ if (_turnCount % 10 === 0)
9589
+ return true;
9544
9590
  return false;
9545
9591
  }
9546
9592
 
@@ -9597,7 +9643,7 @@ async function apiComputeControlVector(state, action, optimizationMode) {
9597
9643
  const res = await remoteCall("blackboxControlVector", [state, action, optimizationMode], null);
9598
9644
  if (res?.control_vector) {
9599
9645
  const local = computeControlVector2(state, action, optimizationMode);
9600
- return { ...res.control_vector, tier_bias: local.tier_bias, optimization_mode: local.optimization_mode };
9646
+ return { ...res.control_vector, tier_bias: local.tier_bias, optimization_mode: local.optimization_mode, enforcement_mode: local.enforcement_mode, flow_mode: local.flow_mode, tdd_mode: local.tdd_mode, thinking_mode: local.thinking_mode };
9601
9647
  }
9602
9648
  } catch {
9603
9649
  }
@@ -10268,6 +10314,17 @@ var onSystemTransform = async (_input, output) => {
10268
10314
  };
10269
10315
 
10270
10316
  // src/lib/hooks/shared-footer.ts
10317
+ var REGIME_TAG = {
10318
+ INIT: "INIT",
10319
+ DIVERGENT: "DVRG",
10320
+ EXPLORING: "XPLR",
10321
+ REFINING: "RFNE",
10322
+ CONVERGING: "CVGE",
10323
+ CLOSED: "CLSD",
10324
+ LOOPING: "LOOP",
10325
+ AUDIT: "AUDT",
10326
+ FORENSIC: "FRNC"
10327
+ };
10271
10328
  var BRAND_MAP = {
10272
10329
  vibeultrax: "VibeUltraX",
10273
10330
  vibeqmax: "VibeQMaX",
@@ -10331,9 +10388,10 @@ function buildEnforcementTags(opts) {
10331
10388
  return tags;
10332
10389
  }
10333
10390
  function buildFooterLine(input) {
10334
- const { activeSlot, sessionSlot, providerLabel, modelName, ltTotal, ltTrend, vibeBrand, optMode, flashIcon, enfTags, vectorChangedSlot } = input;
10391
+ const { activeSlot, sessionSlot, providerLabel, modelName, ltTotal, ltTrend, vibeBrand, optMode, flashIcon, enfTags, vectorChangedSlot, subRegime } = input;
10335
10392
  const tierIcon = resolveTierIcon(activeSlot);
10336
- let line = `\u2014 ${tierIcon} ${activeSlot} | ${providerLabel} | ${modelName}`;
10393
+ const regimeTag = subRegime ? REGIME_TAG[subRegime] || subRegime.slice(0, 4) : null;
10394
+ let line = `\u2014 ${tierIcon} ${activeSlot} | ${providerLabel} | ${modelName}${regimeTag ? ` \u25B6 ${regimeTag}` : ""}`;
10337
10395
  if (ltTotal > 0) {
10338
10396
  const savingsPulse = formatSavingsPulse(ltTotal, ltTrend);
10339
10397
  if (savingsPulse) line += ` | ${savingsPulse}`;
@@ -10568,6 +10626,7 @@ async function _appendFooter(input, output, directory3) {
10568
10626
  const vibeBrand = resolveBrand(optModeFooter, activeSlot);
10569
10627
  const flashIcon = isApiConnected2() ? " \u26A1" : "";
10570
10628
  const displayMode = selNowFooter?.optimization_mode || optMode || "auto";
10629
+ const currentSubRegime = _latestBlackboxState?.sub_regime || classifyTurnSimple2(latestUserIntent || "");
10571
10630
  const vibeLine = buildFooterLine({
10572
10631
  activeSlot,
10573
10632
  providerLabel: execution.provider_label,
@@ -10579,7 +10638,8 @@ async function _appendFooter(input, output, directory3) {
10579
10638
  flashIcon,
10580
10639
  enfTags,
10581
10640
  sessionSlot,
10582
- vectorChangedSlot: selNowFooter?.vector_changed_slot
10641
+ vectorChangedSlot: selNowFooter?.vector_changed_slot,
10642
+ subRegime: currentSubRegime
10583
10643
  });
10584
10644
  const footerText = stripped + `
10585
10645
 
@@ -10633,7 +10693,7 @@ import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync9, ex
10633
10693
  import { join as join17, dirname as dirname14, basename as basename9 } from "node:path";
10634
10694
  import { createHash as createHash5 } from "node:crypto";
10635
10695
 
10636
- // src/lib/cost-anomaly.ts
10696
+ // src/lib/cost-anomaly.js
10637
10697
  var COST_WINDOW_SIZE = 20;
10638
10698
  var COST_ANOMALY_THRESHOLD = 3;
10639
10699
  var COST_WARMUP_SAMPLES = 5;
@@ -10644,21 +10704,26 @@ var CostAnomalyDetector = class {
10644
10704
  currentAnomalyCost = 0;
10645
10705
  currentAnomalyMean = 0;
10646
10706
  record(cost) {
10647
- if (this.disabled) return;
10707
+ if (this.disabled)
10708
+ return;
10648
10709
  this.costHistory.push(cost);
10649
10710
  if (this.costHistory.length > COST_WINDOW_SIZE) {
10650
10711
  this.costHistory.shift();
10651
10712
  }
10652
10713
  }
10653
10714
  get mean() {
10654
- if (this.costHistory.length === 0) return 0;
10715
+ if (this.costHistory.length === 0)
10716
+ return 0;
10655
10717
  return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
10656
10718
  }
10657
10719
  checkAnomaly(model, cost) {
10658
- if (this.disabled) return false;
10659
- if (this.costHistory.length < COST_WARMUP_SAMPLES) return false;
10720
+ if (this.disabled)
10721
+ return false;
10722
+ if (this.costHistory.length < COST_WARMUP_SAMPLES)
10723
+ return false;
10660
10724
  const avg = this.mean;
10661
- if (avg <= 0 || cost <= avg) return false;
10725
+ if (avg <= 0 || cost <= avg)
10726
+ return false;
10662
10727
  const ratio = cost / avg;
10663
10728
  if (ratio > COST_ANOMALY_THRESHOLD) {
10664
10729
  this.currentAnomalyModel = model;
@@ -10680,7 +10745,8 @@ var CostAnomalyDetector = class {
10680
10745
  };
10681
10746
  var _costDetector = null;
10682
10747
  function getCostAnomalyDetector() {
10683
- if (!_costDetector) _costDetector = new CostAnomalyDetector();
10748
+ if (!_costDetector)
10749
+ _costDetector = new CostAnomalyDetector();
10684
10750
  return _costDetector;
10685
10751
  }
10686
10752
 
@@ -10692,9 +10758,10 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync15, appen
10692
10758
  import { join as join16, dirname as dirname13 } from "node:path";
10693
10759
  import { createHash as createHash4 } from "node:crypto";
10694
10760
 
10695
- // src/utils/tdd-helpers.ts
10761
+ // src/utils/tdd-helpers.js
10696
10762
  function extractExports(sourceContent, ext) {
10697
- if (!sourceContent || typeof sourceContent !== "string") return [];
10763
+ if (!sourceContent || typeof sourceContent !== "string")
10764
+ return [];
10698
10765
  const exports = [];
10699
10766
  const seen = /* @__PURE__ */ new Set();
10700
10767
  const add = (name, type = "function") => {
@@ -10705,51 +10772,69 @@ function extractExports(sourceContent, ext) {
10705
10772
  };
10706
10773
  switch (ext) {
10707
10774
  case "py": {
10708
- for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm)) add(m[1]);
10709
- for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm)) add(m[1], "class");
10775
+ for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
10776
+ add(m[1]);
10777
+ for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm))
10778
+ add(m[1], "class");
10710
10779
  break;
10711
10780
  }
10712
10781
  case "js":
10713
10782
  case "mjs":
10714
10783
  case "jsx": {
10715
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10716
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g)) add(m[1]);
10784
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
10785
+ add(m[1]);
10786
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g))
10787
+ add(m[1]);
10717
10788
  if (exports.length === 0) {
10718
- for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm)) add(m[1]);
10789
+ for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
10790
+ add(m[1]);
10719
10791
  }
10720
10792
  break;
10721
10793
  }
10722
10794
  case "ts":
10723
10795
  case "tsx": {
10724
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10725
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g)) add(m[1]);
10726
- for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g)) add(m[1], "class");
10796
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
10797
+ add(m[1]);
10798
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g))
10799
+ add(m[1]);
10800
+ for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g))
10801
+ add(m[1], "class");
10727
10802
  break;
10728
10803
  }
10729
10804
  case "go": {
10730
- for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g)) add(m[1]);
10805
+ for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
10806
+ add(m[1]);
10731
10807
  break;
10732
10808
  }
10733
10809
  case "rs": {
10734
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g)) add(m[1]);
10735
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g)) add(m[1]);
10736
- for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g)) add(m[1], "struct");
10810
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
10811
+ add(m[1]);
10812
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g))
10813
+ add(m[1]);
10814
+ for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g))
10815
+ add(m[1], "struct");
10737
10816
  break;
10738
10817
  }
10739
10818
  case "rb": {
10740
- for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g)) add(m[1]);
10741
- for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g)) add(m[1], "class");
10819
+ for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
10820
+ add(m[1]);
10821
+ for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g))
10822
+ add(m[1], "class");
10742
10823
  break;
10743
10824
  }
10744
10825
  case "java":
10745
10826
  case "kt": {
10746
- for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10747
- for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
10827
+ for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
10828
+ add(m[1]);
10829
+ for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g))
10830
+ add(m[1]);
10748
10831
  break;
10749
10832
  }
10750
10833
  case "sh": {
10751
- for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm)) add(m[1]);
10752
- for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm)) add(m[1]);
10834
+ for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
10835
+ add(m[1]);
10836
+ for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm))
10837
+ add(m[1]);
10753
10838
  break;
10754
10839
  }
10755
10840
  }
@@ -10771,7 +10856,8 @@ function generateTestCaseNames(funcName, _type, quality = false) {
10771
10856
  ];
10772
10857
  }
10773
10858
  function inferFunctionParams(sourceContent, funcName) {
10774
- if (!sourceContent || !funcName) return [];
10859
+ if (!sourceContent || !funcName)
10860
+ return [];
10775
10861
  const patterns = [
10776
10862
  new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
10777
10863
  new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
@@ -10784,7 +10870,8 @@ function inferFunctionParams(sourceContent, funcName) {
10784
10870
  if (m) {
10785
10871
  return m[1].split(",").map((s) => {
10786
10872
  const trimmed = s.trim();
10787
- if (!trimmed) return null;
10873
+ if (!trimmed)
10874
+ return null;
10788
10875
  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*[,)]))/);
10789
10876
  const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
10790
10877
  const defaultMatch = trimmed.match(/=\s*(.+)$/);
@@ -10800,22 +10887,35 @@ function inferFunctionParams(sourceContent, funcName) {
10800
10887
  return [];
10801
10888
  }
10802
10889
  function inferTypeFromName(paramName, defaultValue) {
10803
- if (!paramName) return "any";
10890
+ if (!paramName)
10891
+ return "any";
10804
10892
  const name = paramName.toLowerCase();
10805
10893
  if (defaultValue !== null && defaultValue !== void 0) {
10806
- if (/^["']/.test(defaultValue)) return "string";
10807
- if (/^\d+\.?\d*$/.test(defaultValue)) return "number";
10808
- if (/^(true|false)$/i.test(defaultValue)) return "boolean";
10809
- if (/^\[/.test(defaultValue)) return "array";
10810
- if (/^\{/.test(defaultValue)) return "object";
10811
- if (/^null$/i.test(defaultValue)) return "null";
10812
- }
10813
- if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name)) return "boolean";
10814
- if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name)) return "number";
10815
- if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name)) return "string";
10816
- if (/^(items|list|arr|entries|data|values|args)_?/.test(name)) return "array";
10817
- if (/^(obj|config|opts|options|settings|params|props)_?/.test(name)) return "object";
10818
- if (/^(fn|cb|callback|handler|on[A-Z])/.test(name)) return "function";
10894
+ if (/^["']/.test(defaultValue))
10895
+ return "string";
10896
+ if (/^\d+\.?\d*$/.test(defaultValue))
10897
+ return "number";
10898
+ if (/^(true|false)$/i.test(defaultValue))
10899
+ return "boolean";
10900
+ if (/^\[/.test(defaultValue))
10901
+ return "array";
10902
+ if (/^\{/.test(defaultValue))
10903
+ return "object";
10904
+ if (/^null$/i.test(defaultValue))
10905
+ return "null";
10906
+ }
10907
+ if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name))
10908
+ return "boolean";
10909
+ if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name))
10910
+ return "number";
10911
+ if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name))
10912
+ return "string";
10913
+ if (/^(items|list|arr|entries|data|values|args)_?/.test(name))
10914
+ return "array";
10915
+ if (/^(obj|config|opts|options|settings|params|props)_?/.test(name))
10916
+ return "object";
10917
+ if (/^(fn|cb|callback|handler|on[A-Z])/.test(name))
10918
+ return "function";
10819
10919
  return "any";
10820
10920
  }
10821
10921
  function _langComment(lang) {
@@ -10828,14 +10928,22 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10828
10928
  let block = "";
10829
10929
  const testValues = params.map((p) => {
10830
10930
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10831
- if (t === "string" || t === "String") return '"sample_input"';
10832
- if (t === "number" || t === "int" || t === "float" || t === "Number") return "42";
10833
- if (t === "boolean" || t === "bool" || t === "Boolean") return "true";
10834
- if (t === "array" || t === "Array" || t === "list" || t === "List") return "[]";
10835
- if (t === "object" || t === "Object" || t === "dict" || t === "Dict") return "{}";
10836
- if (t === "function" || t === "Function") return "() => {}";
10837
- if (t === "any") return '"test"';
10838
- if (t === "null") return "null";
10931
+ if (t === "string" || t === "String")
10932
+ return '"sample_input"';
10933
+ if (t === "number" || t === "int" || t === "float" || t === "Number")
10934
+ return "42";
10935
+ if (t === "boolean" || t === "bool" || t === "Boolean")
10936
+ return "true";
10937
+ if (t === "array" || t === "Array" || t === "list" || t === "List")
10938
+ return "[]";
10939
+ if (t === "object" || t === "Object" || t === "dict" || t === "Dict")
10940
+ return "{}";
10941
+ if (t === "function" || t === "Function")
10942
+ return "() => {}";
10943
+ if (t === "any")
10944
+ return '"test"';
10945
+ if (t === "null")
10946
+ return "null";
10839
10947
  return '"test"';
10840
10948
  });
10841
10949
  const args = testValues.join(", ");
@@ -10865,8 +10973,10 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10865
10973
  `;
10866
10974
  const ecArgs = params.map((p) => {
10867
10975
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10868
- if (t === "string") return '""';
10869
- if (t === "number" || t === "int" || t === "float") return "0";
10976
+ if (t === "string")
10977
+ return '""';
10978
+ if (t === "number" || t === "int" || t === "float")
10979
+ return "0";
10870
10980
  return '"edge"';
10871
10981
  }).join(", ");
10872
10982
  block += `${indent} result = ${funcName}(${ecArgs})
@@ -10904,11 +11014,16 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10904
11014
  `;
10905
11015
  const ecArgsJS = params.map((p) => {
10906
11016
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10907
- if (t === "string") return '""';
10908
- if (t === "number" || t === "int" || t === "float") return "0";
10909
- if (t === "boolean") return "false";
10910
- if (t === "array") return "[]";
10911
- if (t === "object") return "{}";
11017
+ if (t === "string")
11018
+ return '""';
11019
+ if (t === "number" || t === "int" || t === "float")
11020
+ return "0";
11021
+ if (t === "boolean")
11022
+ return "false";
11023
+ if (t === "array")
11024
+ return "[]";
11025
+ if (t === "object")
11026
+ return "{}";
10912
11027
  return "undefined";
10913
11028
  }).join(", ");
10914
11029
  block += `${indent} const result = mod.${funcName}(${ecArgsJS});
@@ -10941,14 +11056,15 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10941
11056
  return block;
10942
11057
  }
10943
11058
  function isSkeletonUseless(content) {
10944
- if (!content) return true;
11059
+ if (!content)
11060
+ return true;
10945
11061
  const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
10946
11062
  const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
10947
11063
  const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
10948
11064
  return meaningfulLines.length < 2;
10949
11065
  }
10950
11066
 
10951
- // src/lib/test-skeletons.ts
11067
+ // src/lib/test-skeletons.js
10952
11068
  var TEST_SKELETONS = {
10953
11069
  py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
10954
11070
  const moduleImport = name.replace(/-/g, "_");
@@ -10976,7 +11092,8 @@ var TEST_SKELETONS = {
10976
11092
 
10977
11093
  `;
10978
11094
  for (const exp of exports) {
10979
- if (exp.type === "class") continue;
11095
+ if (exp.type === "class")
11096
+ continue;
10980
11097
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
10981
11098
  content += `# TODO: implement tests for ${exp.name}
10982
11099
  `;
@@ -10984,10 +11101,12 @@ var TEST_SKELETONS = {
10984
11101
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
10985
11102
  content += `def test_${caseFunc}():
10986
11103
  `;
10987
- if (strict) content += ` raise AssertionError("TODO: implement ${caseName}")
11104
+ if (strict)
11105
+ content += ` raise AssertionError("TODO: implement ${caseName}")
10988
11106
 
10989
11107
  `;
10990
- else content += ` pytest.skip("TODO: implement ${caseName}")
11108
+ else
11109
+ content += ` pytest.skip("TODO: implement ${caseName}")
10991
11110
 
10992
11111
  `;
10993
11112
  }
@@ -10999,10 +11118,12 @@ var TEST_SKELETONS = {
10999
11118
  if (exports.length === 0) {
11000
11119
  content += `def test_${name}_placeholder():
11001
11120
  `;
11002
- if (strict) content += ` raise AssertionError("TODO: implement tests for ${name}")
11121
+ if (strict)
11122
+ content += ` raise AssertionError("TODO: implement tests for ${name}")
11003
11123
 
11004
11124
  `;
11005
- else content += ` pytest.skip("TODO: implement tests for ${name}")
11125
+ else
11126
+ content += ` pytest.skip("TODO: implement tests for ${name}")
11006
11127
 
11007
11128
  `;
11008
11129
  }
@@ -11036,7 +11157,8 @@ var TEST_SKELETONS = {
11036
11157
 
11037
11158
  `;
11038
11159
  for (const exp of exports) {
11039
- if (exp.type === "class") continue;
11160
+ if (exp.type === "class")
11161
+ continue;
11040
11162
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11041
11163
  content += ` // TODO: implement tests for ${exp.name}
11042
11164
  `;
@@ -11052,9 +11174,11 @@ var TEST_SKELETONS = {
11052
11174
  `;
11053
11175
  content += ` // TODO: implement ${caseName}
11054
11176
  `;
11055
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11177
+ if (strict)
11178
+ content += ` throw new Error('TODO: implement ${caseName}');
11056
11179
  `;
11057
- else content += ` expect(true).toBe(true);
11180
+ else
11181
+ content += ` expect(true).toBe(true);
11058
11182
  `;
11059
11183
  content += ` });
11060
11184
 
@@ -11107,7 +11231,8 @@ var TEST_SKELETONS = {
11107
11231
 
11108
11232
  `;
11109
11233
  for (const exp of exports) {
11110
- if (exp.type === "class") continue;
11234
+ if (exp.type === "class")
11235
+ continue;
11111
11236
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11112
11237
  content += ` // TODO: implement tests for ${exp.name}
11113
11238
  `;
@@ -11123,9 +11248,11 @@ var TEST_SKELETONS = {
11123
11248
  `;
11124
11249
  content += ` // TODO: implement ${caseName}
11125
11250
  `;
11126
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11251
+ if (strict)
11252
+ content += ` throw new Error('TODO: implement ${caseName}');
11127
11253
  `;
11128
- else content += ` expect(true).toBe(true);
11254
+ else
11255
+ content += ` expect(true).toBe(true);
11129
11256
  `;
11130
11257
  content += ` });
11131
11258
 
@@ -11178,7 +11305,8 @@ var TEST_SKELETONS = {
11178
11305
 
11179
11306
  `;
11180
11307
  for (const exp of exports) {
11181
- if (exp.type === "class") continue;
11308
+ if (exp.type === "class")
11309
+ continue;
11182
11310
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11183
11311
  content += ` // TODO: implement tests for ${exp.name}
11184
11312
  `;
@@ -11194,9 +11322,11 @@ var TEST_SKELETONS = {
11194
11322
  `;
11195
11323
  content += ` // TODO: implement ${caseName}
11196
11324
  `;
11197
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11325
+ if (strict)
11326
+ content += ` throw new Error('TODO: implement ${caseName}');
11198
11327
  `;
11199
- else content += ` expect(true).toBe(true);
11328
+ else
11329
+ content += ` expect(true).toBe(true);
11200
11330
  `;
11201
11331
  content += ` });
11202
11332
 
@@ -11256,7 +11386,8 @@ var TEST_SKELETONS = {
11256
11386
 
11257
11387
  `;
11258
11388
  for (const exp of exports) {
11259
- if (exp.type === "class") continue;
11389
+ if (exp.type === "class")
11390
+ continue;
11260
11391
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11261
11392
  const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
11262
11393
  content += `// TODO: implement tests for ${exp.name}
@@ -11265,9 +11396,11 @@ var TEST_SKELETONS = {
11265
11396
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11266
11397
  content += `func Test${cap}_${caseFunc}(t *testing.T) {
11267
11398
  `;
11268
- if (strict) content += ` t.Error("TODO: implement ${caseName}")
11399
+ if (strict)
11400
+ content += ` t.Error("TODO: implement ${caseName}")
11269
11401
  `;
11270
- else content += ` t.Skip("TODO: implement ${caseName}")
11402
+ else
11403
+ content += ` t.Skip("TODO: implement ${caseName}")
11271
11404
  `;
11272
11405
  content += `}
11273
11406
 
@@ -11287,9 +11420,11 @@ var TEST_SKELETONS = {
11287
11420
  if (exports.length === 0) {
11288
11421
  content += `func Test${cap}_Placeholder(t *testing.T) {
11289
11422
  `;
11290
- if (strict) content += ` t.Error("TODO: implement tests for ${name}")
11423
+ if (strict)
11424
+ content += ` t.Error("TODO: implement tests for ${name}")
11291
11425
  `;
11292
- else content += ` t.Skip("TODO: implement tests for ${name}")
11426
+ else
11427
+ content += ` t.Skip("TODO: implement tests for ${name}")
11293
11428
  `;
11294
11429
  content += `}
11295
11430
  `;
@@ -11322,9 +11457,11 @@ var TEST_SKELETONS = {
11322
11457
  `;
11323
11458
  content += ` echo "TODO: implement ${caseName}"
11324
11459
  `;
11325
- if (strict) content += ` exit 1
11460
+ if (strict)
11461
+ content += ` exit 1
11326
11462
  `;
11327
- else content += ` echo "SKIP: ${caseName}"
11463
+ else
11464
+ content += ` echo "SKIP: ${caseName}"
11328
11465
  `;
11329
11466
  content += `}
11330
11467
 
@@ -11338,9 +11475,11 @@ var TEST_SKELETONS = {
11338
11475
  if (exports.length === 0) {
11339
11476
  content += `function test_smoke {
11340
11477
  `;
11341
- if (strict) content += ` echo "TODO: implement tests for ${name}" && exit 1
11478
+ if (strict)
11479
+ content += ` echo "TODO: implement tests for ${name}" && exit 1
11342
11480
  `;
11343
- else content += ` echo "TODO: implement tests for ${name}"
11481
+ else
11482
+ content += ` echo "TODO: implement tests for ${name}"
11344
11483
  `;
11345
11484
  content += `}
11346
11485
  `;
@@ -11380,7 +11519,8 @@ mod tests {
11380
11519
 
11381
11520
  `;
11382
11521
  for (const exp of exports) {
11383
- if (exp.type === "class") continue;
11522
+ if (exp.type === "class")
11523
+ continue;
11384
11524
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11385
11525
  content += ` // TODO: implement tests for ${exp.name}
11386
11526
  `;
@@ -11389,9 +11529,11 @@ mod tests {
11389
11529
  content += ` #[test]
11390
11530
  fn test_${caseFunc}() {
11391
11531
  `;
11392
- if (strict) content += ` panic!("TODO: implement ${caseName}");
11532
+ if (strict)
11533
+ content += ` panic!("TODO: implement ${caseName}");
11393
11534
  `;
11394
- else content += ` // TODO: implement ${caseName}
11535
+ else
11536
+ content += ` // TODO: implement ${caseName}
11395
11537
  `;
11396
11538
  content += ` }
11397
11539
 
@@ -11406,9 +11548,11 @@ mod tests {
11406
11548
  content += ` #[test]
11407
11549
  fn ${name}_placeholder() {
11408
11550
  `;
11409
- if (strict) content += ` panic!("TODO: implement tests for ${name}");
11551
+ if (strict)
11552
+ content += ` panic!("TODO: implement tests for ${name}");
11410
11553
  `;
11411
- else content += ` // TODO: implement tests for ${name}
11554
+ else
11555
+ content += ` // TODO: implement tests for ${name}
11412
11556
  `;
11413
11557
  content += ` }
11414
11558
  `;
@@ -11448,7 +11592,8 @@ mod tests {
11448
11592
 
11449
11593
  `;
11450
11594
  for (const exp of exports) {
11451
- if (exp.type === "class") continue;
11595
+ if (exp.type === "class")
11596
+ continue;
11452
11597
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11453
11598
  content += ` # TODO: implement tests for ${exp.name}
11454
11599
  `;
@@ -11456,9 +11601,11 @@ mod tests {
11456
11601
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11457
11602
  content += ` def test_${caseFunc}
11458
11603
  `;
11459
- if (strict) content += ` flunk "TODO: implement ${caseName}"
11604
+ if (strict)
11605
+ content += ` flunk "TODO: implement ${caseName}"
11460
11606
  `;
11461
- else content += ` # TODO: implement ${caseName}
11607
+ else
11608
+ content += ` # TODO: implement ${caseName}
11462
11609
  `;
11463
11610
  content += ` end
11464
11611
 
@@ -11472,9 +11619,11 @@ mod tests {
11472
11619
  if (exports.length === 0) {
11473
11620
  content += ` def test_placeholder
11474
11621
  `;
11475
- if (strict) content += ` flunk "TODO: implement tests for ${name}"
11622
+ if (strict)
11623
+ content += ` flunk "TODO: implement tests for ${name}"
11476
11624
  `;
11477
- else content += ` # TODO: implement tests for ${name}
11625
+ else
11626
+ content += ` # TODO: implement tests for ${name}
11478
11627
  `;
11479
11628
  content += ` end
11480
11629
  `;
@@ -11520,15 +11669,18 @@ mod tests {
11520
11669
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11521
11670
  for (const caseName of cases) {
11522
11671
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11523
- if (!strict) content += ` // @Disabled("TODO")
11672
+ if (!strict)
11673
+ content += ` // @Disabled("TODO")
11524
11674
  `;
11525
11675
  content += ` @Test
11526
11676
  `;
11527
11677
  content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11528
11678
  `;
11529
- if (strict) content += ` fail("TODO: implement ${caseName}");
11679
+ if (strict)
11680
+ content += ` fail("TODO: implement ${caseName}");
11530
11681
  `;
11531
- else content += ` assertTrue(true); // TODO: implement ${caseName}
11682
+ else
11683
+ content += ` assertTrue(true); // TODO: implement ${caseName}
11532
11684
  `;
11533
11685
  content += ` }
11534
11686
 
@@ -11590,15 +11742,18 @@ mod tests {
11590
11742
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11591
11743
  for (const caseName of cases) {
11592
11744
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11593
- if (!strict) content += ` // @Disabled("TODO")
11745
+ if (!strict)
11746
+ content += ` // @Disabled("TODO")
11594
11747
  `;
11595
11748
  content += ` @Test
11596
11749
  `;
11597
11750
  content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11598
11751
  `;
11599
- if (strict) content += ` fail("TODO: implement ${caseName}")
11752
+ if (strict)
11753
+ content += ` fail("TODO: implement ${caseName}")
11600
11754
  `;
11601
- else content += ` assertTrue(true) // TODO: implement ${caseName}
11755
+ else
11756
+ content += ` assertTrue(true) // TODO: implement ${caseName}
11602
11757
  `;
11603
11758
  content += ` }
11604
11759
 
@@ -12476,7 +12631,10 @@ var onToolExecuteAfter = async (input, output) => {
12476
12631
  const optModeFooter = loadSessionOptMode(currentSid + "_opt") || loadOptimizationMode() || "budget";
12477
12632
  const activeSlot = selNow.active_slot || (execution.quality === "brain" ? "brain" : execution.quality === "medium" ? "medium" : "cheap");
12478
12633
  const vibeBrand = resolveBrand(optModeFooter, activeSlot);
12479
- const flashIcon = VIBEOS_API_ENABLED ? " \u26A1" : "";
12634
+ const sessionSlot = loadSessionSlot(currentSid);
12635
+ const displayMode = selNow.optimization_mode || optModeFooter || "auto";
12636
+ const currentSubRegime = loadBlackboxState()?.sessions?.[currentSid]?.sub_regime || classifyTurnSimple2(latestUserIntent || "");
12637
+ const flashIcon = isApiConnected2() ? " \u26A1" : "";
12480
12638
  _footerText = buildFooterLine({
12481
12639
  activeSlot,
12482
12640
  providerLabel: execution.provider_label,
@@ -12484,10 +12642,12 @@ var onToolExecuteAfter = async (input, output) => {
12484
12642
  ltTotal,
12485
12643
  ltTrend: sesTrend || "",
12486
12644
  vibeBrand,
12487
- optMode: optModeFooter,
12645
+ optMode: displayMode,
12488
12646
  flashIcon,
12489
12647
  enfTags,
12490
- vectorChangedSlot: selNow.vector_changed_slot
12648
+ sessionSlot,
12649
+ vectorChangedSlot: selNow.vector_changed_slot,
12650
+ subRegime: currentSubRegime
12491
12651
  }) + "\n\n";
12492
12652
  const footerTarget = _payload(output);
12493
12653
  output.title = _footerText.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.24.3",
3
+ "version": "0.24.6",
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",