vibeostheog 0.19.0 → 0.19.2
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/.opencode/plugins/vibeOS-tui.tsx +340 -0
- package/CHANGELOG.md +11 -0
- package/README.md +12 -15
- package/package.json +8 -5
- package/src/index.js +867 -302
- package/src/lib/vibeos-mcp-server.js +320 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import type { TuiPlugin } from "@opencode-ai/plugin/tui"
|
|
2
|
+
import { createSignal } from "solid-js"
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
4
|
+
import { join } from "node:path"
|
|
5
|
+
import { homedir } from "node:os"
|
|
6
|
+
|
|
7
|
+
const DEFAULT_PORT = 9578
|
|
8
|
+
const TIERS_FILE = join(homedir(), ".claude/model-tiers.json")
|
|
9
|
+
|
|
10
|
+
function getBaseUrl() {
|
|
11
|
+
try {
|
|
12
|
+
if (existsSync(TIERS_FILE)) {
|
|
13
|
+
const tiers = JSON.parse(readFileSync(TIERS_FILE, "utf-8"))
|
|
14
|
+
const port = Number(tiers?.selection?.mcp_port)
|
|
15
|
+
if (Number.isFinite(port) && port > 0) return `http://localhost:${port}`
|
|
16
|
+
}
|
|
17
|
+
} catch {}
|
|
18
|
+
return `http://localhost:${DEFAULT_PORT}`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type StatusResponse = {
|
|
22
|
+
todos: {
|
|
23
|
+
total: number
|
|
24
|
+
pending: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
enabled: boolean
|
|
28
|
+
active_slot: string
|
|
29
|
+
enforce: boolean
|
|
30
|
+
flow_enforcer: boolean
|
|
31
|
+
flow_extract_todos: boolean
|
|
32
|
+
tdd_enforcer: boolean
|
|
33
|
+
tdd_strict: boolean
|
|
34
|
+
thinking: string
|
|
35
|
+
current_model: string
|
|
36
|
+
credit_percent: number
|
|
37
|
+
version: string
|
|
38
|
+
backend_connected?: boolean
|
|
39
|
+
backend_health_url?: string | null
|
|
40
|
+
model_locked?: boolean
|
|
41
|
+
locked_slot?: string | null
|
|
42
|
+
locked_model?: string | null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type SavingsResponse = {
|
|
46
|
+
lifetime: {
|
|
47
|
+
delegation_usd: number
|
|
48
|
+
cache_usd: number
|
|
49
|
+
missed_context7_usd: number
|
|
50
|
+
total_warns: number
|
|
51
|
+
}
|
|
52
|
+
current_session: {
|
|
53
|
+
delegation_usd: number
|
|
54
|
+
cache_usd: number
|
|
55
|
+
warns_count: number
|
|
56
|
+
tool_breakdown: Record<string, number>
|
|
57
|
+
}
|
|
58
|
+
cache_hits_this_session: number
|
|
59
|
+
trend: string
|
|
60
|
+
savings_rate_per_hour: number
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Named export for TUI auto-discovery
|
|
64
|
+
export const vibeOSTui = async (api, _options, _meta) => {
|
|
65
|
+
try {
|
|
66
|
+
if (api?.ui?.toast) {
|
|
67
|
+
api.ui.toast({ variant: "info", message: "vibeOS TUI plugin executing" })
|
|
68
|
+
}
|
|
69
|
+
if (typeof process !== "undefined") {
|
|
70
|
+
process.stderr?.write?.("[vibeOS-tui] plugin function called\n")
|
|
71
|
+
}
|
|
72
|
+
} catch (e) {
|
|
73
|
+
if (typeof process !== "undefined") {
|
|
74
|
+
process.stderr?.write?.("[vibeOS-tui] ERROR: " + String(e) + "\n")
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const plugin: TuiPlugin = async (api, _options, _meta) => {
|
|
80
|
+
const [status, setStatus] = createSignal<StatusResponse | null>(null)
|
|
81
|
+
const [savings, setSavings] = createSignal<SavingsResponse | null>(null)
|
|
82
|
+
const [error, setError] = createSignal<string | null>(null)
|
|
83
|
+
|
|
84
|
+
const poll = async () => {
|
|
85
|
+
try {
|
|
86
|
+
const baseUrl = getBaseUrl()
|
|
87
|
+
const [s, sa] = await Promise.all([
|
|
88
|
+
fetch(`${baseUrl}/status`).then((r) => r.json()),
|
|
89
|
+
fetch(`${baseUrl}/savings`).then((r) => r.json()),
|
|
90
|
+
])
|
|
91
|
+
setStatus(s)
|
|
92
|
+
setSavings(sa)
|
|
93
|
+
setError(null)
|
|
94
|
+
} catch {
|
|
95
|
+
setError("vibeOS MCP offline")
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
await poll()
|
|
100
|
+
const timer = setInterval(poll, 3000)
|
|
101
|
+
|
|
102
|
+
api.lifecycle.onDispose(() => {
|
|
103
|
+
clearInterval(timer)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const doAction = async (body: Record<string, unknown>) => {
|
|
107
|
+
try {
|
|
108
|
+
const res = await fetch(`${getBaseUrl()}/trinity`, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { "Content-Type": "application/json" },
|
|
111
|
+
body: JSON.stringify(body),
|
|
112
|
+
})
|
|
113
|
+
const data = await res.json()
|
|
114
|
+
if (data.ok) {
|
|
115
|
+
api.ui.toast({ variant: "success", message: data.result })
|
|
116
|
+
await poll()
|
|
117
|
+
} else {
|
|
118
|
+
api.ui.toast({ variant: "error", message: "Action failed" })
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
api.ui.toast({ variant: "error", message: "vibeOS offline" })
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const Slot = api.ui.Slot
|
|
126
|
+
|
|
127
|
+
api.slots.register((props: { session_id: string }) => {
|
|
128
|
+
const s = status()
|
|
129
|
+
const sv = savings()
|
|
130
|
+
|
|
131
|
+
if (error()) {
|
|
132
|
+
return (
|
|
133
|
+
<box flexDirection="column">
|
|
134
|
+
<Slot name="sidebar_title" session_id={props.session_id} title="vibeOS">
|
|
135
|
+
<text dim>vibeOS offline</text>
|
|
136
|
+
</Slot>
|
|
137
|
+
<Slot name="sidebar_content" session_id={props.session_id}>
|
|
138
|
+
<box flexDirection="column" padding={1}>
|
|
139
|
+
<text dim>vibeOS MCP not running</text>
|
|
140
|
+
<newline />
|
|
141
|
+
<text dim>ensure the server plugin is active</text>
|
|
142
|
+
</box>
|
|
143
|
+
</Slot>
|
|
144
|
+
<Slot name="sidebar_footer" session_id={props.session_id}>
|
|
145
|
+
<text dim>vibeOS MCP offline</text>
|
|
146
|
+
</Slot>
|
|
147
|
+
</box>
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const activeSlot = s?.active_slot ?? "?"
|
|
152
|
+
const enabled = s?.enabled ?? false
|
|
153
|
+
const trendArrow = sv?.trend === "up" ? "^" : sv?.trend === "down" ? "v" : "-"
|
|
154
|
+
const delegation = (sv?.current_session?.delegation_usd ?? 0) + (sv?.lifetime?.delegation_usd ?? 0)
|
|
155
|
+
const cache = (sv?.current_session?.cache_usd ?? 0) + (sv?.lifetime?.cache_usd ?? 0)
|
|
156
|
+
const lifetime = (sv?.lifetime?.delegation_usd ?? 0) + (sv?.lifetime?.cache_usd ?? 0)
|
|
157
|
+
const missedC7 = sv?.lifetime?.missed_context7_usd ?? 0
|
|
158
|
+
const toolBreakdown = sv?.current_session?.tool_breakdown ?? {}
|
|
159
|
+
const topTools = Object.entries(toolBreakdown)
|
|
160
|
+
.sort(([, a], [, b]) => (b as number) - (a as number))
|
|
161
|
+
.slice(0, 5)
|
|
162
|
+
const trendColor = sv?.trend === "up" ? "green" : sv?.trend === "down" ? "red" : "yellow"
|
|
163
|
+
const shortModel = s?.current_model?.split("/")[1] ?? s?.current_model ?? "?"
|
|
164
|
+
const flowOn = s?.flow_enforcer ?? false
|
|
165
|
+
const tddOn = s?.tdd_enforcer ?? false
|
|
166
|
+
const backendConnected = s?.backend_connected ?? false
|
|
167
|
+
const lockLabel = s?.model_locked
|
|
168
|
+
? `${s?.locked_slot ? `${s.locked_slot} ` : ""}${s?.locked_model ?? ""}`.trim()
|
|
169
|
+
: "off"
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<box flexDirection="column">
|
|
173
|
+
<Slot name="sidebar_title" session_id={props.session_id} title="vibeOS">
|
|
174
|
+
<box>
|
|
175
|
+
<text bold>vibeOS</text>
|
|
176
|
+
<text dim> | </text>
|
|
177
|
+
<text color={enabled ? "green" : "red"} bold>{activeSlot}</text>
|
|
178
|
+
<text> </text>
|
|
179
|
+
<text color={enabled ? "green" : "red"}>{enabled ? "." : "o"}</text>
|
|
180
|
+
</box>
|
|
181
|
+
</Slot>
|
|
182
|
+
<Slot name="sidebar_content" session_id={props.session_id}>
|
|
183
|
+
<box flexDirection="column" padding={1}>
|
|
184
|
+
<text dim bold>MODEL STATUS</text>
|
|
185
|
+
<newline />
|
|
186
|
+
<box>
|
|
187
|
+
<text bold={activeSlot === "brain"} color={activeSlot === "brain" ? "green" : undefined}>
|
|
188
|
+
{shortModel}
|
|
189
|
+
</text>
|
|
190
|
+
{activeSlot === "brain" && <text color="green"> active</text>}
|
|
191
|
+
</box>
|
|
192
|
+
<newline />
|
|
193
|
+
<box>
|
|
194
|
+
<text>Backend </text>
|
|
195
|
+
<text color={backendConnected ? "green" : "red"} bold>{backendConnected ? "ON" : "OFF"}</text>
|
|
196
|
+
</box>
|
|
197
|
+
<newline />
|
|
198
|
+
<box>
|
|
199
|
+
<text>Lock </text>
|
|
200
|
+
<text color={s?.model_locked ? "green" : "red"} bold>{s?.model_locked ? "ON" : "OFF"}</text>
|
|
201
|
+
{s?.model_locked && lockLabel && <text dim> {lockLabel}</text>}
|
|
202
|
+
</box>
|
|
203
|
+
<newline />
|
|
204
|
+
<text dim>---</text>
|
|
205
|
+
<newline />
|
|
206
|
+
<box>
|
|
207
|
+
<text>Flow </text>
|
|
208
|
+
<text color={flowOn ? "green" : "red"} bold>{flowOn ? "ON" : "OFF"}</text>
|
|
209
|
+
</box>
|
|
210
|
+
<newline />
|
|
211
|
+
<box>
|
|
212
|
+
<text>TDD </text>
|
|
213
|
+
<text color={tddOn ? "green" : "red"} bold>{tddOn ? "ON" : "OFF"}</text>
|
|
214
|
+
{tddOn && s?.tdd_strict && <text dim> strict</text>}
|
|
215
|
+
</box>
|
|
216
|
+
<newline />
|
|
217
|
+
<box>
|
|
218
|
+
<text>Enforce </text>
|
|
219
|
+
<text color={s?.enforce ? "green" : "red"} bold>{s?.enforce ? "ON" : "OFF"}</text>
|
|
220
|
+
</box>
|
|
221
|
+
<newline />
|
|
222
|
+
<text dim>---</text>
|
|
223
|
+
<newline />
|
|
224
|
+
<box>
|
|
225
|
+
<text>Thinking: </text>
|
|
226
|
+
<text>{s?.thinking ?? "?"}</text>
|
|
227
|
+
</box>
|
|
228
|
+
<newline />
|
|
229
|
+
<newline />
|
|
230
|
+
<text dim bold>SAVINGS</text>
|
|
231
|
+
<newline />
|
|
232
|
+
<box>
|
|
233
|
+
<text bold>Saved: </text>
|
|
234
|
+
<text bold color={trendColor}>${lifetime.toFixed(2)} {trendArrow}</text>
|
|
235
|
+
</box>
|
|
236
|
+
<newline />
|
|
237
|
+
<box><text> Delegation: </text><text>${delegation.toFixed(2)}</text></box>
|
|
238
|
+
<newline />
|
|
239
|
+
<box><text> Cache: </text><text>${cache.toFixed(2)}</text></box>
|
|
240
|
+
<newline />
|
|
241
|
+
<box><text> C7 missed: </text><text>${missedC7.toFixed(2)}</text></box>
|
|
242
|
+
<newline />
|
|
243
|
+
<text dim>---</text>
|
|
244
|
+
<newline />
|
|
245
|
+
<box><text>Rate: </text><text>${sv?.savings_rate_per_hour?.toFixed(2) ?? "0.00"}/hr</text></box>
|
|
246
|
+
<newline />
|
|
247
|
+
<box><text>Warns: </text><text>{sv?.current_session?.warns_count ?? 0}</text></box>
|
|
248
|
+
<newline />
|
|
249
|
+
<text dim>---</text>
|
|
250
|
+
<newline />
|
|
251
|
+
<text dim>Tool split:</text>
|
|
252
|
+
<newline />
|
|
253
|
+
{topTools.map(([tool, val]) => (
|
|
254
|
+
<newline />
|
|
255
|
+
<text dim bold>TODOS</text>
|
|
256
|
+
<newline />
|
|
257
|
+
<box>
|
|
258
|
+
<text>Pending: </text>
|
|
259
|
+
<text color={s?.todos?.pending > 0 ? "yellow" : "green"} bold>
|
|
260
|
+
{s?.todos?.pending ?? 0}
|
|
261
|
+
</text>
|
|
262
|
+
<text> / {s?.todos?.total ?? 0}</text>
|
|
263
|
+
</box>
|
|
264
|
+
<newline />
|
|
265
|
+
|
|
266
|
+
<>
|
|
267
|
+
<box>
|
|
268
|
+
<text> {tool.padEnd(8)}</text>
|
|
269
|
+
<text>${(val as number).toFixed(2)}</text>
|
|
270
|
+
</box>
|
|
271
|
+
<newline />
|
|
272
|
+
</>
|
|
273
|
+
))}
|
|
274
|
+
<newline />
|
|
275
|
+
<text dim bold>CONTROLS</text>
|
|
276
|
+
<newline />
|
|
277
|
+
<box>
|
|
278
|
+
<text
|
|
279
|
+
onClick={() => doAction({ action: "set", slot: "brain", level: null })}
|
|
280
|
+
color={activeSlot === "brain" ? "green" : "dim"}
|
|
281
|
+
bold={activeSlot === "brain"}
|
|
282
|
+
>[brain]</text>
|
|
283
|
+
<text> </text>
|
|
284
|
+
<text
|
|
285
|
+
onClick={() => doAction({ action: "set", slot: "medium", level: null })}
|
|
286
|
+
color={activeSlot === "medium" ? "green" : "dim"}
|
|
287
|
+
bold={activeSlot === "medium"}
|
|
288
|
+
>[medium]</text>
|
|
289
|
+
<text> </text>
|
|
290
|
+
<text
|
|
291
|
+
onClick={() => doAction({ action: "set", slot: "cheap", level: null })}
|
|
292
|
+
color={activeSlot === "cheap" ? "green" : "dim"}
|
|
293
|
+
bold={activeSlot === "cheap"}
|
|
294
|
+
>[cheap]</text>
|
|
295
|
+
</box>
|
|
296
|
+
<newline />
|
|
297
|
+
<box>
|
|
298
|
+
<text
|
|
299
|
+
onClick={() => doAction({ action: "flow", slot: flowOn ? "off" : "on", level: null })}
|
|
300
|
+
color={flowOn ? "green" : "red"} bold
|
|
301
|
+
>[Flow {flowOn ? "ON" : "OFF"}]</text>
|
|
302
|
+
</box>
|
|
303
|
+
<newline />
|
|
304
|
+
<box>
|
|
305
|
+
<text
|
|
306
|
+
onClick={() => doAction({ action: "tdd", slot: tddOn ? "off" : "on", level: null })}
|
|
307
|
+
color={tddOn ? "green" : "red"} bold
|
|
308
|
+
>[TDD {tddOn ? "ON" : "OFF"}]</text>
|
|
309
|
+
</box>
|
|
310
|
+
<newline />
|
|
311
|
+
<box>
|
|
312
|
+
<text
|
|
313
|
+
onClick={() => doAction({ action: "enforce", slot: s?.enforce ? "off" : "on", level: null })}
|
|
314
|
+
color={s?.enforce ? "green" : "red"} bold
|
|
315
|
+
>[Enforce {s?.enforce ? "ON" : "OFF"}]</text>
|
|
316
|
+
</box>
|
|
317
|
+
<newline />
|
|
318
|
+
<box>
|
|
319
|
+
<text
|
|
320
|
+
onClick={() => doAction({ action: "disable", slot: null, level: null })}
|
|
321
|
+
color="red" bold
|
|
322
|
+
>[Disable]</text>
|
|
323
|
+
</box>
|
|
324
|
+
</box>
|
|
325
|
+
</Slot>
|
|
326
|
+
<Slot name="sidebar_footer" session_id={props.session_id}>
|
|
327
|
+
<box>
|
|
328
|
+
<text dim>Saved </text>
|
|
329
|
+
<text color={trendColor}>{lifetime.toFixed(2)}</text>
|
|
330
|
+
<text dim> {trendArrow} </text>
|
|
331
|
+
<text>{sv?.savings_rate_per_hour?.toFixed(2) ?? "0.00"}/hr</text>
|
|
332
|
+
<text dim> | {sv?.current_session?.warns_count ?? 0} warns</text>
|
|
333
|
+
</box>
|
|
334
|
+
</Slot>
|
|
335
|
+
</box>
|
|
336
|
+
)
|
|
337
|
+
})
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export default { tui: plugin }
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 0.19.2
|
|
2
|
+
- fix: export server and tui entrypoints
|
|
3
|
+
|
|
4
|
+
## 0.19.1
|
|
5
|
+
- fix: make README and runtime self-contained
|
|
6
|
+
- test: add 59 integration + e2e tests for cross-module behavior and user workflows
|
|
7
|
+
Merge pull request #49 from DrunkkToys/oc-desktop-live-savings-refresh
|
|
8
|
+
Merge pull request #48 from DrunkkToys/codex/live-savings-refresh
|
|
9
|
+
Invalidate savings cache on state writes
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
## 0.19.0
|
|
2
13
|
- feat: quality governance — self-protection, 2h release gate, outcome tracking (#44)
|
|
3
14
|
- fix: chooseEpisodeMode defaults to budget (was always quality) + simplify isApiConnected check
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ It also adds guardrails: delegation enforcement, flow and TDD controls, pattern
|
|
|
21
21
|
1. Install the package:
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
npm install
|
|
24
|
+
npm install vibeostheog
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
2. Register it in `~/.config/opencode/opencode.json`:
|
|
@@ -29,41 +29,39 @@ npm install vibeOS
|
|
|
29
29
|
```json
|
|
30
30
|
{
|
|
31
31
|
"plugins": [
|
|
32
|
-
{ "id": "vibeOS", "path": "node_modules/
|
|
32
|
+
{ "id": "vibeOS", "path": "node_modules/vibeostheog/src/index.js" }
|
|
33
33
|
]
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
### Local plugin file
|
|
38
38
|
|
|
39
|
-
If you keep a local
|
|
39
|
+
If you keep a local checkout of the plugin, point OpenCode at the built file instead:
|
|
40
40
|
|
|
41
41
|
```json
|
|
42
42
|
{
|
|
43
43
|
"plugins": [
|
|
44
|
-
{ "id": "vibeOS", "path": "
|
|
44
|
+
{ "id": "vibeOS", "path": "/absolute/path/to/theSaver-oc/src/index.js" }
|
|
45
45
|
]
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
Restart OpenCode Desktop after changing the config.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
The package also exposes `vibeostheog/server` and `vibeostheog/tui` for integrations that need the MCP server or sidebar plugin entrypoints directly.
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Use that folder when you need the API server, MCP server, or dashboard build chain:
|
|
53
|
+
## Common Npm Commands
|
|
56
54
|
|
|
57
55
|
```bash
|
|
58
|
-
npm
|
|
59
|
-
npm run
|
|
60
|
-
npm run build:dashboard
|
|
61
|
-
npm run dev:dashboard
|
|
62
|
-
npm run dashboard:serve
|
|
56
|
+
npm install
|
|
57
|
+
npm run build
|
|
63
58
|
npm run typecheck
|
|
64
59
|
npm test
|
|
60
|
+
npm run release:patch
|
|
65
61
|
```
|
|
66
62
|
|
|
63
|
+
`npm run build` compiles `src/index.ts` to `src/index.js` and deploys the built plugin into the OpenCode plugin directory. `npm run typecheck` validates the TypeScript sources without emitting files.
|
|
64
|
+
|
|
67
65
|
## Core Controls
|
|
68
66
|
|
|
69
67
|
Use `trinity help` for the full command list. The most common controls are:
|
|
@@ -127,11 +125,10 @@ Without a token, vibeOS keeps running in local-only mode with bundled algorithms
|
|
|
127
125
|
- If writes or edits are blocked, that is usually delegation enforcement working as intended on the brain tier.
|
|
128
126
|
- If the footer is missing, check that the plugin is enabled and that the current OpenCode session is receiving assistant completions.
|
|
129
127
|
- If the remote API is down or the token is invalid, use `trinity api-token <token>` or rely on local-only mode.
|
|
130
|
-
- If the dashboard does not load, rebuild
|
|
128
|
+
- If the dashboard does not load, rebuild the plugin with `npm run build` and restart OpenCode.
|
|
131
129
|
- If state or config looks inconsistent, run `trinity diagnose` and `trinity guard`.
|
|
132
130
|
|
|
133
131
|
## Notes
|
|
134
132
|
|
|
135
133
|
- `trinity help` is the canonical command reference.
|
|
136
|
-
- `../vibeOScore` is the backend sibling directory on the Desktop.
|
|
137
134
|
- The README stays intentionally high level so the command details can follow the code without a rewrite.
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibeostheog",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.2",
|
|
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",
|
|
7
7
|
"release:patch": "node scripts/release.mjs patch --yes",
|
|
8
8
|
"release:minor": "node scripts/release.mjs minor --yes",
|
|
9
9
|
"release:major": "node scripts/release.mjs major --yes",
|
|
10
|
-
"build": "tsc -p tsconfig.json --noEmit && npx esbuild src/index.ts --bundle --outfile=src/index.js --platform=node --format=esm --target=node22 --external:node:*
|
|
10
|
+
"build": "tsc -p tsconfig.json --noEmit && npx esbuild src/index.ts --bundle --outfile=src/index.js --platform=node --format=esm --target=node22 --external:node:* && node scripts/deploy.mjs",
|
|
11
11
|
"deploy": "node scripts/deploy.mjs",
|
|
12
12
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
13
13
|
"checkpoint:validate": "node scripts/checkpoint-validate.mjs",
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
},
|
|
27
27
|
"type": "module",
|
|
28
28
|
"exports": {
|
|
29
|
-
".": "./src/index.js"
|
|
29
|
+
".": "./src/index.js",
|
|
30
|
+
"./server": "./src/lib/vibeos-mcp-server.js",
|
|
31
|
+
"./tui": "./.opencode/plugins/vibeOS-tui.tsx"
|
|
30
32
|
},
|
|
31
33
|
"keywords": [
|
|
32
34
|
"opencode",
|
|
@@ -46,6 +48,8 @@
|
|
|
46
48
|
},
|
|
47
49
|
"files": [
|
|
48
50
|
"src/index.js",
|
|
51
|
+
"src/lib/vibeos-mcp-server.js",
|
|
52
|
+
".opencode/plugins/vibeOS-tui.tsx",
|
|
49
53
|
"scripts/deploy.mjs",
|
|
50
54
|
"model-tiers.sample.json",
|
|
51
55
|
"README.md",
|
|
@@ -66,8 +70,7 @@
|
|
|
66
70
|
"@types/node": "^22.15.30",
|
|
67
71
|
"esbuild": "^0.28.0",
|
|
68
72
|
"express": "^5.2.1",
|
|
69
|
-
"typescript": "^5.9.3"
|
|
70
|
-
"vibeOScore": "file:../vibeOScore"
|
|
73
|
+
"typescript": "^5.9.3"
|
|
71
74
|
},
|
|
72
75
|
"dependencies": {}
|
|
73
76
|
}
|