opencode-mask-j0k3r-dev-rgl 2.0.20 → 2.0.22
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/components.tsx +11 -19
- package/package.json +1 -1
- package/tui.tsx +75 -26
package/components.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
/** @jsxImportSource @opentui/solid */
|
|
3
|
-
import type { TuiThemeCurrent,
|
|
4
|
-
import type { Message } from "@opencode-ai/sdk/v2"
|
|
3
|
+
import type { TuiThemeCurrent, TuiSidebarMcpItem, TuiSidebarLspItem, TuiSidebarTodoItem } from "@opencode-ai/plugin/tui"
|
|
5
4
|
import type { Cfg } from "./config"
|
|
6
5
|
import { getOSName, getProviders } from "./detection"
|
|
7
6
|
import {
|
|
@@ -77,14 +76,13 @@ const ProgressBar = (props: {
|
|
|
77
76
|
export const SidebarArch = (props: {
|
|
78
77
|
theme: TuiThemeCurrent
|
|
79
78
|
config: Cfg
|
|
80
|
-
sessionID?: string
|
|
81
79
|
branch?: string
|
|
82
|
-
files?: ReadonlyArray<TuiSidebarFileItem>
|
|
83
80
|
mcpItems?: ReadonlyArray<TuiSidebarMcpItem>
|
|
84
81
|
lspItems?: ReadonlyArray<TuiSidebarLspItem>
|
|
85
82
|
todos?: ReadonlyArray<TuiSidebarTodoItem>
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
contextTokens: number
|
|
84
|
+
contextCost: number
|
|
85
|
+
contextLimit: number
|
|
88
86
|
}) => {
|
|
89
87
|
if (!props.config.show_sidebar) return null
|
|
90
88
|
|
|
@@ -107,14 +105,10 @@ export const SidebarArch = (props: {
|
|
|
107
105
|
const lspActive = lspItems.filter(l => l.status === "idle" || l.status === "running").length
|
|
108
106
|
const lspTotal = lspItems.length
|
|
109
107
|
|
|
110
|
-
// ──
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const totalCost = assistantMsgs.reduce((s, m) => s + (m.cost ?? 0), 0)
|
|
115
|
-
|
|
116
|
-
// context window real del modelo via api.state.provider → model.limit.context
|
|
117
|
-
const contextLimit = props.contextLimit ?? 1_000_000
|
|
108
|
+
// ── Context — valores ya calculados en tui.tsx via eventos ────────────────
|
|
109
|
+
const contextTokens = props.contextTokens
|
|
110
|
+
const totalCost = props.contextCost
|
|
111
|
+
const contextLimit = props.contextLimit
|
|
118
112
|
const contextPct = Math.min(100, Math.round((contextTokens / contextLimit) * 100))
|
|
119
113
|
const costPct = Math.min(100, Math.round(totalCost * 100))
|
|
120
114
|
|
|
@@ -145,9 +139,8 @@ export const SidebarArch = (props: {
|
|
|
145
139
|
</box>
|
|
146
140
|
)}
|
|
147
141
|
|
|
148
|
-
{/* ── Context (tokens + % used + cost) ── */}
|
|
149
|
-
|
|
150
|
-
<box flexDirection="column" alignItems="center" marginTop={1}>
|
|
142
|
+
{/* ── Context (tokens + % used + cost) ── siempre visible */}
|
|
143
|
+
<box flexDirection="column" alignItems="center" marginTop={1}>
|
|
151
144
|
<text fg={t.textMuted} bold={true}>Context</text>
|
|
152
145
|
|
|
153
146
|
{/* tokens */}
|
|
@@ -170,8 +163,7 @@ export const SidebarArch = (props: {
|
|
|
170
163
|
<text fg={t.textMuted}>spent</text>
|
|
171
164
|
</box>
|
|
172
165
|
<ProgressBar value={costPct} width={18} fillColor="#ffd166" emptyColor="#3a3a3a" theme={t} />
|
|
173
|
-
|
|
174
|
-
)}
|
|
166
|
+
</box>
|
|
175
167
|
|
|
176
168
|
{/* ── Todos ── */}
|
|
177
169
|
{totalTodos > 0 && (
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-mask-j0k3r-dev-rgl",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.22",
|
|
5
5
|
"description": "Arch Linux TUI mask for OpenCode — hot pink theme with prominent ASCII logo and j0k3r-dev-rgl@latest legend",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
package/tui.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
/** @jsxImportSource @opentui/solid */
|
|
3
3
|
import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui"
|
|
4
|
+
import { createSignal } from "solid-js"
|
|
4
5
|
import { cfg } from "./config"
|
|
5
6
|
import { HomeLogo, SidebarArch, DetectedEnv } from "./components"
|
|
6
7
|
|
|
@@ -15,68 +16,116 @@ const tui: TuiPlugin = async (api, options) => {
|
|
|
15
16
|
const boot = cfg(rec(options))
|
|
16
17
|
if (!boot.enabled) return
|
|
17
18
|
|
|
18
|
-
// Theme setup
|
|
19
|
+
// Theme setup
|
|
19
20
|
try {
|
|
20
21
|
await api.theme.install("./themes/j0k3r-dev-rgl.json")
|
|
21
|
-
if (boot.set_theme)
|
|
22
|
-
api.theme.set(boot.theme)
|
|
23
|
-
}
|
|
22
|
+
if (boot.set_theme) api.theme.set(boot.theme)
|
|
24
23
|
} catch (error) {
|
|
25
24
|
console.error("[j0k3r-dev-rgl] Theme setup failed:", error)
|
|
26
25
|
}
|
|
27
26
|
|
|
27
|
+
// ── Reactive context tracker via events ──────────────────────────────────
|
|
28
|
+
// sessionID → { tokens, cost }
|
|
29
|
+
type CtxStats = { tokens: number; cost: number }
|
|
30
|
+
const ctxStore = new Map<string, CtxStats>()
|
|
31
|
+
const msgCostTracker = new Map<string, number>() // `sid:msgId` → cost
|
|
32
|
+
|
|
33
|
+
const [ctxTick, setCtxTick] = createSignal(0)
|
|
34
|
+
|
|
35
|
+
let debugLogged = false
|
|
36
|
+
api.event.on("message.updated", (event) => {
|
|
37
|
+
// Debug: loguear estructura completa la primera vez
|
|
38
|
+
if (!debugLogged) {
|
|
39
|
+
debugLogged = true
|
|
40
|
+
const propsKeys = Object.keys((event as any).properties ?? {}).join(",")
|
|
41
|
+
const infoKeys = Object.keys(((event as any).properties?.info ?? (event as any).properties) ?? {}).join(",")
|
|
42
|
+
console.error("[j0k3r-mask] event.properties keys:", propsKeys)
|
|
43
|
+
console.error("[j0k3r-mask] info/msg keys:", infoKeys)
|
|
44
|
+
console.error("[j0k3r-mask] full event:", JSON.stringify(event).slice(0, 800))
|
|
45
|
+
api.ui.toast({ variant: "info", message: `props: ${propsKeys} | info: ${infoKeys}`, duration: 8000 })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Intentar ambas estructuras: { properties: { info: Message } } o { properties: Message }
|
|
49
|
+
const props = (event as any).properties
|
|
50
|
+
const msg = props?.info ?? props
|
|
51
|
+
if (!msg || msg.role !== "assistant") return
|
|
52
|
+
|
|
53
|
+
const sid: string | undefined = msg.sessionID
|
|
54
|
+
if (!sid) return
|
|
55
|
+
|
|
56
|
+
const t = msg.tokens ?? {}
|
|
57
|
+
const tokens = t.input ?? 0
|
|
58
|
+
const msgId: string = msg.id ?? `${sid}-unknown`
|
|
59
|
+
msgCostTracker.set(`${sid}:${msgId}`, msg.cost ?? 0)
|
|
60
|
+
|
|
61
|
+
const cost = Array.from(msgCostTracker.entries())
|
|
62
|
+
.filter(([k]) => k.startsWith(`${sid}:`))
|
|
63
|
+
.reduce((s, [, v]) => s + v, 0)
|
|
64
|
+
|
|
65
|
+
const prev = ctxStore.get(sid) ?? { tokens: 0, cost: 0 }
|
|
66
|
+
ctxStore.set(sid, { tokens: Math.max(prev.tokens, tokens), cost })
|
|
67
|
+
|
|
68
|
+
console.error(`[j0k3r-mask] sid=${sid} tokens=${tokens} cost=${cost}`)
|
|
69
|
+
setCtxTick(v => v + 1)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// Resolver context window real del modelo activo
|
|
73
|
+
const getContextLimit = (): number => {
|
|
74
|
+
try {
|
|
75
|
+
const modelStr = api.state.config?.model ?? ""
|
|
76
|
+
const [providerID, modelID] = modelStr.split("/")
|
|
77
|
+
const provider = api.state.provider.find(p => p.id === providerID)
|
|
78
|
+
const model = provider?.models?.[modelID]
|
|
79
|
+
if (model?.limit?.context) return model.limit.context
|
|
80
|
+
} catch (_) {}
|
|
81
|
+
return 1_000_000
|
|
82
|
+
}
|
|
83
|
+
|
|
28
84
|
// Slot registration
|
|
29
85
|
api.slots.register({
|
|
30
86
|
slots: {
|
|
31
|
-
// Home screen: large Arch logo + j0k3r-dev-rgl@latest legend
|
|
32
87
|
home_logo(ctx) {
|
|
33
88
|
return <HomeLogo theme={ctx.theme.current} />
|
|
34
89
|
},
|
|
35
90
|
|
|
36
|
-
// Below the prompt: environment detection
|
|
37
91
|
home_bottom(ctx) {
|
|
38
92
|
return <DetectedEnv theme={ctx.theme.current} providers={api.state.provider} config={boot} />
|
|
39
93
|
},
|
|
40
94
|
|
|
41
|
-
// Sidebar: Arch logo + live stats with progress bars
|
|
42
95
|
sidebar_content(ctx, value) {
|
|
43
96
|
const sessionID = value?.session_id
|
|
97
|
+
|
|
98
|
+
// Registrar sesión en el tracker si es nueva
|
|
99
|
+
if (sessionID && !ctxStore.has(sessionID)) {
|
|
100
|
+
ctxStore.set(sessionID, { tokens: 0, cost: 0 })
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Suscribirse a la señal reactiva
|
|
104
|
+
const _ = ctxTick()
|
|
105
|
+
const stats = sessionID
|
|
106
|
+
? (ctxStore.get(sessionID) ?? { tokens: 0, cost: 0 })
|
|
107
|
+
: { tokens: 0, cost: 0 }
|
|
108
|
+
|
|
44
109
|
const branch = api.state.vcs?.branch
|
|
45
|
-
const files = sessionID ? api.state.session.diff(sessionID) : []
|
|
46
110
|
const todos = sessionID ? api.state.session.todo(sessionID) : []
|
|
47
|
-
const messages = sessionID ? api.state.session.messages(sessionID) : []
|
|
48
111
|
const mcpItems = api.state.mcp()
|
|
49
112
|
const lspItems = api.state.lsp()
|
|
50
113
|
|
|
51
|
-
// Resolver el context window real del modelo activo
|
|
52
|
-
// api.state.config.model = "providerID/modelID"
|
|
53
|
-
// api.state.provider = ReadonlyArray<Provider> donde Provider.models[modelID].limit.context
|
|
54
|
-
let contextLimit: number | undefined
|
|
55
|
-
try {
|
|
56
|
-
const modelStr = api.state.config?.model ?? ""
|
|
57
|
-
const [providerID, modelID] = modelStr.split("/")
|
|
58
|
-
const provider = api.state.provider.find(p => p.id === providerID)
|
|
59
|
-
const model = provider?.models?.[modelID]
|
|
60
|
-
if (model?.limit?.context) contextLimit = model.limit.context
|
|
61
|
-
} catch (_) {}
|
|
62
|
-
|
|
63
114
|
return (
|
|
64
115
|
<SidebarArch
|
|
65
116
|
theme={ctx.theme.current}
|
|
66
117
|
config={boot}
|
|
67
|
-
sessionID={sessionID}
|
|
68
118
|
branch={branch}
|
|
69
|
-
files={files}
|
|
70
119
|
todos={todos}
|
|
71
|
-
messages={messages}
|
|
72
120
|
mcpItems={mcpItems}
|
|
73
121
|
lspItems={lspItems}
|
|
74
|
-
|
|
122
|
+
contextTokens={stats.tokens}
|
|
123
|
+
contextCost={stats.cost}
|
|
124
|
+
contextLimit={getContextLimit()}
|
|
75
125
|
/>
|
|
76
126
|
)
|
|
77
127
|
},
|
|
78
128
|
|
|
79
|
-
// Prompt bar right side: session info
|
|
80
129
|
session_prompt_right(ctx, value) {
|
|
81
130
|
const t = ctx.theme.current
|
|
82
131
|
return (
|