vibeostheog 0.24.5 → 0.24.7
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/README.md +1 -1
- package/dist/vibeOS.js +341 -183
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -175,7 +175,7 @@ Local dev checkout:
|
|
|
175
175
|
| Command | Effect |
|
|
176
176
|
|---------|--------|
|
|
177
177
|
| `trinity status` | Tier, enforcement, savings, stress, lock state |
|
|
178
|
-
| `trinity set brain\|medium\|cheap` | Switch active model tier |
|
|
178
|
+
| `trinity set brain\|medium\|cheap [model=<model_id>]` | Switch active model tier or override the slot model |
|
|
179
179
|
| `trinity brain\|medium\|cheap` | Shorthand tier switch |
|
|
180
180
|
| `trinity enable\|disable` | Toggle plugin on/off |
|
|
181
181
|
| `trinity mode budget\|quality\|speed\|longrun\|auto` | Set optimization mode |
|
package/dist/vibeOS.js
CHANGED
|
@@ -1532,7 +1532,7 @@ import { dirname as dirname3 } from "node:path";
|
|
|
1532
1532
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
1533
1533
|
import { homedir } from "node:os";
|
|
1534
1534
|
|
|
1535
|
-
// src/lib/runtime-state.
|
|
1535
|
+
// src/lib/runtime-state.js
|
|
1536
1536
|
var RUNTIME_KEY = "__vibeOSRuntimeState";
|
|
1537
1537
|
function getRuntimeState() {
|
|
1538
1538
|
const g = globalThis;
|
|
@@ -1559,7 +1559,8 @@ function markApiDisconnected() {
|
|
|
1559
1559
|
const state = getRuntimeState();
|
|
1560
1560
|
state.apiConnected = false;
|
|
1561
1561
|
state.apiFallbackMode = true;
|
|
1562
|
-
if (!state.apiFallbackSince)
|
|
1562
|
+
if (!state.apiFallbackSince)
|
|
1563
|
+
state.apiFallbackSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
1563
1564
|
}
|
|
1564
1565
|
function resetApiConnection() {
|
|
1565
1566
|
const state = getRuntimeState();
|
|
@@ -2424,42 +2425,56 @@ function writeSessionOptMode(sid, mode) {
|
|
|
2424
2425
|
}
|
|
2425
2426
|
}
|
|
2426
2427
|
|
|
2427
|
-
// src/lib/pattern-helpers.
|
|
2428
|
+
// src/lib/pattern-helpers.js
|
|
2428
2429
|
import { relative, basename as basename2 } from "node:path";
|
|
2429
2430
|
function normalizeObservedPath(filePath, directory3) {
|
|
2430
|
-
if (!filePath || typeof filePath !== "string")
|
|
2431
|
+
if (!filePath || typeof filePath !== "string")
|
|
2432
|
+
return "unknown";
|
|
2431
2433
|
let p = filePath;
|
|
2432
2434
|
try {
|
|
2433
2435
|
if (directory3 && p.startsWith("/")) {
|
|
2434
2436
|
const rel = relative(directory3, p);
|
|
2435
|
-
if (rel && !rel.startsWith("..") && !rel.startsWith("/"))
|
|
2437
|
+
if (rel && !rel.startsWith("..") && !rel.startsWith("/"))
|
|
2438
|
+
p = rel;
|
|
2436
2439
|
}
|
|
2437
2440
|
} catch {
|
|
2438
2441
|
}
|
|
2439
2442
|
p = p.replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
2440
|
-
if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p))
|
|
2443
|
+
if (/^(src\/index\.js|package\.json|README\.md|CHANGELOG\.md|tsconfig\.json)$/i.test(p))
|
|
2444
|
+
return p;
|
|
2441
2445
|
const m = p.match(/\.([a-z0-9]+)$/i);
|
|
2442
|
-
if (p.startsWith("src/") && m)
|
|
2443
|
-
|
|
2446
|
+
if (p.startsWith("src/") && m)
|
|
2447
|
+
return `src/*.${m[1].toLowerCase()}`;
|
|
2448
|
+
if (p.startsWith("tests/") && m)
|
|
2449
|
+
return `tests/*.${m[1].toLowerCase()}`;
|
|
2444
2450
|
return basename2(p) || "unknown";
|
|
2445
2451
|
}
|
|
2446
2452
|
function commandFamily(command) {
|
|
2447
2453
|
const c = String(command || "").trim().toLowerCase();
|
|
2448
|
-
if (!c)
|
|
2449
|
-
|
|
2450
|
-
if (/\
|
|
2451
|
-
|
|
2452
|
-
if (/\bnpm\s+run\s+
|
|
2453
|
-
|
|
2454
|
-
if (/\
|
|
2454
|
+
if (!c)
|
|
2455
|
+
return "unknown";
|
|
2456
|
+
if (/\bnode\s+--check\b/.test(c))
|
|
2457
|
+
return "syntax-check";
|
|
2458
|
+
if (/\bnpm\s+run\s+typecheck\b|\btsc\b.*--noemit/.test(c))
|
|
2459
|
+
return "typecheck";
|
|
2460
|
+
if (/\bnpm\s+test\b|\bnode\s+--test\b|\bvitest\b|\bjest\b|\bpytest\b/.test(c))
|
|
2461
|
+
return "test";
|
|
2462
|
+
if (/\bnpm\s+run\s+build\b|\btsc\s+-p\b/.test(c))
|
|
2463
|
+
return "build";
|
|
2464
|
+
if (/\bgit\s+status\b/.test(c))
|
|
2465
|
+
return "git-status";
|
|
2466
|
+
if (/\bgit\s+commit\b/.test(c))
|
|
2467
|
+
return "git-commit";
|
|
2455
2468
|
const first = c.replace(/^[a-z_][a-z0-9_]*=\S+\s+/g, "").split(/\s+/)[0];
|
|
2456
2469
|
return /^[a-z0-9._/-]{1,30}$/.test(first) ? first : "command";
|
|
2457
2470
|
}
|
|
2458
2471
|
function commandFailed(output) {
|
|
2459
2472
|
const code = output?.exitCode ?? output?.statusCode ?? output?.code;
|
|
2460
|
-
if (Number.isFinite(Number(code)) && Number(code) !== 0)
|
|
2473
|
+
if (Number.isFinite(Number(code)) && Number(code) !== 0)
|
|
2474
|
+
return true;
|
|
2461
2475
|
const raw = output?.result ?? output?.text ?? output?.content ?? output?.data ?? "";
|
|
2462
|
-
if (typeof raw !== "string")
|
|
2476
|
+
if (typeof raw !== "string")
|
|
2477
|
+
return false;
|
|
2463
2478
|
return /\b(exit code|exited with code)\s*[:=]?\s*[1-9]\b|\b(assertionerror|syntaxerror|typeerror|referenceerror)\b|\b(failed|error:|err!)\b/i.test(raw);
|
|
2464
2479
|
}
|
|
2465
2480
|
function mergeProjectBucket(dst, src) {
|
|
@@ -2476,7 +2491,8 @@ function mergeProjectBucket(dst, src) {
|
|
|
2476
2491
|
row.sessions = [.../* @__PURE__ */ new Set([...row.sessions || [], ...v?.sessions || []])].slice(-10);
|
|
2477
2492
|
row.lastSeen = [row.lastSeen, v?.lastSeen].filter(Boolean).sort().slice(-1)[0] || null;
|
|
2478
2493
|
row.summary = row.summary || v?.summary || "";
|
|
2479
|
-
if (v?.kind)
|
|
2494
|
+
if (v?.kind)
|
|
2495
|
+
row.kind = v.kind;
|
|
2480
2496
|
out[key] = row;
|
|
2481
2497
|
}
|
|
2482
2498
|
}
|
|
@@ -2495,9 +2511,11 @@ function mergeProjectBucket(dst, src) {
|
|
|
2495
2511
|
};
|
|
2496
2512
|
}
|
|
2497
2513
|
function _pruneOldSessions(state) {
|
|
2498
|
-
if (!state?.sessions)
|
|
2514
|
+
if (!state?.sessions)
|
|
2515
|
+
return;
|
|
2499
2516
|
const entries = Object.entries(state.sessions);
|
|
2500
|
-
if (entries.length <= 30)
|
|
2517
|
+
if (entries.length <= 30)
|
|
2518
|
+
return;
|
|
2501
2519
|
entries.sort((a, b) => {
|
|
2502
2520
|
const da = a[1]?.started || a[1]?.last_costed || "";
|
|
2503
2521
|
const db = b[1]?.started || b[1]?.last_costed || "";
|
|
@@ -4662,7 +4680,6 @@ function _sortByCostAsc(models = []) {
|
|
|
4662
4680
|
function buildDeterministicTrinity(models, options = {}) {
|
|
4663
4681
|
const list = Array.isArray(models) ? models.filter((m) => m && typeof m === "object" && String(m.id || "").trim()) : [];
|
|
4664
4682
|
if (list.length === 0) return null;
|
|
4665
|
-
const selectedTier = String(options.selectedTier || "brain").toLowerCase();
|
|
4666
4683
|
const selectedModelId = String(options.selectedModelId || "").trim();
|
|
4667
4684
|
const providerHint = String(options.provider || "").trim();
|
|
4668
4685
|
const selectedModel = selectedModelId ? list.find((m) => m.id === selectedModelId || normalizeModelId(m.id) === normalizeModelId(selectedModelId)) || null : null;
|
|
@@ -4671,14 +4688,15 @@ function buildDeterministicTrinity(models, options = {}) {
|
|
|
4671
4688
|
const scoped = providerModels.length > 0 ? providerModels : list;
|
|
4672
4689
|
const qualityRanked = _sortByQualityDesc(scoped);
|
|
4673
4690
|
const costRanked = _sortByCostAsc(scoped);
|
|
4674
|
-
const
|
|
4675
|
-
const
|
|
4676
|
-
const
|
|
4677
|
-
const cheap = costRanked[0] ||
|
|
4691
|
+
const brain = selectedModel || qualityRanked[0] || costRanked[0] || scoped[0] || list[0];
|
|
4692
|
+
const medium = qualityRanked.find((m) => m.id !== brain?.id) || brain;
|
|
4693
|
+
const freeModel = scoped.find((m) => isModelFree(m.id));
|
|
4694
|
+
const cheap = freeModel || costRanked[0] || medium;
|
|
4695
|
+
const brainClass = isModelFree(brain?.id) ? "free" : classify(brain?.id);
|
|
4678
4696
|
return {
|
|
4679
4697
|
provider,
|
|
4680
|
-
selected_tier:
|
|
4681
|
-
selected_model:
|
|
4698
|
+
selected_tier: brainClass,
|
|
4699
|
+
selected_model: brain?.id || selectedModelId || "",
|
|
4682
4700
|
brain: brain?.id || "",
|
|
4683
4701
|
medium: medium?.id || "",
|
|
4684
4702
|
cheap: cheap?.id || "",
|
|
@@ -5527,7 +5545,8 @@ function _refreshModel(directory3) {
|
|
|
5527
5545
|
}
|
|
5528
5546
|
}
|
|
5529
5547
|
if (!_modelLocked) {
|
|
5530
|
-
const
|
|
5548
|
+
const activeIsManual = tiersData?.trinity?.[activeSlot]?.manual === true;
|
|
5549
|
+
const cfgModel = activeIsManual ? "" : readConfig(directory3) || readConfig(getOpenCodeHome()) || "";
|
|
5531
5550
|
if (cfgModel && cfgModel.includes("/") && cfgModel !== currentModel) {
|
|
5532
5551
|
const oldModel = currentModel;
|
|
5533
5552
|
const oldTier = currentTier;
|
|
@@ -5574,7 +5593,7 @@ function applySlot2(slot, projectDir = "") {
|
|
|
5574
5593
|
writeFileSync5(ocConfig, JSON.stringify(oc, null, 2) + "\n");
|
|
5575
5594
|
}
|
|
5576
5595
|
clearWorkspaceFollowupPauseForSession(getCurrentSessionId());
|
|
5577
|
-
_refreshModel(
|
|
5596
|
+
_refreshModel(dir);
|
|
5578
5597
|
return { ok: true, ocModel };
|
|
5579
5598
|
} catch (err) {
|
|
5580
5599
|
return { ok: false, reason: err.message };
|
|
@@ -7480,6 +7499,15 @@ function createTrinityTool(deps) {
|
|
|
7480
7499
|
const _brandedModeIds = ["vibeultrax", "vibeqmax", "vibemax", "vibelitex"];
|
|
7481
7500
|
const _builtInModeIds = ["budget", "quality", "speed", "longrun", "auto", "balanced", "audit", "forensic"];
|
|
7482
7501
|
if (!action || action === "status") {
|
|
7502
|
+
if (slot && (_brandedModeIds.includes(slot) || _builtInModeIds.includes(slot))) {
|
|
7503
|
+
action = "mode";
|
|
7504
|
+
} else if (["brain", "medium", "cheap"].includes(slot)) {
|
|
7505
|
+
action = "set";
|
|
7506
|
+
} else if (["full", "brief", "off"].includes(slot)) {
|
|
7507
|
+
action = "thinking";
|
|
7508
|
+
level = slot;
|
|
7509
|
+
slot = void 0;
|
|
7510
|
+
}
|
|
7483
7511
|
} else if (_brandedModeIds.includes(action) || _builtInModeIds.includes(action)) {
|
|
7484
7512
|
slot = action;
|
|
7485
7513
|
action = "mode";
|
|
@@ -7504,7 +7532,7 @@ function createTrinityTool(deps) {
|
|
|
7504
7532
|
const providers = deps._loadOpenCodeProviders();
|
|
7505
7533
|
const auth = deps._readAuth();
|
|
7506
7534
|
const models = await deps.discoverAvailableModels(providers, auth);
|
|
7507
|
-
const trinity = buildDeterministicTrinity(models, { selectedModelId: deps.currentModel
|
|
7535
|
+
const trinity = buildDeterministicTrinity(models, { selectedModelId: deps.currentModel });
|
|
7508
7536
|
if (trinity && trinity.brain) {
|
|
7509
7537
|
const probed = {
|
|
7510
7538
|
brain: models.find((m) => m.id === trinity.brain) || { id: trinity.brain, cost: deps._modelCost(trinity.brain), tier: deps._modelTier(trinity.brain) },
|
|
@@ -7640,12 +7668,24 @@ function createTrinityTool(deps) {
|
|
|
7640
7668
|
if (!tiers.trinity[slot]) tiers.trinity[slot] = {};
|
|
7641
7669
|
tiers.trinity[slot].oc = model;
|
|
7642
7670
|
tiers.trinity[slot].cc = model;
|
|
7671
|
+
tiers.trinity[slot].manual = true;
|
|
7643
7672
|
const _tmp = deps.TIERS_FILE + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
|
|
7644
7673
|
deps.writeFileSync(_tmp, JSON.stringify(tiers, null, 2) + "\n");
|
|
7645
7674
|
deps.renameSync(_tmp, deps.TIERS_FILE);
|
|
7646
7675
|
} catch (e) {
|
|
7647
7676
|
return `\u274C Failed to write model to tiers: ${e.message}`;
|
|
7648
7677
|
}
|
|
7678
|
+
} else {
|
|
7679
|
+
try {
|
|
7680
|
+
const tiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
|
|
7681
|
+
if (tiers?.trinity?.[slot]?.manual) {
|
|
7682
|
+
delete tiers.trinity[slot].manual;
|
|
7683
|
+
const _tmp = deps.TIERS_FILE + ".tmp." + Date.now() + "." + Math.random().toString(36).slice(2, 8);
|
|
7684
|
+
deps.writeFileSync(_tmp, JSON.stringify(tiers, null, 2) + "\n");
|
|
7685
|
+
deps.renameSync(_tmp, deps.TIERS_FILE);
|
|
7686
|
+
}
|
|
7687
|
+
} catch {
|
|
7688
|
+
}
|
|
7649
7689
|
}
|
|
7650
7690
|
let targetModel = "";
|
|
7651
7691
|
try {
|
|
@@ -7664,10 +7704,10 @@ function createTrinityTool(deps) {
|
|
|
7664
7704
|
console.error("[vibeOS] WARN: probe error for " + targetModel + ": " + e.message + " - switching anyway");
|
|
7665
7705
|
}
|
|
7666
7706
|
deps.writeSessionSlot(deps._OC_SID, slot);
|
|
7667
|
-
const result = deps.applySlot(slot);
|
|
7707
|
+
const result = deps.applySlot(slot, deps.directory);
|
|
7668
7708
|
if (!result.ok) return `\u274C Failed to set slot: ${result.reason}`;
|
|
7669
7709
|
try {
|
|
7670
|
-
const selected =
|
|
7710
|
+
const selected = resolveExecutionIdentity(result.ocModel, deps.directory);
|
|
7671
7711
|
if (selected) {
|
|
7672
7712
|
deps.writeSelection("selected_provider", selected.provider || "");
|
|
7673
7713
|
deps.writeSelection("selected_quality_tier", selected.quality || slot);
|
|
@@ -7862,8 +7902,7 @@ Lock is per-session (resets on restart).`;
|
|
|
7862
7902
|
} catch {
|
|
7863
7903
|
}
|
|
7864
7904
|
const selectedModel = deps.currentModel || existing?.selection?.selected_model || existing?.selection?.executed_model || "";
|
|
7865
|
-
const
|
|
7866
|
-
const trinity = buildDeterministicTrinity(discovered, { selectedModelId: selectedModel, selectedTier });
|
|
7905
|
+
const trinity = buildDeterministicTrinity(discovered, { selectedModelId: selectedModel });
|
|
7867
7906
|
const brain = trinity?.brain || existing?.trinity?.brain?.oc || selectedModel || "";
|
|
7868
7907
|
const medium = trinity?.medium || existing?.trinity?.medium?.oc || brain;
|
|
7869
7908
|
const cheap = trinity?.cheap || existing?.trinity?.cheap?.oc || medium || brain;
|
|
@@ -7882,14 +7921,14 @@ Lock is per-session (resets on restart).`;
|
|
|
7882
7921
|
tiers.selection.thinking_level = "off";
|
|
7883
7922
|
tiers.selection.setup_completed_at = now;
|
|
7884
7923
|
tiers.selection.selected_provider = trinity?.provider || resolveExecutionIdentity(selectedModel, deps.directory)?.provider || "";
|
|
7885
|
-
tiers.selection.selected_quality_tier = trinity?.selected_tier ||
|
|
7924
|
+
tiers.selection.selected_quality_tier = trinity?.selected_tier || "brain";
|
|
7886
7925
|
tiers.selection.selected_model = trinity?.selected_model || selectedModel || "";
|
|
7887
7926
|
tiers.selection.executed_provider = tiers.selection.selected_provider;
|
|
7888
7927
|
tiers.selection.executed_quality_tier = tiers.selection.selected_quality_tier;
|
|
7889
7928
|
tiers.selection.executed_model = tiers.selection.selected_model;
|
|
7890
|
-
if (brain) tiers.trinity.brain = { oc: brain, cc: deps.modelToCcAlias(brain) };
|
|
7891
|
-
if (medium) tiers.trinity.medium = { oc: medium, cc: deps.modelToCcAlias(medium) };
|
|
7892
|
-
if (cheap) tiers.trinity.cheap = { oc: cheap, cc: deps.modelToCcAlias(cheap) };
|
|
7929
|
+
if (brain && existing?.trinity?.brain?.manual !== true) tiers.trinity.brain = { oc: brain, cc: deps.modelToCcAlias(brain) };
|
|
7930
|
+
if (medium && existing?.trinity?.medium?.manual !== true) tiers.trinity.medium = { oc: medium, cc: deps.modelToCcAlias(medium) };
|
|
7931
|
+
if (cheap && existing?.trinity?.cheap?.manual !== true) tiers.trinity.cheap = { oc: cheap, cc: deps.modelToCcAlias(cheap) };
|
|
7893
7932
|
deps.mkdirSync(dirname9(deps.TIERS_FILE), { recursive: true });
|
|
7894
7933
|
deps.writeFileSync(deps.TIERS_FILE, JSON.stringify(tiers, null, 2) + "\n");
|
|
7895
7934
|
if (typeof deps._refreshModel === "function") deps._refreshModel(deps.directory);
|
|
@@ -8222,8 +8261,7 @@ ${L.repeat(40)}`);
|
|
|
8222
8261
|
const auth = deps._readAuth();
|
|
8223
8262
|
const models = await deps.discoverAvailableModels(providers, auth);
|
|
8224
8263
|
const selectedModel = deps.currentModel || deps.loadSelection?.().selected_model || deps.loadSelection?.().executed_model || "";
|
|
8225
|
-
const
|
|
8226
|
-
const trinity = buildDeterministicTrinity(models, { selectedModelId: selectedModel, selectedTier });
|
|
8264
|
+
const trinity = buildDeterministicTrinity(models, { selectedModelId: selectedModel });
|
|
8227
8265
|
if (!trinity) {
|
|
8228
8266
|
return "\u274C No models discovered from any configured provider.";
|
|
8229
8267
|
}
|
|
@@ -8244,14 +8282,15 @@ ${L.repeat(40)}`);
|
|
|
8244
8282
|
}
|
|
8245
8283
|
try {
|
|
8246
8284
|
const tiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
|
|
8285
|
+
const existing = tiers.trinity || {};
|
|
8247
8286
|
tiers.trinity = {
|
|
8248
|
-
brain: { oc: probed.brain.id, cc: deps.modelToCcAlias(probed.brain.id) },
|
|
8249
|
-
medium: { oc: probed.medium.id, cc: deps.modelToCcAlias(probed.medium.id) },
|
|
8250
|
-
cheap: { oc: probed.cheap.id, cc: deps.modelToCcAlias(probed.cheap.id) }
|
|
8287
|
+
brain: existing.brain?.manual === true ? { ...existing.brain } : { oc: probed.brain.id, cc: deps.modelToCcAlias(probed.brain.id) },
|
|
8288
|
+
medium: existing.medium?.manual === true ? { ...existing.medium } : { oc: probed.medium.id, cc: deps.modelToCcAlias(probed.medium.id) },
|
|
8289
|
+
cheap: existing.cheap?.manual === true ? { ...existing.cheap } : { oc: probed.cheap.id, cc: deps.modelToCcAlias(probed.cheap.id) }
|
|
8251
8290
|
};
|
|
8252
8291
|
tiers.selection ??= {};
|
|
8253
8292
|
tiers.selection.selected_provider = trinity.provider || resolveExecutionIdentity(selectedModel, deps.directory)?.provider || "";
|
|
8254
|
-
tiers.selection.selected_quality_tier = trinity.selected_tier ||
|
|
8293
|
+
tiers.selection.selected_quality_tier = trinity.selected_tier || "brain";
|
|
8255
8294
|
tiers.selection.selected_model = trinity.selected_model || selectedModel || "";
|
|
8256
8295
|
tiers.selection.executed_provider = tiers.selection.selected_provider;
|
|
8257
8296
|
tiers.selection.executed_quality_tier = tiers.selection.selected_quality_tier;
|
|
@@ -8267,11 +8306,14 @@ ${L.repeat(40)}`);
|
|
|
8267
8306
|
} catch (e) {
|
|
8268
8307
|
console.error("[vibeOS] auto-activate brain failed:", e.message);
|
|
8269
8308
|
}
|
|
8309
|
+
const _finalTiers = deps.safeJsonParse(deps.readFileSync(deps.TIERS_FILE, "utf-8"));
|
|
8310
|
+
const _trinity = _finalTiers?.trinity || {};
|
|
8311
|
+
const _pMan = (s) => _trinity[s]?.manual === true ? " [manual, preserved]" : "";
|
|
8270
8312
|
const lines = [
|
|
8271
8313
|
`\u{1F50D} Auto-detected models from provider: ${trinity.provider || "unknown"}`,
|
|
8272
|
-
" \u{1F9E0} brain \u2192 " + probed.brain.id + " (tier: " + probed.brain.tier + ", $" + probed.brain.cost.toFixed(4) + "/turn) \u2705",
|
|
8273
|
-
" \u2699 medium \u2192 " + probed.medium.id + " (tier: " + probed.medium.tier + ", $" + probed.medium.cost.toFixed(4) + "/turn) \u2705",
|
|
8274
|
-
" \u26A1 cheap \u2192 " + probed.cheap.id + " (tier: " + probed.cheap.tier + ", $" + probed.cheap.cost.toFixed(4) + "/turn) \u2705"
|
|
8314
|
+
" \u{1F9E0} brain \u2192 " + probed.brain.id + " (tier: " + probed.brain.tier + ", $" + probed.brain.cost.toFixed(4) + "/turn) \u2705" + _pMan("brain"),
|
|
8315
|
+
" \u2699 medium \u2192 " + probed.medium.id + " (tier: " + probed.medium.tier + ", $" + probed.medium.cost.toFixed(4) + "/turn) \u2705" + _pMan("medium"),
|
|
8316
|
+
" \u26A1 cheap \u2192 " + probed.cheap.id + " (tier: " + probed.cheap.tier + ", $" + probed.cheap.cost.toFixed(4) + "/turn) \u2705" + _pMan("cheap")
|
|
8275
8317
|
];
|
|
8276
8318
|
if (failed.length > 0) {
|
|
8277
8319
|
lines.push("", "Probe failures (skipped):");
|
|
@@ -8922,7 +8964,7 @@ import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, appen
|
|
|
8922
8964
|
import { join as join14, dirname as dirname11, basename as basename7 } from "node:path";
|
|
8923
8965
|
import { createHash as createHash3 } from "node:crypto";
|
|
8924
8966
|
|
|
8925
|
-
// src/lib/mode-policy.
|
|
8967
|
+
// src/lib/mode-policy.js
|
|
8926
8968
|
var STRESS_QUALITY_THRESHOLD = 1.5;
|
|
8927
8969
|
var BASELINE_MODE = "budget";
|
|
8928
8970
|
var LOOP_REGIMES = /* @__PURE__ */ new Set(["LOOPING", "DIVERGENT"]);
|
|
@@ -8930,7 +8972,8 @@ var QUALITY_REGIMES = /* @__PURE__ */ new Set(["CONVERGING", "CLOSED"]);
|
|
|
8930
8972
|
var MANUAL_MODES = /* @__PURE__ */ new Set(["balanced", "quality", "speed", "longrun", "vibemax", "vibeqmax", "vibeultrax"]);
|
|
8931
8973
|
function normalizeMode(mode) {
|
|
8932
8974
|
const normalized = String(mode || BASELINE_MODE).toLowerCase();
|
|
8933
|
-
if (normalized === "auto" || normalized === "")
|
|
8975
|
+
if (normalized === "auto" || normalized === "")
|
|
8976
|
+
return BASELINE_MODE;
|
|
8934
8977
|
if (normalized === "budget" || normalized === "quality" || normalized === "speed" || normalized === "longrun" || normalized === "balanced" || normalized === "vibemax" || normalized === "vibeqmax" || normalized === "vibeultrax") {
|
|
8935
8978
|
return normalized;
|
|
8936
8979
|
}
|
|
@@ -8943,9 +8986,12 @@ function isManualOverride(mode) {
|
|
|
8943
8986
|
return MANUAL_MODES.has(normalizeMode(mode));
|
|
8944
8987
|
}
|
|
8945
8988
|
function chooseEpisodeMode(regime, suggestedMode, stress) {
|
|
8946
|
-
if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax")
|
|
8947
|
-
|
|
8948
|
-
if (
|
|
8989
|
+
if (suggestedMode === "vibeultrax" || suggestedMode === "vibeqmax" || suggestedMode === "vibemax")
|
|
8990
|
+
return suggestedMode;
|
|
8991
|
+
if (LOOP_REGIMES.has(regime) || suggestedMode === "speed")
|
|
8992
|
+
return "speed";
|
|
8993
|
+
if (QUALITY_REGIMES.has(regime) || suggestedMode === "quality")
|
|
8994
|
+
return "quality";
|
|
8949
8995
|
return stress > STRESS_QUALITY_THRESHOLD ? "quality" : "budget";
|
|
8950
8996
|
}
|
|
8951
8997
|
function defaultPolicy() {
|
|
@@ -8966,15 +9012,19 @@ function defaultPolicy() {
|
|
|
8966
9012
|
}
|
|
8967
9013
|
function modeToSlot(mode) {
|
|
8968
9014
|
const normalized = normalizeMode(mode);
|
|
8969
|
-
if (normalized === "speed")
|
|
8970
|
-
|
|
9015
|
+
if (normalized === "speed")
|
|
9016
|
+
return "medium";
|
|
9017
|
+
if (normalized === "quality" || normalized === "longrun" || normalized === "vibeultrax" || normalized === "vibeqmax")
|
|
9018
|
+
return "brain";
|
|
8971
9019
|
return "cheap";
|
|
8972
9020
|
}
|
|
8973
9021
|
function loadSessionPolicy() {
|
|
8974
9022
|
const state = loadBlackboxState();
|
|
8975
|
-
if (!state.sessions || typeof state.sessions !== "object")
|
|
9023
|
+
if (!state.sessions || typeof state.sessions !== "object")
|
|
9024
|
+
state.sessions = {};
|
|
8976
9025
|
const sid = _OC_SID;
|
|
8977
|
-
if (!state.sessions[sid] || typeof state.sessions[sid] !== "object")
|
|
9026
|
+
if (!state.sessions[sid] || typeof state.sessions[sid] !== "object")
|
|
9027
|
+
state.sessions[sid] = {};
|
|
8978
9028
|
const session = state.sessions[sid];
|
|
8979
9029
|
if (!session.mode_policy || typeof session.mode_policy !== "object") {
|
|
8980
9030
|
session.mode_policy = defaultPolicy();
|
|
@@ -9102,7 +9152,7 @@ function recordBudgetFirstOutcome(input = {}) {
|
|
|
9102
9152
|
import { join as join13 } from "node:path";
|
|
9103
9153
|
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
9104
9154
|
|
|
9105
|
-
// src/lib/text-compress.
|
|
9155
|
+
// src/lib/text-compress.js
|
|
9106
9156
|
var VERBOSE_LINE_RE = [
|
|
9107
9157
|
/^[\s#*/\\\-_=+|~:;'"`@\$%^&<>{}\[\]()!?.,0-9]+$/,
|
|
9108
9158
|
/^(Filed|Created|Modified|Deleted|Updated|Renamed|Copied|Moved|Changed):/,
|
|
@@ -9119,12 +9169,15 @@ function extractBulletLines(lines, targetChars, minLines) {
|
|
|
9119
9169
|
const keyLines = [];
|
|
9120
9170
|
const otherLines = [];
|
|
9121
9171
|
for (const line of lines) {
|
|
9122
|
-
if (BULLET_PATTERNS.some((re) => re.test(line)))
|
|
9123
|
-
|
|
9172
|
+
if (BULLET_PATTERNS.some((re) => re.test(line)))
|
|
9173
|
+
keyLines.push(line);
|
|
9174
|
+
else
|
|
9175
|
+
otherLines.push(line);
|
|
9124
9176
|
}
|
|
9125
9177
|
const selected = [...keyLines];
|
|
9126
9178
|
for (const line of otherLines) {
|
|
9127
|
-
if (selected.length >= minLines && selected.join("\n").length >= targetChars)
|
|
9179
|
+
if (selected.length >= minLines && selected.join("\n").length >= targetChars)
|
|
9180
|
+
break;
|
|
9128
9181
|
selected.push(line);
|
|
9129
9182
|
}
|
|
9130
9183
|
while (selected.length > minLines && selected.join("\n").length > targetChars * 2) {
|
|
@@ -9133,7 +9186,8 @@ function extractBulletLines(lines, targetChars, minLines) {
|
|
|
9133
9186
|
return selected;
|
|
9134
9187
|
}
|
|
9135
9188
|
function compressText(text) {
|
|
9136
|
-
if (!text || typeof text !== "string")
|
|
9189
|
+
if (!text || typeof text !== "string")
|
|
9190
|
+
return text;
|
|
9137
9191
|
let lines = text.split("\n");
|
|
9138
9192
|
let removed = 0;
|
|
9139
9193
|
const out = [];
|
|
@@ -9146,14 +9200,16 @@ function compressText(text) {
|
|
|
9146
9200
|
break;
|
|
9147
9201
|
}
|
|
9148
9202
|
}
|
|
9149
|
-
if (!skip)
|
|
9203
|
+
if (!skip)
|
|
9204
|
+
out.push(line);
|
|
9150
9205
|
}
|
|
9151
9206
|
const collapsed = [];
|
|
9152
9207
|
let blanks = 0;
|
|
9153
9208
|
for (const line of out) {
|
|
9154
9209
|
if (line.trim() === "") {
|
|
9155
9210
|
blanks++;
|
|
9156
|
-
if (blanks <= 2)
|
|
9211
|
+
if (blanks <= 2)
|
|
9212
|
+
collapsed.push(line);
|
|
9157
9213
|
} else {
|
|
9158
9214
|
blanks = 0;
|
|
9159
9215
|
collapsed.push(line);
|
|
@@ -9161,10 +9217,7 @@ function compressText(text) {
|
|
|
9161
9217
|
}
|
|
9162
9218
|
let result = collapsed.join("\n").trim();
|
|
9163
9219
|
if (result.length > COMPRESS_THRESHOLD) {
|
|
9164
|
-
const targetChars = Math.max(
|
|
9165
|
-
Math.round(result.length * COMPRESS_RATIO),
|
|
9166
|
-
COMPRESS_THRESHOLD
|
|
9167
|
-
);
|
|
9220
|
+
const targetChars = Math.max(Math.round(result.length * COMPRESS_RATIO), COMPRESS_THRESHOLD);
|
|
9168
9221
|
const minLines = Math.max(1, Math.round(collapsed.length * MIN_KEPT_LINES_RATIO));
|
|
9169
9222
|
const bulletLines = extractBulletLines(collapsed, targetChars, minLines);
|
|
9170
9223
|
result = bulletLines.join("\n").trim();
|
|
@@ -9463,7 +9516,7 @@ function recordSaving(tool2, reason, saveEst, meta = {}) {
|
|
|
9463
9516
|
}
|
|
9464
9517
|
}
|
|
9465
9518
|
|
|
9466
|
-
// src/lib/constants.
|
|
9519
|
+
// src/lib/constants.js
|
|
9467
9520
|
var SAVE_EST = {
|
|
9468
9521
|
// Realistic: v4-pro (0.00057) - v4-flash (0.000182) = 0.000388/turn
|
|
9469
9522
|
WRITE_EDIT: 4e-4,
|
|
@@ -9481,7 +9534,7 @@ var COMPRESS_MARKER = "[ctx-compressed-v1]";
|
|
|
9481
9534
|
var PROTOCOL_MARKER = "[wbp-v1]";
|
|
9482
9535
|
var PROTOCOL_TEXT = PROTOCOL_MARKER + " [Worker-to-Brain Report Protocol] When synthesizing the preceding Task output: 1) EXTRACT core findings/data. 2) REFORMAT into bullet points. 3) VERIFY against the original ask. 4) SYNTHESIZE into final response.";
|
|
9483
9536
|
|
|
9484
|
-
// src/lib/templates.
|
|
9537
|
+
// src/lib/templates.js
|
|
9485
9538
|
var TEMPLATES = {
|
|
9486
9539
|
save: {
|
|
9487
9540
|
tier_bias: "cheap",
|
|
@@ -9520,7 +9573,8 @@ var TEMPLATES = {
|
|
|
9520
9573
|
var DEFAULT_TEMPLATE = "save";
|
|
9521
9574
|
var SEC_KEYWORDS = /\b(security|vuln|exploit|injection|xss|csrf|secret|credential|token leak|auth bypass|privacy|breach|backdoor|sql injection|cve)\b/i;
|
|
9522
9575
|
function detectSecuritySignal(text) {
|
|
9523
|
-
if (!text || typeof text !== "string")
|
|
9576
|
+
if (!text || typeof text !== "string")
|
|
9577
|
+
return false;
|
|
9524
9578
|
return SEC_KEYWORDS.test(text);
|
|
9525
9579
|
}
|
|
9526
9580
|
function detectBudgetSignal(creditPercent) {
|
|
@@ -9533,16 +9587,21 @@ function detectStressSpike(stressScore) {
|
|
|
9533
9587
|
return delta > 0.3 && stressScore > 0.5;
|
|
9534
9588
|
}
|
|
9535
9589
|
function resolveTemplate(prevTemplate, stressScore, userText, creditPercent) {
|
|
9536
|
-
if (detectSecuritySignal(userText))
|
|
9537
|
-
|
|
9538
|
-
if (
|
|
9590
|
+
if (detectSecuritySignal(userText))
|
|
9591
|
+
return "security";
|
|
9592
|
+
if (detectBudgetSignal(creditPercent))
|
|
9593
|
+
return "save";
|
|
9594
|
+
if (detectStressSpike(stressScore))
|
|
9595
|
+
return "quality";
|
|
9539
9596
|
return prevTemplate || DEFAULT_TEMPLATE;
|
|
9540
9597
|
}
|
|
9541
9598
|
var _turnCount = 0;
|
|
9542
9599
|
function shouldInjectTemplate(template, prevTemplate) {
|
|
9543
9600
|
_turnCount++;
|
|
9544
|
-
if (template !== prevTemplate)
|
|
9545
|
-
|
|
9601
|
+
if (template !== prevTemplate)
|
|
9602
|
+
return true;
|
|
9603
|
+
if (_turnCount % 10 === 0)
|
|
9604
|
+
return true;
|
|
9546
9605
|
return false;
|
|
9547
9606
|
}
|
|
9548
9607
|
|
|
@@ -10649,7 +10708,7 @@ import { writeFileSync as writeFileSync16, appendFileSync as appendFileSync9, ex
|
|
|
10649
10708
|
import { join as join17, dirname as dirname14, basename as basename9 } from "node:path";
|
|
10650
10709
|
import { createHash as createHash5 } from "node:crypto";
|
|
10651
10710
|
|
|
10652
|
-
// src/lib/cost-anomaly.
|
|
10711
|
+
// src/lib/cost-anomaly.js
|
|
10653
10712
|
var COST_WINDOW_SIZE = 20;
|
|
10654
10713
|
var COST_ANOMALY_THRESHOLD = 3;
|
|
10655
10714
|
var COST_WARMUP_SAMPLES = 5;
|
|
@@ -10660,21 +10719,26 @@ var CostAnomalyDetector = class {
|
|
|
10660
10719
|
currentAnomalyCost = 0;
|
|
10661
10720
|
currentAnomalyMean = 0;
|
|
10662
10721
|
record(cost) {
|
|
10663
|
-
if (this.disabled)
|
|
10722
|
+
if (this.disabled)
|
|
10723
|
+
return;
|
|
10664
10724
|
this.costHistory.push(cost);
|
|
10665
10725
|
if (this.costHistory.length > COST_WINDOW_SIZE) {
|
|
10666
10726
|
this.costHistory.shift();
|
|
10667
10727
|
}
|
|
10668
10728
|
}
|
|
10669
10729
|
get mean() {
|
|
10670
|
-
if (this.costHistory.length === 0)
|
|
10730
|
+
if (this.costHistory.length === 0)
|
|
10731
|
+
return 0;
|
|
10671
10732
|
return this.costHistory.reduce((a, b) => a + b, 0) / this.costHistory.length;
|
|
10672
10733
|
}
|
|
10673
10734
|
checkAnomaly(model, cost) {
|
|
10674
|
-
if (this.disabled)
|
|
10675
|
-
|
|
10735
|
+
if (this.disabled)
|
|
10736
|
+
return false;
|
|
10737
|
+
if (this.costHistory.length < COST_WARMUP_SAMPLES)
|
|
10738
|
+
return false;
|
|
10676
10739
|
const avg = this.mean;
|
|
10677
|
-
if (avg <= 0 || cost <= avg)
|
|
10740
|
+
if (avg <= 0 || cost <= avg)
|
|
10741
|
+
return false;
|
|
10678
10742
|
const ratio = cost / avg;
|
|
10679
10743
|
if (ratio > COST_ANOMALY_THRESHOLD) {
|
|
10680
10744
|
this.currentAnomalyModel = model;
|
|
@@ -10696,7 +10760,8 @@ var CostAnomalyDetector = class {
|
|
|
10696
10760
|
};
|
|
10697
10761
|
var _costDetector = null;
|
|
10698
10762
|
function getCostAnomalyDetector() {
|
|
10699
|
-
if (!_costDetector)
|
|
10763
|
+
if (!_costDetector)
|
|
10764
|
+
_costDetector = new CostAnomalyDetector();
|
|
10700
10765
|
return _costDetector;
|
|
10701
10766
|
}
|
|
10702
10767
|
|
|
@@ -10708,9 +10773,10 @@ import { readFileSync as readFileSync15, writeFileSync as writeFileSync15, appen
|
|
|
10708
10773
|
import { join as join16, dirname as dirname13 } from "node:path";
|
|
10709
10774
|
import { createHash as createHash4 } from "node:crypto";
|
|
10710
10775
|
|
|
10711
|
-
// src/utils/tdd-helpers.
|
|
10776
|
+
// src/utils/tdd-helpers.js
|
|
10712
10777
|
function extractExports(sourceContent, ext) {
|
|
10713
|
-
if (!sourceContent || typeof sourceContent !== "string")
|
|
10778
|
+
if (!sourceContent || typeof sourceContent !== "string")
|
|
10779
|
+
return [];
|
|
10714
10780
|
const exports = [];
|
|
10715
10781
|
const seen = /* @__PURE__ */ new Set();
|
|
10716
10782
|
const add = (name, type = "function") => {
|
|
@@ -10721,51 +10787,69 @@ function extractExports(sourceContent, ext) {
|
|
|
10721
10787
|
};
|
|
10722
10788
|
switch (ext) {
|
|
10723
10789
|
case "py": {
|
|
10724
|
-
for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
|
|
10725
|
-
|
|
10790
|
+
for (const m of sourceContent.matchAll(/^def\s+([a-zA-Z]\w*)\s*\(/gm))
|
|
10791
|
+
add(m[1]);
|
|
10792
|
+
for (const m of sourceContent.matchAll(/^class\s+([a-zA-Z_]\w*)\s*[\(:]/gm))
|
|
10793
|
+
add(m[1], "class");
|
|
10726
10794
|
break;
|
|
10727
10795
|
}
|
|
10728
10796
|
case "js":
|
|
10729
10797
|
case "mjs":
|
|
10730
10798
|
case "jsx": {
|
|
10731
|
-
for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10732
|
-
|
|
10799
|
+
for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10800
|
+
add(m[1]);
|
|
10801
|
+
for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*=/g))
|
|
10802
|
+
add(m[1]);
|
|
10733
10803
|
if (exports.length === 0) {
|
|
10734
|
-
for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
|
|
10804
|
+
for (const m of sourceContent.matchAll(/^(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/gm))
|
|
10805
|
+
add(m[1]);
|
|
10735
10806
|
}
|
|
10736
10807
|
break;
|
|
10737
10808
|
}
|
|
10738
10809
|
case "ts":
|
|
10739
10810
|
case "tsx": {
|
|
10740
|
-
for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10741
|
-
|
|
10742
|
-
for (const m of sourceContent.matchAll(/export\s+
|
|
10811
|
+
for (const m of sourceContent.matchAll(/export\s+(?:async\s+)?function\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10812
|
+
add(m[1]);
|
|
10813
|
+
for (const m of sourceContent.matchAll(/export\s+const\s+([a-zA-Z_$]\w*)\s*[:=]/g))
|
|
10814
|
+
add(m[1]);
|
|
10815
|
+
for (const m of sourceContent.matchAll(/export\s+class\s+([a-zA-Z_$]\w*)/g))
|
|
10816
|
+
add(m[1], "class");
|
|
10743
10817
|
break;
|
|
10744
10818
|
}
|
|
10745
10819
|
case "go": {
|
|
10746
|
-
for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
|
|
10820
|
+
for (const m of sourceContent.matchAll(/func\s+(?:\([^)]+\)\s+)?([A-Z]\w*)\s*\(/g))
|
|
10821
|
+
add(m[1]);
|
|
10747
10822
|
break;
|
|
10748
10823
|
}
|
|
10749
10824
|
case "rs": {
|
|
10750
|
-
for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
|
|
10751
|
-
|
|
10752
|
-
for (const m of sourceContent.matchAll(/pub\s+
|
|
10825
|
+
for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*</g))
|
|
10826
|
+
add(m[1]);
|
|
10827
|
+
for (const m of sourceContent.matchAll(/pub\s+fn\s+([a-zA-Z_]\w*)\s*\(/g))
|
|
10828
|
+
add(m[1]);
|
|
10829
|
+
for (const m of sourceContent.matchAll(/pub\s+struct\s+([a-zA-Z_]\w*)/g))
|
|
10830
|
+
add(m[1], "struct");
|
|
10753
10831
|
break;
|
|
10754
10832
|
}
|
|
10755
10833
|
case "rb": {
|
|
10756
|
-
for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
|
|
10757
|
-
|
|
10834
|
+
for (const m of sourceContent.matchAll(/def\s+(?:self\.)?([a-zA-Z_]\w*[?!=]?)/g))
|
|
10835
|
+
add(m[1]);
|
|
10836
|
+
for (const m of sourceContent.matchAll(/class\s+([A-Z]\w*)/g))
|
|
10837
|
+
add(m[1], "class");
|
|
10758
10838
|
break;
|
|
10759
10839
|
}
|
|
10760
10840
|
case "java":
|
|
10761
10841
|
case "kt": {
|
|
10762
|
-
for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10763
|
-
|
|
10842
|
+
for (const m of sourceContent.matchAll(/(?:public|protected)\s+(?:static\s+)?(?:final\s+)?\S+\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10843
|
+
add(m[1]);
|
|
10844
|
+
for (const m of sourceContent.matchAll(/fun\s+([a-zA-Z_$]\w*)\s*\(/g))
|
|
10845
|
+
add(m[1]);
|
|
10764
10846
|
break;
|
|
10765
10847
|
}
|
|
10766
10848
|
case "sh": {
|
|
10767
|
-
for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
|
|
10768
|
-
|
|
10849
|
+
for (const m of sourceContent.matchAll(/^(?:function\s+)?([a-zA-Z_]\w*)\s*\(\)\s*\{/gm))
|
|
10850
|
+
add(m[1]);
|
|
10851
|
+
for (const m of sourceContent.matchAll(/^function\s+([a-zA-Z_]\w*)/gm))
|
|
10852
|
+
add(m[1]);
|
|
10769
10853
|
break;
|
|
10770
10854
|
}
|
|
10771
10855
|
}
|
|
@@ -10787,7 +10871,8 @@ function generateTestCaseNames(funcName, _type, quality = false) {
|
|
|
10787
10871
|
];
|
|
10788
10872
|
}
|
|
10789
10873
|
function inferFunctionParams(sourceContent, funcName) {
|
|
10790
|
-
if (!sourceContent || !funcName)
|
|
10874
|
+
if (!sourceContent || !funcName)
|
|
10875
|
+
return [];
|
|
10791
10876
|
const patterns = [
|
|
10792
10877
|
new RegExp(`(?:export\\s+)?(?:async\\s+)?function\\s+${funcName}\\s*\\(([^)]*)\\)`, "m"),
|
|
10793
10878
|
new RegExp(`(?:export\\s+)?const\\s+${funcName}\\s*[:=]\\s*(?:async\\s+)?\\(([^)]*)\\)`, "m"),
|
|
@@ -10800,7 +10885,8 @@ function inferFunctionParams(sourceContent, funcName) {
|
|
|
10800
10885
|
if (m) {
|
|
10801
10886
|
return m[1].split(",").map((s) => {
|
|
10802
10887
|
const trimmed = s.trim();
|
|
10803
|
-
if (!trimmed)
|
|
10888
|
+
if (!trimmed)
|
|
10889
|
+
return null;
|
|
10804
10890
|
const nameMatch = trimmed.match(/^\s*((?:public|protected)|static|final|val|var|let|const)?\s*(?:readonly\s+)?(?:[_$a-zA-Z][_$a-zA-Z0-9]*)\s*(?::|(?=\s*=)|(?=\s*[,)]))/);
|
|
10805
10891
|
const rawName = trimmed.replace(/^[^a-zA-Z_$]*/, "").replace(/[=:].*$/, "").replace(/\s+.*$/, "").trim();
|
|
10806
10892
|
const defaultMatch = trimmed.match(/=\s*(.+)$/);
|
|
@@ -10816,22 +10902,35 @@ function inferFunctionParams(sourceContent, funcName) {
|
|
|
10816
10902
|
return [];
|
|
10817
10903
|
}
|
|
10818
10904
|
function inferTypeFromName(paramName, defaultValue) {
|
|
10819
|
-
if (!paramName)
|
|
10905
|
+
if (!paramName)
|
|
10906
|
+
return "any";
|
|
10820
10907
|
const name = paramName.toLowerCase();
|
|
10821
10908
|
if (defaultValue !== null && defaultValue !== void 0) {
|
|
10822
|
-
if (/^["']/.test(defaultValue))
|
|
10823
|
-
|
|
10824
|
-
if (
|
|
10825
|
-
|
|
10826
|
-
if (
|
|
10827
|
-
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10909
|
+
if (/^["']/.test(defaultValue))
|
|
10910
|
+
return "string";
|
|
10911
|
+
if (/^\d+\.?\d*$/.test(defaultValue))
|
|
10912
|
+
return "number";
|
|
10913
|
+
if (/^(true|false)$/i.test(defaultValue))
|
|
10914
|
+
return "boolean";
|
|
10915
|
+
if (/^\[/.test(defaultValue))
|
|
10916
|
+
return "array";
|
|
10917
|
+
if (/^\{/.test(defaultValue))
|
|
10918
|
+
return "object";
|
|
10919
|
+
if (/^null$/i.test(defaultValue))
|
|
10920
|
+
return "null";
|
|
10921
|
+
}
|
|
10922
|
+
if (/^(is|has|can|should|will|did|was|are|contains?_|[A-Z])/.test(name))
|
|
10923
|
+
return "boolean";
|
|
10924
|
+
if (/^(count|index|limit|offset|max|min|size|length|total|num|age)_?/.test(name))
|
|
10925
|
+
return "number";
|
|
10926
|
+
if (/^(name|title|label|msg|message|text|str|prefix|suffix|path|url|email|id)_?/.test(name))
|
|
10927
|
+
return "string";
|
|
10928
|
+
if (/^(items|list|arr|entries|data|values|args)_?/.test(name))
|
|
10929
|
+
return "array";
|
|
10930
|
+
if (/^(obj|config|opts|options|settings|params|props)_?/.test(name))
|
|
10931
|
+
return "object";
|
|
10932
|
+
if (/^(fn|cb|callback|handler|on[A-Z])/.test(name))
|
|
10933
|
+
return "function";
|
|
10835
10934
|
return "any";
|
|
10836
10935
|
}
|
|
10837
10936
|
function _langComment(lang) {
|
|
@@ -10844,14 +10943,22 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
|
|
|
10844
10943
|
let block = "";
|
|
10845
10944
|
const testValues = params.map((p) => {
|
|
10846
10945
|
const t = p.type || inferTypeFromName(p.name, p.defaultValue);
|
|
10847
|
-
if (t === "string" || t === "String")
|
|
10848
|
-
|
|
10849
|
-
if (t === "
|
|
10850
|
-
|
|
10851
|
-
if (t === "
|
|
10852
|
-
|
|
10853
|
-
if (t === "
|
|
10854
|
-
|
|
10946
|
+
if (t === "string" || t === "String")
|
|
10947
|
+
return '"sample_input"';
|
|
10948
|
+
if (t === "number" || t === "int" || t === "float" || t === "Number")
|
|
10949
|
+
return "42";
|
|
10950
|
+
if (t === "boolean" || t === "bool" || t === "Boolean")
|
|
10951
|
+
return "true";
|
|
10952
|
+
if (t === "array" || t === "Array" || t === "list" || t === "List")
|
|
10953
|
+
return "[]";
|
|
10954
|
+
if (t === "object" || t === "Object" || t === "dict" || t === "Dict")
|
|
10955
|
+
return "{}";
|
|
10956
|
+
if (t === "function" || t === "Function")
|
|
10957
|
+
return "() => {}";
|
|
10958
|
+
if (t === "any")
|
|
10959
|
+
return '"test"';
|
|
10960
|
+
if (t === "null")
|
|
10961
|
+
return "null";
|
|
10855
10962
|
return '"test"';
|
|
10856
10963
|
});
|
|
10857
10964
|
const args = testValues.join(", ");
|
|
@@ -10881,8 +10988,10 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
|
|
|
10881
10988
|
`;
|
|
10882
10989
|
const ecArgs = params.map((p) => {
|
|
10883
10990
|
const t = p.type || inferTypeFromName(p.name, p.defaultValue);
|
|
10884
|
-
if (t === "string")
|
|
10885
|
-
|
|
10991
|
+
if (t === "string")
|
|
10992
|
+
return '""';
|
|
10993
|
+
if (t === "number" || t === "int" || t === "float")
|
|
10994
|
+
return "0";
|
|
10886
10995
|
return '"edge"';
|
|
10887
10996
|
}).join(", ");
|
|
10888
10997
|
block += `${indent} result = ${funcName}(${ecArgs})
|
|
@@ -10920,11 +11029,16 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
|
|
|
10920
11029
|
`;
|
|
10921
11030
|
const ecArgsJS = params.map((p) => {
|
|
10922
11031
|
const t = p.type || inferTypeFromName(p.name, p.defaultValue);
|
|
10923
|
-
if (t === "string")
|
|
10924
|
-
|
|
10925
|
-
if (t === "
|
|
10926
|
-
|
|
10927
|
-
if (t === "
|
|
11032
|
+
if (t === "string")
|
|
11033
|
+
return '""';
|
|
11034
|
+
if (t === "number" || t === "int" || t === "float")
|
|
11035
|
+
return "0";
|
|
11036
|
+
if (t === "boolean")
|
|
11037
|
+
return "false";
|
|
11038
|
+
if (t === "array")
|
|
11039
|
+
return "[]";
|
|
11040
|
+
if (t === "object")
|
|
11041
|
+
return "{}";
|
|
10928
11042
|
return "undefined";
|
|
10929
11043
|
}).join(", ");
|
|
10930
11044
|
block += `${indent} const result = mod.${funcName}(${ecArgsJS});
|
|
@@ -10957,14 +11071,15 @@ function buildQualityAssertionsForFunc(funcName, params, lang, indent) {
|
|
|
10957
11071
|
return block;
|
|
10958
11072
|
}
|
|
10959
11073
|
function isSkeletonUseless(content) {
|
|
10960
|
-
if (!content)
|
|
11074
|
+
if (!content)
|
|
11075
|
+
return true;
|
|
10961
11076
|
const lines = content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("//") && !l.trim().startsWith("#") && !l.trim().startsWith("/*") && !l.trim().startsWith("*"));
|
|
10962
11077
|
const todoLines = content.split("\n").filter((l) => /TODO|placeholder|smoke|is exported|module loads/.test(l));
|
|
10963
11078
|
const meaningfulLines = lines.filter((l) => !/TODO|placeholder|smoke|is exported|module loads|throw new Error|raise AssertionError|pytest\.skip|assert.*true/.test(l));
|
|
10964
11079
|
return meaningfulLines.length < 2;
|
|
10965
11080
|
}
|
|
10966
11081
|
|
|
10967
|
-
// src/lib/test-skeletons.
|
|
11082
|
+
// src/lib/test-skeletons.js
|
|
10968
11083
|
var TEST_SKELETONS = {
|
|
10969
11084
|
py: (name, exports = [], depth = "full", strict = true, quality = true, sourceContent = "") => {
|
|
10970
11085
|
const moduleImport = name.replace(/-/g, "_");
|
|
@@ -10992,7 +11107,8 @@ var TEST_SKELETONS = {
|
|
|
10992
11107
|
|
|
10993
11108
|
`;
|
|
10994
11109
|
for (const exp of exports) {
|
|
10995
|
-
if (exp.type === "class")
|
|
11110
|
+
if (exp.type === "class")
|
|
11111
|
+
continue;
|
|
10996
11112
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
10997
11113
|
content += `# TODO: implement tests for ${exp.name}
|
|
10998
11114
|
`;
|
|
@@ -11000,10 +11116,12 @@ var TEST_SKELETONS = {
|
|
|
11000
11116
|
const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
11001
11117
|
content += `def test_${caseFunc}():
|
|
11002
11118
|
`;
|
|
11003
|
-
if (strict)
|
|
11119
|
+
if (strict)
|
|
11120
|
+
content += ` raise AssertionError("TODO: implement ${caseName}")
|
|
11004
11121
|
|
|
11005
11122
|
`;
|
|
11006
|
-
else
|
|
11123
|
+
else
|
|
11124
|
+
content += ` pytest.skip("TODO: implement ${caseName}")
|
|
11007
11125
|
|
|
11008
11126
|
`;
|
|
11009
11127
|
}
|
|
@@ -11015,10 +11133,12 @@ var TEST_SKELETONS = {
|
|
|
11015
11133
|
if (exports.length === 0) {
|
|
11016
11134
|
content += `def test_${name}_placeholder():
|
|
11017
11135
|
`;
|
|
11018
|
-
if (strict)
|
|
11136
|
+
if (strict)
|
|
11137
|
+
content += ` raise AssertionError("TODO: implement tests for ${name}")
|
|
11019
11138
|
|
|
11020
11139
|
`;
|
|
11021
|
-
else
|
|
11140
|
+
else
|
|
11141
|
+
content += ` pytest.skip("TODO: implement tests for ${name}")
|
|
11022
11142
|
|
|
11023
11143
|
`;
|
|
11024
11144
|
}
|
|
@@ -11052,7 +11172,8 @@ var TEST_SKELETONS = {
|
|
|
11052
11172
|
|
|
11053
11173
|
`;
|
|
11054
11174
|
for (const exp of exports) {
|
|
11055
|
-
if (exp.type === "class")
|
|
11175
|
+
if (exp.type === "class")
|
|
11176
|
+
continue;
|
|
11056
11177
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11057
11178
|
content += ` // TODO: implement tests for ${exp.name}
|
|
11058
11179
|
`;
|
|
@@ -11068,9 +11189,11 @@ var TEST_SKELETONS = {
|
|
|
11068
11189
|
`;
|
|
11069
11190
|
content += ` // TODO: implement ${caseName}
|
|
11070
11191
|
`;
|
|
11071
|
-
if (strict)
|
|
11192
|
+
if (strict)
|
|
11193
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11072
11194
|
`;
|
|
11073
|
-
else
|
|
11195
|
+
else
|
|
11196
|
+
content += ` expect(true).toBe(true);
|
|
11074
11197
|
`;
|
|
11075
11198
|
content += ` });
|
|
11076
11199
|
|
|
@@ -11123,7 +11246,8 @@ var TEST_SKELETONS = {
|
|
|
11123
11246
|
|
|
11124
11247
|
`;
|
|
11125
11248
|
for (const exp of exports) {
|
|
11126
|
-
if (exp.type === "class")
|
|
11249
|
+
if (exp.type === "class")
|
|
11250
|
+
continue;
|
|
11127
11251
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11128
11252
|
content += ` // TODO: implement tests for ${exp.name}
|
|
11129
11253
|
`;
|
|
@@ -11139,9 +11263,11 @@ var TEST_SKELETONS = {
|
|
|
11139
11263
|
`;
|
|
11140
11264
|
content += ` // TODO: implement ${caseName}
|
|
11141
11265
|
`;
|
|
11142
|
-
if (strict)
|
|
11266
|
+
if (strict)
|
|
11267
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11143
11268
|
`;
|
|
11144
|
-
else
|
|
11269
|
+
else
|
|
11270
|
+
content += ` expect(true).toBe(true);
|
|
11145
11271
|
`;
|
|
11146
11272
|
content += ` });
|
|
11147
11273
|
|
|
@@ -11194,7 +11320,8 @@ var TEST_SKELETONS = {
|
|
|
11194
11320
|
|
|
11195
11321
|
`;
|
|
11196
11322
|
for (const exp of exports) {
|
|
11197
|
-
if (exp.type === "class")
|
|
11323
|
+
if (exp.type === "class")
|
|
11324
|
+
continue;
|
|
11198
11325
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11199
11326
|
content += ` // TODO: implement tests for ${exp.name}
|
|
11200
11327
|
`;
|
|
@@ -11210,9 +11337,11 @@ var TEST_SKELETONS = {
|
|
|
11210
11337
|
`;
|
|
11211
11338
|
content += ` // TODO: implement ${caseName}
|
|
11212
11339
|
`;
|
|
11213
|
-
if (strict)
|
|
11340
|
+
if (strict)
|
|
11341
|
+
content += ` throw new Error('TODO: implement ${caseName}');
|
|
11214
11342
|
`;
|
|
11215
|
-
else
|
|
11343
|
+
else
|
|
11344
|
+
content += ` expect(true).toBe(true);
|
|
11216
11345
|
`;
|
|
11217
11346
|
content += ` });
|
|
11218
11347
|
|
|
@@ -11272,7 +11401,8 @@ var TEST_SKELETONS = {
|
|
|
11272
11401
|
|
|
11273
11402
|
`;
|
|
11274
11403
|
for (const exp of exports) {
|
|
11275
|
-
if (exp.type === "class")
|
|
11404
|
+
if (exp.type === "class")
|
|
11405
|
+
continue;
|
|
11276
11406
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11277
11407
|
const expCap = exp.name.charAt(0).toUpperCase() + exp.name.slice(1);
|
|
11278
11408
|
content += `// TODO: implement tests for ${exp.name}
|
|
@@ -11281,9 +11411,11 @@ var TEST_SKELETONS = {
|
|
|
11281
11411
|
const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
11282
11412
|
content += `func Test${cap}_${caseFunc}(t *testing.T) {
|
|
11283
11413
|
`;
|
|
11284
|
-
if (strict)
|
|
11414
|
+
if (strict)
|
|
11415
|
+
content += ` t.Error("TODO: implement ${caseName}")
|
|
11285
11416
|
`;
|
|
11286
|
-
else
|
|
11417
|
+
else
|
|
11418
|
+
content += ` t.Skip("TODO: implement ${caseName}")
|
|
11287
11419
|
`;
|
|
11288
11420
|
content += `}
|
|
11289
11421
|
|
|
@@ -11303,9 +11435,11 @@ var TEST_SKELETONS = {
|
|
|
11303
11435
|
if (exports.length === 0) {
|
|
11304
11436
|
content += `func Test${cap}_Placeholder(t *testing.T) {
|
|
11305
11437
|
`;
|
|
11306
|
-
if (strict)
|
|
11438
|
+
if (strict)
|
|
11439
|
+
content += ` t.Error("TODO: implement tests for ${name}")
|
|
11307
11440
|
`;
|
|
11308
|
-
else
|
|
11441
|
+
else
|
|
11442
|
+
content += ` t.Skip("TODO: implement tests for ${name}")
|
|
11309
11443
|
`;
|
|
11310
11444
|
content += `}
|
|
11311
11445
|
`;
|
|
@@ -11338,9 +11472,11 @@ var TEST_SKELETONS = {
|
|
|
11338
11472
|
`;
|
|
11339
11473
|
content += ` echo "TODO: implement ${caseName}"
|
|
11340
11474
|
`;
|
|
11341
|
-
if (strict)
|
|
11475
|
+
if (strict)
|
|
11476
|
+
content += ` exit 1
|
|
11342
11477
|
`;
|
|
11343
|
-
else
|
|
11478
|
+
else
|
|
11479
|
+
content += ` echo "SKIP: ${caseName}"
|
|
11344
11480
|
`;
|
|
11345
11481
|
content += `}
|
|
11346
11482
|
|
|
@@ -11354,9 +11490,11 @@ var TEST_SKELETONS = {
|
|
|
11354
11490
|
if (exports.length === 0) {
|
|
11355
11491
|
content += `function test_smoke {
|
|
11356
11492
|
`;
|
|
11357
|
-
if (strict)
|
|
11493
|
+
if (strict)
|
|
11494
|
+
content += ` echo "TODO: implement tests for ${name}" && exit 1
|
|
11358
11495
|
`;
|
|
11359
|
-
else
|
|
11496
|
+
else
|
|
11497
|
+
content += ` echo "TODO: implement tests for ${name}"
|
|
11360
11498
|
`;
|
|
11361
11499
|
content += `}
|
|
11362
11500
|
`;
|
|
@@ -11396,7 +11534,8 @@ mod tests {
|
|
|
11396
11534
|
|
|
11397
11535
|
`;
|
|
11398
11536
|
for (const exp of exports) {
|
|
11399
|
-
if (exp.type === "class")
|
|
11537
|
+
if (exp.type === "class")
|
|
11538
|
+
continue;
|
|
11400
11539
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11401
11540
|
content += ` // TODO: implement tests for ${exp.name}
|
|
11402
11541
|
`;
|
|
@@ -11405,9 +11544,11 @@ mod tests {
|
|
|
11405
11544
|
content += ` #[test]
|
|
11406
11545
|
fn test_${caseFunc}() {
|
|
11407
11546
|
`;
|
|
11408
|
-
if (strict)
|
|
11547
|
+
if (strict)
|
|
11548
|
+
content += ` panic!("TODO: implement ${caseName}");
|
|
11409
11549
|
`;
|
|
11410
|
-
else
|
|
11550
|
+
else
|
|
11551
|
+
content += ` // TODO: implement ${caseName}
|
|
11411
11552
|
`;
|
|
11412
11553
|
content += ` }
|
|
11413
11554
|
|
|
@@ -11422,9 +11563,11 @@ mod tests {
|
|
|
11422
11563
|
content += ` #[test]
|
|
11423
11564
|
fn ${name}_placeholder() {
|
|
11424
11565
|
`;
|
|
11425
|
-
if (strict)
|
|
11566
|
+
if (strict)
|
|
11567
|
+
content += ` panic!("TODO: implement tests for ${name}");
|
|
11426
11568
|
`;
|
|
11427
|
-
else
|
|
11569
|
+
else
|
|
11570
|
+
content += ` // TODO: implement tests for ${name}
|
|
11428
11571
|
`;
|
|
11429
11572
|
content += ` }
|
|
11430
11573
|
`;
|
|
@@ -11464,7 +11607,8 @@ mod tests {
|
|
|
11464
11607
|
|
|
11465
11608
|
`;
|
|
11466
11609
|
for (const exp of exports) {
|
|
11467
|
-
if (exp.type === "class")
|
|
11610
|
+
if (exp.type === "class")
|
|
11611
|
+
continue;
|
|
11468
11612
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11469
11613
|
content += ` # TODO: implement tests for ${exp.name}
|
|
11470
11614
|
`;
|
|
@@ -11472,9 +11616,11 @@ mod tests {
|
|
|
11472
11616
|
const caseFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
11473
11617
|
content += ` def test_${caseFunc}
|
|
11474
11618
|
`;
|
|
11475
|
-
if (strict)
|
|
11619
|
+
if (strict)
|
|
11620
|
+
content += ` flunk "TODO: implement ${caseName}"
|
|
11476
11621
|
`;
|
|
11477
|
-
else
|
|
11622
|
+
else
|
|
11623
|
+
content += ` # TODO: implement ${caseName}
|
|
11478
11624
|
`;
|
|
11479
11625
|
content += ` end
|
|
11480
11626
|
|
|
@@ -11488,9 +11634,11 @@ mod tests {
|
|
|
11488
11634
|
if (exports.length === 0) {
|
|
11489
11635
|
content += ` def test_placeholder
|
|
11490
11636
|
`;
|
|
11491
|
-
if (strict)
|
|
11637
|
+
if (strict)
|
|
11638
|
+
content += ` flunk "TODO: implement tests for ${name}"
|
|
11492
11639
|
`;
|
|
11493
|
-
else
|
|
11640
|
+
else
|
|
11641
|
+
content += ` # TODO: implement tests for ${name}
|
|
11494
11642
|
`;
|
|
11495
11643
|
content += ` end
|
|
11496
11644
|
`;
|
|
@@ -11536,15 +11684,18 @@ mod tests {
|
|
|
11536
11684
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11537
11685
|
for (const caseName of cases) {
|
|
11538
11686
|
const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
11539
|
-
if (!strict)
|
|
11687
|
+
if (!strict)
|
|
11688
|
+
content += ` // @Disabled("TODO")
|
|
11540
11689
|
`;
|
|
11541
11690
|
content += ` @Test
|
|
11542
11691
|
`;
|
|
11543
11692
|
content += ` void test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
|
|
11544
11693
|
`;
|
|
11545
|
-
if (strict)
|
|
11694
|
+
if (strict)
|
|
11695
|
+
content += ` fail("TODO: implement ${caseName}");
|
|
11546
11696
|
`;
|
|
11547
|
-
else
|
|
11697
|
+
else
|
|
11698
|
+
content += ` assertTrue(true); // TODO: implement ${caseName}
|
|
11548
11699
|
`;
|
|
11549
11700
|
content += ` }
|
|
11550
11701
|
|
|
@@ -11606,15 +11757,18 @@ mod tests {
|
|
|
11606
11757
|
const cases = generateTestCaseNames(exp.name, exp.type, quality);
|
|
11607
11758
|
for (const caseName of cases) {
|
|
11608
11759
|
const testFunc = caseName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
11609
|
-
if (!strict)
|
|
11760
|
+
if (!strict)
|
|
11761
|
+
content += ` // @Disabled("TODO")
|
|
11610
11762
|
`;
|
|
11611
11763
|
content += ` @Test
|
|
11612
11764
|
`;
|
|
11613
11765
|
content += ` fun test${testFunc.charAt(0).toUpperCase() + testFunc.slice(1)}() {
|
|
11614
11766
|
`;
|
|
11615
|
-
if (strict)
|
|
11767
|
+
if (strict)
|
|
11768
|
+
content += ` fail("TODO: implement ${caseName}")
|
|
11616
11769
|
`;
|
|
11617
|
-
else
|
|
11770
|
+
else
|
|
11771
|
+
content += ` assertTrue(true) // TODO: implement ${caseName}
|
|
11618
11772
|
`;
|
|
11619
11773
|
content += ` }
|
|
11620
11774
|
|
|
@@ -12492,7 +12646,10 @@ var onToolExecuteAfter = async (input, output) => {
|
|
|
12492
12646
|
const optModeFooter = loadSessionOptMode(currentSid + "_opt") || loadOptimizationMode() || "budget";
|
|
12493
12647
|
const activeSlot = selNow.active_slot || (execution.quality === "brain" ? "brain" : execution.quality === "medium" ? "medium" : "cheap");
|
|
12494
12648
|
const vibeBrand = resolveBrand(optModeFooter, activeSlot);
|
|
12495
|
-
const
|
|
12649
|
+
const sessionSlot = loadSessionSlot(currentSid);
|
|
12650
|
+
const displayMode = selNow.optimization_mode || optModeFooter || "auto";
|
|
12651
|
+
const currentSubRegime = loadBlackboxState()?.sessions?.[currentSid]?.sub_regime || classifyTurnSimple2(latestUserIntent || "");
|
|
12652
|
+
const flashIcon = isApiConnected2() ? " \u26A1" : "";
|
|
12496
12653
|
_footerText = buildFooterLine({
|
|
12497
12654
|
activeSlot,
|
|
12498
12655
|
providerLabel: execution.provider_label,
|
|
@@ -12500,10 +12657,12 @@ var onToolExecuteAfter = async (input, output) => {
|
|
|
12500
12657
|
ltTotal,
|
|
12501
12658
|
ltTrend: sesTrend || "",
|
|
12502
12659
|
vibeBrand,
|
|
12503
|
-
optMode:
|
|
12660
|
+
optMode: displayMode,
|
|
12504
12661
|
flashIcon,
|
|
12505
12662
|
enfTags,
|
|
12506
|
-
|
|
12663
|
+
sessionSlot,
|
|
12664
|
+
vectorChangedSlot: selNow.vector_changed_slot,
|
|
12665
|
+
subRegime: currentSubRegime
|
|
12507
12666
|
}) + "\n\n";
|
|
12508
12667
|
const footerTarget = _payload(output);
|
|
12509
12668
|
output.title = _footerText.trim();
|
|
@@ -12982,15 +13141,14 @@ async function _seedModelTiersIfMissing(directory3) {
|
|
|
12982
13141
|
discovered = await discoverAvailableModels(providers, auth);
|
|
12983
13142
|
} catch {
|
|
12984
13143
|
}
|
|
12985
|
-
let
|
|
13144
|
+
let trinity = null;
|
|
12986
13145
|
try {
|
|
12987
|
-
|
|
13146
|
+
trinity = buildDeterministicTrinity(discovered, { selectedModelId: currentModel });
|
|
12988
13147
|
} catch {
|
|
12989
13148
|
}
|
|
12990
|
-
|
|
12991
|
-
let
|
|
12992
|
-
let
|
|
12993
|
-
let cheap = ranked?.cheap?.id || medium || brain;
|
|
13149
|
+
let brain = trinity?.brain || currentModel || readConfig(directory3) || readConfig(getOpenCodeHome3()) || process?.env?.OPENCODE_MODEL || "";
|
|
13150
|
+
let medium = trinity?.medium || brain;
|
|
13151
|
+
let cheap = trinity?.cheap || medium || brain;
|
|
12994
13152
|
if (!brain) {
|
|
12995
13153
|
brain = "deepseek/deepseek-v4-pro";
|
|
12996
13154
|
medium = "deepseek/deepseek-v4-flash";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.7",
|
|
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",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"type": "module",
|
|
33
33
|
"main": "./dist/vibeOS.js",
|
|
34
34
|
"bin": {
|
|
35
|
-
"vibeostheog": "
|
|
35
|
+
"vibeostheog": "bin/setup.js"
|
|
36
36
|
},
|
|
37
37
|
"exports": {
|
|
38
38
|
".": "./dist/vibeOS.js",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
],
|
|
72
72
|
"repository": {
|
|
73
73
|
"type": "git",
|
|
74
|
-
"url": "https://github.com/DrunkkToys/vibeOS.git"
|
|
74
|
+
"url": "git+https://github.com/DrunkkToys/vibeOS.git"
|
|
75
75
|
},
|
|
76
76
|
"homepage": "https://github.com/DrunkkToys/vibeOS#readme",
|
|
77
77
|
"bugs": {
|