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.
- package/CHANGELOG.md +26 -3
- package/dist/vibeOS.js +314 -175
- 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
|
|
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
|
-
|
|
2455
|
-
|
|
2456
|
-
j.selection
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
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.
|
|
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")
|
|
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("/"))
|
|
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))
|
|
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)
|
|
2553
|
-
|
|
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)
|
|
2559
|
-
|
|
2560
|
-
if (/\
|
|
2561
|
-
|
|
2562
|
-
if (/\bnpm\s+run\s+
|
|
2563
|
-
|
|
2564
|
-
if (/\
|
|
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)
|
|
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")
|
|
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)
|
|
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)
|
|
2625
|
+
if (!state?.sessions)
|
|
2626
|
+
return;
|
|
2609
2627
|
const entries = Object.entries(state.sessions);
|
|
2610
|
-
if (entries.length <= 30)
|
|
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
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
t
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
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
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
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.
|
|
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)))
|
|
9705
|
-
|
|
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)
|
|
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")
|
|
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)
|
|
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)
|
|
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.
|
|
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.
|
|
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")
|
|
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))
|
|
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")
|
|
10176
|
+
if (regime === "LOOPING" || regime === "DIVERGENT")
|
|
10177
|
+
return "speed";
|
|
10149
10178
|
return "save";
|
|
10150
10179
|
}
|
|
10151
|
-
if (detectStressSpike(stressScore))
|
|
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)
|
|
10158
|
-
|
|
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
|
|
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.
|
|
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)
|
|
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)
|
|
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)
|
|
11377
|
-
|
|
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)
|
|
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)
|
|
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.
|
|
11463
|
+
// src/utils/tdd-helpers.js
|
|
11414
11464
|
function extractExports(sourceContent, ext) {
|
|
11415
|
-
if (!sourceContent || typeof sourceContent !== "string")
|
|
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))
|
|
11427
|
-
|
|
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))
|
|
11434
|
-
|
|
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))
|
|
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))
|
|
11443
|
-
|
|
11444
|
-
for (const m of sourceContent.matchAll(/export\s+
|
|
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))
|
|
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))
|
|
11453
|
-
|
|
11454
|
-
for (const m of sourceContent.matchAll(/pub\s+
|
|
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))
|
|
11459
|
-
|
|
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))
|
|
11465
|
-
|
|
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))
|
|
11470
|
-
|
|
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)
|
|
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)
|
|
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)
|
|
11592
|
+
if (!paramName)
|
|
11593
|
+
return "any";
|
|
11522
11594
|
const name = paramName.toLowerCase();
|
|
11523
11595
|
if (defaultValue !== null && defaultValue !== void 0) {
|
|
11524
|
-
if (/^["']/.test(defaultValue))
|
|
11525
|
-
|
|
11526
|
-
if (
|
|
11527
|
-
|
|
11528
|
-
if (
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
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")
|
|
11550
|
-
|
|
11551
|
-
if (t === "
|
|
11552
|
-
|
|
11553
|
-
if (t === "
|
|
11554
|
-
|
|
11555
|
-
if (t === "
|
|
11556
|
-
|
|
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")
|
|
11587
|
-
|
|
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")
|
|
11626
|
-
|
|
11627
|
-
if (t === "
|
|
11628
|
-
|
|
11629
|
-
if (t === "
|
|
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)
|
|
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.
|
|
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")
|
|
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)
|
|
11806
|
+
if (strict)
|
|
11807
|
+
content += ` raise AssertionError("TODO: implement ${caseName}")
|
|
11706
11808
|
|
|
11707
11809
|
`;
|
|
11708
|
-
else
|
|
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)
|
|
11823
|
+
if (strict)
|
|
11824
|
+
content += ` raise AssertionError("TODO: implement tests for ${name}")
|
|
11721
11825
|
|
|
11722
11826
|
`;
|
|
11723
|
-
else
|
|
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")
|
|
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)
|
|
11879
|
+
if (strict)
|
|
11880
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11774
11881
|
`;
|
|
11775
|
-
else
|
|
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")
|
|
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)
|
|
11953
|
+
if (strict)
|
|
11954
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11845
11955
|
`;
|
|
11846
|
-
else
|
|
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")
|
|
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)
|
|
12027
|
+
if (strict)
|
|
12028
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11916
12029
|
`;
|
|
11917
|
-
else
|
|
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")
|
|
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)
|
|
12101
|
+
if (strict)
|
|
12102
|
+
content += ` t.Error("TODO: implement ${caseName}")
|
|
11987
12103
|
`;
|
|
11988
|
-
else
|
|
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)
|
|
12125
|
+
if (strict)
|
|
12126
|
+
content += ` t.Error("TODO: implement tests for ${name}")
|
|
12009
12127
|
`;
|
|
12010
|
-
else
|
|
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)
|
|
12162
|
+
if (strict)
|
|
12163
|
+
content += ` exit 1
|
|
12044
12164
|
`;
|
|
12045
|
-
else
|
|
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)
|
|
12180
|
+
if (strict)
|
|
12181
|
+
content += ` echo "TODO: implement tests for ${name}" && exit 1
|
|
12060
12182
|
`;
|
|
12061
|
-
else
|
|
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")
|
|
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)
|
|
12234
|
+
if (strict)
|
|
12235
|
+
content += ` panic!("TODO: implement ${caseName}");
|
|
12111
12236
|
`;
|
|
12112
|
-
else
|
|
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)
|
|
12253
|
+
if (strict)
|
|
12254
|
+
content += ` panic!("TODO: implement tests for ${name}");
|
|
12128
12255
|
`;
|
|
12129
|
-
else
|
|
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")
|
|
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)
|
|
12306
|
+
if (strict)
|
|
12307
|
+
content += ` flunk "TODO: implement ${caseName}"
|
|
12178
12308
|
`;
|
|
12179
|
-
else
|
|
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)
|
|
12324
|
+
if (strict)
|
|
12325
|
+
content += ` flunk "TODO: implement tests for ${name}"
|
|
12194
12326
|
`;
|
|
12195
|
-
else
|
|
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)
|
|
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)
|
|
12381
|
+
if (strict)
|
|
12382
|
+
content += ` fail("TODO: implement ${caseName}");
|
|
12248
12383
|
`;
|
|
12249
|
-
else
|
|
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)
|
|
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)
|
|
12454
|
+
if (strict)
|
|
12455
|
+
content += ` fail("TODO: implement ${caseName}")
|
|
12318
12456
|
`;
|
|
12319
|
-
else
|
|
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.
|
|
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",
|