opencode-pixel-office 1.0.8 → 1.0.10
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/bin/claude-code-hook.js +13 -11
- package/bin/opencode-pixel-office.js +160 -20
- package/package.json +1 -1
- package/plugin/pixel-office.js +15 -141
package/bin/claude-code-hook.js
CHANGED
|
@@ -48,15 +48,17 @@ const mapHookToEvent = (input) => {
|
|
|
48
48
|
|
|
49
49
|
const info = {
|
|
50
50
|
id: sessionId || `claude-${Date.now()}`,
|
|
51
|
-
sessionID: sessionId
|
|
52
|
-
|
|
51
|
+
sessionID: sessionId,
|
|
52
|
+
agent: "Claude",
|
|
53
|
+
title: cwd || "Claude Code",
|
|
54
|
+
model: { modelID: "claude", providerID: "anthropic" },
|
|
53
55
|
};
|
|
54
56
|
|
|
55
57
|
switch (hook) {
|
|
56
58
|
case "SessionStart":
|
|
57
59
|
return {
|
|
58
60
|
type: "session.created",
|
|
59
|
-
properties: { info
|
|
61
|
+
properties: { info },
|
|
60
62
|
};
|
|
61
63
|
case "SessionEnd":
|
|
62
64
|
return {
|
|
@@ -67,35 +69,35 @@ const mapHookToEvent = (input) => {
|
|
|
67
69
|
return {
|
|
68
70
|
type: "message.updated",
|
|
69
71
|
properties: {
|
|
70
|
-
info,
|
|
71
|
-
message: { content: prompt },
|
|
72
|
+
info: { ...info, role: "user" },
|
|
73
|
+
message: { content: prompt, role: "user" },
|
|
72
74
|
},
|
|
73
75
|
};
|
|
74
76
|
case "PreToolUse":
|
|
75
77
|
return {
|
|
76
78
|
type: "tool.execute.before",
|
|
77
|
-
properties: { tool: { name: toolName, input: toolInput } },
|
|
79
|
+
properties: { info, tool: { name: toolName, input: toolInput } },
|
|
78
80
|
};
|
|
79
81
|
case "PostToolUse":
|
|
80
82
|
case "PostToolUseFailure":
|
|
81
83
|
return {
|
|
82
84
|
type: "tool.execute.after",
|
|
83
|
-
properties: { tool: { name: toolName, input: toolInput } },
|
|
85
|
+
properties: { info, tool: { name: toolName, input: toolInput } },
|
|
84
86
|
};
|
|
85
87
|
case "PermissionRequest":
|
|
86
88
|
return {
|
|
87
89
|
type: "permission.asked",
|
|
88
|
-
properties: { permission },
|
|
90
|
+
properties: { info, permission },
|
|
89
91
|
};
|
|
90
92
|
case "Notification":
|
|
91
93
|
return {
|
|
92
94
|
type: "tui.toast.show",
|
|
93
|
-
properties: { message: input.message || "" },
|
|
95
|
+
properties: { info, message: input.message || "" },
|
|
94
96
|
};
|
|
95
97
|
case "PreCompact":
|
|
96
98
|
return {
|
|
97
99
|
type: "session.compacted",
|
|
98
|
-
properties: { info
|
|
100
|
+
properties: { info },
|
|
99
101
|
};
|
|
100
102
|
case "Stop":
|
|
101
103
|
return {
|
|
@@ -106,7 +108,7 @@ const mapHookToEvent = (input) => {
|
|
|
106
108
|
case "SubagentStop":
|
|
107
109
|
return {
|
|
108
110
|
type: "session.updated",
|
|
109
|
-
properties: { info
|
|
111
|
+
properties: { info },
|
|
110
112
|
};
|
|
111
113
|
default:
|
|
112
114
|
return null;
|
|
@@ -22,23 +22,37 @@ const shouldInstallClaude = args[0] === "claude-code" && args[1] === "install";
|
|
|
22
22
|
const shouldSwitch = args[0] === "switch";
|
|
23
23
|
const switchTarget = shouldSwitch ? args[1] : null;
|
|
24
24
|
const shouldUninstall = args.includes("uninstall");
|
|
25
|
+
const shouldStart = args[0] === "start";
|
|
26
|
+
const shouldVersion = args.includes("--version") || args.includes("-v");
|
|
25
27
|
const yesFlag = args.includes("--yes") || args.includes("-y");
|
|
26
28
|
const skipJson = args.includes("--no-json");
|
|
27
29
|
const portIndex = args.findIndex((arg) => arg === "--port");
|
|
28
30
|
const portArg = portIndex !== -1 ? args[portIndex + 1] : null;
|
|
29
31
|
|
|
32
|
+
const getVersion = () => {
|
|
33
|
+
try {
|
|
34
|
+
const pkgPath = path.resolve(__dirname, "..", "package.json");
|
|
35
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
36
|
+
return pkg.version || "unknown";
|
|
37
|
+
} catch {
|
|
38
|
+
return "unknown";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
30
42
|
const printHelp = () => {
|
|
31
43
|
console.log("opencode-pixel-office installer\n");
|
|
32
44
|
console.log("Usage:");
|
|
33
45
|
console.log(" opencode-pixel-office install [--yes] [--port <number>]");
|
|
34
46
|
console.log(" opencode-pixel-office claude-code install");
|
|
35
47
|
console.log(" opencode-pixel-office switch <opencode|claude-code>");
|
|
48
|
+
console.log(" opencode-pixel-office start");
|
|
36
49
|
console.log(" opencode-pixel-office uninstall");
|
|
37
50
|
console.log(" opencode-pixel-office stop");
|
|
38
51
|
console.log("\nOptions:");
|
|
39
52
|
console.log(" --port <number> Configure the server port (default: 5100)");
|
|
40
53
|
console.log(" --no-json Skip updating opencode.json");
|
|
41
54
|
console.log(" --yes, -y Overwrite without prompting");
|
|
55
|
+
console.log(" --version, -v Show version number");
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
const installClaudeCodeHooks = () => {
|
|
@@ -129,7 +143,33 @@ const copyRecursiveSync = (src, dest) => {
|
|
|
129
143
|
}
|
|
130
144
|
};
|
|
131
145
|
|
|
146
|
+
const stopServer = (port) => {
|
|
147
|
+
try {
|
|
148
|
+
const pidOutput = execSync(`lsof -t -i :${port} 2>/dev/null`).toString().trim();
|
|
149
|
+
if (pidOutput) {
|
|
150
|
+
const pids = pidOutput.split('\n').map(p => parseInt(p, 10)).filter(p => !isNaN(p) && p > 0);
|
|
151
|
+
for (const pid of pids) {
|
|
152
|
+
try {
|
|
153
|
+
process.kill(pid);
|
|
154
|
+
console.log(`✓ Stopped server (PID: ${pid})`);
|
|
155
|
+
} catch {
|
|
156
|
+
// Process may have already exited
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return pids.length > 0;
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
// lsof failed, no process found
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
};
|
|
166
|
+
|
|
132
167
|
const run = async () => {
|
|
168
|
+
if (shouldVersion) {
|
|
169
|
+
console.log(`opencode-pixel-office v${getVersion()}`);
|
|
170
|
+
process.exit(0);
|
|
171
|
+
}
|
|
172
|
+
|
|
133
173
|
if (shouldSwitch) {
|
|
134
174
|
if (switchTarget !== "opencode" && switchTarget !== "claude-code") {
|
|
135
175
|
console.error("Switch target must be 'opencode' or 'claude-code'.");
|
|
@@ -148,6 +188,14 @@ const run = async () => {
|
|
|
148
188
|
}
|
|
149
189
|
|
|
150
190
|
if (shouldUninstall) {
|
|
191
|
+
// Stop server first
|
|
192
|
+
const config = loadConfig();
|
|
193
|
+
const port = config.port || 5100;
|
|
194
|
+
console.log("Stopping Pixel Office server...");
|
|
195
|
+
if (!stopServer(port)) {
|
|
196
|
+
console.log("- Server not running");
|
|
197
|
+
}
|
|
198
|
+
|
|
151
199
|
const targetPluginPath = path.join(DEFAULT_PLUGIN_DIR, PLUGIN_NAME);
|
|
152
200
|
|
|
153
201
|
// Remove Plugin
|
|
@@ -166,6 +214,56 @@ const run = async () => {
|
|
|
166
214
|
console.log(`- App directory not found at ${DEFAULT_APP_DIR}`);
|
|
167
215
|
}
|
|
168
216
|
|
|
217
|
+
// Remove Claude Code hooks
|
|
218
|
+
const claudeDir = path.join(os.homedir(), ".claude");
|
|
219
|
+
const hookDir = path.join(claudeDir, "hooks");
|
|
220
|
+
const hookFile = path.join(hookDir, "opencode-pixel-office-hook.js");
|
|
221
|
+
const settingsPath = path.join(claudeDir, "settings.json");
|
|
222
|
+
|
|
223
|
+
if (fs.existsSync(hookFile)) {
|
|
224
|
+
fs.unlinkSync(hookFile);
|
|
225
|
+
console.log(`✓ Removed Claude Code hook: ${hookFile}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (fs.existsSync(settingsPath)) {
|
|
229
|
+
try {
|
|
230
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
231
|
+
if (settings.hooks) {
|
|
232
|
+
let modified = false;
|
|
233
|
+
for (const eventName of Object.keys(settings.hooks)) {
|
|
234
|
+
const hooks = settings.hooks[eventName];
|
|
235
|
+
if (Array.isArray(hooks)) {
|
|
236
|
+
const filtered = hooks.filter(h => {
|
|
237
|
+
if (Array.isArray(h.hooks)) {
|
|
238
|
+
h.hooks = h.hooks.filter(inner =>
|
|
239
|
+
!inner.command?.includes("opencode-pixel-office-hook")
|
|
240
|
+
);
|
|
241
|
+
return h.hooks.length > 0;
|
|
242
|
+
}
|
|
243
|
+
return !h.command?.includes("opencode-pixel-office-hook");
|
|
244
|
+
});
|
|
245
|
+
if (filtered.length !== hooks.length) {
|
|
246
|
+
settings.hooks[eventName] = filtered;
|
|
247
|
+
modified = true;
|
|
248
|
+
}
|
|
249
|
+
if (filtered.length === 0) {
|
|
250
|
+
delete settings.hooks[eventName];
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
255
|
+
delete settings.hooks;
|
|
256
|
+
}
|
|
257
|
+
if (modified) {
|
|
258
|
+
fs.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
|
|
259
|
+
console.log(`✓ Removed hooks from Claude Code settings`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
} catch {
|
|
263
|
+
// ignore settings parse errors
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
169
267
|
// Clean up Config (Legacy)
|
|
170
268
|
if (fs.existsSync(DEFAULT_CONFIG_PATH) && !skipJson) {
|
|
171
269
|
try {
|
|
@@ -188,32 +286,73 @@ const run = async () => {
|
|
|
188
286
|
process.exit(0);
|
|
189
287
|
}
|
|
190
288
|
|
|
191
|
-
if (
|
|
289
|
+
if (shouldStart) {
|
|
192
290
|
const config = loadConfig();
|
|
193
|
-
const port = config.port || 5100;
|
|
291
|
+
const port = portArg ? parseInt(portArg, 10) : (config.port || 5100);
|
|
292
|
+
const serverScript = "server/index.ts";
|
|
293
|
+
|
|
294
|
+
const rootSource = path.resolve(__dirname, "..");
|
|
295
|
+
const localServerPath = path.join(rootSource, "server", "index.ts");
|
|
296
|
+
const globalServerPath = path.join(DEFAULT_APP_DIR, "server", "index.ts");
|
|
297
|
+
|
|
298
|
+
let serverCwd;
|
|
299
|
+
let useGlobal = false;
|
|
300
|
+
if (fs.existsSync(localServerPath)) {
|
|
301
|
+
serverCwd = rootSource;
|
|
302
|
+
} else if (fs.existsSync(globalServerPath)) {
|
|
303
|
+
serverCwd = DEFAULT_APP_DIR;
|
|
304
|
+
useGlobal = true;
|
|
305
|
+
} else {
|
|
306
|
+
console.error("Server not found. Run 'opencode-pixel-office install' first.");
|
|
307
|
+
process.exit(1);
|
|
308
|
+
}
|
|
194
309
|
|
|
195
|
-
console.log(`Stopping Pixel Office server on port ${port}...`);
|
|
196
310
|
try {
|
|
197
|
-
const pidOutput = execSync(`lsof -t -i :${port}`).toString().trim();
|
|
311
|
+
const pidOutput = execSync(`lsof -t -i :${port} 2>/dev/null`).toString().trim();
|
|
198
312
|
if (pidOutput) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
} else {
|
|
207
|
-
console.log(`- No server found on port ${port}`);
|
|
313
|
+
console.log(`Pixel Office is already running on port ${port} (PID: ${pidOutput})`);
|
|
314
|
+
const url = `http://localhost:${port}`;
|
|
315
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
316
|
+
try { execSync(`${openCmd} ${url}`); } catch { }
|
|
317
|
+
console.log(`Opened ${url}`);
|
|
318
|
+
process.exit(0);
|
|
208
319
|
}
|
|
209
|
-
} catch
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
320
|
+
} catch { }
|
|
321
|
+
|
|
322
|
+
let tsxBin = "tsx";
|
|
323
|
+
if (useGlobal) {
|
|
324
|
+
const globalTsx = path.join(serverCwd, "node_modules", ".bin", "tsx");
|
|
325
|
+
if (fs.existsSync(globalTsx)) {
|
|
326
|
+
tsxBin = globalTsx;
|
|
215
327
|
}
|
|
216
328
|
}
|
|
329
|
+
|
|
330
|
+
const { spawn } = await import("node:child_process");
|
|
331
|
+
const child = spawn(tsxBin, [serverScript], {
|
|
332
|
+
cwd: serverCwd,
|
|
333
|
+
env: { ...process.env, PORT: String(port) },
|
|
334
|
+
detached: true,
|
|
335
|
+
stdio: "ignore",
|
|
336
|
+
});
|
|
337
|
+
child.unref();
|
|
338
|
+
|
|
339
|
+
console.log(`Pixel Office server started on port ${port} (PID: ${child.pid})`);
|
|
340
|
+
|
|
341
|
+
await new Promise((r) => setTimeout(r, 1500));
|
|
342
|
+
const url = `http://localhost:${port}`;
|
|
343
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
344
|
+
try { execSync(`${openCmd} ${url}`); } catch { }
|
|
345
|
+
console.log(`Opened ${url}`);
|
|
346
|
+
process.exit(0);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (args.includes("stop")) {
|
|
350
|
+
const config = loadConfig();
|
|
351
|
+
const port = config.port || 5100;
|
|
352
|
+
console.log(`Stopping Pixel Office server on port ${port}...`);
|
|
353
|
+
if (!stopServer(port)) {
|
|
354
|
+
console.log(`- No server found on port ${port}`);
|
|
355
|
+
}
|
|
217
356
|
process.exit(0);
|
|
218
357
|
}
|
|
219
358
|
|
|
@@ -298,7 +437,8 @@ const run = async () => {
|
|
|
298
437
|
|
|
299
438
|
console.log(`✓ Standalone app installed to ${DEFAULT_APP_DIR}`);
|
|
300
439
|
|
|
301
|
-
console.log("\
|
|
440
|
+
console.log("\nInstallation complete!");
|
|
441
|
+
console.log("Run 'opencode-pixel-office start' to launch the server.");
|
|
302
442
|
};
|
|
303
443
|
|
|
304
444
|
run().catch((error) => {
|
package/package.json
CHANGED
package/plugin/pixel-office.js
CHANGED
|
@@ -3,31 +3,25 @@ import fs from "node:fs";
|
|
|
3
3
|
|
|
4
4
|
const DEFAULT_PORT = 5100;
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
const
|
|
6
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || "/";
|
|
7
|
+
const globalDistDir = path.join(homeDir, ".opencode", "pixel-office");
|
|
8
|
+
|
|
9
|
+
const getConfiguredPort = () => {
|
|
8
10
|
try {
|
|
9
11
|
const configPath = path.join(globalDistDir, "config.json");
|
|
10
12
|
if (fs.existsSync(configPath)) {
|
|
11
|
-
const start = Date.now();
|
|
12
|
-
// Read synchronously to ensure we have port for endpoint
|
|
13
|
-
// This is okay as it's a tiny local JSON
|
|
14
13
|
const raw = fs.readFileSync(configPath, "utf8");
|
|
15
14
|
const data = JSON.parse(raw);
|
|
16
15
|
if (data && typeof data.port === "number") {
|
|
17
16
|
return data.port;
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
|
-
} catch
|
|
19
|
+
} catch {
|
|
21
20
|
// ignore
|
|
22
21
|
}
|
|
23
22
|
return DEFAULT_PORT;
|
|
24
23
|
};
|
|
25
24
|
|
|
26
|
-
// We need to resolve home dir early to get config
|
|
27
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE || "/";
|
|
28
|
-
const globalDistDir = path.join(homeDir, ".opencode", "pixel-office");
|
|
29
|
-
const configuredPort = getConfiguredPort(globalDistDir);
|
|
30
|
-
|
|
31
25
|
const readMode = () => {
|
|
32
26
|
try {
|
|
33
27
|
const configPath = path.join(globalDistDir, "config.json");
|
|
@@ -38,140 +32,28 @@ const readMode = () => {
|
|
|
38
32
|
return data.mode;
|
|
39
33
|
}
|
|
40
34
|
}
|
|
41
|
-
} catch
|
|
35
|
+
} catch {
|
|
42
36
|
return "opencode";
|
|
43
37
|
}
|
|
44
38
|
return "opencode";
|
|
45
39
|
};
|
|
46
40
|
|
|
47
41
|
const resolveEndpoint = () => {
|
|
48
|
-
const port = process.env.PIXEL_OFFICE_PORT ||
|
|
49
|
-
const raw =
|
|
50
|
-
process.env.PIXEL_OFFICE_URL ||
|
|
51
|
-
`http://localhost:${port}/events`;
|
|
42
|
+
const port = process.env.PIXEL_OFFICE_PORT || getConfiguredPort();
|
|
43
|
+
const raw = process.env.PIXEL_OFFICE_URL || `http://localhost:${port}/events`;
|
|
52
44
|
return raw.endsWith("/events") ? raw : `${raw.replace(/\/$/, "")}/events`;
|
|
53
45
|
};
|
|
54
46
|
|
|
55
|
-
const resolveServerUrl = (endpoint) => endpoint.replace(/\/events$/, "");
|
|
56
|
-
|
|
57
|
-
const resolveEndpointInfo = (endpoint, portOverride) => {
|
|
58
|
-
try {
|
|
59
|
-
const url = new URL(endpoint);
|
|
60
|
-
const port = url.port ? Number(url.port) : portOverride;
|
|
61
|
-
return {
|
|
62
|
-
url,
|
|
63
|
-
port,
|
|
64
|
-
isLocal: url.hostname === "localhost" || url.hostname === "127.0.0.1",
|
|
65
|
-
};
|
|
66
|
-
} catch (error) {
|
|
67
|
-
return { url: null, port: portOverride, isLocal: false };
|
|
68
|
-
}
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const resolveOpenCommand = (url) => {
|
|
72
|
-
if (process.platform === "darwin") {
|
|
73
|
-
return ["open", url];
|
|
74
|
-
}
|
|
75
|
-
if (process.platform === "win32") {
|
|
76
|
-
return ["cmd", "/c", "start", "", url];
|
|
77
|
-
}
|
|
78
|
-
return ["xdg-open", url];
|
|
79
|
-
};
|
|
80
|
-
|
|
81
47
|
export const PixelOfficePlugin = async ({ directory, worktree, client }) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const endpointInfo = resolveEndpointInfo(endpoint, configuredPort);
|
|
86
|
-
const openCommand = resolveOpenCommand(serverUrl);
|
|
87
|
-
|
|
88
|
-
// Path Resolution
|
|
89
|
-
const localServerPath = path.join(rootDir, "server", "index.ts");
|
|
90
|
-
const globalServerPath = path.join(globalDistDir, "server", "index.ts");
|
|
91
|
-
|
|
92
|
-
let serverCwd = rootDir;
|
|
93
|
-
let serverScript = "server/index.ts";
|
|
94
|
-
let useGlobal = false;
|
|
95
|
-
|
|
96
|
-
if (fs.existsSync(localServerPath)) {
|
|
97
|
-
// Local dev mode: run from workspace
|
|
98
|
-
serverCwd = rootDir;
|
|
99
|
-
} else if (fs.existsSync(globalServerPath)) {
|
|
100
|
-
// Global standalone mode: run from ~/.opencode/pixel-office
|
|
101
|
-
serverCwd = globalDistDir;
|
|
102
|
-
useGlobal = true;
|
|
103
|
-
} else {
|
|
104
|
-
// Neither found
|
|
105
|
-
if (endpointInfo.isLocal) {
|
|
106
|
-
console.warn("[Pixel Office] Server not found locally or globally.");
|
|
107
|
-
}
|
|
48
|
+
if (readMode() !== "opencode") {
|
|
49
|
+
// In claude-code mode, plugin does nothing - hooks handle events
|
|
50
|
+
return {};
|
|
108
51
|
}
|
|
109
52
|
|
|
110
|
-
|
|
111
|
-
let browserOpened = false;
|
|
112
|
-
let warnedOnce = false;
|
|
113
|
-
|
|
114
|
-
const startServerIfNeeded = async () => {
|
|
115
|
-
if (!endpointInfo.isLocal || serverProcess) {
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
const env = {
|
|
119
|
-
...process.env,
|
|
120
|
-
PORT: String(process.env.PIXEL_OFFICE_PORT || endpointInfo.port),
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
let cmd = ["tsx", serverScript];
|
|
124
|
-
if (useGlobal) {
|
|
125
|
-
const globalTsx = path.join(serverCwd, "node_modules", ".bin", "tsx");
|
|
126
|
-
if (fs.existsSync(globalTsx)) {
|
|
127
|
-
cmd = [globalTsx, serverScript];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
serverProcess = Bun.spawn({
|
|
133
|
-
cmd,
|
|
134
|
-
cwd: serverCwd,
|
|
135
|
-
env,
|
|
136
|
-
stdout: "ignore",
|
|
137
|
-
stderr: "ignore",
|
|
138
|
-
});
|
|
139
|
-
// console.log(`[Pixel Office] Started server in ${serverCwd} on port ${env.PORT}`);
|
|
140
|
-
} catch (error) {
|
|
141
|
-
await client.app.log({
|
|
142
|
-
service: "pixel-office",
|
|
143
|
-
level: "error",
|
|
144
|
-
message: "Failed to start Pixel Office server",
|
|
145
|
-
extra: { error: String(error), cwd: serverCwd },
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const openBrowserIfNeeded = async () => {
|
|
151
|
-
if (!endpointInfo.isLocal || browserOpened) {
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
browserOpened = true;
|
|
155
|
-
try {
|
|
156
|
-
Bun.spawn({ cmd: openCommand, stdout: "ignore", stderr: "ignore" });
|
|
157
|
-
} catch (error) {
|
|
158
|
-
await client.app.log({
|
|
159
|
-
service: "pixel-office",
|
|
160
|
-
level: "warn",
|
|
161
|
-
message: "Failed to open Pixel Office browser",
|
|
162
|
-
extra: { error: String(error), url: serverUrl },
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
await startServerIfNeeded();
|
|
168
|
-
await openBrowserIfNeeded();
|
|
53
|
+
const endpoint = resolveEndpoint();
|
|
169
54
|
|
|
170
55
|
return {
|
|
171
56
|
event: async ({ event }) => {
|
|
172
|
-
if (readMode() !== "opencode") {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
57
|
if (!event) {
|
|
176
58
|
return;
|
|
177
59
|
}
|
|
@@ -183,18 +65,10 @@ export const PixelOfficePlugin = async ({ directory, worktree, client }) => {
|
|
|
183
65
|
},
|
|
184
66
|
body: JSON.stringify(event),
|
|
185
67
|
});
|
|
186
|
-
} catch
|
|
187
|
-
|
|
188
|
-
warnedOnce = true;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
},
|
|
192
|
-
dispose: async () => {
|
|
193
|
-
if (serverProcess) {
|
|
194
|
-
// console.log("[Pixel Office] Killing server process...");
|
|
195
|
-
serverProcess.kill();
|
|
196
|
-
serverProcess = null;
|
|
68
|
+
} catch {
|
|
69
|
+
// Server not running, silently ignore
|
|
197
70
|
}
|
|
198
71
|
},
|
|
72
|
+
dispose: async () => {},
|
|
199
73
|
};
|
|
200
74
|
};
|