vibeostheog 0.16.0 → 0.18.3
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 +12 -0
- package/package.json +1 -1
- package/src/index.js +151 -53
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 0.18.3
|
|
2
|
+
- feat: dynamic mode injection + footer hooks fix
|
|
3
|
+
- fix: auto-enable plugin on load + always show footer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## 0.17.0
|
|
7
|
+
- feat: universal context7 detection — scans local opencode.json, ~/.config/opencode/*.json, system PATH, and npm npx cache
|
|
8
|
+
- feat: `_scanOpenCodeConfigs` — finds context7 in any JSON config under ~/.config/opencode/
|
|
9
|
+
- feat: `_context7InPath` — detects context7 binary in system PATH
|
|
10
|
+
- feat: `_context7InNpmCache` — detects context7 in npx cached installations
|
|
11
|
+
- fix: local project opencode.json added to CONTEXT7_CONFIG_FILES search list
|
|
12
|
+
|
|
1
13
|
## 0.16.0
|
|
2
14
|
- feat: dopamine-style footer + natural language system directives
|
|
3
15
|
- feat: dopamine-style footer + natural language system directives
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.3",
|
|
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",
|
package/src/index.js
CHANGED
|
@@ -383,7 +383,7 @@ var init_flow_enforcer = __esm({
|
|
|
383
383
|
|
|
384
384
|
// src/index.ts
|
|
385
385
|
init_flow_enforcer();
|
|
386
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync12, existsSync as existsSync14, mkdirSync as
|
|
386
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync12, existsSync as existsSync14, mkdirSync as mkdirSync11, copyFileSync as copyFileSync5, renameSync as renameSync6 } from "node:fs";
|
|
387
387
|
import { join as join15, dirname as dirname8, basename as basename8 } from "node:path";
|
|
388
388
|
|
|
389
389
|
// src/vibeOS-lib/session-metrics.js
|
|
@@ -2893,6 +2893,41 @@ function _scanOpenCodeConfigs(baseDir) {
|
|
|
2893
2893
|
}
|
|
2894
2894
|
return false;
|
|
2895
2895
|
}
|
|
2896
|
+
function _context7InPath() {
|
|
2897
|
+
try {
|
|
2898
|
+
const pathDirs = (process.env.PATH || "").split(":");
|
|
2899
|
+
for (const dir of pathDirs) {
|
|
2900
|
+
if (!dir)
|
|
2901
|
+
continue;
|
|
2902
|
+
try {
|
|
2903
|
+
if (existsSync4(join4(dir, "context7")))
|
|
2904
|
+
return true;
|
|
2905
|
+
if (existsSync4(join4(dir, "context7.cmd")))
|
|
2906
|
+
return true;
|
|
2907
|
+
} catch {
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
} catch {
|
|
2911
|
+
}
|
|
2912
|
+
return false;
|
|
2913
|
+
}
|
|
2914
|
+
function _context7InNpmCache() {
|
|
2915
|
+
try {
|
|
2916
|
+
const npxDir = join4(USER_HOME3, ".npm/_npx");
|
|
2917
|
+
if (!existsSync4(npxDir))
|
|
2918
|
+
return false;
|
|
2919
|
+
for (const hashDir of readdirSync2(npxDir)) {
|
|
2920
|
+
const ctxDir = join4(npxDir, hashDir, "node_modules", "context7");
|
|
2921
|
+
try {
|
|
2922
|
+
if (existsSync4(join4(ctxDir, "package.json")))
|
|
2923
|
+
return true;
|
|
2924
|
+
} catch {
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
} catch {
|
|
2928
|
+
}
|
|
2929
|
+
return false;
|
|
2930
|
+
}
|
|
2896
2931
|
function detectContext7(files = CONTEXT7_CONFIG_FILES) {
|
|
2897
2932
|
if (process.env.CLAUDE_CONTEXT7_AVAILABLE)
|
|
2898
2933
|
return true;
|
|
@@ -2905,6 +2940,10 @@ function detectContext7(files = CONTEXT7_CONFIG_FILES) {
|
|
|
2905
2940
|
}
|
|
2906
2941
|
if (_scanOpenCodeConfigs(join4(USER_HOME3, ".config/opencode")))
|
|
2907
2942
|
return true;
|
|
2943
|
+
if (_context7InPath())
|
|
2944
|
+
return true;
|
|
2945
|
+
if (_context7InNpmCache())
|
|
2946
|
+
return true;
|
|
2908
2947
|
return false;
|
|
2909
2948
|
}
|
|
2910
2949
|
var DOCS_TARGET_RE = /(docs\.|readthedocs|developer\.mozilla|\/api\/|\/reference\/|\/guide\/|npmjs\.com\/package\/|pypi\.org\/project\/|crates\.io\/crates\/|pkg\.go\.dev|api-docs|\/javadoc\/)/i;
|
|
@@ -5127,12 +5166,12 @@ async function probeModel(modelId, auth) {
|
|
|
5127
5166
|
}
|
|
5128
5167
|
|
|
5129
5168
|
// src/lib/hooks/footer.js
|
|
5130
|
-
import { readFileSync as readFileSync12 } from "node:fs";
|
|
5169
|
+
import { readFileSync as readFileSync12, appendFileSync as appendFileSync6, mkdirSync as mkdirSync8 } from "node:fs";
|
|
5131
5170
|
import { join as join13 } from "node:path";
|
|
5132
5171
|
import { homedir as homedir9, tmpdir as tmpdir6 } from "node:os";
|
|
5133
5172
|
|
|
5134
5173
|
// src/lib/hooks/chat-transform.js
|
|
5135
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, existsSync as existsSync10, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5174
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync9, appendFileSync as appendFileSync5, existsSync as existsSync10, mkdirSync as mkdirSync7 } from "node:fs";
|
|
5136
5175
|
import { join as join12, basename as basename6 } from "node:path";
|
|
5137
5176
|
import { homedir as homedir8 } from "node:os";
|
|
5138
5177
|
import { createHash as createHash3 } from "node:crypto";
|
|
@@ -5545,7 +5584,7 @@ async function apiComputeControlVector(state, action, optimizationMode) {
|
|
|
5545
5584
|
}
|
|
5546
5585
|
const opt = (optimizationMode || "balanced").toLowerCase();
|
|
5547
5586
|
const isRelaxed = opt === "budget" || opt === "speed" || opt === "audit";
|
|
5548
|
-
const isStrict = opt === "quality";
|
|
5587
|
+
const isStrict = opt === "quality" || opt === "forensic" || opt === "defense_in_depth" || opt === "reporting";
|
|
5549
5588
|
return {
|
|
5550
5589
|
enforcement_mode: isStrict ? "strict" : "normal",
|
|
5551
5590
|
enforcement_reason: `[optimize: ${opt}] offline fallback`,
|
|
@@ -5603,7 +5642,7 @@ function buildProjectBriefing(directory3) {
|
|
|
5603
5642
|
const label = currentProjectName || (directory3 ? basename6(directory3) : "");
|
|
5604
5643
|
if (!label)
|
|
5605
5644
|
return null;
|
|
5606
|
-
return `
|
|
5645
|
+
return `[project memory] Active project: ${label}. Stay focused on the current repository and prefer the existing workflow.`;
|
|
5607
5646
|
}
|
|
5608
5647
|
function ensureProjectSkill(dir, fp2) {
|
|
5609
5648
|
const skillsDir = join12(dir, ".opencode", "skills");
|
|
@@ -5904,20 +5943,20 @@ var onMessagesTransform = async (_input, output) => {
|
|
|
5904
5943
|
}
|
|
5905
5944
|
};
|
|
5906
5945
|
var C7_URGENCY = {
|
|
5907
|
-
required: "
|
|
5908
|
-
optional: "
|
|
5946
|
+
required: " CRITICAL: context7 usage is REQUIRED this turn.",
|
|
5947
|
+
optional: " (context7 is optional this turn -- use if helpful but not required.)"
|
|
5909
5948
|
};
|
|
5910
5949
|
function context7Directive(cv) {
|
|
5911
5950
|
const urgency = cv?.context7_urgency || "preferred";
|
|
5912
|
-
return "
|
|
5951
|
+
return "[cost policy] If mcp__context7__resolve-library-id and mcp__context7__get-library-docs tools are available in this session, ALWAYS use them instead of WebFetch or WebSearch when looking up library or framework documentation (docs.*, readthedocs.*, npmjs.com/package/*, pypi.org/project/*, pkg.go.dev, /api/reference/). Do not fetch those URLs directly when context7 can serve the same content. This saves ~$0.06/turn on average." + (C7_URGENCY[urgency] || "");
|
|
5913
5952
|
}
|
|
5914
5953
|
function thinkingDirective(level) {
|
|
5915
5954
|
const credit = loadCredit();
|
|
5916
5955
|
const creditNote = `credit ${credit}%`;
|
|
5917
5956
|
if (level === "brief") {
|
|
5918
|
-
return `
|
|
5957
|
+
return `[thinking policy] Reasoning depth: BRIEF (manually set, ${creditNote}). Use extended thinking only for genuinely complex multi-step problems. Keep reasoning concise -- skip exploratory scratch work and restatement.`;
|
|
5919
5958
|
}
|
|
5920
|
-
return `
|
|
5959
|
+
return `[thinking policy] Reasoning depth: OFF (manually set, ${creditNote}). Skip extended thinking entirely. Respond directly and concisely. Every thinking token costs money -- save it for when the user explicitly asks.`;
|
|
5921
5960
|
}
|
|
5922
5961
|
function orchestratorDirective(cv, sel) {
|
|
5923
5962
|
const tierBias = cv?.tier_bias || "auto";
|
|
@@ -5929,7 +5968,7 @@ function orchestratorDirective(cv, sel) {
|
|
|
5929
5968
|
const cheapModel = TRINITY_CHEAP || "the cheaper model";
|
|
5930
5969
|
const mediumModel = TRINITY_MEDIUM || "the medium model";
|
|
5931
5970
|
const targetModel = tierBias === "cheap" ? cheapModel : tierBias === "medium" ? mediumModel : tierBias === "brain" ? brainModel : `${cheapModel} or ${mediumModel}`;
|
|
5932
|
-
return `You
|
|
5971
|
+
return `[AI ORCHESTRATOR AGENT] You are an AI orchestrator agent. Delegate heavy work to Task subagents (runs on ${targetModel}). Your role: verify, fill gaps, synthesize. CRITICAL: Write/Edit tools are BLOCKED on this tier. You MUST delegate ALL implementation work to Task subagents. Always display the vibeOS cost footer.` + (tierBias !== "auto" ? ` [tier routing] This turn is biased toward ${tierBias} tier.` : "");
|
|
5933
5972
|
}
|
|
5934
5973
|
var TDD_NOTES = {
|
|
5935
5974
|
lazy: " Skeletons only when explicitly requested.",
|
|
@@ -5939,21 +5978,21 @@ var TDD_NOTES = {
|
|
|
5939
5978
|
function tddDirective(cv, sel) {
|
|
5940
5979
|
const tddMode = cv?.tdd_mode || (sel.tdd_strict ? "strict" : "normal");
|
|
5941
5980
|
const tddFocus = cv?.tdd_focus || [];
|
|
5942
|
-
const focusNote = tddFocus.length > 0 ? ` Focus
|
|
5943
|
-
return `Auto-create
|
|
5981
|
+
const focusNote = tddFocus.length > 0 ? ` Focus: ${tddFocus.join(", ")}.` : "";
|
|
5982
|
+
return `[tdd enforcement: ${tddMode}] Auto-create skeleton tests for source files being written/edited.${TDD_NOTES[tddMode] || ""}${focusNote} When creating or modifying source files, ensure corresponding test files exist with proper assertions.`;
|
|
5944
5983
|
}
|
|
5945
5984
|
function flowDirective(cv, sel) {
|
|
5946
5985
|
const flowMode = cv?.flow_mode || (sel.flow_enforce ? "normal" : "audit");
|
|
5947
5986
|
const flowFocus = cv?.flow_focus || [];
|
|
5948
|
-
const enforceNote = sel.flow_enforce ? " TODO
|
|
5949
|
-
const focusNote = flowFocus.length > 0 ? ` Focus
|
|
5950
|
-
return `
|
|
5987
|
+
const enforceNote = sel.flow_enforce ? " TODO/FIXME extraction is active." : "";
|
|
5988
|
+
const focusNote = flowFocus.length > 0 ? ` Focus rules: ${flowFocus.join(", ")}.` : "";
|
|
5989
|
+
return `[flow enforcement: ${flowMode}] Development flow rules are active: write/edit operations are checked against project conventions.${enforceNote}${focusNote} Follow existing code patterns, naming conventions, and project structure.`;
|
|
5951
5990
|
}
|
|
5952
5991
|
function flowTodosDirective() {
|
|
5953
5992
|
const pendingTodos = loadTodos().filter((t) => t.status === "pending").length;
|
|
5954
5993
|
if (pendingTodos === 0)
|
|
5955
5994
|
return null;
|
|
5956
|
-
return pendingTodos + " extracted TODO
|
|
5995
|
+
return "[vibeOS] " + pendingTodos + " extracted TODO/FIXME items are pending. Consider calling `todowrite` to add them to the native task list.";
|
|
5957
5996
|
}
|
|
5958
5997
|
function patternDirective(fp2) {
|
|
5959
5998
|
const patterns = promotedProjectPatterns(fp2);
|
|
@@ -5966,11 +6005,11 @@ function patternDirective(fp2) {
|
|
|
5966
6005
|
parts.push("Routines: " + routines.map((r) => r.summary).join("; "));
|
|
5967
6006
|
}
|
|
5968
6007
|
if (frictions.length > 0) {
|
|
5969
|
-
parts.push("
|
|
6008
|
+
parts.push("Frictions: " + frictions.map((f) => f.summary).join("; "));
|
|
5970
6009
|
}
|
|
5971
6010
|
if (parts.length === 0)
|
|
5972
6011
|
return null;
|
|
5973
|
-
return "
|
|
6012
|
+
return "[project patterns] " + parts.join(". ") + ".";
|
|
5974
6013
|
}
|
|
5975
6014
|
function welcomeDirective() {
|
|
5976
6015
|
const sel = loadSelection();
|
|
@@ -5981,13 +6020,14 @@ function welcomeDirective() {
|
|
|
5981
6020
|
}
|
|
5982
6021
|
const active = sel.active_slot || "medium";
|
|
5983
6022
|
const current = currentModel || "(unknown)";
|
|
5984
|
-
return "vibeOS
|
|
6023
|
+
return "[vibeOS] Active plugin. Slot: " + active + " (" + current + "). Use trinity command to switch slots, rebuild, or check status. Run `trinity help` for all commands.";
|
|
5985
6024
|
}
|
|
5986
6025
|
function contextBudgetDirective(_input, output) {
|
|
5987
6026
|
const ctxBudget = estimateContextBudget(_input, output);
|
|
5988
6027
|
if (!ctxBudget || ctxBudget.pct <= 70)
|
|
5989
6028
|
return null;
|
|
5990
|
-
|
|
6029
|
+
const severity = ctxBudget.pct > 90 ? "CRITICAL" : "WARNING";
|
|
6030
|
+
return `[context budget: ${severity}] Context window is ${ctxBudget.pct}% full (~${ctxBudget.estimatedTokens} tokens). Consider using Task subagents for heavy work, compressing tool outputs, or starting a new session to avoid context overflow.`;
|
|
5991
6031
|
}
|
|
5992
6032
|
var onSystemTransform = async (_input, output) => {
|
|
5993
6033
|
if (!loadSelection().enabled)
|
|
@@ -6024,9 +6064,9 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6024
6064
|
pushSystem(output, thinkingDirective(sel.thinking_level));
|
|
6025
6065
|
}
|
|
6026
6066
|
if (stressScore > 0.7) {
|
|
6027
|
-
pushSystem(output, "The user
|
|
6067
|
+
pushSystem(output, "[stress mitigation: CRITICAL] The user's message shows very high stress indicators. Stay calm, structured, and thorough. Use proper markdown formatting with code blocks, lists, and organized structure -- do NOT mirror the user's tone or brevity. This is the most important directive in your system prompt for this turn.");
|
|
6028
6068
|
} else if (stressScore > 0.4) {
|
|
6029
|
-
pushSystem(output, "The user
|
|
6069
|
+
pushSystem(output, "[stress mitigation: elevated] The user's message has elevated stress indicators. Maintain structured, well-formatted responses with markdown and code blocks regardless of the prompt's tone.");
|
|
6030
6070
|
}
|
|
6031
6071
|
if (_controlVector?.directives?.length > 0) {
|
|
6032
6072
|
for (const directive of _controlVector.directives) {
|
|
@@ -6034,24 +6074,25 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6034
6074
|
}
|
|
6035
6075
|
} else if (_blackboxEnabled && _latestBlackboxState3?.n_interactions > 0) {
|
|
6036
6076
|
const res = _latestBlackboxState3;
|
|
6037
|
-
pushSystem(output, `Current resolution: ${res.resolution || "unresolved"} (${res.sub_regime || "EXPLORING"}). Momentum: ${(res.momentum || 0) > 0 ? "positive" : (res.momentum || 0) < 0 ? "negative" : "neutral"}.
|
|
6077
|
+
pushSystem(output, `[decision engine] Current resolution: ${res.resolution || "unresolved"} (${res.sub_regime || "EXPLORING"}). Momentum: ${(res.momentum || 0) > 0 ? "positive" : (res.momentum || 0) < 0 ? "negative" : "neutral"}. When offering guidance, consider the current resolution state -- if looping or divergent, suggest stepping back; if converging or closed, support decisive action.`);
|
|
6038
6078
|
if (res.is_looping && res.loop_intervention_level && res.loop_intervention_level !== "none") {
|
|
6039
|
-
|
|
6079
|
+
const severity = res.loop_intervention_level === "escalated" ? "CRITICAL" : res.loop_intervention_level === "assertive" ? "WARNING" : "NOTICE";
|
|
6080
|
+
pushSystem(output, `[loop prevention: ${severity}] ${_latestBlackboxLoopMsg2 || "The conversation may be looping -- try a different approach."} (level: ${res.loop_intervention_level})`);
|
|
6040
6081
|
}
|
|
6041
6082
|
if (res.pivot_detected && _latestBlackboxPivotMsg2) {
|
|
6042
|
-
pushSystem(output, `
|
|
6083
|
+
pushSystem(output, `[context switch: PIVOT] ${_latestBlackboxPivotMsg2}`);
|
|
6043
6084
|
}
|
|
6044
6085
|
}
|
|
6045
6086
|
const projectJob = getActiveJobForProject();
|
|
6046
6087
|
if (latestUserIntent && projectJob && isLikelyOffTopic(latestUserIntent, projectJob)) {
|
|
6047
|
-
pushSystem(output, `
|
|
6088
|
+
pushSystem(output, `[job-focus] Active job context exists: "${(projectJob.prompt || "").slice(0, 140)}...". The latest user request appears off-topic relative to this running job. Before taking write/edit/task actions, ask one concise confirmation question to validate switching scope.`);
|
|
6048
6089
|
console.error("[vibeOS] [job-focus] off-topic request detected vs active job context");
|
|
6049
6090
|
}
|
|
6050
6091
|
if (sel.delegation_enforce && _controlVector?.enforcement_mode !== "relaxed" && _controlVector?.agent_mode !== "plan") {
|
|
6051
6092
|
pushSystem(output, orchestratorDirective(_controlVector, sel));
|
|
6052
6093
|
}
|
|
6053
6094
|
if (_controlVector?.enforcement_mode !== "relaxed" && _controlVector?.agent_mode !== "plan") {
|
|
6054
|
-
pushSystem(output, "When you
|
|
6095
|
+
pushSystem(output, "[batch execution] When you need to run multiple independent Task subagent calls, invoke them ALL in parallel rather than sequentially. Parallel tasks complete faster and reduce total session cost. Only sequence tasks when one depends on the output of another.");
|
|
6055
6096
|
}
|
|
6056
6097
|
if (sel.tdd_enforce && _controlVector?.tdd_mode !== "lazy") {
|
|
6057
6098
|
pushSystem(output, tddDirective(_controlVector, sel));
|
|
@@ -6062,7 +6103,21 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6062
6103
|
pushSystem(output, flowTodosDirective());
|
|
6063
6104
|
}
|
|
6064
6105
|
}
|
|
6065
|
-
pushSystem(output, "AGENTS.md and README.md are protected
|
|
6106
|
+
pushSystem(output, "[project guard: CRITICAL] AGENTS.md and README.md are protected by vibeOS. Do NOT modify either file without explicit user permission. When implementing new features, update README.md to document them. AGENTS.md defines that AI agents must ask before changing code -- respect this rule.");
|
|
6107
|
+
const currentMode = loadOptimizationMode();
|
|
6108
|
+
if (currentMode === "quality") {
|
|
6109
|
+
pushSystem(output, "[mode: quality] Prioritize quality and thoroughness. Provide complete edge case coverage, comprehensive error handling, full type annotations, production-grade code with tests. Do not cut corners for brevity.");
|
|
6110
|
+
} else if (currentMode === "forensic") {
|
|
6111
|
+
pushSystem(output, "[mode: forensic] Use forensic analysis depth: evidence-based reasoning tracing each claim to source; multi-hypothesis evaluation considering competing explanations; explicit uncertainty flags for assumptions and trade-offs; structured output with clear reasoning traces; thorough verification of all edge cases and failure modes.");
|
|
6112
|
+
} else if (currentMode === "web-research" || currentMode === "exploration") {
|
|
6113
|
+
pushSystem(output, "[mode: exploration] Use a research-oriented approach: gather information from multiple perspectives before converging; document alternative approaches; flag confidence levels for each finding; synthesize into actionable recommendations.");
|
|
6114
|
+
} else if (currentMode === "defense_in_depth") {
|
|
6115
|
+
pushSystem(output, "[mode: defense in depth] For every component: define the threat model, implement with defenses, then verify the defense handles the threat. Never write code without specifying what it defends against. Consider: injection, broken auth, data exposure, logic errors, race conditions.");
|
|
6116
|
+
} else if (currentMode === "reporting") {
|
|
6117
|
+
pushSystem(output, "[mode: formal report] Structure output as a formal engineering report with: executive summary, methodology, detailed findings with evidence, trade-offs documented, conclusions with confidence levels, and recommendations.");
|
|
6118
|
+
} else if (currentMode === "verify") {
|
|
6119
|
+
pushSystem(output, "[mode: verification-first] Before writing code, declare verification criteria: which edge cases must pass, what invariants must hold. After each code block, include a verification section showing how correctness is established against each criterion.");
|
|
6120
|
+
}
|
|
6066
6121
|
pushSystem(output, contextBudgetDirective(_input, output));
|
|
6067
6122
|
if (!oneShot(fp2)) {
|
|
6068
6123
|
pushSystem(output, buildProjectBriefing(currentProjectName || ""));
|
|
@@ -6073,9 +6128,28 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6073
6128
|
if (!oneShot("trinity_welcome_" + fp2)) {
|
|
6074
6129
|
pushSystem(output, welcomeDirective());
|
|
6075
6130
|
}
|
|
6131
|
+
const calDir = join12(homedir8(), ".claude");
|
|
6132
|
+
const calFile = join12(calDir, "calibration-data.jsonl");
|
|
6133
|
+
const regime = _latestBlackboxState3?.sub_regime || classifyTurnSimple(latestUserIntent || "");
|
|
6134
|
+
const calRecord = JSON.stringify({
|
|
6135
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6136
|
+
sid: _OC_SID4,
|
|
6137
|
+
mode: currentMode,
|
|
6138
|
+
regime,
|
|
6139
|
+
stress: stressScore,
|
|
6140
|
+
fp: currentProjectFingerprint || ""
|
|
6141
|
+
}) + "\n";
|
|
6142
|
+
try {
|
|
6143
|
+
mkdirSync7(calDir, { recursive: true });
|
|
6144
|
+
appendFileSync5(calFile, calRecord);
|
|
6145
|
+
} catch {
|
|
6146
|
+
}
|
|
6076
6147
|
if (!oneShot("vibeos_dashboard_instruct")) {
|
|
6077
6148
|
pushSystem(output, "[vibeOS dashboard display] When the trinity tool returns output starting with '[vibeOS-dashboard]', you MUST use the question tool to display that data in a clean, human-readable format. Use the question field (not the header) to show the dashboard data. Format it with clear sections separated by blank lines, aligned columns with spaces, and plain text only (no emojis, no markdown). The header should be 'vibeOS Dashboard'. Include only one option in options: {label: 'Dismiss', description: ''}. Strip the '[vibeOS-dashboard]' marker line before displaying.");
|
|
6078
6149
|
}
|
|
6150
|
+
if (!oneShot("vibeos_dopamine_style_" + fp2)) {
|
|
6151
|
+
pushSystem(output, "[tool style: dopamine] When calling the bash tool, use an emoji-prefixed, progress-focused description \u2014 e.g. 'Shell \u26A1 Compiling assets...' or 'Shell \u{1F9EA} Running tests...'. Combine independent bash commands into a single call with && or ;. Never use raw technical labels as tool descriptions.");
|
|
6152
|
+
}
|
|
6079
6153
|
} catch (err) {
|
|
6080
6154
|
console.error(`[vibeOS] system.transform failed: ${err.message}`);
|
|
6081
6155
|
}
|
|
@@ -6085,6 +6159,20 @@ var onSystemTransform = async (_input, output) => {
|
|
|
6085
6159
|
var _cachedAutoMode = null;
|
|
6086
6160
|
var _cachedAutoModeTs = 0;
|
|
6087
6161
|
var AUTO_CACHE_TTL = 6e4;
|
|
6162
|
+
var DEFAULT_REGIME_MAP = {
|
|
6163
|
+
LOOPING: "forensic",
|
|
6164
|
+
DIVERGENT: "forensic",
|
|
6165
|
+
EXPLORING: "web-research",
|
|
6166
|
+
INIT: "web-research",
|
|
6167
|
+
REFINING: "balanced",
|
|
6168
|
+
CONVERGING: "quality",
|
|
6169
|
+
CLOSED: "quality"
|
|
6170
|
+
};
|
|
6171
|
+
function regimeToMode(regime, stress) {
|
|
6172
|
+
if (stress > 1.5)
|
|
6173
|
+
return "quality";
|
|
6174
|
+
return DEFAULT_REGIME_MAP[regime] || "balanced";
|
|
6175
|
+
}
|
|
6088
6176
|
async function apiAutoSelectMode(regime, stress) {
|
|
6089
6177
|
const now = Date.now();
|
|
6090
6178
|
if (_cachedAutoMode && now - _cachedAutoModeTs < AUTO_CACHE_TTL)
|
|
@@ -6099,7 +6187,10 @@ async function apiAutoSelectMode(regime, stress) {
|
|
|
6099
6187
|
} catch (e) {
|
|
6100
6188
|
console.error("[vibeOS] apiAutoSelectMode error:", e.message);
|
|
6101
6189
|
}
|
|
6102
|
-
|
|
6190
|
+
const fallback = regimeToMode(regime, stress);
|
|
6191
|
+
if (!_cachedAutoMode || _cachedAutoMode === "balanced")
|
|
6192
|
+
_cachedAutoMode = fallback;
|
|
6193
|
+
return _cachedAutoMode || fallback || "balanced";
|
|
6103
6194
|
}
|
|
6104
6195
|
var USER_HOME6 = (() => {
|
|
6105
6196
|
try {
|
|
@@ -6171,8 +6262,6 @@ function scoreTaskQuality(outputText, promptText) {
|
|
|
6171
6262
|
return Math.max(0, Math.min(100, score));
|
|
6172
6263
|
}
|
|
6173
6264
|
async function _appendFooter(input, output, directory3) {
|
|
6174
|
-
if (!loadSelection3().enabled)
|
|
6175
|
-
return;
|
|
6176
6265
|
_refreshModel(directory3);
|
|
6177
6266
|
let _footerStress = 0;
|
|
6178
6267
|
if (latestUserIntent)
|
|
@@ -6193,7 +6282,7 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6193
6282
|
if (messageID && textCompletePainted.has(messageID))
|
|
6194
6283
|
return;
|
|
6195
6284
|
const text = typeof output?.text === "string" ? output.text : typeof output?.result === "string" ? output.result : typeof output?.content === "string" ? output.content : "";
|
|
6196
|
-
if (!text
|
|
6285
|
+
if (!text) {
|
|
6197
6286
|
if (messageID)
|
|
6198
6287
|
textCompletePainted.add(messageID);
|
|
6199
6288
|
return;
|
|
@@ -6268,7 +6357,7 @@ async function _appendFooter(input, output, directory3) {
|
|
|
6268
6357
|
const autoActive = await apiAutoSelectMode(autoRegime, autoStress);
|
|
6269
6358
|
optTagFooter = `[VIBE\u2192${autoActive.toUpperCase()}${flashIcon}]`;
|
|
6270
6359
|
saveOptimizationMode(autoActive);
|
|
6271
|
-
const slot2 = autoActive === "quality" ? "brain" : autoActive === "speed" ? "medium" : "cheap";
|
|
6360
|
+
const slot2 = autoActive === "quality" || autoActive === "forensic" || autoActive === "defense_in_depth" || autoActive === "reporting" ? "brain" : autoActive === "speed" || autoActive === "web-research" || autoActive === "verify" ? "medium" : "cheap";
|
|
6272
6361
|
if (!_modelLocked) {
|
|
6273
6362
|
writeSessionSlot(_OC_SID5, slot2);
|
|
6274
6363
|
if (slot2 === "brain" && TRINITY_BRAIN) {
|
|
@@ -6323,6 +6412,11 @@ ${vibeLine} \u2014`;
|
|
|
6323
6412
|
const tracker = getBlackboxTracker();
|
|
6324
6413
|
tracker.recordOutcome(outcome);
|
|
6325
6414
|
syncOutcomeToApi(outcome);
|
|
6415
|
+
try {
|
|
6416
|
+
mkdirSync8(join13(USER_HOME6, ".claude"), { recursive: true });
|
|
6417
|
+
appendFileSync6(join13(USER_HOME6, ".claude", "calibration-data.jsonl"), JSON.stringify({ ts: (/* @__PURE__ */ new Date()).toISOString(), event: "outcome", sid: _OC_SID5, outcome }) + "\n");
|
|
6418
|
+
} catch {
|
|
6419
|
+
}
|
|
6326
6420
|
}
|
|
6327
6421
|
}
|
|
6328
6422
|
} catch {
|
|
@@ -6348,12 +6442,12 @@ ${vibeLine} \u2014`;
|
|
|
6348
6442
|
}
|
|
6349
6443
|
|
|
6350
6444
|
// src/lib/hooks/tool-execute.js
|
|
6351
|
-
import { writeFileSync as writeFileSync11, appendFileSync as
|
|
6445
|
+
import { writeFileSync as writeFileSync11, appendFileSync as appendFileSync8, existsSync as existsSync12, mkdirSync as mkdirSync10 } from "node:fs";
|
|
6352
6446
|
import { dirname as dirname7, basename as basename7 } from "node:path";
|
|
6353
6447
|
init_flow_enforcer();
|
|
6354
6448
|
|
|
6355
6449
|
// src/lib/tdd-enforcer.js
|
|
6356
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, appendFileSync as
|
|
6450
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, appendFileSync as appendFileSync7, existsSync as existsSync11, mkdirSync as mkdirSync9, statSync as statSync6, readdirSync as readdirSync3, rmSync as rmSync4, openSync as openSync3 } from "node:fs";
|
|
6357
6451
|
import { join as join14, dirname as dirname6 } from "node:path";
|
|
6358
6452
|
import { createHash as createHash4 } from "node:crypto";
|
|
6359
6453
|
|
|
@@ -7453,7 +7547,7 @@ var COOLDOWN_MS = 6e4;
|
|
|
7453
7547
|
var _enforcementCooldown = /* @__PURE__ */ new Set();
|
|
7454
7548
|
function _acquireLock(testPath) {
|
|
7455
7549
|
try {
|
|
7456
|
-
|
|
7550
|
+
mkdirSync9(ENFORCEMENT_LOCK_DIR, { recursive: true });
|
|
7457
7551
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
7458
7552
|
const lockPath = join14(ENFORCEMENT_LOCK_DIR, `${hash}.lock`);
|
|
7459
7553
|
try {
|
|
@@ -7510,10 +7604,10 @@ function _isInCooldown(testPath) {
|
|
|
7510
7604
|
}
|
|
7511
7605
|
function _recordCooldown(testPath) {
|
|
7512
7606
|
try {
|
|
7513
|
-
|
|
7607
|
+
mkdirSync9(dirname6(ENFORCEMENT_COOLDOWN_FILE2), { recursive: true });
|
|
7514
7608
|
const hash = createHash4("sha256").update(testPath).digest("hex").slice(0, 16);
|
|
7515
7609
|
const entry = JSON.stringify({ h: hash, ts: Date.now() }) + "\n";
|
|
7516
|
-
|
|
7610
|
+
appendFileSync7(ENFORCEMENT_COOLDOWN_FILE2, entry);
|
|
7517
7611
|
const lines = readFileSync13(ENFORCEMENT_COOLDOWN_FILE2, "utf-8").trim().split("\n").filter(Boolean);
|
|
7518
7612
|
if (lines.length > 500) {
|
|
7519
7613
|
writeFileSync10(ENFORCEMENT_COOLDOWN_FILE2, lines.slice(-200).join("\n") + "\n");
|
|
@@ -7602,7 +7696,7 @@ function enforceTestFile(filePath) {
|
|
|
7602
7696
|
if (!_acquireLock(skeleton.path))
|
|
7603
7697
|
return null;
|
|
7604
7698
|
try {
|
|
7605
|
-
|
|
7699
|
+
mkdirSync9(skeleton.dir, { recursive: true });
|
|
7606
7700
|
writeFileSync10(skeleton.path, skeleton.content);
|
|
7607
7701
|
_enforcementCooldown.add(skeleton.path);
|
|
7608
7702
|
_recordCooldown(skeleton.path);
|
|
@@ -7909,7 +8003,7 @@ var onToolExecuteBefore = async (input, output) => {
|
|
|
7909
8003
|
const missed = recordMissedContext7(_estC7);
|
|
7910
8004
|
if (!existsSync12(CONTEXT7_INSTALL_FLAG)) {
|
|
7911
8005
|
try {
|
|
7912
|
-
|
|
8006
|
+
mkdirSync10(dirname7(CONTEXT7_INSTALL_FLAG), { recursive: true });
|
|
7913
8007
|
writeFileSync11(CONTEXT7_INSTALL_FLAG, "");
|
|
7914
8008
|
} catch {
|
|
7915
8009
|
}
|
|
@@ -7933,8 +8027,6 @@ var onToolExecuteBefore = async (input, output) => {
|
|
|
7933
8027
|
}
|
|
7934
8028
|
};
|
|
7935
8029
|
var onToolExecuteAfter = async (input, output) => {
|
|
7936
|
-
if (!loadSelection().enabled)
|
|
7937
|
-
return;
|
|
7938
8030
|
_refreshModel(projectDirectory);
|
|
7939
8031
|
let _footerText = "";
|
|
7940
8032
|
try {
|
|
@@ -8054,7 +8146,7 @@ var onToolExecuteAfter = async (input, output) => {
|
|
|
8054
8146
|
if (t === "task") {
|
|
8055
8147
|
const quality = scoreTaskQuality(output?.result || output?.text || "", input?.args?.prompt || "");
|
|
8056
8148
|
try {
|
|
8057
|
-
|
|
8149
|
+
appendFileSync8(SAVINGS_LEDGER_FILE, JSON.stringify({
|
|
8058
8150
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8059
8151
|
kind: "quality",
|
|
8060
8152
|
score: quality,
|
|
@@ -8329,6 +8421,8 @@ var setShellDirectory = (dir) => {
|
|
|
8329
8421
|
var onShellEnv = async (_input, output) => {
|
|
8330
8422
|
try {
|
|
8331
8423
|
_refreshModel(directory2 || process.cwd());
|
|
8424
|
+
if (!output)
|
|
8425
|
+
output = {};
|
|
8332
8426
|
output.env ??= {};
|
|
8333
8427
|
output.env.OPENCODE_MODEL_TIER = currentTier || "unknown";
|
|
8334
8428
|
output.env.OPENCODE_MODEL = currentModel || "unknown";
|
|
@@ -8381,7 +8475,7 @@ function backupFile(path, label) {
|
|
|
8381
8475
|
try {
|
|
8382
8476
|
if (!existsSync14(path)) return null;
|
|
8383
8477
|
const bkDir = join15(USER_HOME2, ".claude", ".backups");
|
|
8384
|
-
|
|
8478
|
+
mkdirSync11(bkDir, { recursive: true });
|
|
8385
8479
|
const bk = join15(bkDir, `${basename8(path)}.${label}.${Date.now()}.bak`);
|
|
8386
8480
|
copyFileSync5(path, bk);
|
|
8387
8481
|
return bk;
|
|
@@ -8423,7 +8517,7 @@ function persistMcpPort(port) {
|
|
|
8423
8517
|
tiers.selection ??= {};
|
|
8424
8518
|
if (Number(tiers.selection.mcp_port) === Number(port)) return;
|
|
8425
8519
|
tiers.selection.mcp_port = port;
|
|
8426
|
-
|
|
8520
|
+
mkdirSync11(dirname8(TIERS_FILE2), { recursive: true });
|
|
8427
8521
|
const tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
8428
8522
|
writeFileSync12(tmp, JSON.stringify(tiers, null, 2) + "\n", "utf-8");
|
|
8429
8523
|
renameSync6(tmp, TIERS_FILE2);
|
|
@@ -8693,7 +8787,7 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8693
8787
|
if (_tiersData2) {
|
|
8694
8788
|
_tiersData2.selection ??= {};
|
|
8695
8789
|
if (_tiersData2.selection.mcp_port === void 0) _tiersData2.selection.mcp_port = 9578;
|
|
8696
|
-
|
|
8790
|
+
mkdirSync11(dirname8(TIERS_FILE2), { recursive: true });
|
|
8697
8791
|
const _tmp = TIERS_FILE2 + ".tmp." + Date.now();
|
|
8698
8792
|
writeFileSync12(_tmp, JSON.stringify(_tiersData2, null, 2) + "\n", "utf-8");
|
|
8699
8793
|
renameSync6(_tmp, TIERS_FILE2);
|
|
@@ -8751,6 +8845,10 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8751
8845
|
} catch (err) {
|
|
8752
8846
|
console.error(`[vibeOS] Project Guard init failed: ${err.message}`);
|
|
8753
8847
|
}
|
|
8848
|
+
try {
|
|
8849
|
+
writeSelection("enabled", true);
|
|
8850
|
+
} catch {
|
|
8851
|
+
}
|
|
8754
8852
|
const _tiersData = (() => {
|
|
8755
8853
|
try {
|
|
8756
8854
|
return safeJsonParse3(readFileSync15(TIERS_FILE2, "utf-8"));
|
|
@@ -8848,12 +8946,6 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8848
8946
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
8849
8947
|
return onMessagesTransform(_input, output);
|
|
8850
8948
|
},
|
|
8851
|
-
"experimental.text.complete": async (input, output) => {
|
|
8852
|
-
await _appendFooter(input, output, directory3);
|
|
8853
|
-
},
|
|
8854
|
-
"message.updated": async (input, output) => {
|
|
8855
|
-
await _appendFooter(input, output, directory3);
|
|
8856
|
-
},
|
|
8857
8949
|
"experimental.session.compacting": async (_input, output) => {
|
|
8858
8950
|
return onSessionCompacting(_input, output);
|
|
8859
8951
|
},
|
|
@@ -8864,6 +8956,12 @@ async function DelegationEnforcer({ client: client2, directory: directory3 } = {
|
|
|
8864
8956
|
if (typeof setShellDirectory === "function") setShellDirectory(directory3 || "");
|
|
8865
8957
|
return onShellEnv(_input, output);
|
|
8866
8958
|
},
|
|
8959
|
+
"experimental.text.complete": async (_input, output) => {
|
|
8960
|
+
await _appendFooter(_input, output, directory3);
|
|
8961
|
+
},
|
|
8962
|
+
"message.updated": async (_input, output) => {
|
|
8963
|
+
await _appendFooter(_input, output, directory3);
|
|
8964
|
+
},
|
|
8867
8965
|
tool: {
|
|
8868
8966
|
trinity: tool(createTrinityTool(trinityDeps)),
|
|
8869
8967
|
"research-audit": tool({
|