opencube 0.1.0 → 0.1.1

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  <p align="center">
2
- <img src="assets/opencode-icon.png" width="96" height="96" alt="OpenCub icon" />
2
+ <img src="assets/opencode-icon.png" width="96" height="96" alt="OpenCube icon" />
3
3
  </p>
4
4
 
5
- # OpenCub
5
+ # OpenCube
6
6
 
7
- OpenCub is a tiny desktop pet for [opencode](https://opencode.ai/).
7
+ OpenCube is a tiny desktop pet for [opencode](https://opencode.ai/).
8
8
 
9
9
  It watches opencode session activity and renders a small Three.js cube on your desktop:
10
10
 
@@ -13,16 +13,14 @@ It watches opencode session activity and renders a small Three.js cube on your d
13
13
  - `/pet_say_hello` flashes one free face
14
14
  - `/pet_fancy_say_hello` plays a randomized light show on free faces
15
15
 
16
- OpenCub is packaged as an opencode plugin plus an Electron desktop process.
16
+ OpenCube is packaged as an opencode plugin plus an Electron desktop process.
17
17
 
18
18
  ## Install
19
19
 
20
- > OpenCub is not published yet. These are the intended install commands once published.
21
-
22
20
  Install globally through opencode:
23
21
 
24
22
  ```sh
25
- opencode plugin opencub --global
23
+ opencode plugin opencube --global
26
24
  ```
27
25
 
28
26
  Then restart opencode and run:
@@ -35,7 +33,7 @@ You can also add it manually to `~/.config/opencode/opencode.json`:
35
33
 
36
34
  ```json
37
35
  {
38
- "plugin": ["opencub"]
36
+ "plugin": ["opencube"]
39
37
  }
40
38
  ```
41
39
 
@@ -43,8 +41,8 @@ You can also add it manually to `~/.config/opencode/opencode.json`:
43
41
 
44
42
  | Command | Description |
45
43
  | --- | --- |
46
- | `/pet` | Show or start OpenCub. |
47
- | `/pet_stop` | Quit OpenCub. |
44
+ | `/pet` | Show or start OpenCube. |
45
+ | `/pet_stop` | Quit OpenCube. |
48
46
  | `/pet_say_hello` | Flash one currently free face three times with a random color. |
49
47
  | `/pet_fancy_say_hello` | Run a denser randomized light show across currently free faces. |
50
48
 
@@ -52,7 +50,7 @@ These commands are handled by the plugin and do not get sent to the model.
52
50
 
53
51
  ## How it works
54
52
 
55
- OpenCub has two parts in one npm package:
53
+ OpenCube has two parts in one npm package:
56
54
 
57
55
  1. `src/plugin-server.cjs` — the opencode plugin entrypoint.
58
56
  2. `src/main.js` — the Electron desktop pet.
@@ -60,7 +58,7 @@ OpenCub has two parts in one npm package:
60
58
  The plugin registers slash commands, listens for opencode `session.status` events, and sends events to the desktop pet over a local HTTP API:
61
59
 
62
60
  ```text
63
- opencode plugin -> http://127.0.0.1:47832 -> Electron OpenCub
61
+ opencode plugin -> http://127.0.0.1:47832 -> Electron OpenCube
64
62
  ```
65
63
 
66
64
  The Electron process owns the window, Three.js renderer, cube rotation, face glow state, and inbox/debug endpoints.
@@ -77,7 +75,7 @@ Users do not need to run `npm install` manually when installing via `opencode pl
77
75
 
78
76
  - The first install may take a while because Electron is downloaded as a runtime dependency.
79
77
  - If commands do not appear after installation, restart opencode.
80
- - OpenCub uses a local-only HTTP server on `127.0.0.1:47832`.
78
+ - OpenCube uses a local-only HTTP server on `127.0.0.1:47832`.
81
79
  - If that port is already in use, set `OPENCODE_PET_PORT` before starting opencode.
82
80
 
83
81
  ## Local development
@@ -93,7 +91,7 @@ For local opencode plugin testing, point your opencode config at the package dir
93
91
 
94
92
  ```json
95
93
  {
96
- "plugin": ["/path/to/opencub"]
94
+ "plugin": ["/path/to/opencube"]
97
95
  }
98
96
  ```
99
97
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencube",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "A tiny Three.js desktop pet for opencode session activity.",
5
5
  "main": "src/main.js",
6
6
  "exports": {
package/src/main.js CHANGED
@@ -9,7 +9,7 @@ const { DEFAULT_SESSION_COLORS, pixelPetSvg } = require("./pixel-pet-reference.c
9
9
  const APP_NAME = "opencode pet"
10
10
  const HOST = "127.0.0.1"
11
11
  const PORT = Number(process.env.OPENCODE_PET_PORT || 47832)
12
- const DATA_DIR = path.join(os.homedir(), ".local", "share", "opencode-pet")
12
+ const DATA_DIR = path.join(os.homedir(), ".local", "share", "opencube")
13
13
  const STATE_FILE = path.join(DATA_DIR, "state.json")
14
14
  const PET_HTML_FILE = path.join(DATA_DIR, "pet.html")
15
15
  const ICON_PATH = process.env.OPENCODE_PET_ICON || path.join(__dirname, "..", "assets", "opencode-icon.png")
@@ -1169,7 +1169,7 @@ function startServer() {
1169
1169
  pid: process.pid,
1170
1170
  port: PORT,
1171
1171
  events: events.length,
1172
- pet: "pixel-opencode-pet",
1172
+ pet: "opencube",
1173
1173
  sessions: getPetState().sessions.map(({ sessionID, state, busyIndex, idleIndex, color }) => ({
1174
1174
  sessionID,
1175
1175
  state,
@@ -48,7 +48,7 @@ function cubNotice(text, icon = CUB_ICON) {
48
48
  }
49
49
 
50
50
  module.exports = {
51
- id: "opencode-pet",
51
+ id: "opencube",
52
52
  server: async ({ client }) => {
53
53
  const sessionStatus = new Map()
54
54
 
@@ -68,11 +68,11 @@ module.exports = {
68
68
  }
69
69
  cfg.command.pet_say_hello = {
70
70
  template: "/pet_say_hello",
71
- description: "Send a hello test event to OpenCub.",
71
+ description: "Send a hello test event to OpenCube.",
72
72
  }
73
73
  cfg.command.pet_fancy_say_hello = {
74
74
  template: "/pet_fancy_say_hello",
75
- description: "Trigger a randomized light show on OpenCub's free faces.",
75
+ description: "Trigger a randomized light show on OpenCube's free faces.",
76
76
  }
77
77
  },
78
78
 
@@ -87,7 +87,7 @@ module.exports = {
87
87
 
88
88
  if (shouldQuit(input)) {
89
89
  await quitPet()
90
- await injectNotice(client, input.sessionID, cubNotice("OpenCub is going to sleep 🐾", "◌"))
90
+ await injectNotice(client, input.sessionID, cubNotice("OpenCube is going to sleep 🐾", "◌"))
91
91
  } else if (isSayHello(input)) {
92
92
  const result = await sendEvent({
93
93
  type: "hello",
@@ -95,12 +95,12 @@ module.exports = {
95
95
  command: input.command,
96
96
  arguments: input.arguments,
97
97
  sessionID: input.sessionID,
98
- source: "opencode-pet-plugin",
98
+ source: "opencube-plugin",
99
99
  })
100
100
  await injectNotice(
101
101
  client,
102
102
  input.sessionID,
103
- result ? cubNotice("OpenCub got your hello 🐾", "✦") : cubNotice("OpenCub is sleeping... zzz Use /pet to wake it.", "☾"),
103
+ result ? cubNotice("OpenCube got your hello 🐾", "✦") : cubNotice("OpenCube is sleeping... zzz Use /pet to wake it.", "☾"),
104
104
  )
105
105
  } else if (isFancySayHello(input)) {
106
106
  const result = await sendEvent({
@@ -109,14 +109,14 @@ module.exports = {
109
109
  command: input.command,
110
110
  arguments: input.arguments,
111
111
  sessionID: input.sessionID,
112
- source: "opencode-pet-plugin",
112
+ source: "opencube-plugin",
113
113
  })
114
114
  await injectNotice(
115
115
  client,
116
116
  input.sessionID,
117
117
  result
118
- ? cubNotice("OpenCub is putting on a light show ✨", "✺")
119
- : cubNotice("OpenCub is sleeping... zzz Start it with /pet before the light show.", "☾"),
118
+ ? cubNotice("OpenCube is putting on a light show ✨", "✺")
119
+ : cubNotice("OpenCube is sleeping... zzz Start it with /pet before the light show.", "☾"),
120
120
  )
121
121
  } else {
122
122
  await showPet({
@@ -146,7 +146,7 @@ module.exports = {
146
146
  sessionID,
147
147
  status,
148
148
  previousStatus: previous,
149
- source: "opencode-pet-plugin",
149
+ source: "opencube-plugin",
150
150
  })
151
151
  return
152
152
  }
@@ -161,7 +161,7 @@ module.exports = {
161
161
  sessionID,
162
162
  status,
163
163
  previousStatus: previous,
164
- source: "opencode-pet-plugin",
164
+ source: "opencube-plugin",
165
165
  })
166
166
  },
167
167
  }
@@ -30,7 +30,7 @@ async function emitProgress(onProgress, message) {
30
30
  try {
31
31
  await onProgress(message)
32
32
  } catch {
33
- // Progress is best-effort; never block OpenCub startup on UI notices.
33
+ // Progress is best-effort; never block OpenCube startup on UI notices.
34
34
  }
35
35
  }
36
36
 
@@ -76,11 +76,11 @@ async function installElectronBinary(electronDir, options = {}) {
76
76
  const executablePath = path.join(distPath, platformPath)
77
77
 
78
78
  if (fs.existsSync(executablePath)) {
79
- await emitProgress(options.onProgress, "OpenCub: Electron binary is ready ✅")
79
+ await emitProgress(options.onProgress, "OpenCube: Electron binary is ready ✅")
80
80
  return executablePath
81
81
  }
82
82
 
83
- await emitProgress(options.onProgress, `OpenCub: downloading Electron ${version} for ${platform}/${arch}...`)
83
+ await emitProgress(options.onProgress, `OpenCube: downloading Electron ${version} for ${platform}/${arch}...`)
84
84
  const zipPath = await downloadArtifact({
85
85
  version,
86
86
  artifactName: "electron",
@@ -89,19 +89,19 @@ async function installElectronBinary(electronDir, options = {}) {
89
89
  platform,
90
90
  arch,
91
91
  })
92
- await emitProgress(options.onProgress, "OpenCub: extracting Electron binary...")
92
+ await emitProgress(options.onProgress, "OpenCube: extracting Electron binary...")
93
93
  await extractElectronZip(zipPath, distPath)
94
94
  await fs.promises.writeFile(path.join(electronDir, "path.txt"), platformPath)
95
- await emitProgress(options.onProgress, "OpenCub: Electron binary installed ✅")
95
+ await emitProgress(options.onProgress, "OpenCube: Electron binary installed ✅")
96
96
  return executablePath
97
97
  }
98
98
 
99
99
  async function resolveElectronPath(options = {}) {
100
- await emitProgress(options.onProgress, "OpenCub: checking Electron runtime...")
100
+ await emitProgress(options.onProgress, "OpenCube: checking Electron runtime...")
101
101
  try {
102
102
  const electronPath = require("electron")
103
103
  if (typeof electronPath === "string") {
104
- await emitProgress(options.onProgress, "OpenCub: Electron runtime is ready ✅")
104
+ await emitProgress(options.onProgress, "OpenCube: Electron runtime is ready ✅")
105
105
  return electronPath
106
106
  }
107
107
 
@@ -109,12 +109,12 @@ async function resolveElectronPath(options = {}) {
109
109
  // environment require("electron") can resolve to Electron's built-in API
110
110
  // object instead of the npm package's executable path string. Fall through
111
111
  // to the npm package directory and resolve/repair the packaged binary.
112
- await emitProgress(options.onProgress, "OpenCub: locating packaged Electron binary...")
112
+ await emitProgress(options.onProgress, "OpenCube: locating packaged Electron binary...")
113
113
  const electronPackage = require.resolve("electron/package.json")
114
114
  const electronDir = path.dirname(electronPackage)
115
115
  return await installElectronBinary(electronDir, options)
116
116
  } catch (error) {
117
- await emitProgress(options.onProgress, "OpenCub: Electron runtime is incomplete; repairing...")
117
+ await emitProgress(options.onProgress, "OpenCube: Electron runtime is incomplete; repairing...")
118
118
  const electronPackage = require.resolve("electron/package.json")
119
119
  const electronDir = path.dirname(electronPackage)
120
120
  return await installElectronBinary(electronDir, options)
@@ -123,7 +123,7 @@ async function resolveElectronPath(options = {}) {
123
123
 
124
124
  async function launchPet(args = [], options = {}) {
125
125
  const electronPath = await resolveElectronPath(options)
126
- await emitProgress(options.onProgress, "OpenCub: launching desktop pet...")
126
+ await emitProgress(options.onProgress, "OpenCube: launching desktop pet...")
127
127
  const child = spawn(electronPath, [PET_APP_DIR, ...args], {
128
128
  cwd: PET_APP_DIR,
129
129
  detached: true,
@@ -134,7 +134,7 @@ async function launchPet(args = [], options = {}) {
134
134
  },
135
135
  })
136
136
  child.unref()
137
- await emitProgress(options.onProgress, "OpenCub: launch request sent 🐾")
137
+ await emitProgress(options.onProgress, "OpenCube: launch request sent 🐾")
138
138
  }
139
139
 
140
140
  async function requestPet(pathname, options = {}) {
@@ -165,28 +165,28 @@ async function healthPet() {
165
165
  }
166
166
 
167
167
  async function waitForPet(timeoutMs = 3500, options = {}) {
168
- await emitProgress(options.onProgress, "OpenCub: waiting for local server...")
168
+ await emitProgress(options.onProgress, "OpenCube: waiting for local server...")
169
169
  const startedAt = Date.now()
170
170
  while (Date.now() - startedAt < timeoutMs) {
171
171
  const health = await healthPet()
172
172
  if (health) {
173
- await emitProgress(options.onProgress, "OpenCub: local server is ready ✅")
173
+ await emitProgress(options.onProgress, "OpenCube: local server is ready ✅")
174
174
  return health
175
175
  }
176
176
  await new Promise((resolve) => setTimeout(resolve, 150))
177
177
  }
178
- await emitProgress(options.onProgress, "OpenCub: local server did not answer yet")
178
+ await emitProgress(options.onProgress, "OpenCube: local server did not answer yet")
179
179
  return undefined
180
180
  }
181
181
 
182
182
  async function ensurePet(options = {}) {
183
- await emitProgress(options.onProgress, "OpenCub: checking whether it is already running...")
183
+ await emitProgress(options.onProgress, "OpenCube: checking whether it is already running...")
184
184
  const existing = await healthPet()
185
185
  if (existing) {
186
- await emitProgress(options.onProgress, "OpenCub: already running; showing window...")
186
+ await emitProgress(options.onProgress, "OpenCube: already running; showing window...")
187
187
  return existing
188
188
  }
189
- await emitProgress(options.onProgress, "OpenCub: not running; starting now...")
189
+ await emitProgress(options.onProgress, "OpenCube: not running; starting now...")
190
190
  await launchPet(["--show"], options)
191
191
  return await waitForPet(3500, options)
192
192
  }
@@ -194,7 +194,7 @@ async function ensurePet(options = {}) {
194
194
  async function showPet(options = {}) {
195
195
  const health = await ensurePet(options)
196
196
  await requestPet("/show", { method: "POST", timeoutMs: 800 })
197
- await emitProgress(options.onProgress, health ? "OpenCub: shown ✨" : "OpenCub: start requested, still warming up...")
197
+ await emitProgress(options.onProgress, health ? "OpenCube: shown ✨" : "OpenCube: start requested, still warming up...")
198
198
  return health
199
199
  }
200
200
 
@@ -208,7 +208,7 @@ async function quitPet() {
208
208
  }
209
209
 
210
210
  async function sendEvent(event) {
211
- // Only /pet is allowed to start OpenCub. Session lifecycle events and hello
211
+ // Only /pet is allowed to start OpenCube. Session lifecycle events and hello
212
212
  // commands should talk to the desktop pet only if it is already running.
213
213
  const health = await healthPet()
214
214
  if (!health) return undefined
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
- id: "opencode-pet",
2
+ id: "opencube",
3
3
  // Slash commands are registered from the server plugin via cfg.command, using
4
4
  // the same command.execute.before abort trick as @slkiser/opencode-quota.
5
5
  // Keep a no-op TUI entry so opencode can load ./tui without duplicate /pet rows.