opencode-webui 2.3.0 → 3.0.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.
@@ -0,0 +1,118 @@
1
+ /**
2
+ * The built-in OpenCode lifecycle plugin, shipped as source.
3
+ *
4
+ * Why a string and not a real file: this must install identically from an npm
5
+ * package (a real `plugin/` directory) AND from a `bun build --compile`
6
+ * executable (no real filesystem). Embedding the source as a string makes both
7
+ * paths one code path with no extra embed machinery.
8
+ *
9
+ * Installed to `<opencode config>/plugins/opencode-webui/` — a directory the
10
+ * engine auto-discovers globally (V2 plugin discovery). Its `setup()` runs when
11
+ * OpenCode activates the location's plugins (verified: the engine does this
12
+ * lazily, on first use — not at raw daemon boot), and starts the webui proxy
13
+ * detached. It reads the launch command the webui keeps fresh in
14
+ * `~/.local/state/opencode-webui/launch.json` and never blocks the engine.
15
+ *
16
+ * CommonJS `module.exports = { id, setup }`, matching the proven local-engine
17
+ * shape (webui-extensions/brother-agent/engine/index.js). The source avoids
18
+ * template literals on purpose so it can live in this TS template verbatim.
19
+ */
20
+
21
+ export const LIFECYCLE_PLUGIN_ID = "opencode-webui";
22
+
23
+ export const LIFECYCLE_PLUGIN_SOURCE = `// opencode-webui lifecycle plugin
24
+ //
25
+ // Managed by opencode-webui — do not edit. This file is (re)written on every
26
+ // webui boot and removed by \`opencode-webui uninstall\`.
27
+ //
28
+ // Job: when OpenCode activates this location's plugins (i.e. as soon as you
29
+ // use OpenCode), start the opencode-webui proxy in the background if it is not
30
+ // already serving. Fire-and-forget: the engine must never wait on it, and the
31
+ // proxy outlives the engine (detached + unref).
32
+
33
+ const { spawn } = require("node:child_process");
34
+ const fs = require("node:fs");
35
+ const os = require("node:os");
36
+ const path = require("node:path");
37
+
38
+ const SERVICE = "opencode-webui";
39
+ let started = false;
40
+
41
+ function stateDir() {
42
+ const base =
43
+ process.env.XDG_STATE_HOME || path.join(os.homedir(), ".local", "state");
44
+ return path.join(base, SERVICE);
45
+ }
46
+
47
+ // The webui writes launch.json on every boot; it is the stable handoff.
48
+ function readLaunch() {
49
+ try {
50
+ const raw = fs.readFileSync(path.join(stateDir(), "launch.json"), "utf8");
51
+ const parsed = JSON.parse(raw);
52
+ if (Array.isArray(parsed.cmd) && parsed.cmd.length > 0) {
53
+ return { cmd: parsed.cmd, port: Number(parsed.port) || 0 };
54
+ }
55
+ } catch (err) {
56
+ /* fall through to wrapper discovery */
57
+ }
58
+ const candidates = [];
59
+ if (process.env.WEBUI_BIN_DIR) {
60
+ candidates.push(path.join(process.env.WEBUI_BIN_DIR, SERVICE));
61
+ }
62
+ candidates.push(path.join(os.homedir(), ".local", "bin", SERVICE));
63
+ candidates.push(path.join(os.homedir(), ".bun", "bin", SERVICE));
64
+ for (const candidate of candidates) {
65
+ try {
66
+ if (fs.existsSync(candidate)) return { cmd: [candidate], port: 0 };
67
+ } catch (err) {
68
+ /* keep looking */
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ async function alreadyRunning(port) {
75
+ if (!port) return false;
76
+ try {
77
+ const res = await fetch("http://127.0.0.1:" + port + "/login", {
78
+ redirect: "manual",
79
+ signal: AbortSignal.timeout(1500),
80
+ });
81
+ if (!res.ok) return false;
82
+ return (await res.text()).includes("opencode webui");
83
+ } catch (err) {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ module.exports = {
89
+ id: SERVICE,
90
+ async setup() {
91
+ if (started) return;
92
+ if (process.env.WEBUI_NO_PLUGIN === "1") return;
93
+ const launch = readLaunch();
94
+ if (!launch) return;
95
+ if (await alreadyRunning(launch.port)) return;
96
+ started = true;
97
+ try {
98
+ const child = spawn(launch.cmd[0], launch.cmd.slice(1), {
99
+ detached: true,
100
+ stdio: "ignore",
101
+ windowsHide: true,
102
+ env: Object.assign({}, process.env, { WEBUI_SPAWNED_BY: "opencode-plugin" }),
103
+ });
104
+ child.unref();
105
+ } catch (err) {
106
+ started = false;
107
+ }
108
+ },
109
+ };
110
+ `;
111
+
112
+ export const LIFECYCLE_PLUGIN_PACKAGE_JSON = `{
113
+ "name": "opencode-webui-lifecycle",
114
+ "private": true,
115
+ "main": "index.js",
116
+ "description": "Starts the opencode-webui proxy when the OpenCode engine loads. Managed by opencode-webui."
117
+ }
118
+ `;