vibeostheog 0.24.8 → 0.24.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/vibeOS.js +149 -274
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 0.24.12
2
+ - feat: smooth delegation UX — conversational reasoning over error injection
3
+ - fix: write npm auth for github release publish
4
+ - fix: reset api fallback on token refresh (#138)
5
+ - fix: _prevBlackboxState -> _latestBlackboxState, update pattern key test
6
+ - fix: sync-ts-build was cleaning JS artifacts without copying compiled output back
7
+ - fix: forensic anti-lying + quality enforcement pipeline
8
+ - docs: add cross-project index, DEV ONLY markers, ESLint cleanup
9
+ - test: add 13 cascade integration tests for forensic quality pipeline
10
+ - chore: sync package version to latest github release
11
+ - chore: sync package version to latest release
12
+ Merge pull request #136 from DrunkkToys/release/v0.24.8-merge
13
+
14
+
1
15
  ## 0.24.5
2
16
  - fix: cap saveEst at to prevent runaway pricing data corruption
3
17
  - chore: v0.24.4
package/dist/vibeOS.js CHANGED
@@ -2152,9 +2152,13 @@ function setApiToken(newToken) {
2152
2152
  VIBEOS_API_TOKEN = normalizeApiToken(newToken, EMBEDDED_API_TOKEN);
2153
2153
  VIBEOS_API_BOOTSTRAP_TOKEN = readBootstrapTokenFromDisk() || VIBEOS_API_BOOTSTRAP_TOKEN;
2154
2154
  VIBEOS_API_ENABLED = process.env.VIBEOS_API_ENABLED !== "false" && (!!VIBEOS_API_TOKEN || !!VIBEOS_API_BOOTSTRAP_TOKEN);
2155
+ _apiClient = null;
2156
+ _apiFallbackMode = false;
2157
+ _apiFallbackSince = null;
2155
2158
  persistPrimaryApiEnvState({ token: VIBEOS_API_TOKEN, disabled: false });
2156
2159
  if (_anomalyDetector)
2157
2160
  _anomalyDetector.reset();
2161
+ resetApiConnection();
2158
2162
  console.error("[vibeOS] API token updated via setApiToken");
2159
2163
  } catch (e) {
2160
2164
  console.error("[vibeOS] Failed to update API token:", e.message);
@@ -2529,56 +2533,42 @@ function writeSessionOptMode(sid, mode) {
2529
2533
  }
2530
2534
  }
2531
2535
 
2532
- // src/lib/pattern-helpers.js
2536
+ // src/lib/pattern-helpers.ts
2533
2537
  import { relative, basename as basename2 } from "node:path";
2534
2538
  function normalizeObservedPath(filePath, directory3) {
2535
- if (!filePath || typeof filePath !== "string")
2536
- return "unknown";
2539
+ if (!filePath || typeof filePath !== "string") return "unknown";
2537
2540
  let p = filePath;
2538
2541
  try {
2539
2542
  if (directory3 && p.startsWith("/")) {
2540
2543
  const rel = relative(directory3, p);
2541
- if (rel && !rel.startsWith("..") && !rel.startsWith("/"))
2542
- p = rel;
2544
+ if (rel && !rel.startsWith("..") && !rel.startsWith("/")) p = rel;
2543
2545
  }
2544
2546
  } catch {
2545
2547
  }
2546
2548
  p = p.replace(/\\/g, "/").replace(/^\.\/+/, "");
2547
- if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p))
2548
- return p;
2549
+ if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p)) return p;
2549
2550
  const m = p.match(/\.([a-z0-9]+)$/i);
2550
- if (p.startsWith("src/") && m)
2551
- return `src/*.${m[1].toLowerCase()}`;
2552
- if (p.startsWith("tests/") && m)
2553
- return `tests/*.${m[1].toLowerCase()}`;
2551
+ if (p.startsWith("src/") && m) return `src/*.${m[1].toLowerCase()}`;
2552
+ if (p.startsWith("tests/") && m) return `tests/*.${m[1].toLowerCase()}`;
2554
2553
  return basename2(p) || "unknown";
2555
2554
  }
2556
2555
  function commandFamily(command) {
2557
2556
  const c = String(command || "").trim().toLowerCase();
2558
- if (!c)
2559
- return "unknown";
2560
- if (/\bnode\s+--check\b/.test(c))
2561
- return "syntax-check";
2562
- if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c))
2563
- return "typecheck";
2564
- if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c))
2565
- return "test";
2566
- if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c))
2567
- return "build";
2568
- if (/\bgit\s+status\b/.test(c))
2569
- return "git-status";
2570
- if (/\bgit\s+commit\b/.test(c))
2571
- return "git-commit";
2557
+ if (!c) return "unknown";
2558
+ if (/\bnode\s+--check\b/.test(c)) return "syntax-check";
2559
+ if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c)) return "typecheck";
2560
+ if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c)) return "test";
2561
+ if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c)) return "build";
2562
+ if (/\bgit\s+status\b/.test(c)) return "git-status";
2563
+ if (/\bgit\s+commit\b/.test(c)) return "git-commit";
2572
2564
  const first = c.replace(/^[a-z_][a-z0-9_]*=\S+\s+/g, "").split(/\s+/)[0];
2573
2565
  return /^[a-z0-9._/-]{1,30}$/.test(first) ? first : "command";
2574
2566
  }
2575
2567
  function commandFailed(output) {
2576
2568
  const code = output?.exitCode ?? output?.statusCode ?? output?.code;
2577
- if (Number.isFinite(Number(code)) && Number(code) !== 0)
2578
- return true;
2569
+ if (Number.isFinite(Number(code)) && Number(code) !== 0) return true;
2579
2570
  const raw = output?.result ?? output?.text ?? output?.content ?? output?.data ?? "";
2580
- if (typeof raw !== "string")
2581
- return false;
2571
+ if (typeof raw !== "string") return false;
2582
2572
  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);
2583
2573
  }
2584
2574
  function mergeProjectBucket(dst, src) {
@@ -2595,8 +2585,7 @@ function mergeProjectBucket(dst, src) {
2595
2585
  row.sessions = [.../* @__PURE__ */ new Set([...row.sessions || [], ...v?.sessions || []])].slice(-10);
2596
2586
  row.lastSeen = [row.lastSeen, v?.lastSeen].filter(Boolean).sort().slice(-1)[0] || null;
2597
2587
  row.summary = row.summary || v?.summary || "";
2598
- if (v?.kind)
2599
- row.kind = v.kind;
2588
+ if (v?.kind) row.kind = v.kind;
2600
2589
  out[key] = row;
2601
2590
  }
2602
2591
  }
@@ -2615,11 +2604,9 @@ function mergeProjectBucket(dst, src) {
2615
2604
  };
2616
2605
  }
2617
2606
  function _pruneOldSessions(state) {
2618
- if (!state?.sessions)
2619
- return;
2607
+ if (!state?.sessions) return;
2620
2608
  const entries = Object.entries(state.sessions);
2621
- if (entries.length <= 30)
2622
- return;
2609
+ if (entries.length <= 30) return;
2623
2610
  entries.sort((a, b) => {
2624
2611
  const da = a[1]?.started || a[1]?.last_costed || "";
2625
2612
  const db = b[1]?.started || b[1]?.last_costed || "";
@@ -9456,7 +9443,7 @@ import { readFileSync as readFileSync13, writeFileSync as writeFileSync12, appen
9456
9443
  import { join as join14, dirname as dirname10, basename as basename6 } from "node:path";
9457
9444
  import { createHash as createHash3 } from "node:crypto";
9458
9445
 
9459
- // src/lib/mode-policy.js
9446
+ // src/lib/mode-policy.ts
9460
9447
  var STRESS_QUALITY_THRESHOLD = 1.5;
9461
9448
  var BASELINE_MODE = "budget";
9462
9449
  var LOOP_REGIMES = /* @__PURE__ */ new Set(["LOOPING", "DIVERGENT"]);
@@ -9464,8 +9451,7 @@ var QUALITY_REGIMES = /* @__PURE__ */ new Set(["CONVERGING", "CLOSED"]);
9464
9451
  var MANUAL_MODES = /* @__PURE__ */ new Set(["balanced", "quality", "speed", "longrun", "vibemax", "vibeqmax", "vibeultrax"]);
9465
9452
  function normalizeMode(mode) {
9466
9453
  const normalized = String(mode || BASELINE_MODE).toLowerCase();
9467
- if (normalized === "auto" || normalized === "")
9468
- return BASELINE_MODE;
9454
+ if (normalized === "auto" || normalized === "") return BASELINE_MODE;
9469
9455
  if (normalized === "budget" || normalized === "quality" || normalized === "speed" || normalized === "longrun" || normalized === "balanced" || normalized === "vibemax" || normalized === "vibeqmax" || normalized === "vibeultrax") {
9470
9456
  return normalized;
9471
9457
  }
@@ -9478,12 +9464,9 @@ function isManualOverride(mode) {
9478
9464
  return MANUAL_MODES.has(normalizeMode(mode));
9479
9465
  }
9480
9466
  function chooseEpisodeMode(regime, suggestedMode, stress) {
9481
- if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax")
9482
- return suggestedMode;
9483
- if (LOOP_REGIMES.has(regime) || suggestedMode === "speed")
9484
- return "speed";
9485
- if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality")
9486
- return "quality";
9467
+ if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax") return suggestedMode;
9468
+ if (LOOP_REGIMES.has(regime) || suggestedMode === "speed") return "speed";
9469
+ if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality") return "quality";
9487
9470
  return stress > STRESS_QUALITY_THRESHOLD ? "quality" : "budget";
9488
9471
  }
9489
9472
  function defaultPolicy() {
@@ -9504,19 +9487,15 @@ function defaultPolicy() {
9504
9487
  }
9505
9488
  function modeToSlot(mode) {
9506
9489
  const normalized = normalizeMode(mode);
9507
- if (normalized === "speed")
9508
- return "medium";
9509
- if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax")
9510
- return "brain";
9490
+ if (normalized === "speed") return "medium";
9491
+ if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax") return "brain";
9511
9492
  return "cheap";
9512
9493
  }
9513
9494
  function loadSessionPolicy() {
9514
9495
  const state = loadBlackboxState();
9515
- if (!state.sessions || typeof state.sessions !== "object")
9516
- state.sessions = {};
9496
+ if (!state.sessions || typeof state.sessions !== "object") state.sessions = {};
9517
9497
  const sid = _OC_SID;
9518
- if (!state.sessions[sid] || typeof state.sessions[sid] !== "object")
9519
- state.sessions[sid] = {};
9498
+ if (!state.sessions[sid] || typeof state.sessions[sid] !== "object") state.sessions[sid] = {};
9520
9499
  const session = state.sessions[sid];
9521
9500
  if (!session.mode_policy || typeof session.mode_policy !== "object") {
9522
9501
  session.mode_policy = defaultPolicy();
@@ -9644,7 +9623,7 @@ function recordBudgetFirstOutcome(input = {}) {
9644
9623
  import { join as join13 } from "node:path";
9645
9624
  import { writeFileSync as writeFileSync11 } from "node:fs";
9646
9625
 
9647
- // src/lib/text-compress.js
9626
+ // src/lib/text-compress.ts
9648
9627
  var VERBOSE_LINE_RE = [
9649
9628
  /^[\s#*/\\\-_=+|~:;'"`@\$%^&<>{}\[\]()!?.,0-9]+$/,
9650
9629
  /^(Filed|Created|Modified|Deleted|Updated|Renamed|Copied|Moved|Changed):/,
@@ -9661,15 +9640,12 @@ function extractBulletLines(lines, targetChars, minLines) {
9661
9640
  const keyLines = [];
9662
9641
  const otherLines = [];
9663
9642
  for (const line of lines) {
9664
- if (BULLET_PATTERNS.some((re) => re.test(line)))
9665
- keyLines.push(line);
9666
- else
9667
- otherLines.push(line);
9643
+ if (BULLET_PATTERNS.some((re) => re.test(line))) keyLines.push(line);
9644
+ else otherLines.push(line);
9668
9645
  }
9669
9646
  const selected = [...keyLines];
9670
9647
  for (const line of otherLines) {
9671
- if (selected.length >= minLines && selected.join("\n").length >= targetChars)
9672
- break;
9648
+ if (selected.length >= minLines && selected.join("\n").length >= targetChars) break;
9673
9649
  selected.push(line);
9674
9650
  }
9675
9651
  while (selected.length > minLines && selected.join("\n").length > targetChars * 2) {
@@ -9678,8 +9654,7 @@ function extractBulletLines(lines, targetChars, minLines) {
9678
9654
  return selected;
9679
9655
  }
9680
9656
  function compressText(text) {
9681
- if (!text || typeof text !== "string")
9682
- return text;
9657
+ if (!text || typeof text !== "string") return text;
9683
9658
  let lines = text.split("\n");
9684
9659
  let removed = 0;
9685
9660
  const out = [];
@@ -9692,16 +9667,14 @@ function compressText(text) {
9692
9667
  break;
9693
9668
  }
9694
9669
  }
9695
- if (!skip)
9696
- out.push(line);
9670
+ if (!skip) out.push(line);
9697
9671
  }
9698
9672
  const collapsed = [];
9699
9673
  let blanks = 0;
9700
9674
  for (const line of out) {
9701
9675
  if (line.trim() === "") {
9702
9676
  blanks++;
9703
- if (blanks <= 2)
9704
- collapsed.push(line);
9677
+ if (blanks <= 2) collapsed.push(line);
9705
9678
  } else {
9706
9679
  blanks = 0;
9707
9680
  collapsed.push(line);
@@ -9709,7 +9682,10 @@ function compressText(text) {
9709
9682
  }
9710
9683
  let result = collapsed.join("\n").trim();
9711
9684
  if (result.length > COMPRESS_THRESHOLD) {
9712
- const targetChars = Math.max(Math.round(result.length * COMPRESS_RATIO), COMPRESS_THRESHOLD);
9685
+ const targetChars = Math.max(
9686
+ Math.round(result.length * COMPRESS_RATIO),
9687
+ COMPRESS_THRESHOLD
9688
+ );
9713
9689
  const minLines = Math.max(1, Math.round(collapsed.length * MIN_KEPT_LINES_RATIO));
9714
9690
  const bulletLines = extractBulletLines(collapsed, targetChars, minLines);
9715
9691
  result = bulletLines.join("\n").trim();
@@ -10024,7 +10000,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
10024
10000
  }
10025
10001
  }
10026
10002
 
10027
- // src/lib/constants.js
10003
+ // src/lib/constants.ts
10028
10004
  var SAVE_EST = {
10029
10005
  // Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
10030
10006
  WRITE_EDIT: 4e-4,
@@ -10042,7 +10018,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
10042
10018
  var PROTOCOL_MARKER = "[wbp-v1]";
10043
10019
  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.";
10044
10020
 
10045
- // src/lib/templates.js
10021
+ // src/lib/templates.ts
10046
10022
  var TEMPLATES = {
10047
10023
  save: {
10048
10024
  tier_bias: "cheap",
@@ -10092,8 +10068,7 @@ var TEMPLATES = {
10092
10068
  var DEFAULT_TEMPLATE = "save";
10093
10069
  var SEC_KEYWORDS = /\b(security|vuln|exploit|injection|xss|csrf|secret|credential|token leak|auth bypass|privacy|breach|backdoor|sql injection|cve)\b/i;
10094
10070
  function detectSecuritySignal(text) {
10095
- if (!text || typeof text !== "string")
10096
- return false;
10071
+ if (!text || typeof text !== "string") return false;
10097
10072
  return SEC_KEYWORDS.test(text);
10098
10073
  }
10099
10074
  function detectBudgetSignal(creditPercent) {
@@ -10106,25 +10081,20 @@ function detectStressSpike(stressScore) {
10106
10081
  return delta > 0.3 && stressScore > 0.5;
10107
10082
  }
10108
10083
  function resolveTemplate(prevTemplate, stressScore, userText, creditPercent, subRegime) {
10109
- if (detectSecuritySignal(userText))
10110
- return "security";
10084
+ if (detectSecuritySignal(userText)) return "security";
10111
10085
  if (detectBudgetSignal(creditPercent)) {
10112
10086
  const regime = String(subRegime || "").toUpperCase();
10113
- if (regime === "LOOPING" || regime === "DIVERGENT")
10114
- return "speed";
10087
+ if (regime === "LOOPING" || regime === "DIVERGENT") return "speed";
10115
10088
  return "save";
10116
10089
  }
10117
- if (detectStressSpike(stressScore))
10118
- return "quality";
10090
+ if (detectStressSpike(stressScore)) return "quality";
10119
10091
  return prevTemplate || DEFAULT_TEMPLATE;
10120
10092
  }
10121
10093
  var _turnCount = 0;
10122
10094
  function shouldInjectTemplate(template, prevTemplate) {
10123
10095
  _turnCount++;
10124
- if (template !== prevTemplate)
10125
- return true;
10126
- if (_turnCount % 10 === 0)
10127
- return true;
10096
+ if (template !== prevTemplate) return true;
10097
+ if (_turnCount % 10 === 0) return true;
10128
10098
  return false;
10129
10099
  }
10130
10100
 
@@ -11313,7 +11283,7 @@ import { writeFileSync as writeFileSync14, appendFileSync as appendFileSync8, ex
11313
11283
  import { join as join17, dirname as dirname12, basename as basename7 } from "node:path";
11314
11284
  import { createHash as createHash5 } from "node:crypto";
11315
11285
 
11316
- // src/lib/cost-anomaly.js
11286
+ // src/lib/cost-anomaly.ts
11317
11287
  var COST_WINDOW_SIZE = 20;
11318
11288
  var COST_ANOMALY_THRESHOLD = 3;
11319
11289
  var COST_WARMUP_SAMPLES = 5;
@@ -11324,26 +11294,21 @@ var CostAnomalyDetector = class {
11324
11294
  currentAnomalyCost = 0;
11325
11295
  currentAnomalyMean = 0;
11326
11296
  record(cost) {
11327
- if (this.disabled)
11328
- return;
11297
+ if (this.disabled) return;
11329
11298
  this.costHistory.push(cost);
11330
11299
  if (this.costHistory.length > COST_WINDOW_SIZE) {
11331
11300
  this.costHistory.shift();
11332
11301
  }
11333
11302
  }
11334
11303
  get mean() {
11335
- if (this.costHistory.length === 0)
11336
- return 0;
11304
+ if (this.costHistory.length === 0) return 0;
11337
11305
  return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
11338
11306
  }
11339
11307
  checkAnomaly(model, cost) {
11340
- if (this.disabled)
11341
- return false;
11342
- if (this.costHistory.length < COST_WARMUP_SAMPLES)
11343
- return false;
11308
+ if (this.disabled) return false;
11309
+ if (this.costHistory.length < COST_WARMUP_SAMPLES) return false;
11344
11310
  const avg = this.mean;
11345
- if (avg <= 0 || cost <= avg)
11346
- return false;
11311
+ if (avg <= 0 || cost <= avg) return false;
11347
11312
  const ratio = cost / avg;
11348
11313
  if (ratio > COST_ANOMALY_THRESHOLD) {
11349
11314
  this.currentAnomalyModel = model;
@@ -11365,8 +11330,7 @@ var CostAnomalyDetector = class {
11365
11330
  };
11366
11331
  var _costDetector = null;
11367
11332
  function getCostAnomalyDetector() {
11368
- if (!_costDetector)
11369
- _costDetector = new CostAnomalyDetector();
11333
+ if (!_costDetector) _costDetector = new CostAnomalyDetector();
11370
11334
  return _costDetector;
11371
11335
  }
11372
11336
 
@@ -11378,10 +11342,9 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, appen
11378
11342
  import { join as join16, dirname as dirname11 } from "node:path";
11379
11343
  import { createHash as createHash4 } from "node:crypto";
11380
11344
 
11381
- // src/utils/tdd-helpers.js
11345
+ // src/utils/tdd-helpers.ts
11382
11346
  function extractExports(sourceContent, ext) {
11383
- if (!sourceContent || typeof sourceContent !== "string")
11384
- return [];
11347
+ if (!sourceContent || typeof sourceContent !== "string") return [];
11385
11348
  const exports = [];
11386
11349
  const seen = /* @__PURE__ */ new Set();
11387
11350
  const add = (name, type = "function") => {
@@ -11392,69 +11355,51 @@ function extractExports(sourceContent, ext) {
11392
11355
  };
11393
11356
  switch (ext) {
11394
11357
  case "py": {
11395
- for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
11396
- add(m[1]);
11397
- for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm))
11398
- add(m[1], "class");
11358
+ for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm)) add(m[1]);
11359
+ for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm)) add(m[1], "class");
11399
11360
  break;
11400
11361
  }
11401
11362
  case "js":
11402
11363
  case "mjs":
11403
11364
  case "jsx": {
11404
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
11405
- add(m[1]);
11406
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g))
11407
- add(m[1]);
11365
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11366
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g)) add(m[1]);
11408
11367
  if (exports.length === 0) {
11409
- for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
11410
- add(m[1]);
11368
+ for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm)) add(m[1]);
11411
11369
  }
11412
11370
  break;
11413
11371
  }
11414
11372
  case "ts":
11415
11373
  case "tsx": {
11416
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
11417
- add(m[1]);
11418
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g))
11419
- add(m[1]);
11420
- for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g))
11421
- add(m[1], "class");
11374
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11375
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g)) add(m[1]);
11376
+ for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g)) add(m[1], "class");
11422
11377
  break;
11423
11378
  }
11424
11379
  case "go": {
11425
- for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
11426
- add(m[1]);
11380
+ for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g)) add(m[1]);
11427
11381
  break;
11428
11382
  }
11429
11383
  case "rs": {
11430
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
11431
- add(m[1]);
11432
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g))
11433
- add(m[1]);
11434
- for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g))
11435
- add(m[1], "struct");
11384
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g)) add(m[1]);
11385
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g)) add(m[1]);
11386
+ for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g)) add(m[1], "struct");
11436
11387
  break;
11437
11388
  }
11438
11389
  case "rb": {
11439
- for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
11440
- add(m[1]);
11441
- for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g))
11442
- add(m[1], "class");
11390
+ for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g)) add(m[1]);
11391
+ for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g)) add(m[1], "class");
11443
11392
  break;
11444
11393
  }
11445
11394
  case "java":
11446
11395
  case "kt": {
11447
- for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
11448
- add(m[1]);
11449
- for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g))
11450
- add(m[1]);
11396
+ for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11397
+ for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11451
11398
  break;
11452
11399
  }
11453
11400
  case "sh": {
11454
- for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
11455
- add(m[1]);
11456
- for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm))
11457
- add(m[1]);
11401
+ for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm)) add(m[1]);
11402
+ for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm)) add(m[1]);
11458
11403
  break;
11459
11404
  }
11460
11405
  }
@@ -11476,8 +11421,7 @@ function generateTestCaseNames(funcName, _type, quality = false) {
11476
11421
  ];
11477
11422
  }
11478
11423
  function inferFunctionParams(sourceContent, funcName) {
11479
- if (!sourceContent || !funcName)
11480
- return [];
11424
+ if (!sourceContent || !funcName) return [];
11481
11425
  const patterns = [
11482
11426
  new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
11483
11427
  new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
@@ -11490,8 +11434,7 @@ function inferFunctionParams(sourceContent, funcName) {
11490
11434
  if (m) {
11491
11435
  return m[1].split(",").map((s) => {
11492
11436
  const trimmed = s.trim();
11493
- if (!trimmed)
11494
- return null;
11437
+ if (!trimmed) return null;
11495
11438
  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*[,)]))/);
11496
11439
  const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
11497
11440
  const defaultMatch = trimmed.match(/=\s*(.+)$/);
@@ -11507,35 +11450,22 @@ function inferFunctionParams(sourceContent, funcName) {
11507
11450
  return [];
11508
11451
  }
11509
11452
  function inferTypeFromName(paramName, defaultValue) {
11510
- if (!paramName)
11511
- return "any";
11453
+ if (!paramName) return "any";
11512
11454
  const name = paramName.toLowerCase();
11513
11455
  if (defaultValue !== null && defaultValue !== void 0) {
11514
- if (/^["']/.test(defaultValue))
11515
- return "string";
11516
- if (/^\d+\.?\d*$/.test(defaultValue))
11517
- return "number";
11518
- if (/^(true|false)$/i.test(defaultValue))
11519
- return "boolean";
11520
- if (/^\[/.test(defaultValue))
11521
- return "array";
11522
- if (/^\{/.test(defaultValue))
11523
- return "object";
11524
- if (/^null$/i.test(defaultValue))
11525
- return "null";
11526
- }
11527
- if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name))
11528
- return "boolean";
11529
- if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name))
11530
- return "number";
11531
- if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name))
11532
- return "string";
11533
- if (/^(items|list|arr|entries|data|values|args)_?/.test(name))
11534
- return "array";
11535
- if (/^(obj|config|opts|options|settings|params|props)_?/.test(name))
11536
- return "object";
11537
- if (/^(fn|cb|callback|handler|on[A-Z])/.test(name))
11538
- return "function";
11456
+ if (/^["']/.test(defaultValue)) return "string";
11457
+ if (/^\d+\.?\d*$/.test(defaultValue)) return "number";
11458
+ if (/^(true|false)$/i.test(defaultValue)) return "boolean";
11459
+ if (/^\[/.test(defaultValue)) return "array";
11460
+ if (/^\{/.test(defaultValue)) return "object";
11461
+ if (/^null$/i.test(defaultValue)) return "null";
11462
+ }
11463
+ if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name)) return "boolean";
11464
+ if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name)) return "number";
11465
+ if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name)) return "string";
11466
+ if (/^(items|list|arr|entries|data|values|args)_?/.test(name)) return "array";
11467
+ if (/^(obj|config|opts|options|settings|params|props)_?/.test(name)) return "object";
11468
+ if (/^(fn|cb|callback|handler|on[A-Z])/.test(name)) return "function";
11539
11469
  return "any";
11540
11470
  }
11541
11471
  function _langComment(lang) {
@@ -11548,22 +11478,14 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11548
11478
  let block = "";
11549
11479
  const testValues = params.map((p) => {
11550
11480
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11551
- if (t === "string" || t === "String")
11552
- return '"sample_input"';
11553
- if (t === "number" || t === "int" || t === "float" || t === "Number")
11554
- return "42";
11555
- if (t === "boolean" || t === "bool" || t === "Boolean")
11556
- return "true";
11557
- if (t === "array" || t === "Array" || t === "list" || t === "List")
11558
- return "[]";
11559
- if (t === "object" || t === "Object" || t === "dict" || t === "Dict")
11560
- return "{}";
11561
- if (t === "function" || t === "Function")
11562
- return "() => {}";
11563
- if (t === "any")
11564
- return '"test"';
11565
- if (t === "null")
11566
- return "null";
11481
+ if (t === "string" || t === "String") return '"sample_input"';
11482
+ if (t === "number" || t === "int" || t === "float" || t === "Number") return "42";
11483
+ if (t === "boolean" || t === "bool" || t === "Boolean") return "true";
11484
+ if (t === "array" || t === "Array" || t === "list" || t === "List") return "[]";
11485
+ if (t === "object" || t === "Object" || t === "dict" || t === "Dict") return "{}";
11486
+ if (t === "function" || t === "Function") return "() => {}";
11487
+ if (t === "any") return '"test"';
11488
+ if (t === "null") return "null";
11567
11489
  return '"test"';
11568
11490
  });
11569
11491
  const args = testValues.join(", ");
@@ -11593,10 +11515,8 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11593
11515
  `;
11594
11516
  const ecArgs = params.map((p) => {
11595
11517
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11596
- if (t === "string")
11597
- return '""';
11598
- if (t === "number" || t === "int" || t === "float")
11599
- return "0";
11518
+ if (t === "string") return '""';
11519
+ if (t === "number" || t === "int" || t === "float") return "0";
11600
11520
  return '"edge"';
11601
11521
  }).join(", ");
11602
11522
  block += `${indent} result = ${funcName}(${ecArgs})
@@ -11634,16 +11554,11 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11634
11554
  `;
11635
11555
  const ecArgsJS = params.map((p) => {
11636
11556
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11637
- if (t === "string")
11638
- return '""';
11639
- if (t === "number" || t === "int" || t === "float")
11640
- return "0";
11641
- if (t === "boolean")
11642
- return "false";
11643
- if (t === "array")
11644
- return "[]";
11645
- if (t === "object")
11646
- return "{}";
11557
+ if (t === "string") return '""';
11558
+ if (t === "number" || t === "int" || t === "float") return "0";
11559
+ if (t === "boolean") return "false";
11560
+ if (t === "array") return "[]";
11561
+ if (t === "object") return "{}";
11647
11562
  return "undefined";
11648
11563
  }).join(", ");
11649
11564
  block += `${indent} const result = mod.${funcName}(${ecArgsJS});
@@ -11676,15 +11591,14 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11676
11591
  return block;
11677
11592
  }
11678
11593
  function isSkeletonUseless(content) {
11679
- if (!content)
11680
- return true;
11594
+ if (!content) return true;
11681
11595
  const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
11682
11596
  const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
11683
11597
  const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
11684
11598
  return meaningfulLines.length < 2;
11685
11599
  }
11686
11600
 
11687
- // src/lib/test-skeletons.js
11601
+ // src/lib/test-skeletons.ts
11688
11602
  var TEST_SKELETONS = {
11689
11603
  py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
11690
11604
  const moduleImport = name.replace(/-/g, "_");
@@ -11712,8 +11626,7 @@ var TEST_SKELETONS = {
11712
11626
 
11713
11627
  `;
11714
11628
  for (const exp of exports) {
11715
- if (exp.type === "class")
11716
- continue;
11629
+ if (exp.type === "class") continue;
11717
11630
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11718
11631
  content += `# TODO: implement tests for ${exp.name}
11719
11632
  `;
@@ -11721,12 +11634,10 @@ var TEST_SKELETONS = {
11721
11634
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11722
11635
  content += `def test_${caseFunc}():
11723
11636
  `;
11724
- if (strict)
11725
- content += ` raise AssertionError("TODO: implement ${caseName}")
11637
+ if (strict) content += ` raise AssertionError("TODO: implement ${caseName}")
11726
11638
 
11727
11639
  `;
11728
- else
11729
- content += ` pytest.skip("TODO: implement ${caseName}")
11640
+ else content += ` pytest.skip("TODO: implement ${caseName}")
11730
11641
 
11731
11642
  `;
11732
11643
  }
@@ -11738,12 +11649,10 @@ var TEST_SKELETONS = {
11738
11649
  if (exports.length === 0) {
11739
11650
  content += `def test_${name}_placeholder():
11740
11651
  `;
11741
- if (strict)
11742
- content += ` raise AssertionError("TODO: implement tests for ${name}")
11652
+ if (strict) content += ` raise AssertionError("TODO: implement tests for ${name}")
11743
11653
 
11744
11654
  `;
11745
- else
11746
- content += ` pytest.skip("TODO: implement tests for ${name}")
11655
+ else content += ` pytest.skip("TODO: implement tests for ${name}")
11747
11656
 
11748
11657
  `;
11749
11658
  }
@@ -11777,8 +11686,7 @@ var TEST_SKELETONS = {
11777
11686
 
11778
11687
  `;
11779
11688
  for (const exp of exports) {
11780
- if (exp.type === "class")
11781
- continue;
11689
+ if (exp.type === "class") continue;
11782
11690
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11783
11691
  content += ` // TODO: implement tests for ${exp.name}
11784
11692
  `;
@@ -11794,11 +11702,9 @@ var TEST_SKELETONS = {
11794
11702
  `;
11795
11703
  content += ` // TODO: implement ${caseName}
11796
11704
  `;
11797
- if (strict)
11798
- content += ` throw new Error('TODO: implement ${caseName}');
11705
+ if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11799
11706
  `;
11800
- else
11801
- content += ` expect(true).toBe(true);
11707
+ else content += ` expect(true).toBe(true);
11802
11708
  `;
11803
11709
  content += ` });
11804
11710
 
@@ -11851,8 +11757,7 @@ var TEST_SKELETONS = {
11851
11757
 
11852
11758
  `;
11853
11759
  for (const exp of exports) {
11854
- if (exp.type === "class")
11855
- continue;
11760
+ if (exp.type === "class") continue;
11856
11761
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11857
11762
  content += ` // TODO: implement tests for ${exp.name}
11858
11763
  `;
@@ -11868,11 +11773,9 @@ var TEST_SKELETONS = {
11868
11773
  `;
11869
11774
  content += ` // TODO: implement ${caseName}
11870
11775
  `;
11871
- if (strict)
11872
- content += ` throw new Error('TODO: implement ${caseName}');
11776
+ if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11873
11777
  `;
11874
- else
11875
- content += ` expect(true).toBe(true);
11778
+ else content += ` expect(true).toBe(true);
11876
11779
  `;
11877
11780
  content += ` });
11878
11781
 
@@ -11925,8 +11828,7 @@ var TEST_SKELETONS = {
11925
11828
 
11926
11829
  `;
11927
11830
  for (const exp of exports) {
11928
- if (exp.type === "class")
11929
- continue;
11831
+ if (exp.type === "class") continue;
11930
11832
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11931
11833
  content += ` // TODO: implement tests for ${exp.name}
11932
11834
  `;
@@ -11942,11 +11844,9 @@ var TEST_SKELETONS = {
11942
11844
  `;
11943
11845
  content += ` // TODO: implement ${caseName}
11944
11846
  `;
11945
- if (strict)
11946
- content += ` throw new Error('TODO: implement ${caseName}');
11847
+ if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11947
11848
  `;
11948
- else
11949
- content += ` expect(true).toBe(true);
11849
+ else content += ` expect(true).toBe(true);
11950
11850
  `;
11951
11851
  content += ` });
11952
11852
 
@@ -12006,8 +11906,7 @@ var TEST_SKELETONS = {
12006
11906
 
12007
11907
  `;
12008
11908
  for (const exp of exports) {
12009
- if (exp.type === "class")
12010
- continue;
11909
+ if (exp.type === "class") continue;
12011
11910
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12012
11911
  const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
12013
11912
  content += `// TODO: implement tests for ${exp.name}
@@ -12016,11 +11915,9 @@ var TEST_SKELETONS = {
12016
11915
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12017
11916
  content += `func Test${cap}_${caseFunc}(t *testing.T) {
12018
11917
  `;
12019
- if (strict)
12020
- content += ` t.Error("TODO: implement ${caseName}")
11918
+ if (strict) content += ` t.Error("TODO: implement ${caseName}")
12021
11919
  `;
12022
- else
12023
- content += ` t.Skip("TODO: implement ${caseName}")
11920
+ else content += ` t.Skip("TODO: implement ${caseName}")
12024
11921
  `;
12025
11922
  content += `}
12026
11923
 
@@ -12040,11 +11937,9 @@ var TEST_SKELETONS = {
12040
11937
  if (exports.length === 0) {
12041
11938
  content += `func Test${cap}_Placeholder(t *testing.T) {
12042
11939
  `;
12043
- if (strict)
12044
- content += ` t.Error("TODO: implement tests for ${name}")
11940
+ if (strict) content += ` t.Error("TODO: implement tests for ${name}")
12045
11941
  `;
12046
- else
12047
- content += ` t.Skip("TODO: implement tests for ${name}")
11942
+ else content += ` t.Skip("TODO: implement tests for ${name}")
12048
11943
  `;
12049
11944
  content += `}
12050
11945
  `;
@@ -12077,11 +11972,9 @@ var TEST_SKELETONS = {
12077
11972
  `;
12078
11973
  content += ` echo "TODO: implement ${caseName}"
12079
11974
  `;
12080
- if (strict)
12081
- content += ` exit 1
11975
+ if (strict) content += ` exit 1
12082
11976
  `;
12083
- else
12084
- content += ` echo "SKIP: ${caseName}"
11977
+ else content += ` echo "SKIP: ${caseName}"
12085
11978
  `;
12086
11979
  content += `}
12087
11980
 
@@ -12095,11 +11988,9 @@ var TEST_SKELETONS = {
12095
11988
  if (exports.length === 0) {
12096
11989
  content += `function test_smoke {
12097
11990
  `;
12098
- if (strict)
12099
- content += ` echo "TODO: implement tests for ${name}" && exit 1
11991
+ if (strict) content += ` echo "TODO: implement tests for ${name}" && exit 1
12100
11992
  `;
12101
- else
12102
- content += ` echo "TODO: implement tests for ${name}"
11993
+ else content += ` echo "TODO: implement tests for ${name}"
12103
11994
  `;
12104
11995
  content += `}
12105
11996
  `;
@@ -12139,8 +12030,7 @@ mod tests {
12139
12030
 
12140
12031
  `;
12141
12032
  for (const exp of exports) {
12142
- if (exp.type === "class")
12143
- continue;
12033
+ if (exp.type === "class") continue;
12144
12034
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12145
12035
  content += ` // TODO: implement tests for ${exp.name}
12146
12036
  `;
@@ -12149,11 +12039,9 @@ mod tests {
12149
12039
  content += ` #[test]
12150
12040
  fn test_${caseFunc}() {
12151
12041
  `;
12152
- if (strict)
12153
- content += ` panic!("TODO: implement ${caseName}");
12042
+ if (strict) content += ` panic!("TODO: implement ${caseName}");
12154
12043
  `;
12155
- else
12156
- content += ` // TODO: implement ${caseName}
12044
+ else content += ` // TODO: implement ${caseName}
12157
12045
  `;
12158
12046
  content += ` }
12159
12047
 
@@ -12168,11 +12056,9 @@ mod tests {
12168
12056
  content += ` #[test]
12169
12057
  fn ${name}_placeholder() {
12170
12058
  `;
12171
- if (strict)
12172
- content += ` panic!("TODO: implement tests for ${name}");
12059
+ if (strict) content += ` panic!("TODO: implement tests for ${name}");
12173
12060
  `;
12174
- else
12175
- content += ` // TODO: implement tests for ${name}
12061
+ else content += ` // TODO: implement tests for ${name}
12176
12062
  `;
12177
12063
  content += ` }
12178
12064
  `;
@@ -12212,8 +12098,7 @@ mod tests {
12212
12098
 
12213
12099
  `;
12214
12100
  for (const exp of exports) {
12215
- if (exp.type === "class")
12216
- continue;
12101
+ if (exp.type === "class") continue;
12217
12102
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12218
12103
  content += ` # TODO: implement tests for ${exp.name}
12219
12104
  `;
@@ -12221,11 +12106,9 @@ mod tests {
12221
12106
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12222
12107
  content += ` def test_${caseFunc}
12223
12108
  `;
12224
- if (strict)
12225
- content += ` flunk "TODO: implement ${caseName}"
12109
+ if (strict) content += ` flunk "TODO: implement ${caseName}"
12226
12110
  `;
12227
- else
12228
- content += ` # TODO: implement ${caseName}
12111
+ else content += ` # TODO: implement ${caseName}
12229
12112
  `;
12230
12113
  content += ` end
12231
12114
 
@@ -12239,11 +12122,9 @@ mod tests {
12239
12122
  if (exports.length === 0) {
12240
12123
  content += ` def test_placeholder
12241
12124
  `;
12242
- if (strict)
12243
- content += ` flunk "TODO: implement tests for ${name}"
12125
+ if (strict) content += ` flunk "TODO: implement tests for ${name}"
12244
12126
  `;
12245
- else
12246
- content += ` # TODO: implement tests for ${name}
12127
+ else content += ` # TODO: implement tests for ${name}
12247
12128
  `;
12248
12129
  content += ` end
12249
12130
  `;
@@ -12289,18 +12170,15 @@ mod tests {
12289
12170
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12290
12171
  for (const caseName of cases) {
12291
12172
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12292
- if (!strict)
12293
- content += ` // @Disabled("TODO")
12173
+ if (!strict) content += ` // @Disabled("TODO")
12294
12174
  `;
12295
12175
  content += ` @Test
12296
12176
  `;
12297
12177
  content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
12298
12178
  `;
12299
- if (strict)
12300
- content += ` fail("TODO: implement ${caseName}");
12179
+ if (strict) content += ` fail("TODO: implement ${caseName}");
12301
12180
  `;
12302
- else
12303
- content += ` assertTrue(true); // TODO: implement ${caseName}
12181
+ else content += ` assertTrue(true); // TODO: implement ${caseName}
12304
12182
  `;
12305
12183
  content += ` }
12306
12184
 
@@ -12362,18 +12240,15 @@ mod tests {
12362
12240
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12363
12241
  for (const caseName of cases) {
12364
12242
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12365
- if (!strict)
12366
- content += ` // @Disabled("TODO")
12243
+ if (!strict) content += ` // @Disabled("TODO")
12367
12244
  `;
12368
12245
  content += ` @Test
12369
12246
  `;
12370
12247
  content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
12371
12248
  `;
12372
- if (strict)
12373
- content += ` fail("TODO: implement ${caseName}")
12249
+ if (strict) content += ` fail("TODO: implement ${caseName}")
12374
12250
  `;
12375
- else
12376
- content += ` assertTrue(true) // TODO: implement ${caseName}
12251
+ else content += ` assertTrue(true) // TODO: implement ${caseName}
12377
12252
  `;
12378
12253
  content += ` }
12379
12254
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.24.8",
3
+ "version": "0.24.12",
4
4
  "description": "Cost-aware delegation enforcer for OpenCode. Tracks model usage, routes Task subagents to cheaper tiers, surfaces cumulative savings in chat. Includes research audit, reporting framework, project memory, progressive scratchpad decadence, and trinity CLI for brain/medium/cheap slot switching.",
5
5
  "scripts": {
6
6
  "release": "node scripts/release.mjs",