vibeostheog 0.25.53 → 0.25.55

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 CHANGED
@@ -1,3 +1,50 @@
1
+ ## 0.25.55
2
+ - fix: persist cascade depth from backend route so footer shows cascade icon (#369)
3
+ - fix: make the cascade real — canonical blackbox records, live audit trail, durable bridges (#366)
4
+ - fix: stop config.update/opencode.json mid-turn writes that abort OpenCode turns (#365)
5
+ - fix: stop mid-turn opencode.json writes that abort OpenCode turns (#357)
6
+ - fix: stop vibeultrax from over-triggering stall recovery (#354)
7
+ - fix: clean up legacy config stubs before turns (#353)
8
+ - fix: unify vibe primary agent topology (#352)
9
+ - fix: add tool-call loop circuit-breaker to stop runaway bash poll loops (#350)
10
+ - fix: remove VIBEOS_API_DISABLED=true persistence from disk (#348)
11
+ - fix: allow explicit setting of embedded API token (#347)
12
+ - fix: deploy script never overwrites VIBEOS_HOME/.env.production (#346)
13
+ - fix: api hot-path deadline + blackbox state consolidation + spec contract (#345)
14
+ - fix: persist cascade depth/root to blackbox state across turns (#343)
15
+ - fix: prevent stale .js shadowing and cascade de-escalation (#342)
16
+ - fix: consolidate runtime OpenCode home resolution to single ~/.opencode (#338)
17
+ - fix: single source of truth for the footer — kill the "always cut" fallback (#331)
18
+ - fix: force pipeline repair when manual mode pipeline is collapsed (#330)
19
+ - fix: force pipeline repair when manual mode pipeline is collapsed
20
+ - fix: footer bail-out + pipeline collapse (#329)
21
+ - refactor: split maintainability boundaries into focused modules (#358)
22
+ - refactor: consolidate safeJsonParse to one canonical helper (#356)
23
+ - chore: untrack internal-only MD files from repo (#351)
24
+ fix cascade: complex prompts at any confidence route to brain tier (#368)
25
+ Fix local loop authority (#367)
26
+ Fix mega test loader paths and spec claims (#364)
27
+ Narrow shell loop guard to polling (#363)
28
+ Suppress repeated LOOPING notices (#362)
29
+ Make LOOPING sticky across authoritative state writes (#361)
30
+ Show cascade escalation labels (#360)
31
+ Unify session events under VIBEOS_HOME (#359)
32
+ Fix/api client consolidation (#355)
33
+ Migrate test suite to TS and fix buildFooterAlert null crash (#344)
34
+ Migrate repo to TS-only sources (#341)
35
+ Codex/fix cascade authority (#340)
36
+ Consolidate vibeOS skill install (#339)
37
+ Bind vibe tiers to live OpenCode agents (#337)
38
+ Fix VibeUltraX cheap-tier default via the OpenCode dropdown lever (#336)
39
+ Fix VibeUltraX cascade with tier subagents (#335)
40
+ Fix VibeUltraX live root state (#334)
41
+ Fix VibeUltraX cascade routing (#333)
42
+ Fix live control vector persistence (#332)
43
+ Revert "fix: force pipeline repair when manual mode pipeline is collapsed"
44
+ Fix blackbox session-id fragmentation freezing all sessions at INIT (#328)
45
+ Fix footer runtime probe path (#327)
46
+
47
+
1
48
  ## 0.25.53
2
49
  - fix: add project/blackbox cards to home summary, fix template source detection, expand recommendations (#302)
3
50
  Merge release v0.25.52 into master
package/README.md CHANGED
@@ -1,10 +1,17 @@
1
- # vibeOS for OpenCode -- Innocence v0.25.52
1
+ # vibeOS for OpenCode -- Innocence v0.25.55
2
2
 
3
3
  A quality-first control plane for AI-assisted coding.
4
4
 
5
5
  When AI coding is cheap, you use more of it. That is the upside of the current moment -- the marginal cost of a code suggestion has collapsed. But volume does not equal quality. The more you delegate to AI, the more often a mediocre suggestion slips through: a half-implemented fix, a fabricated API call, a test that passes only because the assertions are stubs. The quality problem gets worse as the cost problem gets better. vibeOS exists to solve the quality problem. The savings are a side effect.
6
6
 
7
- OpenCode Desktop gives you access to the most capable language models ever created -- Opus, Sonnet, DeepSeek v4 Pro -- but running them on every single turn adds up fast. More importantly, routing every turn through the most expensive model does not guarantee the best output. A cheap model proposing, a mid-tier model reviewing, and a top-tier model polishing often produces better results than a single expensive model guessing alone. vibeOS makes that routing decision automatically, on every turn, based on what you are actually doing.
7
+ OpenCode Desktop gives you access to the most capable language models ever created -- Opus, Sonnet, DeepSeek v4 Pro -- but running them on every single turn adds up fast. More importantly, routing every turn through the most expensive model does not guarantee the best output. vibeOS keeps one primary `vibe` agent in the dropdown, lets same-provider tier changes swap in-thread, and delegates cross-provider tier work to tier subagents without rewriting the active agent every turn.
8
+
9
+ The real system is smaller than the feature list makes it sound:
10
+
11
+ 1. Routing and enforcement decide which tier should act.
12
+ 2. Context compression keeps the hot path small and pushes old tool output into scratch storage.
13
+ 3. Pattern learning remembers recurring friction and routine, per project first and cross-project second.
14
+ 4. Quality signals combine reward, lie detection, and laziness detection so bad runs are visible.
8
15
 
9
16
  ## How It Feels
10
17
 
@@ -22,33 +29,25 @@ The VibeBoX decision engine watches how you work. Are you exploring a new codeba
22
29
 
23
30
  The stress detector reads your messages for signs of frustration -- repeated failures, urgency, abrupt tone. When it senses stress above a threshold, it upgrades your model tier automatically. You get the best possible assistance while you are in the weeds, and you never had to ask.
24
31
 
25
- The lie detector flags when the assistant claims success without evidence. The laziness detector catches short outputs, TODO placeholders, and skipped delegation on brain tier. The reward engine gamifies quality with XP credits for good outcomes and penalties for bad ones. You forget vibeOS is even running. That is the point.
32
+ The lie detector flags when the assistant claims success without evidence. The laziness detector catches short outputs, TODO placeholders, and skipped delegation on brain tier. The reward engine rolls those signals into one quality score so the UI stays simple. You forget vibeOS is even running. That is the point.
26
33
 
27
34
  ## The Cascade Engine
28
35
 
29
- vibeOS uses a three-tier cascade to route every turn through the cheapest model that can produce a quality result.
36
+ vibeOS uses a single primary `vibe` agent plus three tier subagents to route every turn through the cheapest model that can produce a quality result.
30
37
 
31
38
  ### How It Works
32
39
 
33
- 1. **Cheap proposal** -- Your configured cheap slot generates an initial response (e.g., a local Ollama model via `vibe set cheap magiccoder:7b`, or any API model).
34
- 2. **Flash review** -- A mid-tier model (DeepSeek v4 Flash) critiques and refines the proposal.
35
- 3. **Pro polish** -- The brain-tier model (DeepSeek v4 Pro) applies a final quality pass on complex sections.
40
+ 1. **Cheap proposal** -- The unified `vibe` primary starts on your configured cheap slot (e.g., a local Ollama model via `vibe set cheap magiccoder:7b`, or any API model).
41
+ 2. **Flash review** -- The medium tier runs as a subagent and critiques/refines the proposal without changing the dropdown agent.
42
+ 3. **Pro polish** -- The brain tier runs as a subagent on complex sections; cross-provider work delegates there instead of flipping the active agent.
36
43
 
37
44
  Not every turn goes through all three stages. The cascade router estimates input difficulty and routes simple queries directly to the cheap tier. Complex reasoning, multi-file edits, and ambiguous instructions escalate to medium or brain. The router learns from session outcomes and calibrates its thresholds over time.
38
45
 
39
- Benchmarked at **107% of raw brain quality at 58% of cost**. Local inference is free; only the Flash and Pro stages incur API costs. This is the first routing strategy that Pareto-dominates the raw brain baseline -- better quality, lower cost.
46
+ Benchmarked at **107% of raw brain quality at 58% of cost**. Local inference is free; only the Flash and Pro stages incur API costs. This is the first routing strategy that Pareto-dominates the raw brain baseline -- better quality, lower cost, without per-turn agent churn.
40
47
 
41
48
  ### Research Foundation
42
49
 
43
- The cascade design is informed by recent work in LLM routing and cascade inference:
44
-
45
- **Dekoninck et al. (2024)** -- "A Unified Approach to Routing and Cascading for LLMs" (arXiv:2410.10347, 52 citations). Foundational framework showing cascade routing is theoretically optimal when calibrated routers can estimate input difficulty. Proves cascades Pareto-dominate single-model inference on the quality-cost curve. This is the theoretical basis for vibeOS's claim that a three-stage cascade can outperform a single expensive model on both quality and cost simultaneously.
46
-
47
- **Moslem & Kelleher (2026)** -- "Dynamic Model Routing and Cascading for Efficient LLM Inference: A Survey" (arXiv:2603.04445, 10 citations). Comprehensive survey covering all routing paradigms: classifier-based, embedding-based, RL-based, hybrid. Establishes cascade routing as a well-studied class with practical deployment strategies. Validates that the cheap-propose / mid-review / pro-polish pattern is a known and effective architecture, not an ad hoc design.
48
-
49
- **Jiang et al. (2025)** -- "Cascadia: An Efficient Cascade Serving System for Large Language Models" (arXiv:2506.04203, 3 citations). Co-optimizes deployment and routing -- reduces compute cost 42% and latency 50% vs. naive cascade serving. Demonstrates that cascades work in practice, not just in theory. The cost reduction numbers align closely with vibeOS's measured 58% cost reduction under VibeUltraX.
50
-
51
- **Bouchard (2026)** -- "Is Escalation Worth It? A Decision-Theoretic Characterization of Cascade Routing at Inference Time" (arXiv:2604.04408, 1 citation). Models escalation as a binary decision problem. Shows cascades pay off when router accuracy exceeds 84% and cheaper model failure rate is above 5%. Below that, flat routing dominates. This work informs vibeOS's escalation thresholds: the cascade only escalates when the router confidence exceeds the point where flat routing would be better.
50
+ The cascade shape follows the general LLM routing literature, but the live source of truth is the code in this repo. The runtime does not depend on external papers; it depends on the router, the hooks, and the state files below.
52
51
 
53
52
  ### VibeBoX Decision Engine
54
53
 
@@ -69,17 +68,17 @@ A real-time stress scoring pipeline analyzes user messages for frustration signa
69
68
 
70
69
  ### Pattern Learner
71
70
 
72
- Per-project friction and routine tracking. The pattern learner observes which tools you use, what errors recur, and where you spend most of your time. Over time, it surfaces optimization suggestions and learns struggle/tech co-occurrence mappings. Cross-project patterns are stored in global-learning.json and inform pricing hints and routing hints.
71
+ Per-project friction and routine tracking. The learner watches repeated tool failures, recovery loops, and stable workflows, then stores the result locally first. Cross-project hints are merged later into `VIBEOS_HOME/global-learning.json` so the client can stay small while still learning.
73
72
 
74
- ### Token Compression
73
+ ### Context Compression
75
74
 
76
- Three-layer compression pipeline reduces token waste without losing semantic content:
75
+ Three small layers keep context under control without pretending to be a full memory system:
77
76
 
78
- 1. **Web fetch stripping** (`compressText`) -- Applied immediately after webfetch tool execution. Strips verbose status lines, file-operation prefixes, and bullet markers. Collapses blank lines. If the result still exceeds 2000 characters, extracts bullet-priority lines and truncates to 30% of original size. Threshold: 2000 characters minimum.
77
+ 1. **Web fetch stripping** (`compressText`) -- Applied immediately after webfetch tool execution. It strips verbose status lines, file-operation prefixes, and bullet markers, then collapses blank lines. If the result still exceeds 2000 characters, it keeps the most useful lines and truncates the rest.
79
78
 
80
- 2. **Cold-storage context compression** (`compressToolOutputs`) -- Runs on every LLM turn via the messages transform hook. Tool outputs older than the last 10 messages (the "hot window") are written to content-addressed cold storage (`~/.claude/scratchpad/by-hash/{hash}.txt`) and replaced with a ~200-character summary reference. Hot messages stay fully expanded so the LLM can reference recent context. Savings are estimated per-model using `cacheSavePer1MInputTokens()` and recorded to the delegation state.
79
+ 2. **Cold-storage context compression** (`compressToolOutputs`) -- Runs on every LLM turn via the messages transform hook. Tool outputs older than the last 10 messages are written to content-addressed cold storage and replaced with a short summary reference. Hot messages stay expanded so the model can still use recent context.
81
80
 
82
- 3. **Project memory directives** (`projectMemoryDirective`) -- Compresses per-project state (sessions, reports, tech stack, topics) into a single-line directive injected into the system prompt. Full JSON stored for audit; prompt gets only the compact form.
81
+ 3. **Project memory directives** (`projectMemoryDirective`) -- Shrinks per-project state into a single-line directive for the system prompt while keeping the full JSON for audit.
83
82
 
84
83
  The remote API also exposes a `POST /api/v1/compress/context` endpoint for server-side bullet-point extraction, available as a fallback for arbitrary text compression.
85
84
 
@@ -108,7 +107,7 @@ The smart cache predicts whether a tool query will hit scratchpad cache before e
108
107
 
109
108
  The prediction engine (`predictCacheHit`) computes a confidence score and returns whether caching is worthwhile, estimated savings, and the most similar cached entries. Per-tool hit rates are tracked with exponential decay (DECAY = 0.9) so recent performance matters more than historical averages.
110
109
 
111
- Cache state persists across sessions in `~/.claude/global-learning.json` with a 7-day TTL eviction. The prediction results feed into the delegation enforcer's cost calculations and appear in the live footer savings display.
110
+ Cache state persists across sessions in `VIBEOS_HOME/global-learning.json` with a 7-day TTL eviction. The prediction results feed into the delegation enforcer's cost calculations and appear in the live footer savings display.
112
111
 
113
112
  ### Pivot and Counter-Pivot
114
113
 
@@ -158,13 +157,13 @@ DeepSeek Chat costs $0/turn when routed through the Direct DeepSeek provider (no
158
157
 
159
158
  | Policy | Quality vs Brain | Cost vs Brain | Savings | Method |
160
159
  |--------|-----------------|--------------|---------|--------|
161
- | VibeUltraX | 107% | 0.58x | 42% | cheap -> medium -> brain cascade |
160
+ | VibeUltraX | 107% | 0.58x | 42% | vibe primary + tier subagents |
162
161
  | VibeQMaX | ~100% | 0.50x | 50% | same model, framework optimizations |
163
162
  | Raw Brain | 100% | 1.00x | - | baseline |
164
163
  | VibeMaX | ~75% | 0.18x | 82% | trained cascade (conservative escalate) |
165
164
  | Budget | ~40% | 0.00x | 100% | direct routing |
166
165
 
167
- **VibeUltraX** -- Default mode. Cheap slot proposes, medium reviews, brain refines. 107% quality at 58% cost.
166
+ **VibeUltraX** -- Default mode. The unified `vibe` primary starts on cheap, medium and brain run as subagents, and same-provider escalations stay in-thread. 107% quality at 58% cost.
168
167
 
169
168
  **VibeQMaX** -- Routes strategic turns through v4 Pro with full thinking, strict enforcement, strict flow checks, and quality TDD. Write/edit delegated per enforcement rules. Blended cost ~$0.00029/turn (50% of brain baseline).
170
169
 
@@ -178,7 +177,7 @@ DeepSeek Chat costs $0/turn when routed through the Direct DeepSeek provider (no
178
177
  |------|-------|----------|-------------|------|-----|
179
178
  | Raw Brain | v4 Pro | full | - | - | - |
180
179
  | VibeQMaX | v4 Pro | full | strict | strict | quality |
181
- | VibeUltraX | cascade (cheap->medium->brain) | auto | auto | auto | auto |
180
+ | VibeUltraX | vibe primary + tier subagents | auto | auto | auto | auto |
182
181
  | VibeMaX | v4 Flash (auto-escalate) | auto | auto | auto | auto |
183
182
  | Speed | v4 Flash | off | relaxed | audit | lazy |
184
183
  | Budget | DeepSeek Chat | off | relaxed | audit | lazy |
@@ -201,8 +200,8 @@ Stress > 1.5 escalates any regime to quality mode regardless of the above mappin
201
200
  |---------|-------------|
202
201
  | Delegation enforcement | Blocks write/edit on brain tier, routes to cheaper tiers transparently |
203
202
  | Live savings footer | Tier, provider, model name, total savings, mode -- one line of reassurance |
204
- | Web dashboard | Session-first SolidJS SPA with executive Home summary, session actions, per-session templates, SSE real-time push for model split, savings, session history, controls |
205
- | Trinity runtime | Switch tiers mid-session, change optimization mode, toggle subsystems live |
203
+ | Web dashboard | Session-first SolidJS SPA with executive Home summary, session actions, per-session templates, polling refresh for model split, savings, session history, controls |
204
+ | Trinity runtime | Update tier slots and keep the unified vibe primary plus tier subagents synced through the native OpenCode config path, change optimization mode, toggle subsystems live |
206
205
  | Flow enforcer | Pattern-rule checks on write/edit. Extracts TODO/FIXME into append-only queue. |
207
206
  | TDD enforcer | Auto-creates test skeletons for changed source. Strict mode fails TODO tests. |
208
207
  | Pattern learner | Tracks recurring struggle/routine patterns per project, cross-project too |
@@ -210,7 +209,7 @@ Stress > 1.5 escalates any regime to quality mode regardless of the above mappin
210
209
  | Stress-aware routing | Real-time stress scoring, auto-escalation, system prompt inoculation |
211
210
  | Cache savings | Separate cache_savings_usd tracking for scratchpad cache hits |
212
211
  | Report tools | report-save, report-list, report-read, research-audit |
213
- | MCP server | Extended tool capabilities + dashboard serving + SSE push endpoint |
212
+ | MCP server | Extended tool capabilities + dashboard serving + HTTP dashboard endpoints |
214
213
  | Remote API | Fastify server at api.vibetheog.com with token auth and seat management |
215
214
  | Session lock | `vibe lock on\|off` -- freezes model at session start |
216
215
  | Model locking | Per-session lock that skips auto-reconcile with OpenCode config changes |
@@ -223,7 +222,7 @@ Stress > 1.5 escalates any regime to quality mode regardless of the above mappin
223
222
  | Claim verification | Scans assistant output for made-up references, validates against codebase |
224
223
  | Token compression | Web fetch output stripped to 30% of original size -- verbose lines, bullet prefixes, and blank lines collapsed. Tool output history compressed to cold-storage references after the hot window (last 10 messages). Project memory condensed to single-line directives for system prompts. |
225
224
  | Rotation memory | Scratchpad files age through a four-stage lifecycle: fresh (< 5 min, full content), warm (5 min - 24 hr, 500-char summary), cold (24 - 48 hr, 200-char summary), expired (> 48 hr, deleted). Rotation runs opportunistically on every tool execution, throttled to once per minute. Cache hits degrade gracefully over time instead of failing abruptly. |
226
- | Smart cache | Predicts whether a tool query will hit scratchpad cache using composite similarity scoring (Jaccard + cosine bigram + weighted keyword overlap). Per-tool hit rates tracked with exponential decay. Estimated savings calculated and displayed in the live footer. Cache entries persisted across sessions via global-learning.json with 7-day TTL eviction. |
225
+ | Smart cache | Predicts whether a tool query will hit scratchpad cache using composite similarity scoring (Jaccard + cosine bigram + weighted keyword overlap). Per-tool hit rates tracked with exponential decay. Estimated savings calculated and displayed in the live footer. Cache entries persisted across sessions via `VIBEOS_HOME/global-learning.json` with 7-day TTL eviction. |
227
226
  | Pivot / counter-pivot | Detects when you switch topics mid-session (forward pivot) and when you return to a previously abandoned workflow (counter-pivot). Forward pivots snapshot the old workflow context and downgrade to budget mode. Counter-pivots restore files, decisions, blockers, and code snippets from cached workflow snapshots into the system prompt. |
228
227
  | Deferred reports | saveReport deferred to setTimeout to avoid blocking tool output |
229
228
  | Stress gauge footer | Live indicator in footer -- ▁▂▃▅▆█ (none/minimal/calm/elevated/high/critical) |
@@ -303,9 +302,9 @@ vibeOS hooks into OpenCode Desktop through 8 extension points:
303
302
  | experimental.session.compacting | Preserves savings state |
304
303
  | shell.env | Injects OPENCODE_MODEL_TIER and OPENCODE_MODEL |
305
304
 
306
- ### State Files (~/.claude/)
305
+ ### State Files (`VIBEOS_HOME/`)
307
306
 
308
- The plugin persists state to ~/.claude/ for cross-session continuity:
307
+ The plugin persists state to `VIBEOS_HOME/` for cross-session continuity:
309
308
 
310
309
  - **delegation-state.json** -- Sessions, warns, cache hits, lifetime totals
311
310
  - **model-tiers.json** -- Brain/medium/cheap model IDs
@@ -323,7 +322,7 @@ Remote API (api.vibetheog.com) enables: bootstrap token exchange, advanced VibeB
323
322
 
324
323
  ### What Is Missing For A True Session Orchestrator
325
324
 
326
- The live dashboard now covers the executive Home summary, session actions, and session-scoped templates. Still missing: session versioning/undo, template versioning, batch operations, real-time WebSocket updates, session comparison, and export/import.
325
+ The live dashboard now covers the executive Home summary, session actions, and session-scoped templates. Still missing: session versioning/undo, template versioning, batch operations, live push transport, session comparison, and export/import.
327
326
 
328
327
  ### Live Footer
329
328
 
@@ -407,6 +406,19 @@ The footer is the primary status line, appended to every assistant response. It
407
406
  | ⟡ medium | Active slot changed to medium this turn |
408
407
  | ⟡ brain | Active slot changed to brain this turn |
409
408
 
409
+ #### Alert Tags
410
+
411
+ The alert is part of the one footer (it is **not** a separate line). When present it renders
412
+ after the enforcement tags and before the stress gauge. Multiple alerts join with ` · `.
413
+ This table is the single source of truth — `buildFooterAlert()` must match it exactly.
414
+
415
+ | Alert | Trigger |
416
+ |-------|---------|
417
+ | ⚠ api degraded | API latency is degraded / the backend is unhealthy this turn |
418
+ | ⚠ switch pending | A tier switch is deferred and will apply at the next turn boundary |
419
+ | ⚠ model drift | The live model is outside the cascade tiers and differs from the expected slot model |
420
+ | ⚠ model unreachable | The last model call failed with a network error (EHOSTUNREACH / ENOTFOUND / ETIMEDOUT) |
421
+
410
422
  **Segments (left to right):**
411
423
 
412
424
  | Segment | Format | Example | Meaning |
@@ -419,6 +431,7 @@ The footer is the primary status line, appended to every assistant response. It
419
431
  | Brand + mode label | VibeBrand . modeLabel | VibeUltraX . Quality | Requested mode + regime-derived label |
420
432
  | Cascade icon | >>> or >> | >>> | VibeUltraX cascade depth >= 3 |
421
433
  | Enforcement tags | guarded, flow steady, tests live | guarded | Guard state summary |
434
+ | Alert tags | ⚠ alert · ⚠ alert | ⚠ model drift | Live status alerts (see Alert Tags) |
422
435
  | Stress gauge | gaugeChar | _ | Current stress level |
423
436
  | Vector pulse | slot | cheap | Active slot changed this turn |
424
437
 
package/bin/setup.js CHANGED
@@ -1,47 +1,153 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/bin/setup.ts
3
4
  import { execSync } from "node:child_process";
4
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
5
- import { dirname, resolve } from "node:path";
5
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, renameSync as renameSync2 } from "node:fs";
6
+ import { dirname as dirname2, resolve } from "node:path";
6
7
  import { fileURLToPath } from "node:url";
7
- import { resolveOpenCodeHome, resolveOpenCodeHomes } from "../scripts/lib/opencode-homes.mjs";
8
8
 
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
10
- const root = resolve(__dirname, "..");
11
- const args = process.argv.slice(2);
12
- const command = args.find(a => !a.startsWith("-")) ?? "setup";
13
- const isInstallCommand = command === "setup" || command === "set";
14
- const isProject = args.includes("--project");
15
- const isYes = args.includes("--yes") || args.includes("-y");
9
+ // scripts/lib/opencode-homes.mjs
10
+ import { join } from "node:path";
11
+ import { homedir } from "node:os";
12
+ function resolveOpenCodeHomes({ home = homedir() } = {}) {
13
+ const override = process.env.VIBEOS_OPENCODE_HOME;
14
+ if (override) return [override];
15
+ return [join(home, ".opencode")];
16
+ }
17
+ function resolveOpenCodeHome(opts = {}) {
18
+ return resolveOpenCodeHomes(opts)[0];
19
+ }
16
20
 
21
+ // scripts/lib/vibe-tier-agents.mjs
22
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from "node:fs";
23
+ import { dirname, join as join2 } from "node:path";
24
+ import { homedir as homedir2 } from "node:os";
25
+ var VIBE_TIER_AGENT_BY_SLOT = {
26
+ cheap: "vibe-cheap",
27
+ medium: "vibe-medium",
28
+ brain: "vibe-brain"
29
+ };
30
+ var VIBE_PRIMARY_AGENT = "vibe";
31
+ function readJson(path) {
32
+ if (!existsSync(path)) return {};
33
+ try {
34
+ const raw = readFileSync(path, "utf8");
35
+ const cleaned = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
36
+ const parsed = JSON.parse(cleaned);
37
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
38
+ } catch {
39
+ return {};
40
+ }
41
+ }
42
+ function readTiers(home = homedir2()) {
43
+ return readJson(join2(process.env.VIBEOS_HOME || join2(home, ".claude"), "model-tiers.json"));
44
+ }
45
+ function primaryAgent(model, existing = {}) {
46
+ return {
47
+ ...existing && typeof existing === "object" ? existing : {},
48
+ description: "VibeUltraX primary agent",
49
+ mode: "primary",
50
+ model,
51
+ permission: {
52
+ read: "allow",
53
+ edit: "allow",
54
+ glob: "allow",
55
+ grep: "allow",
56
+ list: "allow",
57
+ bash: "allow",
58
+ task: "allow",
59
+ webfetch: "allow",
60
+ websearch: "allow",
61
+ ...existing?.permission && typeof existing.permission === "object" ? existing.permission : {}
62
+ }
63
+ };
64
+ }
65
+ function tierAgent(slot, model, existing = {}) {
66
+ return {
67
+ ...existing && typeof existing === "object" ? existing : {},
68
+ description: `VibeUltraX ${slot} tier subagent`,
69
+ mode: "subagent",
70
+ model,
71
+ permission: {
72
+ read: "allow",
73
+ edit: "allow",
74
+ glob: "allow",
75
+ grep: "allow",
76
+ list: "allow",
77
+ bash: "allow",
78
+ task: "allow",
79
+ webfetch: "allow",
80
+ websearch: "allow",
81
+ ...existing?.permission && typeof existing.permission === "object" ? existing.permission : {}
82
+ }
83
+ };
84
+ }
85
+ function installVibeTierAgentsInConfig(config, tiers = readTiers()) {
86
+ if (!config || typeof config !== "object" || Array.isArray(config)) return false;
87
+ const trinity = tiers?.trinity || {};
88
+ config.$schema ||= "https://opencode.ai/config.json";
89
+ config.agent = config.agent && typeof config.agent === "object" ? config.agent : {};
90
+ let changed = false;
91
+ const primaryModel = String(trinity?.cheap?.oc || "").trim();
92
+ if (primaryModel) {
93
+ const existing = config.agent[VIBE_PRIMARY_AGENT];
94
+ const next = primaryAgent(primaryModel, existing);
95
+ if (JSON.stringify(existing || null) !== JSON.stringify(next)) {
96
+ config.agent[VIBE_PRIMARY_AGENT] = next;
97
+ changed = true;
98
+ }
99
+ if (config.default_agent !== VIBE_PRIMARY_AGENT) {
100
+ config.default_agent = VIBE_PRIMARY_AGENT;
101
+ changed = true;
102
+ }
103
+ }
104
+ for (const slot of ["cheap", "medium", "brain"]) {
105
+ const model = String(trinity?.[slot]?.oc || "").trim();
106
+ const name = VIBE_TIER_AGENT_BY_SLOT[slot];
107
+ if (!model || !name) continue;
108
+ const existing = config.agent[name];
109
+ const next = tierAgent(slot, model, existing);
110
+ if (JSON.stringify(existing || null) !== JSON.stringify(next)) {
111
+ config.agent[name] = next;
112
+ changed = true;
113
+ }
114
+ }
115
+ return changed;
116
+ }
117
+
118
+ // src/bin/setup.ts
119
+ var __dirname = dirname2(fileURLToPath(import.meta.url));
120
+ var root = resolve(__dirname, "..");
121
+ var args = process.argv.slice(2);
122
+ var command = args.find((a) => !a.startsWith("-")) ?? "setup";
123
+ var isInstallCommand = command === "setup" || command === "set";
124
+ var isProject = args.includes("--project");
125
+ var writeLine = (text = "") => {
126
+ process.stdout.write(text + "\n");
127
+ };
17
128
  if (!isInstallCommand || args.includes("--help") || args.includes("-h")) {
18
129
  console.error("Usage: npx vibeostheog set [--project]");
19
130
  console.error(" npx vibeostheog setup [--project]");
20
131
  process.exit(1);
21
132
  }
22
-
23
- console.log("");
24
- console.log("vibeOS — cost-aware delegation enforcer for OpenCode");
25
- console.log("");
26
- console.log("Installing to:");
27
- for (const h of resolveOpenCodeHomes({ cwd: process.cwd() })) console.log(" " + h);
28
- console.log("");
29
-
30
- // Deploy plugin files to ~/.config/opencode/plugins/ and register globally
31
- const deployScript = resolve(root, "scripts", "deploy.mjs");
32
- if (!existsSync(deployScript)) {
133
+ writeLine();
134
+ writeLine("vibeOS \u2014 cost-aware delegation enforcer for OpenCode");
135
+ writeLine();
136
+ writeLine("Installing to:");
137
+ for (const h of resolveOpenCodeHomes({ cwd: process.cwd() })) writeLine(" " + h);
138
+ writeLine();
139
+ var deployScript = resolve(root, "scripts", "deploy.mjs");
140
+ if (!existsSync2(deployScript)) {
33
141
  console.error("Fatal: scripts/deploy.mjs not found at", deployScript);
34
142
  process.exit(1);
35
143
  }
36
144
  execSync(`node "${deployScript}"`, { stdio: "inherit", cwd: process.cwd() });
37
-
38
- // For per-project setup, also register in project-level opencode.json
39
145
  if (isProject) {
40
146
  const configPath = resolve(process.cwd(), "opencode.json");
41
147
  let config = {};
42
- if (existsSync(configPath)) {
148
+ if (existsSync2(configPath)) {
43
149
  try {
44
- config = JSON.parse(readFileSync(configPath, "utf8"));
150
+ config = JSON.parse(readFileSync2(configPath, "utf8"));
45
151
  } catch {
46
152
  config = {};
47
153
  }
@@ -52,13 +158,13 @@ if (isProject) {
52
158
  const installHome = resolveOpenCodeHome({ cwd: process.cwd() });
53
159
  const pluginRef = resolve(installHome, "plugins", "vibeOS.js");
54
160
  config.plugin = config.plugin.filter((p) => !(typeof p === "string" && p.includes("vibeOS")));
55
- if (!config.plugin.includes(pluginRef)) {
56
- config.plugin.push(pluginRef);
57
- mkdirSync(dirname(configPath), { recursive: true });
58
- writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
59
- }
60
- console.log(`vibeOS registered in ${configPath}`);
161
+ installVibeTierAgentsInConfig(config);
162
+ if (!config.plugin.includes(pluginRef)) config.plugin.push(pluginRef);
163
+ mkdirSync2(dirname2(configPath), { recursive: true });
164
+ const tmp = `${configPath}.tmp.${process.pid}.${Date.now()}`;
165
+ writeFileSync2(tmp, JSON.stringify(config, null, 2) + "\n");
166
+ renameSync2(tmp, configPath);
167
+ writeLine(`vibeOS registered in ${configPath}`);
61
168
  }
62
-
63
- console.log("");
64
- console.log("Done. Restart OpenCode to activate the plugin.");
169
+ writeLine();
170
+ writeLine("Done. Restart OpenCode to activate the plugin.");
@@ -1 +1 @@
1
- window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:63452";
1
+ window.__VIBEOS_DASHBOARD_BASE__ = "http://127.0.0.1:53088";