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.
- package/README.md +50 -0
- package/index.tsx +77 -0
- 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
|
+
}
|