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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. 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.16.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 mkdirSync10, copyFileSync as copyFileSync5, renameSync as renameSync6 } from "node:fs";
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 `Working on ${label}. Keep focused on this repository and its conventions.`;
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: " This turn, context7 usage is required.",
5908
- optional: " This turn, context7 is optional \u2014 use it if helpful."
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 "When looking up library or framework documentation (docs.*, readthedocs.*, npmjs.com/package/*, pypi.org/project/*, pkg.go.dev, /api/reference/), use mcp__context7__resolve-library-id and mcp__context7__get-library-docs if they are available instead of WebFetch or WebSearch \u2014 they cost less. Saves roughly $0.06 per turn on average." + (C7_URGENCY[urgency] || "");
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 `You're in brief reasoning mode (${creditNote}). Use extended thinking only for genuinely complex multi-step problems. Keep reasoning concise and skip exploratory scratch work.`;
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 `Extended thinking is off (${creditNote}). Respond directly and concisely \u2014 thinking tokens cost money, save them for when the user explicitly asks.`;
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 coordinate the work. Delegate heavy implementation to Task subagents (runs on ${targetModel}). Your job: verify results, fill gaps, and synthesize. Write/Edit tools are blocked on this tier \u2014 delegate all implementation work. Always show the vibeOS cost footer.` + (tierBias !== "auto" ? ` This turn is biased toward ${tierBias} tier.` : "");
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 on: ${tddFocus.join(", ")}.` : "";
5943
- return `Auto-create test skeletons for source files you write or edit.${TDD_NOTES[tddMode] || ""}${focusNote} Make sure corresponding test files exist with proper assertions.`;
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 and FIXME markers are being tracked." : "";
5949
- const focusNote = flowFocus.length > 0 ? ` Focus on: ${flowFocus.join(", ")}.` : "";
5950
- return `Follow project conventions when writing or editing code \u2014 check existing patterns and naming conventions.${enforceNote}${focusNote}`;
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 or FIXME items are pending. Consider using `todowrite` to add them to the task list.";
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("Things to watch: " + frictions.map((f) => f.summary).join("; "));
6008
+ parts.push("Frictions: " + frictions.map((f) => f.summary).join("; "));
5970
6009
  }
5971
6010
  if (parts.length === 0)
5972
6011
  return null;
5973
- return "Learned patterns for this project \u2014 " + parts.join(". ") + ".";
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 is active. Slot: " + active + " (" + current + "). Use `trinity` to switch slots, rebuild, or check status. Run `trinity help` for all commands.";
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
- return `Context is ${ctxBudget.pct}% full (~${ctxBudget.estimatedTokens} tokens). Consider delegating heavy work to Task subagents, compressing tool outputs, or starting a new session.`;
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 seems quite stressed. Stay calm, structured, and thorough. Use clear markdown with code blocks, lists, and organized sections \u2014 do not mirror their tone. This is important.");
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 seems a bit stressed. Keep responses well-structured with clear markdown and organized sections.");
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"}. If the conversation is looping or stuck, suggest stepping back. If you're converging or closing, push toward a decision.`);
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
- pushSystem(output, `${_latestBlackboxLoopMsg2 || "The conversation may be circling \u2014 try a fresh angle."} (level: ${res.loop_intervention_level})`);
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, `Topic seems to have shifted: ${_latestBlackboxPivotMsg2}`);
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, `There's an active job: "${(projectJob.prompt || "").slice(0, 140)}...". The latest request looks unrelated. Before acting, ask if they want to switch focus.`);
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 have multiple independent tasks, run them all in parallel \u2014 it's faster and cheaper. Only sequence them when one depends on another's output.");
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 files \u2014 never edit them without asking. When you add new features, update README.md to document them. AGENTS.md defines the project rules \u2014 follow them.");
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
- return _cachedAutoMode || "balanced";
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 || text.length < 50) {
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 appendFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync9 } from "node:fs";
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 appendFileSync5, existsSync as existsSync11, mkdirSync as mkdirSync8, statSync as statSync6, readdirSync as readdirSync3, rmSync as rmSync4, openSync as openSync3 } from "node:fs";
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
- mkdirSync8(ENFORCEMENT_LOCK_DIR, { recursive: true });
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
- mkdirSync8(dirname6(ENFORCEMENT_COOLDOWN_FILE2), { recursive: true });
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
- appendFileSync5(ENFORCEMENT_COOLDOWN_FILE2, entry);
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
- mkdirSync8(skeleton.dir, { recursive: true });
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
- mkdirSync9(dirname7(CONTEXT7_INSTALL_FLAG), { recursive: true });
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
- appendFileSync6(SAVINGS_LEDGER_FILE, JSON.stringify({
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
- mkdirSync10(bkDir, { recursive: true });
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
- mkdirSync10(dirname8(TIERS_FILE2), { recursive: true });
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
- mkdirSync10(dirname8(TIERS_FILE2), { recursive: true });
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({