opencode-mask-j0k3r-dev-rgl 2.0.14 → 2.0.16

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/components.tsx +166 -10
  2. package/package.json +1 -1
  3. package/tui.tsx +23 -3
package/components.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  // @ts-nocheck
2
2
  /** @jsxImportSource @opentui/solid */
3
- import type { TuiThemeCurrent } from "@opencode-ai/plugin/tui"
3
+ import type { TuiThemeCurrent, TuiSidebarFileItem, TuiSidebarMcpItem, TuiSidebarLspItem, TuiSidebarTodoItem } from "@opencode-ai/plugin/tui"
4
+ import type { Message } from "@opencode-ai/sdk/v2"
4
5
  import type { Cfg } from "./config"
5
6
  import { getOSName, getProviders } from "./detection"
6
7
  import {
@@ -17,14 +18,12 @@ export const HomeLogo = (props: { theme: TuiThemeCurrent }) => {
17
18
 
18
19
  return (
19
20
  <box flexDirection="column" alignItems="center">
20
- {/* Arch Linux logo — zone-colored */}
21
21
  {archLogoHome.map((line, i) => {
22
22
  const zone = homeLogoZones[i]
23
23
  const color = zoneColors[zone] || t.primary
24
24
  return <text fg={color}>{line}</text>
25
25
  })}
26
26
 
27
- {/* Legend: j0k3r-dev-rgl@latest */}
28
27
  <text> </text>
29
28
  <box flexDirection="row" gap={0}>
30
29
  <text fg="#ff2d78" bold={true}>j0k3r</text>
@@ -36,7 +35,6 @@ export const HomeLogo = (props: { theme: TuiThemeCurrent }) => {
36
35
  <text fg="#ffd166" bold={true}>latest</text>
37
36
  </box>
38
37
 
39
- {/* Subtle separator */}
40
38
  <box flexDirection="row" gap={0} marginTop={1}>
41
39
  <text fg={t.textMuted} dimColor={true}>╭ </text>
42
40
  <text fg={t.textMuted}>arch linux </text>
@@ -50,21 +48,179 @@ export const HomeLogo = (props: { theme: TuiThemeCurrent }) => {
50
48
  )
51
49
  }
52
50
 
53
- // ─── Sidebar: Compact Arch logo ──────────────────────────────────────────────
54
- export const SidebarArch = (props: { theme: TuiThemeCurrent; config: Cfg }) => {
51
+ // ─── Progress bar helper ──────────────────────────────────────────────────────
52
+ const ProgressBar = (props: {
53
+ value: number // 0–100
54
+ width?: number
55
+ fillColor: string
56
+ emptyColor: string
57
+ theme: TuiThemeCurrent
58
+ }) => {
59
+ const width = props.width ?? 12
60
+ const pct = Math.max(0, Math.min(100, props.value))
61
+ const filled = Math.round((pct / 100) * width)
62
+ const empty = width - filled
63
+ const fill = "█".repeat(filled)
64
+ const trail = "░".repeat(empty)
65
+
66
+ return (
67
+ <box flexDirection="row" gap={0}>
68
+ <text fg={props.theme.textMuted}>[</text>
69
+ <text fg={props.fillColor}>{fill}</text>
70
+ <text fg={props.emptyColor}>{trail}</text>
71
+ <text fg={props.theme.textMuted}>]</text>
72
+ </box>
73
+ )
74
+ }
75
+
76
+ // ─── Sidebar: Arch logo + stats panel ────────────────────────────────────────
77
+ export const SidebarArch = (props: {
78
+ theme: TuiThemeCurrent
79
+ config: Cfg
80
+ sessionID?: string
81
+ branch?: string
82
+ files?: ReadonlyArray<TuiSidebarFileItem>
83
+ mcpItems?: ReadonlyArray<TuiSidebarMcpItem>
84
+ lspItems?: ReadonlyArray<TuiSidebarLspItem>
85
+ todos?: ReadonlyArray<TuiSidebarTodoItem>
86
+ messages?: ReadonlyArray<Message>
87
+ }) => {
55
88
  if (!props.config.show_sidebar) return null
56
89
 
90
+ const t = props.theme
91
+
92
+ // ── Files ─────────────────────────────────────────────────────────────────
93
+ const files = props.files ?? []
94
+ const totalAdditions = files.reduce((s, f) => s + f.additions, 0)
95
+ const totalDeletions = files.reduce((s, f) => s + f.deletions, 0)
96
+ const totalChanges = totalAdditions + totalDeletions
97
+
98
+ // ── Todos ─────────────────────────────────────────────────────────────────
99
+ const todos = props.todos ?? []
100
+ const doneTodos = todos.filter(t => t.status === "completed").length
101
+ const totalTodos = todos.length
102
+ const todoPct = totalTodos > 0 ? Math.round((doneTodos / totalTodos) * 100) : 0
103
+
104
+ // ── MCP ───────────────────────────────────────────────────────────────────
105
+ const mcpItems = props.mcpItems ?? []
106
+ const mcpConnected = mcpItems.filter(m => m.status === "connected").length
107
+ const mcpTotal = mcpItems.length
108
+ const mcpPct = mcpTotal > 0 ? Math.round((mcpConnected / mcpTotal) * 100) : 0
109
+
110
+ // ── LSP ───────────────────────────────────────────────────────────────────
111
+ const lspItems = props.lspItems ?? []
112
+ const lspActive = lspItems.filter(l => l.status === "idle" || l.status === "running").length
113
+ const lspTotal = lspItems.length
114
+
115
+ // ── Tokens & Cost — sumados de los AssistantMessages ─────────────────────
116
+ const messages = props.messages ?? []
117
+ const assistantMsgs = messages.filter(m => m.role === "assistant")
118
+ const totalTokens = assistantMsgs.reduce((s, m) => s + (m.tokens?.total ?? (m.tokens?.input ?? 0) + (m.tokens?.output ?? 0)), 0)
119
+ const totalCost = assistantMsgs.reduce((s, m) => s + (m.cost ?? 0), 0)
120
+
121
+ // Context window: OpenCode muestra "% used" basado en el modelo.
122
+ // Usamos 200_000 como referencia (Claude 3.5 Sonnet / GPT-4o max).
123
+ const CONTEXT_LIMIT = 200_000
124
+ const contextPct = Math.min(100, Math.round((totalTokens / CONTEXT_LIMIT) * 100))
125
+
126
+ const fmtTokens = (n: number) => n >= 1000 ? `${(n / 1000).toFixed(1)}k` : `${n}`
127
+ const fmtCost = (n: number) => `$${n.toFixed(2)}`
128
+
129
+ // Color del context bar: verde → amarillo → rojo según el %
130
+ const ctxColor = contextPct < 50 ? "#00e5a0" : contextPct < 80 ? "#ffd166" : "#ff2d78"
131
+
57
132
  return (
58
133
  <box flexDirection="column" alignItems="center">
59
- {/* Compact Arch logo — zone-colored */}
134
+
135
+ {/* Mini Arch logo */}
60
136
  {archLogoSidebar.map((line, i) => {
61
137
  const zone = sidebarLogoZones[i]
62
- const color = zoneColors[zone] || props.theme.primary
138
+ const color = zoneColors[zone] || t.primary
63
139
  return <text fg={color}>{line}</text>
64
140
  })}
65
141
 
66
- {/* Compact label */}
67
- <text fg={props.theme.textMuted}>j0k3r@latest</text>
142
+ <text fg={t.textMuted}>j0k3r@latest</text>
143
+ <text> </text>
144
+
145
+ {/* Git branch */}
146
+ {props.branch && (
147
+ <box flexDirection="row" gap={1}>
148
+ <text fg="#ffd166">⎇</text>
149
+ <text fg={t.text}>{props.branch}</text>
150
+ </box>
151
+ )}
152
+
153
+ {/* ── Context (tokens + cost) ── */}
154
+ {totalTokens > 0 && (
155
+ <box flexDirection="column" marginTop={1}>
156
+ <text fg={t.textMuted} bold={true}>Context</text>
157
+ <box flexDirection="row" gap={1}>
158
+ <text fg={t.text}>{fmtTokens(totalTokens)}</text>
159
+ <text fg={t.textMuted}>tokens</text>
160
+ </box>
161
+ <ProgressBar value={contextPct} width={12} fillColor={ctxColor} emptyColor="#3a3a3a" theme={t} />
162
+ <box flexDirection="row" gap={1}>
163
+ <text fg={ctxColor}>{contextPct}%</text>
164
+ <text fg={t.textMuted}>used</text>
165
+ </box>
166
+ <box flexDirection="row" gap={1}>
167
+ <text fg="#ffd166">{fmtCost(totalCost)}</text>
168
+ <text fg={t.textMuted}>spent</text>
169
+ </box>
170
+ </box>
171
+ )}
172
+
173
+ {/* ── Files changed ── */}
174
+ {totalChanges > 0 && (
175
+ <box flexDirection="column" marginTop={1}>
176
+ <box flexDirection="row" gap={1}>
177
+ <text fg={t.textMuted}>files</text>
178
+ <text fg={t.text}>{files.length}</text>
179
+ </box>
180
+ <box flexDirection="row" gap={0}>
181
+ <text fg="#00e5a0">+{totalAdditions} </text>
182
+ <text fg="#ff2d78">-{totalDeletions}</text>
183
+ </box>
184
+ <ProgressBar
185
+ value={totalChanges > 0 ? Math.min(100, (totalAdditions / totalChanges) * 100) : 0}
186
+ width={12}
187
+ fillColor="#00e5a0"
188
+ emptyColor="#ff2d78"
189
+ theme={t}
190
+ />
191
+ </box>
192
+ )}
193
+
194
+ {/* ── Todos ── */}
195
+ {totalTodos > 0 && (
196
+ <box flexDirection="column" marginTop={1}>
197
+ <box flexDirection="row" gap={1}>
198
+ <text fg={t.textMuted}>todos</text>
199
+ <text fg={t.text}>{doneTodos}/{totalTodos}</text>
200
+ </box>
201
+ <ProgressBar value={todoPct} width={12} fillColor="#9d4edd" emptyColor="#3a3a3a" theme={t} />
202
+ </box>
203
+ )}
204
+
205
+ {/* ── MCP ── */}
206
+ {mcpTotal > 0 && (
207
+ <box flexDirection="column" marginTop={1}>
208
+ <box flexDirection="row" gap={1}>
209
+ <text fg={t.textMuted}>mcp</text>
210
+ <text fg={t.text}>{mcpConnected}/{mcpTotal}</text>
211
+ </box>
212
+ <ProgressBar value={mcpPct} width={12} fillColor="#00c8ff" emptyColor="#3a3a3a" theme={t} />
213
+ </box>
214
+ )}
215
+
216
+ {/* ── LSP ── */}
217
+ {lspTotal > 0 && (
218
+ <box flexDirection="row" gap={1} marginTop={1}>
219
+ <text fg={t.textMuted}>lsp</text>
220
+ <text fg={lspActive > 0 ? "#00e5a0" : "#555555"}>{lspActive}/{lspTotal}</text>
221
+ </box>
222
+ )}
223
+
68
224
  <text> </text>
69
225
  </box>
70
226
  )
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.14",
4
+ "version": "2.0.16",
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
@@ -38,9 +38,29 @@ const tui: TuiPlugin = async (api, options) => {
38
38
  return <DetectedEnv theme={ctx.theme.current} providers={api.state.provider} config={boot} />
39
39
  },
40
40
 
41
- // Sidebar: compact Arch logo
42
- sidebar_content(ctx) {
43
- return <SidebarArch theme={ctx.theme.current} config={boot} />
41
+ // Sidebar: Arch logo + live stats with progress bars
42
+ sidebar_content(ctx, value) {
43
+ const sessionID = value?.session_id
44
+ const branch = api.state.vcs?.branch
45
+ const files = sessionID ? api.state.session.diff(sessionID) : []
46
+ const todos = sessionID ? api.state.session.todo(sessionID) : []
47
+ const messages = sessionID ? api.state.session.messages(sessionID) : []
48
+ const mcpItems = api.state.mcp()
49
+ const lspItems = api.state.lsp()
50
+
51
+ return (
52
+ <SidebarArch
53
+ theme={ctx.theme.current}
54
+ config={boot}
55
+ sessionID={sessionID}
56
+ branch={branch}
57
+ files={files}
58
+ todos={todos}
59
+ messages={messages}
60
+ mcpItems={mcpItems}
61
+ lspItems={lspItems}
62
+ />
63
+ )
44
64
  },
45
65
 
46
66
  // Prompt bar right side: session info