vibeostheog 0.24.5 → 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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/vibeOS.js +297 -153
  3. package/package.json +1 -1
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 };
@@ -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();
@@ -9463,7 +9501,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
9463
9501
  }
9464
9502
  }
9465
9503
 
9466
- // src/lib/constants.ts
9504
+ // src/lib/constants.js
9467
9505
  var SAVE_EST = {
9468
9506
  // Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
9469
9507
  WRITE_EDIT: 4e-4,
@@ -9481,7 +9519,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
9481
9519
  var PROTOCOL_MARKER = "[wbp-v1]";
9482
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.";
9483
9521
 
9484
- // src/lib/templates.ts
9522
+ // src/lib/templates.js
9485
9523
  var TEMPLATES = {
9486
9524
  save: {
9487
9525
  tier_bias: "cheap",
@@ -9520,7 +9558,8 @@ var TEMPLATES = {
9520
9558
  var DEFAULT_TEMPLATE = "save";
9521
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;
9522
9560
  function detectSecuritySignal(text) {
9523
- if (!text || typeof text !== "string") return false;
9561
+ if (!text || typeof text !== "string")
9562
+ return false;
9524
9563
  return SEC_KEYWORDS.test(text);
9525
9564
  }
9526
9565
  function detectBudgetSignal(creditPercent) {
@@ -9533,16 +9572,21 @@ function detectStressSpike(stressScore) {
9533
9572
  return delta > 0.3 && stressScore > 0.5;
9534
9573
  }
9535
9574
  function resolveTemplate(prevTemplate, stressScore, userText, creditPercent) {
9536
- if (detectSecuritySignal(userText)) return "security";
9537
- if (detectBudgetSignal(creditPercent)) return "save";
9538
- 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";
9539
9581
  return prevTemplate || DEFAULT_TEMPLATE;
9540
9582
  }
9541
9583
  var _turnCount = 0;
9542
9584
  function shouldInjectTemplate(template, prevTemplate) {
9543
9585
  _turnCount++;
9544
- if (template !== prevTemplate) return true;
9545
- if (_turnCount % 10 === 0) return true;
9586
+ if (template !== prevTemplate)
9587
+ return true;
9588
+ if (_turnCount % 10 === 0)
9589
+ return true;
9546
9590
  return false;
9547
9591
  }
9548
9592
 
@@ -10649,7 +10693,7 @@ import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync9, ex
10649
10693
  import { join as join17, dirname as dirname14, basename as basename9 } from "node:path";
10650
10694
  import { createHash as createHash5 } from "node:crypto";
10651
10695
 
10652
- // src/lib/cost-anomaly.ts
10696
+ // src/lib/cost-anomaly.js
10653
10697
  var COST_WINDOW_SIZE = 20;
10654
10698
  var COST_ANOMALY_THRESHOLD = 3;
10655
10699
  var COST_WARMUP_SAMPLES = 5;
@@ -10660,21 +10704,26 @@ var CostAnomalyDetector = class {
10660
10704
  currentAnomalyCost = 0;
10661
10705
  currentAnomalyMean = 0;
10662
10706
  record(cost) {
10663
- if (this.disabled) return;
10707
+ if (this.disabled)
10708
+ return;
10664
10709
  this.costHistory.push(cost);
10665
10710
  if (this.costHistory.length > COST_WINDOW_SIZE) {
10666
10711
  this.costHistory.shift();
10667
10712
  }
10668
10713
  }
10669
10714
  get mean() {
10670
- if (this.costHistory.length === 0) return 0;
10715
+ if (this.costHistory.length === 0)
10716
+ return 0;
10671
10717
  return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
10672
10718
  }
10673
10719
  checkAnomaly(model, cost) {
10674
- if (this.disabled) return false;
10675
- 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;
10676
10724
  const avg = this.mean;
10677
- if (avg <= 0 || cost <= avg) return false;
10725
+ if (avg <= 0 || cost <= avg)
10726
+ return false;
10678
10727
  const ratio = cost / avg;
10679
10728
  if (ratio > COST_ANOMALY_THRESHOLD) {
10680
10729
  this.currentAnomalyModel = model;
@@ -10696,7 +10745,8 @@ var CostAnomalyDetector = class {
10696
10745
  };
10697
10746
  var _costDetector = null;
10698
10747
  function getCostAnomalyDetector() {
10699
- if (!_costDetector) _costDetector = new CostAnomalyDetector();
10748
+ if (!_costDetector)
10749
+ _costDetector = new CostAnomalyDetector();
10700
10750
  return _costDetector;
10701
10751
  }
10702
10752
 
@@ -10708,9 +10758,10 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync15, appen
10708
10758
  import { join as join16, dirname as dirname13 } from "node:path";
10709
10759
  import { createHash as createHash4 } from "node:crypto";
10710
10760
 
10711
- // src/utils/tdd-helpers.ts
10761
+ // src/utils/tdd-helpers.js
10712
10762
  function extractExports(sourceContent, ext) {
10713
- if (!sourceContent || typeof sourceContent !== "string") return [];
10763
+ if (!sourceContent || typeof sourceContent !== "string")
10764
+ return [];
10714
10765
  const exports = [];
10715
10766
  const seen = /* @__PURE__ */ new Set();
10716
10767
  const add = (name, type = "function") => {
@@ -10721,51 +10772,69 @@ function extractExports(sourceContent, ext) {
10721
10772
  };
10722
10773
  switch (ext) {
10723
10774
  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");
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");
10726
10779
  break;
10727
10780
  }
10728
10781
  case "js":
10729
10782
  case "mjs":
10730
10783
  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]);
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]);
10733
10788
  if (exports.length === 0) {
10734
- 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]);
10735
10791
  }
10736
10792
  break;
10737
10793
  }
10738
10794
  case "ts":
10739
10795
  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");
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");
10743
10802
  break;
10744
10803
  }
10745
10804
  case "go": {
10746
- 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]);
10747
10807
  break;
10748
10808
  }
10749
10809
  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");
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");
10753
10816
  break;
10754
10817
  }
10755
10818
  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");
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");
10758
10823
  break;
10759
10824
  }
10760
10825
  case "java":
10761
10826
  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]);
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]);
10764
10831
  break;
10765
10832
  }
10766
10833
  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]);
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]);
10769
10838
  break;
10770
10839
  }
10771
10840
  }
@@ -10787,7 +10856,8 @@ function generateTestCaseNames(funcName, _type, quality = false) {
10787
10856
  ];
10788
10857
  }
10789
10858
  function inferFunctionParams(sourceContent, funcName) {
10790
- if (!sourceContent || !funcName) return [];
10859
+ if (!sourceContent || !funcName)
10860
+ return [];
10791
10861
  const patterns = [
10792
10862
  new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
10793
10863
  new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
@@ -10800,7 +10870,8 @@ function inferFunctionParams(sourceContent, funcName) {
10800
10870
  if (m) {
10801
10871
  return m[1].split(",").map((s) => {
10802
10872
  const trimmed = s.trim();
10803
- if (!trimmed) return null;
10873
+ if (!trimmed)
10874
+ return null;
10804
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*[,)]))/);
10805
10876
  const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
10806
10877
  const defaultMatch = trimmed.match(/=\s*(.+)$/);
@@ -10816,22 +10887,35 @@ function inferFunctionParams(sourceContent, funcName) {
10816
10887
  return [];
10817
10888
  }
10818
10889
  function inferTypeFromName(paramName, defaultValue) {
10819
- if (!paramName) return "any";
10890
+ if (!paramName)
10891
+ return "any";
10820
10892
  const name = paramName.toLowerCase();
10821
10893
  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";
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";
10835
10919
  return "any";
10836
10920
  }
10837
10921
  function _langComment(lang) {
@@ -10844,14 +10928,22 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10844
10928
  let block = "";
10845
10929
  const testValues = params.map((p) => {
10846
10930
  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";
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";
10855
10947
  return '"test"';
10856
10948
  });
10857
10949
  const args = testValues.join(", ");
@@ -10881,8 +10973,10 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10881
10973
  `;
10882
10974
  const ecArgs = params.map((p) => {
10883
10975
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
10884
- if (t === "string") return '""';
10885
- 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";
10886
10980
  return '"edge"';
10887
10981
  }).join(", ");
10888
10982
  block += `${indent} result = ${funcName}(${ecArgs})
@@ -10920,11 +11014,16 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10920
11014
  `;
10921
11015
  const ecArgsJS = params.map((p) => {
10922
11016
  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 "{}";
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 "{}";
10928
11027
  return "undefined";
10929
11028
  }).join(", ");
10930
11029
  block += `${indent} const result = mod.${funcName}(${ecArgsJS});
@@ -10957,14 +11056,15 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
10957
11056
  return block;
10958
11057
  }
10959
11058
  function isSkeletonUseless(content) {
10960
- if (!content) return true;
11059
+ if (!content)
11060
+ return true;
10961
11061
  const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
10962
11062
  const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
10963
11063
  const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
10964
11064
  return meaningfulLines.length < 2;
10965
11065
  }
10966
11066
 
10967
- // src/lib/test-skeletons.ts
11067
+ // src/lib/test-skeletons.js
10968
11068
  var TEST_SKELETONS = {
10969
11069
  py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
10970
11070
  const moduleImport = name.replace(/-/g, "_");
@@ -10992,7 +11092,8 @@ var TEST_SKELETONS = {
10992
11092
 
10993
11093
  `;
10994
11094
  for (const exp of exports) {
10995
- if (exp.type === "class") continue;
11095
+ if (exp.type === "class")
11096
+ continue;
10996
11097
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
10997
11098
  content += `# TODO: implement tests for ${exp.name}
10998
11099
  `;
@@ -11000,10 +11101,12 @@ var TEST_SKELETONS = {
11000
11101
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11001
11102
  content += `def test_${caseFunc}():
11002
11103
  `;
11003
- if (strict) content += ` raise AssertionError("TODO: implement ${caseName}")
11104
+ if (strict)
11105
+ content += ` raise AssertionError("TODO: implement ${caseName}")
11004
11106
 
11005
11107
  `;
11006
- else content += ` pytest.skip("TODO: implement ${caseName}")
11108
+ else
11109
+ content += ` pytest.skip("TODO: implement ${caseName}")
11007
11110
 
11008
11111
  `;
11009
11112
  }
@@ -11015,10 +11118,12 @@ var TEST_SKELETONS = {
11015
11118
  if (exports.length === 0) {
11016
11119
  content += `def test_${name}_placeholder():
11017
11120
  `;
11018
- if (strict) content += ` raise AssertionError("TODO: implement tests for ${name}")
11121
+ if (strict)
11122
+ content += ` raise AssertionError("TODO: implement tests for ${name}")
11019
11123
 
11020
11124
  `;
11021
- else content += ` pytest.skip("TODO: implement tests for ${name}")
11125
+ else
11126
+ content += ` pytest.skip("TODO: implement tests for ${name}")
11022
11127
 
11023
11128
  `;
11024
11129
  }
@@ -11052,7 +11157,8 @@ var TEST_SKELETONS = {
11052
11157
 
11053
11158
  `;
11054
11159
  for (const exp of exports) {
11055
- if (exp.type === "class") continue;
11160
+ if (exp.type === "class")
11161
+ continue;
11056
11162
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11057
11163
  content += ` // TODO: implement tests for ${exp.name}
11058
11164
  `;
@@ -11068,9 +11174,11 @@ var TEST_SKELETONS = {
11068
11174
  `;
11069
11175
  content += ` // TODO: implement ${caseName}
11070
11176
  `;
11071
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11177
+ if (strict)
11178
+ content += ` throw new Error('TODO: implement ${caseName}');
11072
11179
  `;
11073
- else content += ` expect(true).toBe(true);
11180
+ else
11181
+ content += ` expect(true).toBe(true);
11074
11182
  `;
11075
11183
  content += ` });
11076
11184
 
@@ -11123,7 +11231,8 @@ var TEST_SKELETONS = {
11123
11231
 
11124
11232
  `;
11125
11233
  for (const exp of exports) {
11126
- if (exp.type === "class") continue;
11234
+ if (exp.type === "class")
11235
+ continue;
11127
11236
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11128
11237
  content += ` // TODO: implement tests for ${exp.name}
11129
11238
  `;
@@ -11139,9 +11248,11 @@ var TEST_SKELETONS = {
11139
11248
  `;
11140
11249
  content += ` // TODO: implement ${caseName}
11141
11250
  `;
11142
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11251
+ if (strict)
11252
+ content += ` throw new Error('TODO: implement ${caseName}');
11143
11253
  `;
11144
- else content += ` expect(true).toBe(true);
11254
+ else
11255
+ content += ` expect(true).toBe(true);
11145
11256
  `;
11146
11257
  content += ` });
11147
11258
 
@@ -11194,7 +11305,8 @@ var TEST_SKELETONS = {
11194
11305
 
11195
11306
  `;
11196
11307
  for (const exp of exports) {
11197
- if (exp.type === "class") continue;
11308
+ if (exp.type === "class")
11309
+ continue;
11198
11310
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11199
11311
  content += ` // TODO: implement tests for ${exp.name}
11200
11312
  `;
@@ -11210,9 +11322,11 @@ var TEST_SKELETONS = {
11210
11322
  `;
11211
11323
  content += ` // TODO: implement ${caseName}
11212
11324
  `;
11213
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11325
+ if (strict)
11326
+ content += ` throw new Error('TODO: implement ${caseName}');
11214
11327
  `;
11215
- else content += ` expect(true).toBe(true);
11328
+ else
11329
+ content += ` expect(true).toBe(true);
11216
11330
  `;
11217
11331
  content += ` });
11218
11332
 
@@ -11272,7 +11386,8 @@ var TEST_SKELETONS = {
11272
11386
 
11273
11387
  `;
11274
11388
  for (const exp of exports) {
11275
- if (exp.type === "class") continue;
11389
+ if (exp.type === "class")
11390
+ continue;
11276
11391
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11277
11392
  const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
11278
11393
  content += `// TODO: implement tests for ${exp.name}
@@ -11281,9 +11396,11 @@ var TEST_SKELETONS = {
11281
11396
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11282
11397
  content += `func Test${cap}_${caseFunc}(t *testing.T) {
11283
11398
  `;
11284
- if (strict) content += ` t.Error("TODO: implement ${caseName}")
11399
+ if (strict)
11400
+ content += ` t.Error("TODO: implement ${caseName}")
11285
11401
  `;
11286
- else content += ` t.Skip("TODO: implement ${caseName}")
11402
+ else
11403
+ content += ` t.Skip("TODO: implement ${caseName}")
11287
11404
  `;
11288
11405
  content += `}
11289
11406
 
@@ -11303,9 +11420,11 @@ var TEST_SKELETONS = {
11303
11420
  if (exports.length === 0) {
11304
11421
  content += `func Test${cap}_Placeholder(t *testing.T) {
11305
11422
  `;
11306
- if (strict) content += ` t.Error("TODO: implement tests for ${name}")
11423
+ if (strict)
11424
+ content += ` t.Error("TODO: implement tests for ${name}")
11307
11425
  `;
11308
- else content += ` t.Skip("TODO: implement tests for ${name}")
11426
+ else
11427
+ content += ` t.Skip("TODO: implement tests for ${name}")
11309
11428
  `;
11310
11429
  content += `}
11311
11430
  `;
@@ -11338,9 +11457,11 @@ var TEST_SKELETONS = {
11338
11457
  `;
11339
11458
  content += ` echo "TODO: implement ${caseName}"
11340
11459
  `;
11341
- if (strict) content += ` exit 1
11460
+ if (strict)
11461
+ content += ` exit 1
11342
11462
  `;
11343
- else content += ` echo "SKIP: ${caseName}"
11463
+ else
11464
+ content += ` echo "SKIP: ${caseName}"
11344
11465
  `;
11345
11466
  content += `}
11346
11467
 
@@ -11354,9 +11475,11 @@ var TEST_SKELETONS = {
11354
11475
  if (exports.length === 0) {
11355
11476
  content += `function test_smoke {
11356
11477
  `;
11357
- if (strict) content += ` echo "TODO: implement tests for ${name}" && exit 1
11478
+ if (strict)
11479
+ content += ` echo "TODO: implement tests for ${name}" && exit 1
11358
11480
  `;
11359
- else content += ` echo "TODO: implement tests for ${name}"
11481
+ else
11482
+ content += ` echo "TODO: implement tests for ${name}"
11360
11483
  `;
11361
11484
  content += `}
11362
11485
  `;
@@ -11396,7 +11519,8 @@ mod tests {
11396
11519
 
11397
11520
  `;
11398
11521
  for (const exp of exports) {
11399
- if (exp.type === "class") continue;
11522
+ if (exp.type === "class")
11523
+ continue;
11400
11524
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11401
11525
  content += ` // TODO: implement tests for ${exp.name}
11402
11526
  `;
@@ -11405,9 +11529,11 @@ mod tests {
11405
11529
  content += ` #[test]
11406
11530
  fn test_${caseFunc}() {
11407
11531
  `;
11408
- if (strict) content += ` panic!("TODO: implement ${caseName}");
11532
+ if (strict)
11533
+ content += ` panic!("TODO: implement ${caseName}");
11409
11534
  `;
11410
- else content += ` // TODO: implement ${caseName}
11535
+ else
11536
+ content += ` // TODO: implement ${caseName}
11411
11537
  `;
11412
11538
  content += ` }
11413
11539
 
@@ -11422,9 +11548,11 @@ mod tests {
11422
11548
  content += ` #[test]
11423
11549
  fn ${name}_placeholder() {
11424
11550
  `;
11425
- if (strict) content += ` panic!("TODO: implement tests for ${name}");
11551
+ if (strict)
11552
+ content += ` panic!("TODO: implement tests for ${name}");
11426
11553
  `;
11427
- else content += ` // TODO: implement tests for ${name}
11554
+ else
11555
+ content += ` // TODO: implement tests for ${name}
11428
11556
  `;
11429
11557
  content += ` }
11430
11558
  `;
@@ -11464,7 +11592,8 @@ mod tests {
11464
11592
 
11465
11593
  `;
11466
11594
  for (const exp of exports) {
11467
- if (exp.type === "class") continue;
11595
+ if (exp.type === "class")
11596
+ continue;
11468
11597
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11469
11598
  content += ` # TODO: implement tests for ${exp.name}
11470
11599
  `;
@@ -11472,9 +11601,11 @@ mod tests {
11472
11601
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11473
11602
  content += ` def test_${caseFunc}
11474
11603
  `;
11475
- if (strict) content += ` flunk "TODO: implement ${caseName}"
11604
+ if (strict)
11605
+ content += ` flunk "TODO: implement ${caseName}"
11476
11606
  `;
11477
- else content += ` # TODO: implement ${caseName}
11607
+ else
11608
+ content += ` # TODO: implement ${caseName}
11478
11609
  `;
11479
11610
  content += ` end
11480
11611
 
@@ -11488,9 +11619,11 @@ mod tests {
11488
11619
  if (exports.length === 0) {
11489
11620
  content += ` def test_placeholder
11490
11621
  `;
11491
- if (strict) content += ` flunk "TODO: implement tests for ${name}"
11622
+ if (strict)
11623
+ content += ` flunk "TODO: implement tests for ${name}"
11492
11624
  `;
11493
- else content += ` # TODO: implement tests for ${name}
11625
+ else
11626
+ content += ` # TODO: implement tests for ${name}
11494
11627
  `;
11495
11628
  content += ` end
11496
11629
  `;
@@ -11536,15 +11669,18 @@ mod tests {
11536
11669
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11537
11670
  for (const caseName of cases) {
11538
11671
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11539
- if (!strict) content += ` // @Disabled("TODO")
11672
+ if (!strict)
11673
+ content += ` // @Disabled("TODO")
11540
11674
  `;
11541
11675
  content += ` @Test
11542
11676
  `;
11543
11677
  content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11544
11678
  `;
11545
- if (strict) content += ` fail("TODO: implement ${caseName}");
11679
+ if (strict)
11680
+ content += ` fail("TODO: implement ${caseName}");
11546
11681
  `;
11547
- else content += ` assertTrue(true); // TODO: implement ${caseName}
11682
+ else
11683
+ content += ` assertTrue(true); // TODO: implement ${caseName}
11548
11684
  `;
11549
11685
  content += ` }
11550
11686
 
@@ -11606,15 +11742,18 @@ mod tests {
11606
11742
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11607
11743
  for (const caseName of cases) {
11608
11744
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11609
- if (!strict) content += ` // @Disabled("TODO")
11745
+ if (!strict)
11746
+ content += ` // @Disabled("TODO")
11610
11747
  `;
11611
11748
  content += ` @Test
11612
11749
  `;
11613
11750
  content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
11614
11751
  `;
11615
- if (strict) content += ` fail("TODO: implement ${caseName}")
11752
+ if (strict)
11753
+ content += ` fail("TODO: implement ${caseName}")
11616
11754
  `;
11617
- else content += ` assertTrue(true) // TODO: implement ${caseName}
11755
+ else
11756
+ content += ` assertTrue(true) // TODO: implement ${caseName}
11618
11757
  `;
11619
11758
  content += ` }
11620
11759
 
@@ -12492,7 +12631,10 @@ var onToolExecuteAfter = async (input, output) => {
12492
12631
  const optModeFooter = loadSessionOptMode(currentSid + "_opt") || loadOptimizationMode() || "budget";
12493
12632
  const activeSlot = selNow.active_slot || (execution.quality === "brain" ? "brain" : execution.quality === "medium" ? "medium" : "cheap");
12494
12633
  const vibeBrand = resolveBrand(optModeFooter, activeSlot);
12495
- 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" : "";
12496
12638
  _footerText = buildFooterLine({
12497
12639
  activeSlot,
12498
12640
  providerLabel: execution.provider_label,
@@ -12500,10 +12642,12 @@ var onToolExecuteAfter = async (input, output) => {
12500
12642
  ltTotal,
12501
12643
  ltTrend: sesTrend || "",
12502
12644
  vibeBrand,
12503
- optMode: optModeFooter,
12645
+ optMode: displayMode,
12504
12646
  flashIcon,
12505
12647
  enfTags,
12506
- vectorChangedSlot: selNow.vector_changed_slot
12648
+ sessionSlot,
12649
+ vectorChangedSlot: selNow.vector_changed_slot,
12650
+ subRegime: currentSubRegime
12507
12651
  }) + "\n\n";
12508
12652
  const footerTarget = _payload(output);
12509
12653
  output.title = _footerText.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.24.5",
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",