vibeostheog 0.24.14 → 0.24.16

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 +26 -3
  2. package/dist/vibeOS.js +314 -175
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,7 +1,31 @@
1
+ ## 0.24.16
2
+ - fix: serialize model tiers writes
3
+ - test: add concurrent tiers write regression
4
+
5
+
6
+ ## 0.24.15
7
+ - feat: smooth delegation UX — conversational reasoning over error injection
8
+ - fix: preserve local agent mode in remote control merge
9
+ - fix: harden live regression paths (#140)
10
+ - fix: write npm auth for github release publish
11
+ - fix: reset api fallback on token refresh (#138)
12
+ - fix: _prevBlackboxState -> _latestBlackboxState, update pattern key test
13
+ - fix: sync-ts-build was cleaning JS artifacts without copying compiled output back
14
+ - fix: forensic anti-lying + quality enforcement pipeline
15
+ - docs: add cross-project index, DEV ONLY markers, ESLint cleanup
16
+ - test: add 13 cascade integration tests for forensic quality pipeline
17
+ - chore: v0.24.14
18
+ - chore: sync package version to v0.24.12
19
+ - chore: sync package version to latest github release
20
+ - chore: sync package version to latest release
21
+ Fix live regressions and add integration coverage (#139)
22
+ Merge pull request #136 from DrunkkToys/release/v0.24.8-merge
23
+
24
+
1
25
  ## 0.24.14
2
26
  - feat: smooth delegation UX — conversational reasoning over error injection
3
- - fix: preserve audit and forensic modes
4
- - fix: harden live regression paths
27
+ - fix: preserve local agent mode in remote control merge
28
+ - fix: harden live regression paths (#140)
5
29
  - fix: write npm auth for github release publish
6
30
  - fix: reset api fallback on token refresh (#138)
7
31
  - fix: _prevBlackboxState -> _latestBlackboxState, update pattern key test
@@ -9,7 +33,6 @@
9
33
  - fix: forensic anti-lying + quality enforcement pipeline
10
34
  - docs: add cross-project index, DEV ONLY markers, ESLint cleanup
11
35
  - test: add 13 cascade integration tests for forensic quality pipeline
12
- - chore: sync package version to v0.24.13
13
36
  - chore: sync package version to v0.24.12
14
37
  - chore: sync package version to latest github release
15
38
  - chore: sync package version to latest release
package/dist/vibeOS.js CHANGED
@@ -2451,14 +2451,16 @@ function loadSelection() {
2451
2451
  function writeSelection(key, value) {
2452
2452
  const TIERS_FILE3 = join3(getVibeOSHome2(), "model-tiers.json");
2453
2453
  try {
2454
- const j = safeJsonParse2(readFileSync3(TIERS_FILE3, "utf-8"));
2455
- if (!j.selection)
2456
- j.selection = {};
2457
- j.selection[key] = value;
2458
- const tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
2459
- writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
2460
- renameSync2(tmp, TIERS_FILE3);
2461
- return true;
2454
+ return withFileLock(TIERS_FILE3, () => {
2455
+ const j = safeJsonParse2(readFileSync3(TIERS_FILE3, "utf-8"));
2456
+ if (!j.selection)
2457
+ j.selection = {};
2458
+ j.selection[key] = value;
2459
+ const tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
2460
+ writeFileSync3(tmp, JSON.stringify(j, null, 2) + "\n");
2461
+ renameSync2(tmp, TIERS_FILE3);
2462
+ return true;
2463
+ });
2462
2464
  } catch (err) {
2463
2465
  console.error(`[vibeOS] writeSelection failed: ${err.message}`);
2464
2466
  return false;
@@ -2534,42 +2536,56 @@ function writeSessionOptMode(sid, mode) {
2534
2536
  }
2535
2537
  }
2536
2538
 
2537
- // src/lib/pattern-helpers.ts
2539
+ // src/lib/pattern-helpers.js
2538
2540
  import { relative, basename as basename2 } from "node:path";
2539
2541
  function normalizeObservedPath(filePath, directory3) {
2540
- if (!filePath || typeof filePath !== "string") return "unknown";
2542
+ if (!filePath || typeof filePath !== "string")
2543
+ return "unknown";
2541
2544
  let p = filePath;
2542
2545
  try {
2543
2546
  if (directory3 && p.startsWith("/")) {
2544
2547
  const rel = relative(directory3, p);
2545
- if (rel && !rel.startsWith("..") && !rel.startsWith("/")) p = rel;
2548
+ if (rel && !rel.startsWith("..") && !rel.startsWith("/"))
2549
+ p = rel;
2546
2550
  }
2547
2551
  } catch {
2548
2552
  }
2549
2553
  p = p.replace(/\\/g, "/").replace(/^\.\/+/, "");
2550
- if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p)) return p;
2554
+ if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p))
2555
+ return p;
2551
2556
  const m = p.match(/\.([a-z0-9]+)$/i);
2552
- if (p.startsWith("src/") && m) return `src/*.${m[1].toLowerCase()}`;
2553
- if (p.startsWith("tests/") && m) return `tests/*.${m[1].toLowerCase()}`;
2557
+ if (p.startsWith("src/") && m)
2558
+ return `src/*.${m[1].toLowerCase()}`;
2559
+ if (p.startsWith("tests/") && m)
2560
+ return `tests/*.${m[1].toLowerCase()}`;
2554
2561
  return basename2(p) || "unknown";
2555
2562
  }
2556
2563
  function commandFamily(command) {
2557
2564
  const c = String(command || "").trim().toLowerCase();
2558
- if (!c) return "unknown";
2559
- if (/\bnode\s+--check\b/.test(c)) return "syntax-check";
2560
- if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c)) return "typecheck";
2561
- if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c)) return "test";
2562
- if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c)) return "build";
2563
- if (/\bgit\s+status\b/.test(c)) return "git-status";
2564
- if (/\bgit\s+commit\b/.test(c)) return "git-commit";
2565
+ if (!c)
2566
+ return "unknown";
2567
+ if (/\bnode\s+--check\b/.test(c))
2568
+ return "syntax-check";
2569
+ if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c))
2570
+ return "typecheck";
2571
+ if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c))
2572
+ return "test";
2573
+ if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c))
2574
+ return "build";
2575
+ if (/\bgit\s+status\b/.test(c))
2576
+ return "git-status";
2577
+ if (/\bgit\s+commit\b/.test(c))
2578
+ return "git-commit";
2565
2579
  const first = c.replace(/^[a-z_][a-z0-9_]*=\S+\s+/g, "").split(/\s+/)[0];
2566
2580
  return /^[a-z0-9._/-]{1,30}$/.test(first) ? first : "command";
2567
2581
  }
2568
2582
  function commandFailed(output) {
2569
2583
  const code = output?.exitCode ?? output?.statusCode ?? output?.code;
2570
- if (Number.isFinite(Number(code)) && Number(code) !== 0) return true;
2584
+ if (Number.isFinite(Number(code)) && Number(code) !== 0)
2585
+ return true;
2571
2586
  const raw = output?.result ?? output?.text ?? output?.content ?? output?.data ?? "";
2572
- if (typeof raw !== "string") return false;
2587
+ if (typeof raw !== "string")
2588
+ return false;
2573
2589
  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);
2574
2590
  }
2575
2591
  function mergeProjectBucket(dst, src) {
@@ -2586,7 +2602,8 @@ function mergeProjectBucket(dst, src) {
2586
2602
  row.sessions = [.../* @__PURE__ */ new Set([...row.sessions || [], ...v?.sessions || []])].slice(-10);
2587
2603
  row.lastSeen = [row.lastSeen, v?.lastSeen].filter(Boolean).sort().slice(-1)[0] || null;
2588
2604
  row.summary = row.summary || v?.summary || "";
2589
- if (v?.kind) row.kind = v.kind;
2605
+ if (v?.kind)
2606
+ row.kind = v.kind;
2590
2607
  out[key] = row;
2591
2608
  }
2592
2609
  }
@@ -2605,9 +2622,11 @@ function mergeProjectBucket(dst, src) {
2605
2622
  };
2606
2623
  }
2607
2624
  function _pruneOldSessions(state) {
2608
- if (!state?.sessions) return;
2625
+ if (!state?.sessions)
2626
+ return;
2609
2627
  const entries = Object.entries(state.sessions);
2610
- if (entries.length <= 30) return;
2628
+ if (entries.length <= 30)
2629
+ return;
2611
2630
  entries.sort((a, b) => {
2612
2631
  const da = a[1]?.started || a[1]?.last_costed || "";
2613
2632
  const db = b[1]?.started || b[1]?.last_costed || "";
@@ -5857,18 +5876,20 @@ function _refreshModel(directory3) {
5857
5876
  console.error(`[vibeOS] model refresh (config): ${oldModel}(${oldTier}) \u2192 ${currentModel}(${currentTier})`);
5858
5877
  try {
5859
5878
  if (existsSync6(TIERS_FILE3)) {
5860
- const t = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
5861
- for (const s of getTrinitySlotOrder(t)) {
5862
- if (t?.trinity?.[s]?.oc === cfgModel) {
5863
- t.selection.active_slot = s;
5864
- const _tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
5865
- writeFileSync5(_tmp, JSON.stringify(t, null, 2) + "\n", "utf-8");
5866
- renameSync4(_tmp, TIERS_FILE3);
5867
- if (DEBUG_INTERNALS)
5868
- console.error(`[vibeOS] model refresh (config): synced active_slot \u2192 ${s}`);
5869
- break;
5879
+ withFileLock2(TIERS_FILE3, () => {
5880
+ const t = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
5881
+ for (const s of getTrinitySlotOrder(t)) {
5882
+ if (t?.trinity?.[s]?.oc === cfgModel) {
5883
+ t.selection.active_slot = s;
5884
+ const _tmp = TIERS_FILE3 + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
5885
+ writeFileSync5(_tmp, JSON.stringify(t, null, 2) + "\n", "utf-8");
5886
+ renameSync4(_tmp, TIERS_FILE3);
5887
+ if (DEBUG_INTERNALS)
5888
+ console.error(`[vibeOS] model refresh (config): synced active_slot \u2192 ${s}`);
5889
+ break;
5890
+ }
5870
5891
  }
5871
- }
5892
+ });
5872
5893
  }
5873
5894
  } catch {
5874
5895
  }
@@ -5880,25 +5901,27 @@ function _refreshModel(directory3) {
5880
5901
  function applySlot2(slot, projectDir = "") {
5881
5902
  try {
5882
5903
  const TIERS_FILE3 = join5(getVibeOSHome4(), "model-tiers.json");
5883
- const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
5884
- const ocModel = j?.trinity?.[slot]?.oc;
5885
- if (!ocModel)
5886
- return { ok: false, reason: `slot '${slot}' has no oc model` };
5887
- j.selection.active_slot = slot;
5888
- const _tmp = TIERS_FILE3 + ".tmp." + Date.now();
5889
- writeFileSync5(_tmp, JSON.stringify(j, null, 2) + "\n", "utf-8");
5890
- renameSync4(_tmp, TIERS_FILE3);
5891
- const dir = projectDir || process.cwd();
5892
- const localOcConfig = join5(dir, "opencode.json");
5893
- const ocConfig = existsSync6(localOcConfig) ? localOcConfig : join5(getOpenCodeHome(), "opencode.json");
5894
- if (existsSync6(ocConfig)) {
5895
- const oc = safeJsonParse3(readFileSync5(ocConfig, "utf-8"));
5896
- oc.model = ocModel;
5897
- writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
5898
- }
5899
- clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
5900
- _refreshModel(dir);
5901
- return { ok: true, ocModel };
5904
+ return withFileLock2(TIERS_FILE3, () => {
5905
+ const j = safeJsonParse3(readFileSync5(TIERS_FILE3, "utf-8"));
5906
+ const ocModel = j?.trinity?.[slot]?.oc;
5907
+ if (!ocModel)
5908
+ return { ok: false, reason: `slot '${slot}' has no oc model` };
5909
+ j.selection.active_slot = slot;
5910
+ const _tmp = TIERS_FILE3 + ".tmp." + Date.now();
5911
+ writeFileSync5(_tmp, JSON.stringify(j, null, 2) + "\n", "utf-8");
5912
+ renameSync4(_tmp, TIERS_FILE3);
5913
+ const dir = projectDir || process.cwd();
5914
+ const localOcConfig = join5(dir, "opencode.json");
5915
+ const ocConfig = existsSync6(localOcConfig) ? localOcConfig : join5(getOpenCodeHome(), "opencode.json");
5916
+ if (existsSync6(ocConfig)) {
5917
+ const oc = safeJsonParse3(readFileSync5(ocConfig, "utf-8"));
5918
+ oc.model = ocModel;
5919
+ writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
5920
+ }
5921
+ clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
5922
+ _refreshModel(dir);
5923
+ return { ok: true, ocModel };
5924
+ });
5902
5925
  } catch (err) {
5903
5926
  return { ok: false, reason: err.message };
5904
5927
  }
@@ -9684,7 +9707,7 @@ function recordBudgetFirstOutcome(input = {}) {
9684
9707
  import { join as join13 } from "node:path";
9685
9708
  import { writeFileSync as writeFileSync11 } from "node:fs";
9686
9709
 
9687
- // src/lib/text-compress.ts
9710
+ // src/lib/text-compress.js
9688
9711
  var VERBOSE_LINE_RE = [
9689
9712
  /^[\s#*/\\\-_=+|~:;'"`@\$%^&<>{}\[\]()!?.,0-9]+$/,
9690
9713
  /^(Filed|Created|Modified|Deleted|Updated|Renamed|Copied|Moved|Changed):/,
@@ -9701,12 +9724,15 @@ function extractBulletLines(lines, targetChars, minLines) {
9701
9724
  const keyLines = [];
9702
9725
  const otherLines = [];
9703
9726
  for (const line of lines) {
9704
- if (BULLET_PATTERNS.some((re) => re.test(line))) keyLines.push(line);
9705
- else otherLines.push(line);
9727
+ if (BULLET_PATTERNS.some((re) => re.test(line)))
9728
+ keyLines.push(line);
9729
+ else
9730
+ otherLines.push(line);
9706
9731
  }
9707
9732
  const selected = [...keyLines];
9708
9733
  for (const line of otherLines) {
9709
- if (selected.length >= minLines && selected.join("\n").length >= targetChars) break;
9734
+ if (selected.length >= minLines && selected.join("\n").length >= targetChars)
9735
+ break;
9710
9736
  selected.push(line);
9711
9737
  }
9712
9738
  while (selected.length > minLines && selected.join("\n").length > targetChars * 2) {
@@ -9715,7 +9741,8 @@ function extractBulletLines(lines, targetChars, minLines) {
9715
9741
  return selected;
9716
9742
  }
9717
9743
  function compressText(text) {
9718
- if (!text || typeof text !== "string") return text;
9744
+ if (!text || typeof text !== "string")
9745
+ return text;
9719
9746
  let lines = text.split("\n");
9720
9747
  let removed = 0;
9721
9748
  const out = [];
@@ -9728,14 +9755,16 @@ function compressText(text) {
9728
9755
  break;
9729
9756
  }
9730
9757
  }
9731
- if (!skip) out.push(line);
9758
+ if (!skip)
9759
+ out.push(line);
9732
9760
  }
9733
9761
  const collapsed = [];
9734
9762
  let blanks = 0;
9735
9763
  for (const line of out) {
9736
9764
  if (line.trim() === "") {
9737
9765
  blanks++;
9738
- if (blanks <= 2) collapsed.push(line);
9766
+ if (blanks <= 2)
9767
+ collapsed.push(line);
9739
9768
  } else {
9740
9769
  blanks = 0;
9741
9770
  collapsed.push(line);
@@ -9743,10 +9772,7 @@ function compressText(text) {
9743
9772
  }
9744
9773
  let result = collapsed.join("\n").trim();
9745
9774
  if (result.length > COMPRESS_THRESHOLD) {
9746
- const targetChars = Math.max(
9747
- Math.round(result.length * COMPRESS_RATIO),
9748
- COMPRESS_THRESHOLD
9749
- );
9775
+ const targetChars = Math.max(Math.round(result.length * COMPRESS_RATIO), COMPRESS_THRESHOLD);
9750
9776
  const minLines = Math.max(1, Math.round(collapsed.length * MIN_KEPT_LINES_RATIO));
9751
9777
  const bulletLines = extractBulletLines(collapsed, targetChars, minLines);
9752
9778
  result = bulletLines.join("\n").trim();
@@ -10061,7 +10087,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
10061
10087
  }
10062
10088
  }
10063
10089
 
10064
- // src/lib/constants.ts
10090
+ // src/lib/constants.js
10065
10091
  var SAVE_EST = {
10066
10092
  // Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
10067
10093
  WRITE_EDIT: 4e-4,
@@ -10079,7 +10105,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
10079
10105
  var PROTOCOL_MARKER = "[wbp-v1]";
10080
10106
  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.";
10081
10107
 
10082
- // src/lib/templates.ts
10108
+ // src/lib/templates.js
10083
10109
  var TEMPLATES = {
10084
10110
  save: {
10085
10111
  tier_bias: "cheap",
@@ -10129,7 +10155,8 @@ var TEMPLATES = {
10129
10155
  var DEFAULT_TEMPLATE = "save";
10130
10156
  var SEC_KEYWORDS = /\b(security|vuln|exploit|injection|xss|csrf|secret|credential|token leak|auth bypass|privacy|breach|backdoor|sql injection|cve)\b/i;
10131
10157
  function detectSecuritySignal(text) {
10132
- if (!text || typeof text !== "string") return false;
10158
+ if (!text || typeof text !== "string")
10159
+ return false;
10133
10160
  return SEC_KEYWORDS.test(text);
10134
10161
  }
10135
10162
  function detectBudgetSignal(creditPercent) {
@@ -10142,20 +10169,25 @@ function detectStressSpike(stressScore) {
10142
10169
  return delta > 0.3 && stressScore > 0.5;
10143
10170
  }
10144
10171
  function resolveTemplate(prevTemplate, stressScore, userText, creditPercent, subRegime) {
10145
- if (detectSecuritySignal(userText)) return "security";
10172
+ if (detectSecuritySignal(userText))
10173
+ return "security";
10146
10174
  if (detectBudgetSignal(creditPercent)) {
10147
10175
  const regime = String(subRegime || "").toUpperCase();
10148
- if (regime === "LOOPING" || regime === "DIVERGENT") return "speed";
10176
+ if (regime === "LOOPING" || regime === "DIVERGENT")
10177
+ return "speed";
10149
10178
  return "save";
10150
10179
  }
10151
- if (detectStressSpike(stressScore)) return "quality";
10180
+ if (detectStressSpike(stressScore))
10181
+ return "quality";
10152
10182
  return prevTemplate || DEFAULT_TEMPLATE;
10153
10183
  }
10154
10184
  var _turnCount = 0;
10155
10185
  function shouldInjectTemplate(template, prevTemplate) {
10156
10186
  _turnCount++;
10157
- if (template !== prevTemplate) return true;
10158
- if (_turnCount % 10 === 0) return true;
10187
+ if (template !== prevTemplate)
10188
+ return true;
10189
+ if (_turnCount % 10 === 0)
10190
+ return true;
10159
10191
  return false;
10160
10192
  }
10161
10193
 
@@ -10164,6 +10196,18 @@ var BYTES_PER_TOKEN = 4;
10164
10196
  function getVibeOSHome9() {
10165
10197
  return process.env.VIBEOS_HOME || join14(process.env.HOME || "", ".claude");
10166
10198
  }
10199
+ function mergeRemoteControlVector(remoteControlVector, localControlVector) {
10200
+ return {
10201
+ ...remoteControlVector,
10202
+ agent_mode: localControlVector?.agent_mode,
10203
+ tier_bias: localControlVector?.tier_bias,
10204
+ optimization_mode: localControlVector?.optimization_mode,
10205
+ enforcement_mode: localControlVector?.enforcement_mode,
10206
+ flow_mode: localControlVector?.flow_mode,
10207
+ tdd_mode: localControlVector?.tdd_mode,
10208
+ thinking_mode: localControlVector?.thinking_mode
10209
+ };
10210
+ }
10167
10211
  function resolveRestorableOpenCodeAgent(currentSel) {
10168
10212
  const remembered = typeof currentSel?.previous_default_agent === "string" ? currentSel.previous_default_agent.trim() : "";
10169
10213
  if (remembered && remembered !== "plan")
@@ -10216,7 +10260,7 @@ async function apiComputeControlVector(state, action, optimizationMode) {
10216
10260
  const res = await remoteCall("blackboxControlVector", [state, action, optimizationMode], null);
10217
10261
  if (res?.control_vector) {
10218
10262
  const local = computeControlVector2(state, action, optimizationMode);
10219
- 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 };
10263
+ return mergeRemoteControlVector(res.control_vector, local);
10220
10264
  }
10221
10265
  } catch {
10222
10266
  }
@@ -11351,7 +11395,7 @@ import { writeFileSync as writeFileSync14, appendFileSync as appendFileSync8, ex
11351
11395
  import { join as join17, dirname as dirname12, basename as basename7 } from "node:path";
11352
11396
  import { createHash as createHash5 } from "node:crypto";
11353
11397
 
11354
- // src/lib/cost-anomaly.ts
11398
+ // src/lib/cost-anomaly.js
11355
11399
  var COST_WINDOW_SIZE = 20;
11356
11400
  var COST_ANOMALY_THRESHOLD = 3;
11357
11401
  var COST_WARMUP_SAMPLES = 5;
@@ -11362,21 +11406,26 @@ var CostAnomalyDetector = class {
11362
11406
  currentAnomalyCost = 0;
11363
11407
  currentAnomalyMean = 0;
11364
11408
  record(cost) {
11365
- if (this.disabled) return;
11409
+ if (this.disabled)
11410
+ return;
11366
11411
  this.costHistory.push(cost);
11367
11412
  if (this.costHistory.length > COST_WINDOW_SIZE) {
11368
11413
  this.costHistory.shift();
11369
11414
  }
11370
11415
  }
11371
11416
  get mean() {
11372
- if (this.costHistory.length === 0) return 0;
11417
+ if (this.costHistory.length === 0)
11418
+ return 0;
11373
11419
  return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
11374
11420
  }
11375
11421
  checkAnomaly(model, cost) {
11376
- if (this.disabled) return false;
11377
- if (this.costHistory.length < COST_WARMUP_SAMPLES) return false;
11422
+ if (this.disabled)
11423
+ return false;
11424
+ if (this.costHistory.length < COST_WARMUP_SAMPLES)
11425
+ return false;
11378
11426
  const avg = this.mean;
11379
- if (avg <= 0 || cost <= avg) return false;
11427
+ if (avg <= 0 || cost <= avg)
11428
+ return false;
11380
11429
  const ratio = cost / avg;
11381
11430
  if (ratio > COST_ANOMALY_THRESHOLD) {
11382
11431
  this.currentAnomalyModel = model;
@@ -11398,7 +11447,8 @@ var CostAnomalyDetector = class {
11398
11447
  };
11399
11448
  var _costDetector = null;
11400
11449
  function getCostAnomalyDetector() {
11401
- if (!_costDetector) _costDetector = new CostAnomalyDetector();
11450
+ if (!_costDetector)
11451
+ _costDetector = new CostAnomalyDetector();
11402
11452
  return _costDetector;
11403
11453
  }
11404
11454
 
@@ -11410,9 +11460,10 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync13, appen
11410
11460
  import { join as join16, dirname as dirname11 } from "node:path";
11411
11461
  import { createHash as createHash4 } from "node:crypto";
11412
11462
 
11413
- // src/utils/tdd-helpers.ts
11463
+ // src/utils/tdd-helpers.js
11414
11464
  function extractExports(sourceContent, ext) {
11415
- if (!sourceContent || typeof sourceContent !== "string") return [];
11465
+ if (!sourceContent || typeof sourceContent !== "string")
11466
+ return [];
11416
11467
  const exports = [];
11417
11468
  const seen = /* @__PURE__ */ new Set();
11418
11469
  const add = (name, type = "function") => {
@@ -11423,51 +11474,69 @@ function extractExports(sourceContent, ext) {
11423
11474
  };
11424
11475
  switch (ext) {
11425
11476
  case "py": {
11426
- for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm)) add(m[1]);
11427
- for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm)) add(m[1], "class");
11477
+ for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
11478
+ add(m[1]);
11479
+ for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm))
11480
+ add(m[1], "class");
11428
11481
  break;
11429
11482
  }
11430
11483
  case "js":
11431
11484
  case "mjs":
11432
11485
  case "jsx": {
11433
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11434
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g)) add(m[1]);
11486
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
11487
+ add(m[1]);
11488
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g))
11489
+ add(m[1]);
11435
11490
  if (exports.length === 0) {
11436
- for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm)) add(m[1]);
11491
+ for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
11492
+ add(m[1]);
11437
11493
  }
11438
11494
  break;
11439
11495
  }
11440
11496
  case "ts":
11441
11497
  case "tsx": {
11442
- for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11443
- for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g)) add(m[1]);
11444
- for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g)) add(m[1], "class");
11498
+ for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
11499
+ add(m[1]);
11500
+ for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g))
11501
+ add(m[1]);
11502
+ for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g))
11503
+ add(m[1], "class");
11445
11504
  break;
11446
11505
  }
11447
11506
  case "go": {
11448
- for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g)) add(m[1]);
11507
+ for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
11508
+ add(m[1]);
11449
11509
  break;
11450
11510
  }
11451
11511
  case "rs": {
11452
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g)) add(m[1]);
11453
- for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g)) add(m[1]);
11454
- for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g)) add(m[1], "struct");
11512
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
11513
+ add(m[1]);
11514
+ for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g))
11515
+ add(m[1]);
11516
+ for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g))
11517
+ add(m[1], "struct");
11455
11518
  break;
11456
11519
  }
11457
11520
  case "rb": {
11458
- for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g)) add(m[1]);
11459
- for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g)) add(m[1], "class");
11521
+ for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
11522
+ add(m[1]);
11523
+ for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g))
11524
+ add(m[1], "class");
11460
11525
  break;
11461
11526
  }
11462
11527
  case "java":
11463
11528
  case "kt": {
11464
- for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11465
- for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g)) add(m[1]);
11529
+ for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
11530
+ add(m[1]);
11531
+ for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g))
11532
+ add(m[1]);
11466
11533
  break;
11467
11534
  }
11468
11535
  case "sh": {
11469
- for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm)) add(m[1]);
11470
- for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm)) add(m[1]);
11536
+ for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
11537
+ add(m[1]);
11538
+ for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm))
11539
+ add(m[1]);
11471
11540
  break;
11472
11541
  }
11473
11542
  }
@@ -11489,7 +11558,8 @@ function generateTestCaseNames(funcName, _type, quality = false) {
11489
11558
  ];
11490
11559
  }
11491
11560
  function inferFunctionParams(sourceContent, funcName) {
11492
- if (!sourceContent || !funcName) return [];
11561
+ if (!sourceContent || !funcName)
11562
+ return [];
11493
11563
  const patterns = [
11494
11564
  new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
11495
11565
  new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
@@ -11502,7 +11572,8 @@ function inferFunctionParams(sourceContent, funcName) {
11502
11572
  if (m) {
11503
11573
  return m[1].split(",").map((s) => {
11504
11574
  const trimmed = s.trim();
11505
- if (!trimmed) return null;
11575
+ if (!trimmed)
11576
+ return null;
11506
11577
  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*[,)]))/);
11507
11578
  const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
11508
11579
  const defaultMatch = trimmed.match(/=\s*(.+)$/);
@@ -11518,22 +11589,35 @@ function inferFunctionParams(sourceContent, funcName) {
11518
11589
  return [];
11519
11590
  }
11520
11591
  function inferTypeFromName(paramName, defaultValue) {
11521
- if (!paramName) return "any";
11592
+ if (!paramName)
11593
+ return "any";
11522
11594
  const name = paramName.toLowerCase();
11523
11595
  if (defaultValue !== null && defaultValue !== void 0) {
11524
- if (/^["']/.test(defaultValue)) return "string";
11525
- if (/^\d+\.?\d*$/.test(defaultValue)) return "number";
11526
- if (/^(true|false)$/i.test(defaultValue)) return "boolean";
11527
- if (/^\[/.test(defaultValue)) return "array";
11528
- if (/^\{/.test(defaultValue)) return "object";
11529
- if (/^null$/i.test(defaultValue)) return "null";
11530
- }
11531
- if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name)) return "boolean";
11532
- if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name)) return "number";
11533
- if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name)) return "string";
11534
- if (/^(items|list|arr|entries|data|values|args)_?/.test(name)) return "array";
11535
- if (/^(obj|config|opts|options|settings|params|props)_?/.test(name)) return "object";
11536
- if (/^(fn|cb|callback|handler|on[A-Z])/.test(name)) return "function";
11596
+ if (/^["']/.test(defaultValue))
11597
+ return "string";
11598
+ if (/^\d+\.?\d*$/.test(defaultValue))
11599
+ return "number";
11600
+ if (/^(true|false)$/i.test(defaultValue))
11601
+ return "boolean";
11602
+ if (/^\[/.test(defaultValue))
11603
+ return "array";
11604
+ if (/^\{/.test(defaultValue))
11605
+ return "object";
11606
+ if (/^null$/i.test(defaultValue))
11607
+ return "null";
11608
+ }
11609
+ if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name))
11610
+ return "boolean";
11611
+ if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name))
11612
+ return "number";
11613
+ if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name))
11614
+ return "string";
11615
+ if (/^(items|list|arr|entries|data|values|args)_?/.test(name))
11616
+ return "array";
11617
+ if (/^(obj|config|opts|options|settings|params|props)_?/.test(name))
11618
+ return "object";
11619
+ if (/^(fn|cb|callback|handler|on[A-Z])/.test(name))
11620
+ return "function";
11537
11621
  return "any";
11538
11622
  }
11539
11623
  function _langComment(lang) {
@@ -11546,14 +11630,22 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11546
11630
  let block = "";
11547
11631
  const testValues = params.map((p) => {
11548
11632
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11549
- if (t === "string" || t === "String") return '"sample_input"';
11550
- if (t === "number" || t === "int" || t === "float" || t === "Number") return "42";
11551
- if (t === "boolean" || t === "bool" || t === "Boolean") return "true";
11552
- if (t === "array" || t === "Array" || t === "list" || t === "List") return "[]";
11553
- if (t === "object" || t === "Object" || t === "dict" || t === "Dict") return "{}";
11554
- if (t === "function" || t === "Function") return "() => {}";
11555
- if (t === "any") return '"test"';
11556
- if (t === "null") return "null";
11633
+ if (t === "string" || t === "String")
11634
+ return '"sample_input"';
11635
+ if (t === "number" || t === "int" || t === "float" || t === "Number")
11636
+ return "42";
11637
+ if (t === "boolean" || t === "bool" || t === "Boolean")
11638
+ return "true";
11639
+ if (t === "array" || t === "Array" || t === "list" || t === "List")
11640
+ return "[]";
11641
+ if (t === "object" || t === "Object" || t === "dict" || t === "Dict")
11642
+ return "{}";
11643
+ if (t === "function" || t === "Function")
11644
+ return "() => {}";
11645
+ if (t === "any")
11646
+ return '"test"';
11647
+ if (t === "null")
11648
+ return "null";
11557
11649
  return '"test"';
11558
11650
  });
11559
11651
  const args = testValues.join(", ");
@@ -11583,8 +11675,10 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11583
11675
  `;
11584
11676
  const ecArgs = params.map((p) => {
11585
11677
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11586
- if (t === "string") return '""';
11587
- if (t === "number" || t === "int" || t === "float") return "0";
11678
+ if (t === "string")
11679
+ return '""';
11680
+ if (t === "number" || t === "int" || t === "float")
11681
+ return "0";
11588
11682
  return '"edge"';
11589
11683
  }).join(", ");
11590
11684
  block += `${indent} result = ${funcName}(${ecArgs})
@@ -11622,11 +11716,16 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11622
11716
  `;
11623
11717
  const ecArgsJS = params.map((p) => {
11624
11718
  const t = p.type || inferTypeFromName(p.name, p.defaultValue);
11625
- if (t === "string") return '""';
11626
- if (t === "number" || t === "int" || t === "float") return "0";
11627
- if (t === "boolean") return "false";
11628
- if (t === "array") return "[]";
11629
- if (t === "object") return "{}";
11719
+ if (t === "string")
11720
+ return '""';
11721
+ if (t === "number" || t === "int" || t === "float")
11722
+ return "0";
11723
+ if (t === "boolean")
11724
+ return "false";
11725
+ if (t === "array")
11726
+ return "[]";
11727
+ if (t === "object")
11728
+ return "{}";
11630
11729
  return "undefined";
11631
11730
  }).join(", ");
11632
11731
  block += `${indent} const result = mod.${funcName}(${ecArgsJS});
@@ -11659,14 +11758,15 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
11659
11758
  return block;
11660
11759
  }
11661
11760
  function isSkeletonUseless(content) {
11662
- if (!content) return true;
11761
+ if (!content)
11762
+ return true;
11663
11763
  const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
11664
11764
  const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
11665
11765
  const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
11666
11766
  return meaningfulLines.length < 2;
11667
11767
  }
11668
11768
 
11669
- // src/lib/test-skeletons.ts
11769
+ // src/lib/test-skeletons.js
11670
11770
  var TEST_SKELETONS = {
11671
11771
  py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
11672
11772
  const moduleImport = name.replace(/-/g, "_");
@@ -11694,7 +11794,8 @@ var TEST_SKELETONS = {
11694
11794
 
11695
11795
  `;
11696
11796
  for (const exp of exports) {
11697
- if (exp.type === "class") continue;
11797
+ if (exp.type === "class")
11798
+ continue;
11698
11799
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11699
11800
  content += `# TODO: implement tests for ${exp.name}
11700
11801
  `;
@@ -11702,10 +11803,12 @@ var TEST_SKELETONS = {
11702
11803
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11703
11804
  content += `def test_${caseFunc}():
11704
11805
  `;
11705
- if (strict) content += ` raise AssertionError("TODO: implement ${caseName}")
11806
+ if (strict)
11807
+ content += ` raise AssertionError("TODO: implement ${caseName}")
11706
11808
 
11707
11809
  `;
11708
- else content += ` pytest.skip("TODO: implement ${caseName}")
11810
+ else
11811
+ content += ` pytest.skip("TODO: implement ${caseName}")
11709
11812
 
11710
11813
  `;
11711
11814
  }
@@ -11717,10 +11820,12 @@ var TEST_SKELETONS = {
11717
11820
  if (exports.length === 0) {
11718
11821
  content += `def test_${name}_placeholder():
11719
11822
  `;
11720
- if (strict) content += ` raise AssertionError("TODO: implement tests for ${name}")
11823
+ if (strict)
11824
+ content += ` raise AssertionError("TODO: implement tests for ${name}")
11721
11825
 
11722
11826
  `;
11723
- else content += ` pytest.skip("TODO: implement tests for ${name}")
11827
+ else
11828
+ content += ` pytest.skip("TODO: implement tests for ${name}")
11724
11829
 
11725
11830
  `;
11726
11831
  }
@@ -11754,7 +11859,8 @@ var TEST_SKELETONS = {
11754
11859
 
11755
11860
  `;
11756
11861
  for (const exp of exports) {
11757
- if (exp.type === "class") continue;
11862
+ if (exp.type === "class")
11863
+ continue;
11758
11864
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11759
11865
  content += ` // TODO: implement tests for ${exp.name}
11760
11866
  `;
@@ -11770,9 +11876,11 @@ var TEST_SKELETONS = {
11770
11876
  `;
11771
11877
  content += ` // TODO: implement ${caseName}
11772
11878
  `;
11773
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11879
+ if (strict)
11880
+ content += ` throw new Error('TODO: implement ${caseName}');
11774
11881
  `;
11775
- else content += ` expect(true).toBe(true);
11882
+ else
11883
+ content += ` expect(true).toBe(true);
11776
11884
  `;
11777
11885
  content += ` });
11778
11886
 
@@ -11825,7 +11933,8 @@ var TEST_SKELETONS = {
11825
11933
 
11826
11934
  `;
11827
11935
  for (const exp of exports) {
11828
- if (exp.type === "class") continue;
11936
+ if (exp.type === "class")
11937
+ continue;
11829
11938
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11830
11939
  content += ` // TODO: implement tests for ${exp.name}
11831
11940
  `;
@@ -11841,9 +11950,11 @@ var TEST_SKELETONS = {
11841
11950
  `;
11842
11951
  content += ` // TODO: implement ${caseName}
11843
11952
  `;
11844
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
11953
+ if (strict)
11954
+ content += ` throw new Error('TODO: implement ${caseName}');
11845
11955
  `;
11846
- else content += ` expect(true).toBe(true);
11956
+ else
11957
+ content += ` expect(true).toBe(true);
11847
11958
  `;
11848
11959
  content += ` });
11849
11960
 
@@ -11896,7 +12007,8 @@ var TEST_SKELETONS = {
11896
12007
 
11897
12008
  `;
11898
12009
  for (const exp of exports) {
11899
- if (exp.type === "class") continue;
12010
+ if (exp.type === "class")
12011
+ continue;
11900
12012
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11901
12013
  content += ` // TODO: implement tests for ${exp.name}
11902
12014
  `;
@@ -11912,9 +12024,11 @@ var TEST_SKELETONS = {
11912
12024
  `;
11913
12025
  content += ` // TODO: implement ${caseName}
11914
12026
  `;
11915
- if (strict) content += ` throw new Error('TODO: implement ${caseName}');
12027
+ if (strict)
12028
+ content += ` throw new Error('TODO: implement ${caseName}');
11916
12029
  `;
11917
- else content += ` expect(true).toBe(true);
12030
+ else
12031
+ content += ` expect(true).toBe(true);
11918
12032
  `;
11919
12033
  content += ` });
11920
12034
 
@@ -11974,7 +12088,8 @@ var TEST_SKELETONS = {
11974
12088
 
11975
12089
  `;
11976
12090
  for (const exp of exports) {
11977
- if (exp.type === "class") continue;
12091
+ if (exp.type === "class")
12092
+ continue;
11978
12093
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
11979
12094
  const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
11980
12095
  content += `// TODO: implement tests for ${exp.name}
@@ -11983,9 +12098,11 @@ var TEST_SKELETONS = {
11983
12098
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
11984
12099
  content += `func Test${cap}_${caseFunc}(t *testing.T) {
11985
12100
  `;
11986
- if (strict) content += ` t.Error("TODO: implement ${caseName}")
12101
+ if (strict)
12102
+ content += ` t.Error("TODO: implement ${caseName}")
11987
12103
  `;
11988
- else content += ` t.Skip("TODO: implement ${caseName}")
12104
+ else
12105
+ content += ` t.Skip("TODO: implement ${caseName}")
11989
12106
  `;
11990
12107
  content += `}
11991
12108
 
@@ -12005,9 +12122,11 @@ var TEST_SKELETONS = {
12005
12122
  if (exports.length === 0) {
12006
12123
  content += `func Test${cap}_Placeholder(t *testing.T) {
12007
12124
  `;
12008
- if (strict) content += ` t.Error("TODO: implement tests for ${name}")
12125
+ if (strict)
12126
+ content += ` t.Error("TODO: implement tests for ${name}")
12009
12127
  `;
12010
- else content += ` t.Skip("TODO: implement tests for ${name}")
12128
+ else
12129
+ content += ` t.Skip("TODO: implement tests for ${name}")
12011
12130
  `;
12012
12131
  content += `}
12013
12132
  `;
@@ -12040,9 +12159,11 @@ var TEST_SKELETONS = {
12040
12159
  `;
12041
12160
  content += ` echo "TODO: implement ${caseName}"
12042
12161
  `;
12043
- if (strict) content += ` exit 1
12162
+ if (strict)
12163
+ content += ` exit 1
12044
12164
  `;
12045
- else content += ` echo "SKIP: ${caseName}"
12165
+ else
12166
+ content += ` echo "SKIP: ${caseName}"
12046
12167
  `;
12047
12168
  content += `}
12048
12169
 
@@ -12056,9 +12177,11 @@ var TEST_SKELETONS = {
12056
12177
  if (exports.length === 0) {
12057
12178
  content += `function test_smoke {
12058
12179
  `;
12059
- if (strict) content += ` echo "TODO: implement tests for ${name}" && exit 1
12180
+ if (strict)
12181
+ content += ` echo "TODO: implement tests for ${name}" && exit 1
12060
12182
  `;
12061
- else content += ` echo "TODO: implement tests for ${name}"
12183
+ else
12184
+ content += ` echo "TODO: implement tests for ${name}"
12062
12185
  `;
12063
12186
  content += `}
12064
12187
  `;
@@ -12098,7 +12221,8 @@ mod tests {
12098
12221
 
12099
12222
  `;
12100
12223
  for (const exp of exports) {
12101
- if (exp.type === "class") continue;
12224
+ if (exp.type === "class")
12225
+ continue;
12102
12226
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12103
12227
  content += ` // TODO: implement tests for ${exp.name}
12104
12228
  `;
@@ -12107,9 +12231,11 @@ mod tests {
12107
12231
  content += ` #[test]
12108
12232
  fn test_${caseFunc}() {
12109
12233
  `;
12110
- if (strict) content += ` panic!("TODO: implement ${caseName}");
12234
+ if (strict)
12235
+ content += ` panic!("TODO: implement ${caseName}");
12111
12236
  `;
12112
- else content += ` // TODO: implement ${caseName}
12237
+ else
12238
+ content += ` // TODO: implement ${caseName}
12113
12239
  `;
12114
12240
  content += ` }
12115
12241
 
@@ -12124,9 +12250,11 @@ mod tests {
12124
12250
  content += ` #[test]
12125
12251
  fn ${name}_placeholder() {
12126
12252
  `;
12127
- if (strict) content += ` panic!("TODO: implement tests for ${name}");
12253
+ if (strict)
12254
+ content += ` panic!("TODO: implement tests for ${name}");
12128
12255
  `;
12129
- else content += ` // TODO: implement tests for ${name}
12256
+ else
12257
+ content += ` // TODO: implement tests for ${name}
12130
12258
  `;
12131
12259
  content += ` }
12132
12260
  `;
@@ -12166,7 +12294,8 @@ mod tests {
12166
12294
 
12167
12295
  `;
12168
12296
  for (const exp of exports) {
12169
- if (exp.type === "class") continue;
12297
+ if (exp.type === "class")
12298
+ continue;
12170
12299
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12171
12300
  content += ` # TODO: implement tests for ${exp.name}
12172
12301
  `;
@@ -12174,9 +12303,11 @@ mod tests {
12174
12303
  const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12175
12304
  content += ` def test_${caseFunc}
12176
12305
  `;
12177
- if (strict) content += ` flunk "TODO: implement ${caseName}"
12306
+ if (strict)
12307
+ content += ` flunk "TODO: implement ${caseName}"
12178
12308
  `;
12179
- else content += ` # TODO: implement ${caseName}
12309
+ else
12310
+ content += ` # TODO: implement ${caseName}
12180
12311
  `;
12181
12312
  content += ` end
12182
12313
 
@@ -12190,9 +12321,11 @@ mod tests {
12190
12321
  if (exports.length === 0) {
12191
12322
  content += ` def test_placeholder
12192
12323
  `;
12193
- if (strict) content += ` flunk "TODO: implement tests for ${name}"
12324
+ if (strict)
12325
+ content += ` flunk "TODO: implement tests for ${name}"
12194
12326
  `;
12195
- else content += ` # TODO: implement tests for ${name}
12327
+ else
12328
+ content += ` # TODO: implement tests for ${name}
12196
12329
  `;
12197
12330
  content += ` end
12198
12331
  `;
@@ -12238,15 +12371,18 @@ mod tests {
12238
12371
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12239
12372
  for (const caseName of cases) {
12240
12373
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12241
- if (!strict) content += ` // @Disabled("TODO")
12374
+ if (!strict)
12375
+ content += ` // @Disabled("TODO")
12242
12376
  `;
12243
12377
  content += ` @Test
12244
12378
  `;
12245
12379
  content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
12246
12380
  `;
12247
- if (strict) content += ` fail("TODO: implement ${caseName}");
12381
+ if (strict)
12382
+ content += ` fail("TODO: implement ${caseName}");
12248
12383
  `;
12249
- else content += ` assertTrue(true); // TODO: implement ${caseName}
12384
+ else
12385
+ content += ` assertTrue(true); // TODO: implement ${caseName}
12250
12386
  `;
12251
12387
  content += ` }
12252
12388
 
@@ -12308,15 +12444,18 @@ mod tests {
12308
12444
  const cases = generateTestCaseNames(exp.name, exp.type, quality);
12309
12445
  for (const caseName of cases) {
12310
12446
  const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
12311
- if (!strict) content += ` // @Disabled("TODO")
12447
+ if (!strict)
12448
+ content += ` // @Disabled("TODO")
12312
12449
  `;
12313
12450
  content += ` @Test
12314
12451
  `;
12315
12452
  content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
12316
12453
  `;
12317
- if (strict) content += ` fail("TODO: implement ${caseName}")
12454
+ if (strict)
12455
+ content += ` fail("TODO: implement ${caseName}")
12318
12456
  `;
12319
- else content += ` assertTrue(true) // TODO: implement ${caseName}
12457
+ else
12458
+ content += ` assertTrue(true) // TODO: implement ${caseName}
12320
12459
  `;
12321
12460
  content += ` }
12322
12461
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibeostheog",
3
- "version": "0.24.14",
3
+ "version": "0.24.16",
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",