opencode-brl-cost 0.1.0

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/README.md +50 -0
  2. package/index.tsx +77 -0
  3. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # opencode-brl-cost
2
+
3
+ OpenCode **TUI plugin** that pins the current session's cost to the bottom bar, in Brazilian Reais (R$).
4
+
5
+ ## How it works
6
+
7
+ - Renders a fixed status bar via the `app_bottom` TUI slot.
8
+ - Shows **the active session's total cost** (`session.cost`, USD) converted with a **hardcoded rate of R$ 5,00 / US$ 1,00**.
9
+ - On the home screen (no session selected) the bar stays empty. It never shows a stale value.
10
+ - Currency formatting uses `Intl.NumberFormat` with `pt-BR` (e.g. `R$ 1,23`).
11
+
12
+ ## Install
13
+
14
+ TUI plugins are loaded from a file plugin or an npm package. Add the plugin to `tui.json`:
15
+
16
+ ```json
17
+ {
18
+ "plugin": ["opencode-brl-cost"]
19
+ }
20
+ ```
21
+
22
+ Then restart OpenCode. The bottom bar appears when a session is open.
23
+
24
+ This repo is published as a `.tsx` source plugin (the format OpenCode's TUI loader transpiles natively),
25
+ mirroring `@br4zz4/opencode-skill-picker`.
26
+
27
+ ## Local development
28
+
29
+ ```bash
30
+ npm install
31
+ npm run typecheck
32
+ ```
33
+
34
+ To test locally, point `tui.json` at the source file:
35
+
36
+ ```json
37
+ {
38
+ "plugin": ["file:///absolute/path/to/opencode-brl-cost/index.tsx"]
39
+ }
40
+ ```
41
+
42
+ ## Roadmap
43
+
44
+ - Configurable USD→BRL rate (instead of the hardcoded 5)
45
+ - Session cost delta per last response
46
+ - Token counters (input/output)
47
+
48
+ ## License
49
+
50
+ MIT
package/index.tsx ADDED
@@ -0,0 +1,77 @@
1
+ /** @jsxImportSource @opentui/solid */
2
+ import { createSignal } from "solid-js"
3
+ import type { TuiPlugin, TuiPluginModule } from "@opencode-ai/plugin/tui"
4
+
5
+ const BRL_PER_USD = 5
6
+
7
+ const formatBRL = (usd: number) => {
8
+ const rounded = Math.round(usd * BRL_PER_USD * 100) / 100
9
+ return new Intl.NumberFormat("pt-BR", {
10
+ style: "currency",
11
+ currency: "BRL",
12
+ }).format(rounded)
13
+ }
14
+
15
+ const tui: TuiPlugin = async (api) => {
16
+ const [cost, setCost] = createSignal<string | undefined>(undefined)
17
+ const [busy, setBusy] = createSignal(false)
18
+
19
+ const currentSessionID = (): string | undefined => {
20
+ const route = api.route.current
21
+ return route.name === "session" && typeof route.params?.sessionID === "string"
22
+ ? route.params.sessionID
23
+ : undefined
24
+ }
25
+
26
+ const refresh = async () => {
27
+ const sessionID = currentSessionID()
28
+ if (!sessionID) {
29
+ setCost(undefined)
30
+ return
31
+ }
32
+
33
+ // Prefer the live SDK session (server truth, has cost); fall back to the store.
34
+ let usd: number | undefined
35
+ try {
36
+ const res = await api.client.session.get({ sessionID }, { throwOnError: true })
37
+ usd = res.data?.cost
38
+ } catch {
39
+ const session = api.state.session.get(sessionID)
40
+ usd = session?.cost
41
+ }
42
+ setCost(typeof usd === "number" ? formatBRL(usd) : undefined)
43
+ }
44
+
45
+ void refresh()
46
+
47
+ api.event.on("session.updated", (event) => {
48
+ if (event.properties.sessionID === currentSessionID()) void refresh()
49
+ })
50
+ api.event.on("session.idle", (event) => {
51
+ if (event.properties.sessionID === currentSessionID()) void refresh()
52
+ })
53
+ api.event.on("tui.session.select", (event) => {
54
+ if (event.properties.sessionID === currentSessionID()) void refresh()
55
+ })
56
+
57
+ api.slots.register({
58
+ slots: {
59
+ app_bottom(ctx) {
60
+ const theme = ctx.theme.current
61
+ const value = cost() ?? formatBRL(0)
62
+ return (
63
+ <box flexDirection="row" justifyContent="flex-end" paddingRight={2} gap={1}>
64
+ <text fg={theme.textMuted}>{value}</text>
65
+ </box>
66
+ )
67
+ },
68
+ },
69
+ })
70
+ }
71
+
72
+ const plugin: TuiPluginModule = {
73
+ id: "opencode-brl-cost",
74
+ tui,
75
+ }
76
+
77
+ export default plugin
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "opencode-brl-cost",
3
+ "version": "0.1.0",
4
+ "description": "OpenCode TUI plugin that shows the session cost in Brazilian Reais (R$)",
5
+ "type": "module",
6
+ "main": "./index.tsx",
7
+ "files": [
8
+ "index.tsx"
9
+ ],
10
+ "exports": {
11
+ ".": "./index.tsx",
12
+ "./tui": "./index.tsx"
13
+ },
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit"
16
+ },
17
+ "keywords": [
18
+ "opencode",
19
+ "opencode-plugin",
20
+ "tui",
21
+ "cost",
22
+ "brl",
23
+ "currency"
24
+ ],
25
+ "license": "MIT",
26
+ "devDependencies": {
27
+ "@opencode-ai/plugin": "1.18.29",
28
+ "@opentui/solid": "0.4.5",
29
+ "@opencode-ai/sdk": "1.18.29",
30
+ "solid-js": "^1.8.0",
31
+ "typescript": "5.8.2"
32
+ }
33
+ }