opencode-system-metrics-tui 0.1.3 → 0.1.4
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 +30 -9
- package/package.json +4 -2
- package/scripts/install-plugin.ts +30 -0
- package/scripts/plugin-installation.ts +107 -0
package/README.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# OpenCode System Metrics TUI
|
|
2
2
|
|
|
3
|
+
## Install globally in OpenCode
|
|
4
|
+
|
|
5
|
+
```powershell
|
|
6
|
+
opencode plugin -g opencode-system-metrics-tui@0.1.3 --force
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
This is the primary installation path. The version must match `package.json`; `--force` asks OpenCode to refresh its package cache. Verify the actual installed artifact afterward:
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
npm run install-plugin
|
|
13
|
+
npm run verify-installation
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`npm run install-plugin` runs the same global OpenCode installer command with the current `package.json` version. The explicit command above is provided for users installing without this checkout.
|
|
17
|
+
|
|
18
|
+
Restart OpenCode after installation. This installs the plugin globally for all projects. The OpenCode cache directory name, including `@latest`, is only a package-specifier label and does not prove the package version. Verification reads the nested package's own `package.json` and checks `dist/tui.js`; it reports stale entries without deleting anything.
|
|
19
|
+
|
|
3
20
|
OpenCode TUI plugin that adds live CPU, RAM, GPU, GPU VRAM, temperature, and network metrics to the `sidebar_content` slot.
|
|
4
21
|
|
|
5
22
|
The README is available in **Español**, **English**, and **Português**.
|
|
@@ -72,7 +89,7 @@ npm publish --access public
|
|
|
72
89
|
En otro equipo:
|
|
73
90
|
|
|
74
91
|
```bash
|
|
75
|
-
opencode plugin opencode-system-metrics-tui
|
|
92
|
+
opencode plugin opencode-system-metrics-tui@0.1.3
|
|
76
93
|
```
|
|
77
94
|
|
|
78
95
|
El paquete exporta tanto la raíz (`opencode-system-metrics-tui`) como `./tui`; ambas rutas cargan el mismo bundle TUI.
|
|
@@ -82,12 +99,14 @@ El instalador de OpenCode configura el plugin TUI automáticamente. Reinicia Ope
|
|
|
82
99
|
Publicar en npm e instalar en OpenCode son pasos distintos:
|
|
83
100
|
|
|
84
101
|
- `npm publish --access public` publica el paquete en npm.
|
|
85
|
-
- `opencode plugin opencode-system-metrics-tui` lo instala solo en el proyecto actual.
|
|
86
|
-
- `opencode plugin -g opencode-system-metrics-tui` lo instala globalmente para todos los proyectos.
|
|
102
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.3` lo instala solo en el proyecto actual.
|
|
103
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` lo instala globalmente para todos los proyectos.
|
|
87
104
|
|
|
88
105
|
### Verificación
|
|
89
106
|
|
|
90
107
|
```bash
|
|
108
|
+
npm run install-plugin
|
|
109
|
+
npm run verify-installation
|
|
91
110
|
npm test
|
|
92
111
|
npm run typecheck
|
|
93
112
|
npm run build
|
|
@@ -161,7 +180,7 @@ npm publish --access public
|
|
|
161
180
|
On another machine:
|
|
162
181
|
|
|
163
182
|
```bash
|
|
164
|
-
opencode plugin opencode-system-metrics-tui
|
|
183
|
+
opencode plugin opencode-system-metrics-tui@0.1.3
|
|
165
184
|
```
|
|
166
185
|
|
|
167
186
|
The package exports both the root (`opencode-system-metrics-tui`) and `./tui`; both paths load the same TUI bundle.
|
|
@@ -171,12 +190,14 @@ The OpenCode installer configures the TUI plugin automatically. Restart OpenCode
|
|
|
171
190
|
Publishing to npm and installing in OpenCode are separate steps:
|
|
172
191
|
|
|
173
192
|
- `npm publish --access public` publishes the package to npm.
|
|
174
|
-
- `opencode plugin opencode-system-metrics-tui` installs it for the current project only.
|
|
175
|
-
- `opencode plugin -g opencode-system-metrics-tui` installs it globally for all projects.
|
|
193
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.3` installs it for the current project only.
|
|
194
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` installs it globally for all projects.
|
|
176
195
|
|
|
177
196
|
### Verification
|
|
178
197
|
|
|
179
198
|
```bash
|
|
199
|
+
npm run install-plugin
|
|
200
|
+
npm run verify-installation
|
|
180
201
|
npm test
|
|
181
202
|
npm run typecheck
|
|
182
203
|
npm run build
|
|
@@ -250,7 +271,7 @@ npm publish --access public
|
|
|
250
271
|
Em outro computador:
|
|
251
272
|
|
|
252
273
|
```bash
|
|
253
|
-
opencode plugin opencode-system-metrics-tui
|
|
274
|
+
opencode plugin opencode-system-metrics-tui@0.1.3
|
|
254
275
|
```
|
|
255
276
|
|
|
256
277
|
O pacote exporta tanto a raiz (`opencode-system-metrics-tui`) quanto `./tui`; os dois caminhos carregam o mesmo bundle TUI.
|
|
@@ -260,8 +281,8 @@ O instalador do OpenCode configura o plugin TUI automaticamente. Reinicie o Open
|
|
|
260
281
|
Publicar no npm e instalar no OpenCode são etapas diferentes:
|
|
261
282
|
|
|
262
283
|
- `npm publish --access public` publica o pacote no npm.
|
|
263
|
-
- `opencode plugin opencode-system-metrics-tui` instala o plugin apenas no projeto atual.
|
|
264
|
-
- `opencode plugin -g opencode-system-metrics-tui` instala o plugin globalmente para todos os projetos.
|
|
284
|
+
- `opencode plugin opencode-system-metrics-tui@0.1.3` instala o plugin apenas no projeto atual.
|
|
285
|
+
- `opencode plugin -g opencode-system-metrics-tui@0.1.3 --force` instala o plugin globalmente para todos os projetos.
|
|
265
286
|
|
|
266
287
|
### Verificação
|
|
267
288
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-system-metrics-tui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "OpenCode TUI sidebar plugin for live system metrics",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
"build": "bun scripts/build.ts && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
24
24
|
"test": "tsx --test test/*.test.ts",
|
|
25
25
|
"typecheck": "tsc --noEmit",
|
|
26
|
-
"install-font": "node dist/install-hack-font.js"
|
|
26
|
+
"install-font": "node dist/install-hack-font.js",
|
|
27
|
+
"verify-installation": "tsx scripts/plugin-installation.ts",
|
|
28
|
+
"install-plugin": "tsx scripts/install-plugin.ts"
|
|
27
29
|
},
|
|
28
30
|
"engines": {
|
|
29
31
|
"node": ">=18"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { execFile } from "node:child_process"
|
|
2
|
+
import { readFile } from "node:fs/promises"
|
|
3
|
+
import { promisify } from "node:util"
|
|
4
|
+
import { formatVerificationResult, verifyPluginInstallation } from "./plugin-installation.js"
|
|
5
|
+
|
|
6
|
+
const execFileAsync = promisify(execFile)
|
|
7
|
+
const manifest = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")) as {
|
|
8
|
+
name: string
|
|
9
|
+
version: string
|
|
10
|
+
}
|
|
11
|
+
const packageSpec = `${manifest.name}@${manifest.version}`
|
|
12
|
+
|
|
13
|
+
console.log(`Installing ${packageSpec} globally through OpenCode`)
|
|
14
|
+
try {
|
|
15
|
+
const result = await execFileAsync("opencode", ["plugin", "-g", packageSpec, "--force"], { windowsHide: true })
|
|
16
|
+
if (result.stdout.trim()) console.log(result.stdout.trim())
|
|
17
|
+
if (result.stderr.trim()) console.error(result.stderr.trim())
|
|
18
|
+
} catch (error) {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
20
|
+
console.error(`OpenCode plugin installation failed: ${message}`)
|
|
21
|
+
process.exit(1)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const verification = await verifyPluginInstallation({
|
|
25
|
+
packageName: manifest.name,
|
|
26
|
+
expectedVersion: manifest.version,
|
|
27
|
+
cacheDirectory: process.env.OPENCODE_CACHE_DIR,
|
|
28
|
+
})
|
|
29
|
+
console.log(formatVerificationResult(verification))
|
|
30
|
+
if (!verification.ok) process.exitCode = 1
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { access, readFile, readdir } from "node:fs/promises"
|
|
2
|
+
import { homedir } from "node:os"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
import { join, resolve } from "node:path"
|
|
5
|
+
|
|
6
|
+
export type PluginVerificationOptions = {
|
|
7
|
+
cacheDirectory?: string
|
|
8
|
+
packageName: string
|
|
9
|
+
expectedVersion: string
|
|
10
|
+
distPath?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type PluginVerification = {
|
|
14
|
+
ok: boolean
|
|
15
|
+
packagePath?: string
|
|
16
|
+
actualVersion?: string
|
|
17
|
+
staleEntries: string[]
|
|
18
|
+
errors: string[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type PackageManifest = { name?: unknown; version?: unknown }
|
|
22
|
+
|
|
23
|
+
export function getDefaultOpenCodeCacheDirectory(env: NodeJS.ProcessEnv = process.env, home = homedir()): string {
|
|
24
|
+
const cacheRoot = env.OPENCODE_CACHE_DIR ?? env.XDG_CACHE_HOME ?? join(home, ".cache")
|
|
25
|
+
return join(cacheRoot, "opencode", "packages")
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function readManifest(path: string): Promise<PackageManifest | undefined> {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(await readFile(path, "utf8")) as PackageManifest
|
|
31
|
+
} catch {
|
|
32
|
+
return undefined
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function exists(path: string): Promise<boolean> {
|
|
37
|
+
try {
|
|
38
|
+
await access(path)
|
|
39
|
+
return true
|
|
40
|
+
} catch {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function verifyPluginInstallation(options: PluginVerificationOptions): Promise<PluginVerification> {
|
|
46
|
+
const cacheDirectory = resolve(options.cacheDirectory ?? getDefaultOpenCodeCacheDirectory())
|
|
47
|
+
const errors: string[] = []
|
|
48
|
+
const staleEntries: string[] = []
|
|
49
|
+
let packagePath: string | undefined
|
|
50
|
+
let actualVersion: string | undefined
|
|
51
|
+
|
|
52
|
+
let entries: string[]
|
|
53
|
+
try {
|
|
54
|
+
entries = (await readdir(cacheDirectory, { withFileTypes: true }))
|
|
55
|
+
.filter((entry) => entry.isDirectory() && entry.name.startsWith(`${options.packageName}@`))
|
|
56
|
+
.map((entry) => entry.name)
|
|
57
|
+
} catch {
|
|
58
|
+
return { ok: false, staleEntries, errors: [`OpenCode package cache not found: ${cacheDirectory}`] }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const candidatePath = join(cacheDirectory, entry, "node_modules", options.packageName)
|
|
63
|
+
const manifest = await readManifest(join(candidatePath, "package.json"))
|
|
64
|
+
if (manifest?.name !== options.packageName || typeof manifest.version !== "string") {
|
|
65
|
+
staleEntries.push(join(cacheDirectory, entry))
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
if (manifest.version === options.expectedVersion && packagePath === undefined) {
|
|
69
|
+
packagePath = candidatePath
|
|
70
|
+
actualVersion = manifest.version
|
|
71
|
+
} else if (manifest.version !== options.expectedVersion) {
|
|
72
|
+
staleEntries.push(join(cacheDirectory, entry))
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (packagePath === undefined) {
|
|
77
|
+
errors.push(`Installed ${options.packageName}@${options.expectedVersion} was not found in ${cacheDirectory}`)
|
|
78
|
+
} else if (actualVersion !== options.expectedVersion) {
|
|
79
|
+
errors.push(`Installed version is ${actualVersion ?? "unknown"}; expected ${options.expectedVersion}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (packagePath !== undefined && !(await exists(join(packagePath, options.distPath ?? "dist", "tui.js")))) {
|
|
83
|
+
errors.push(`Required dist/tui.js is missing from ${packagePath}`)
|
|
84
|
+
}
|
|
85
|
+
if (staleEntries.length > 0) errors.push(`Stale OpenCode cache entries detected: ${staleEntries.join(", ")}`)
|
|
86
|
+
|
|
87
|
+
return { ok: errors.length === 0, packagePath, actualVersion, staleEntries, errors }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function formatVerificationResult(result: PluginVerification): string {
|
|
91
|
+
if (result.ok) return `Verified OpenCode plugin ${result.actualVersion} at ${result.packagePath}`
|
|
92
|
+
return result.errors.join("\n")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (process.argv[1] !== undefined && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) {
|
|
96
|
+
const packageManifest = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8")) as {
|
|
97
|
+
name: string
|
|
98
|
+
version: string
|
|
99
|
+
}
|
|
100
|
+
const result = await verifyPluginInstallation({
|
|
101
|
+
packageName: packageManifest.name,
|
|
102
|
+
expectedVersion: packageManifest.version,
|
|
103
|
+
cacheDirectory: process.env.OPENCODE_CACHE_DIR,
|
|
104
|
+
})
|
|
105
|
+
console.log(formatVerificationResult(result))
|
|
106
|
+
if (!result.ok) process.exitCode = 1
|
|
107
|
+
}
|