@geohar/pi-svg-mcp 0.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.
package/dist/index.js ADDED
@@ -0,0 +1,258 @@
1
+ // Pi extension: run the `svg-mcp` MCP server via the `sharedserver` CLI and inject the
2
+ // diagram-authoring directive into the system prompt.
3
+ //
4
+ // It is the Pi counterpart of svg-mcp's Claude Code and OpenCode plugins, and mirrors
5
+ // their behaviour:
6
+ //
7
+ // 1. Stand-down switch — if a combiner already serves svg-mcp (global MCP_COMBINER, or
8
+ // the per-backend MCP_COMBINER_SERVES_SVG_MCP override, which wins), do NOT launch
9
+ // a standalone backend. The combiner owns svg-mcp's lifecycle. Only the launch is
10
+ // gated — the directive applies either way, since svg-mcp's tools are present via
11
+ // the combiner too.
12
+ // 2. Process — on `session_start`, drive `sharedserver use … -- <svg-mcp serve argv>`
13
+ // so one warm svg-mcp is running and refcounted (shared across clients), paying its
14
+ // cold start (numpy + pillow) once. Released on `session_shutdown` when
15
+ // `reason === "quit"` (reload/resume/fork keep the process and re-attach).
16
+ // 3. Directive — append the diagram-authoring text to the system prompt via
17
+ // `before_agent_start` (analogue of CC's additionalContext / OpenCode's
18
+ // system.transform).
19
+ //
20
+ // WHICH svg-mcp RUNS (mirrors the OpenCode plugin's resolveServeArgv):
21
+ // default uvx svg-mcp@<version> (published release, pinned)
22
+ // SVG_MCP_DEV=<dir> uv run --project <dir> (a dev checkout)
23
+ // SVG_MCP_DEV=1 uv run --project <repo> (in-repo source, if resolvable)
24
+ //
25
+ // MCP registration itself (pointing pi-mcp-adapter at svg-mcp) is a single mcp.json
26
+ // entry — see mcp.json.example and the README; static, and unnecessary when
27
+ // combiner-served. The sharedserver resolution is ported from plugins/opencode.
28
+ import { spawnSync } from "node:child_process";
29
+ import { existsSync, readFileSync } from "node:fs";
30
+ import { dirname, join } from "node:path";
31
+ import { fileURLToPath } from "node:url";
32
+ import { resolveSharedserver } from "./sharedserver-resolve.js";
33
+ const DEFAULT_PORT = 7731;
34
+ const DEFAULT_NAME = "svg-mcp";
35
+ const DEFAULT_GRACE = "1h";
36
+ // Floor-only against sharedserver's latest release: svg-mcp consumes sharedserver rather
37
+ // than shipping it. Kept equal to the sibling plugins' value.
38
+ const SHAREDSERVER_MIN_VERSION = "0.6.7";
39
+ // The svg-mcp PyPI release this extension runs by default (`uvx svg-mcp@<v>`). Decoupled
40
+ // from this package's OWN version (matching the OpenCode plugin); override per-launch
41
+ // with $SVG_MCP_VERSION. Keep it pointing at a real svg-mcp release.
42
+ const SVG_MCP_TOOL_VERSION = "0.2.6";
43
+ // ── the diagram-authoring directive ────────────────────────────────
44
+ // Appended to the system prompt so the agent reaches for svg-mcp's tools instead of
45
+ // hand-writing SVG XML. Canonical source: CLAUDE.md.example at the repo root; a
46
+ // release-time `prepack` copies it to this package's root as instructions.txt (see
47
+ // package.json). A dev/unbuilt run without the copy falls back to empty and injects
48
+ // nothing.
49
+ const SVG_DIAGRAM_DIRECTIVE = (() => {
50
+ try {
51
+ const here = dirname(fileURLToPath(import.meta.url));
52
+ return readFileSync(join(here, "..", "instructions.txt"), "utf8");
53
+ }
54
+ catch {
55
+ return "";
56
+ }
57
+ })();
58
+ const DIRECTIVE_MARKER = SVG_DIAGRAM_DIRECTIVE.split("\n", 1)[0] ?? "";
59
+ // ── env configuration ──────────────────────────────────────────────
60
+ // svg-mcp's tool knobs use the shared SVG_MCP_* namespace (as its OpenCode plugin does),
61
+ // so a user's SVG_MCP_PORT/VERSION/DEV apply across every client. Pi-extension-specific
62
+ // toggles use PI_SVG_MCP_*.
63
+ function env(name) {
64
+ const v = process.env[name];
65
+ return v !== undefined && v !== "" ? v : undefined;
66
+ }
67
+ // ── stand-down switch (mirrors the CC hook's combiner_serves) ──────
68
+ function truthy(v) {
69
+ if (v == null)
70
+ return false;
71
+ return !["", "0", "false", "no", "off"].includes(v.trim().toLowerCase());
72
+ }
73
+ /** Does a combiner serve `name`? The per-backend `MCP_COMBINER_SERVES_<NAME>` override
74
+ * wins over the global `MCP_COMBINER` switch (presence, even empty, counts). Shared
75
+ * cross-tool switches — NOT PI_-namespaced. */
76
+ function combinerServes(name) {
77
+ const key = "MCP_COMBINER_SERVES_" + name.toUpperCase().replace(/[-\s]/g, "_");
78
+ if (key in process.env)
79
+ return truthy(process.env[key]);
80
+ return truthy(process.env.MCP_COMBINER);
81
+ }
82
+ function onPath(cmd) {
83
+ return spawnSync(cmd, ["--version"], { stdio: "ignore", env: process.env }).status === 0;
84
+ }
85
+ /** Repo-root guess for `SVG_MCP_DEV=1` — three levels up from dist/index.js
86
+ * (plugins/pi/dist → repo root), only if it holds svg-mcp source. */
87
+ function inRepoSource() {
88
+ try {
89
+ const root = fileURLToPath(new URL("../../..", import.meta.url));
90
+ return existsSync(join(root, "pyproject.toml")) ? root : undefined;
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ }
96
+ /** Resolve the argv that serves svg-mcp over streamable-http, or a `missing` runner. */
97
+ function resolveServeArgv(port) {
98
+ const dev = env("SVG_MCP_DEV");
99
+ if (dev) {
100
+ if (!onPath("uv"))
101
+ return { argv: [], missing: "uv" };
102
+ const project = dev !== "1" && existsSync(dev) ? dev : inRepoSource();
103
+ if (project) {
104
+ return {
105
+ argv: ["uv", "run", "--project", project, "svg-mcp", "--transport", "streamable-http", "--port", port],
106
+ };
107
+ }
108
+ // dev requested but no checkout given and no in-repo source — fall through.
109
+ }
110
+ if (!onPath("uvx"))
111
+ return { argv: [], missing: "uvx" };
112
+ const ver = env("SVG_MCP_VERSION") ?? SVG_MCP_TOOL_VERSION;
113
+ const spec = ver ? `svg-mcp@${ver}` : "svg-mcp";
114
+ return { argv: ["uvx", spec, "--transport", "streamable-http", "--port", port] };
115
+ }
116
+ let attachment = null;
117
+ let cleanupInstalled = false;
118
+ function installProcessCleanup() {
119
+ if (cleanupInstalled)
120
+ return;
121
+ cleanupInstalled = true;
122
+ process.on("exit", () => detach());
123
+ for (const sig of ["SIGINT", "SIGTERM", "SIGHUP"]) {
124
+ process.on(sig, () => {
125
+ detach();
126
+ process.kill(process.pid, sig);
127
+ });
128
+ }
129
+ }
130
+ function detach() {
131
+ if (!attachment)
132
+ return;
133
+ const { binary, name } = attachment;
134
+ attachment = null;
135
+ spawnSync(binary, ["unuse", name, "--pid", String(process.pid)], { stdio: "ignore", env: process.env });
136
+ }
137
+ // ── the extension ──────────────────────────────────────────────────
138
+ export default function svgMcp(pi) {
139
+ const notify = env("PI_SVG_MCP_NOTIFY") !== "false";
140
+ const wantInstructions = env("PI_SVG_MCP_INSTRUCTIONS") !== "false";
141
+ const manage = env("PI_SVG_MCP_MANAGE") !== "false";
142
+ const name = env("PI_SVG_MCP_NAME") ?? DEFAULT_NAME;
143
+ const served = combinerServes(name);
144
+ // ── directive: appended every turn (dup-guarded across turns) ──
145
+ pi.on("before_agent_start", (event) => {
146
+ if (!wantInstructions || !SVG_DIAGRAM_DIRECTIVE)
147
+ return;
148
+ if (DIRECTIVE_MARKER && event.systemPrompt.includes(DIRECTIVE_MARKER))
149
+ return;
150
+ return { systemPrompt: `${event.systemPrompt}\n\n${SVG_DIAGRAM_DIRECTIVE}` };
151
+ });
152
+ // ── /svg-mcp command: inspect the extension (verb: system-prompt) ──
153
+ pi.registerCommand("svg-mcp", {
154
+ description: "svg-mcp extension — verb: system-prompt (show the injected directive)",
155
+ getArgumentCompletions: (prefix) => completeVerbs(prefix),
156
+ handler: (args, ctx) => {
157
+ const verb = args.trim();
158
+ if (verb === "" || verb === "system-prompt") {
159
+ showDirective(ctx, "svg-mcp", SVG_DIAGRAM_DIRECTIVE, wantInstructions);
160
+ return;
161
+ }
162
+ ctx.ui?.notify?.(`svg-mcp: unknown verb "${verb}". Try: system-prompt`, "warn");
163
+ },
164
+ });
165
+ // Combiner-served or manage=false: nothing to launch. The directive still applies.
166
+ if (served || !manage)
167
+ return;
168
+ // ── process: launch on session_start, release on session_shutdown("quit") ──
169
+ pi.on("session_start", (_event, ctx) => {
170
+ if (attachment)
171
+ return;
172
+ const log = makeLog(ctx, notify);
173
+ const binary = resolveSharedserver({
174
+ label: "svg-mcp",
175
+ minVersion: SHAREDSERVER_MIN_VERSION,
176
+ installerUrl: "https://github.com/georgeharker/sharedserver/releases/latest/download/sharedserver-installer.sh",
177
+ }, env("SHAREDSERVER_BIN"), process.env, log);
178
+ if (!binary) {
179
+ log("error", "sharedserver binary not found; set $SHAREDSERVER_BIN, or PI_SVG_MCP_MANAGE=false");
180
+ return;
181
+ }
182
+ const port = env("SVG_MCP_PORT") ?? String(DEFAULT_PORT);
183
+ const { argv, missing } = resolveServeArgv(port);
184
+ if (missing) {
185
+ log("error", `\`${missing}\` not on PATH; install uv (https://docs.astral.sh/uv/), or PI_SVG_MCP_MANAGE=false`);
186
+ return;
187
+ }
188
+ const grace = env("PI_SVG_MCP_GRACE") ?? DEFAULT_GRACE;
189
+ const useArgs = [
190
+ "use",
191
+ name,
192
+ "--pid",
193
+ String(process.pid),
194
+ "--grace-period",
195
+ grace,
196
+ "--metadata",
197
+ `pi-${process.pid}`,
198
+ ];
199
+ const logFile = env("PI_SVG_MCP_LOG");
200
+ if (logFile && logFile !== "none")
201
+ useArgs.push("--log-file", logFile);
202
+ useArgs.push("--", ...argv);
203
+ installProcessCleanup();
204
+ const result = spawnSync(binary, useArgs, { stdio: "pipe", env: process.env });
205
+ if (result.error) {
206
+ log("error", `${name}: failed to spawn sharedserver (${result.error.message})`);
207
+ return;
208
+ }
209
+ if (result.status !== 0) {
210
+ const stderr = result.stderr?.toString().trim();
211
+ log("error", `${name}: sharedserver use exited ${result.status}${stderr ? ` (${stderr})` : ""}`);
212
+ return;
213
+ }
214
+ attachment = { binary, name };
215
+ log("info", `svg-mcp "${name}" attached on port ${port} (${argv.join(" ")})`);
216
+ });
217
+ pi.on("session_shutdown", (event) => {
218
+ if (event.reason === "quit")
219
+ detach();
220
+ });
221
+ }
222
+ // ── helpers ────────────────────────────────────────────────────────
223
+ // The verbs the extension's slash command understands. `system-prompt` shows the
224
+ // directive this extension injects — the show-command pattern from pi-custom-system-prompt,
225
+ // since `before_agent_start` injections are per-turn and never appear in Pi's own
226
+ // `/system-prompt` (which reports the base prompt only).
227
+ const COMMAND_VERBS = ["system-prompt"];
228
+ function completeVerbs(prefix) {
229
+ const p = prefix.trim();
230
+ const matches = COMMAND_VERBS.filter((v) => v.startsWith(p));
231
+ return matches.length ? matches.map((v) => ({ value: v, label: v })) : null;
232
+ }
233
+ const SHOW_LIMIT = 1600;
234
+ function showDirective(ctx, label, directive, enabled) {
235
+ if (!directive) {
236
+ ctx.ui?.notify?.(`${label}: no directive bundled (instructions.txt missing)`, "warn");
237
+ return;
238
+ }
239
+ const head = enabled
240
+ ? `${label} directive — injected into the system prompt on every turn (before_agent_start):`
241
+ : `${label} directive — injection is DISABLED this session; it would be:`;
242
+ const body = directive.length > SHOW_LIMIT
243
+ ? `${directive.slice(0, SHOW_LIMIT)}\n\n… (${directive.length} chars total)`
244
+ : directive;
245
+ ctx.ui?.notify?.(`${head}\n\n${body}`, "info");
246
+ }
247
+ function makeLog(ctx, notify) {
248
+ return (level, message) => {
249
+ const line = `svg-mcp: ${message}`;
250
+ if (notify && ctx.hasUI && ctx.ui?.notify) {
251
+ ctx.ui.notify(line, level === "error" ? "error" : level === "warn" ? "warn" : "info");
252
+ }
253
+ else if (level === "error" || level === "warn") {
254
+ process.stderr.write(`${line}\n`);
255
+ }
256
+ };
257
+ }
258
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/pi.d.ts ADDED
@@ -0,0 +1,70 @@
1
+ export type SessionStartReason = "startup" | "reload" | "new" | "resume" | "fork";
2
+ export type SessionShutdownReason = "quit" | "reload" | "new" | "resume" | "fork";
3
+ export type SessionStartEvent = {
4
+ reason: SessionStartReason;
5
+ previousSessionFile?: string;
6
+ };
7
+ export type SessionShutdownEvent = {
8
+ reason: SessionShutdownReason;
9
+ targetSessionFile?: string;
10
+ };
11
+ export type BeforeAgentStartEvent = {
12
+ systemPrompt: string;
13
+ };
14
+ export type BeforeAgentStartResult = {
15
+ systemPrompt?: string;
16
+ } | void;
17
+ export type ExtensionContext = {
18
+ cwd: string;
19
+ mode: "tui" | "rpc" | "json" | "print";
20
+ hasUI: boolean;
21
+ signal?: AbortSignal;
22
+ ui?: {
23
+ notify?: (message: string, level?: "info" | "warn" | "error") => void;
24
+ };
25
+ };
26
+ /** Context handed to a command handler. Superset of ExtensionContext in practice; we
27
+ * only read `signal`, `ui`, and `hasUI`. */
28
+ export type ExtensionCommandContext = ExtensionContext;
29
+ export type AutocompleteItem = {
30
+ value: string;
31
+ label?: string;
32
+ };
33
+ export type ExecResult = {
34
+ stdout: string;
35
+ stderr: string;
36
+ code: number;
37
+ killed: boolean;
38
+ };
39
+ export type ExecOptions = {
40
+ signal?: AbortSignal;
41
+ timeout?: number;
42
+ cwd?: string;
43
+ env?: NodeJS.ProcessEnv;
44
+ };
45
+ /** An LLM-visible message injected from a command. `display:true` shows it in the TUI;
46
+ * `{triggerTurn:true, deliverAs:"steer"}` makes the model act on it this turn. */
47
+ export type SendMessage = {
48
+ customType: string;
49
+ content: string;
50
+ display?: boolean;
51
+ details?: Record<string, unknown>;
52
+ };
53
+ export type SendMessageOptions = {
54
+ triggerTurn?: boolean;
55
+ deliverAs?: "steer" | "followUp";
56
+ };
57
+ export type CommandSpec = {
58
+ description: string;
59
+ handler: (args: string, ctx: ExtensionCommandContext) => void | Promise<void>;
60
+ getArgumentCompletions?: (prefix: string) => AutocompleteItem[] | null;
61
+ };
62
+ export interface ExtensionAPI {
63
+ on(event: "session_start", handler: (event: SessionStartEvent, ctx: ExtensionContext) => void | Promise<void>): void;
64
+ on(event: "session_shutdown", handler: (event: SessionShutdownEvent, ctx: ExtensionContext) => void | Promise<void>): void;
65
+ on(event: "before_agent_start", handler: (event: BeforeAgentStartEvent, ctx: ExtensionContext) => BeforeAgentStartResult | Promise<BeforeAgentStartResult>): void;
66
+ registerCommand(name: string, spec: CommandSpec): void;
67
+ exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
68
+ sendMessage(message: SendMessage, options?: SendMessageOptions): void;
69
+ }
70
+ //# sourceMappingURL=pi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"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"}
package/dist/pi.js ADDED
@@ -0,0 +1,10 @@
1
+ // Narrow, local typing for the slice of Pi's extension API this plugin uses.
2
+ //
3
+ // Pi (badlogic/pi-mono, earendil-works/pi) ships its ExtensionAPI types with the
4
+ // harness rather than as a standalone npm package we can depend on, so we declare
5
+ // exactly the surface we touch — three lifecycle events, `registerCommand`, `exec`,
6
+ // and `sendMessage`. Kept deliberately minimal: a wider mirror would rot against a
7
+ // moving upstream. Signatures follow the published extension docs
8
+ // (https://pi.dev/docs/latest/extensions).
9
+ export {};
10
+ //# sourceMappingURL=pi.js.map
package/dist/pi.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../src/pi.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,EAAE;AACF,iFAAiF;AACjF,kFAAkF;AAClF,oFAAoF;AACpF,mFAAmF;AACnF,kEAAkE;AAClE,2CAA2C"}
@@ -0,0 +1,19 @@
1
+ export type LogFn = (level: "info" | "warn" | "error", message: string) => void;
2
+ export type ToastFn = (variant: "success" | "warning" | "error", message: string) => void;
3
+ export type ResolveConfig = {
4
+ /** Prefix for user-facing messages. Default "sharedserver". */
5
+ label?: string;
6
+ /** Minimum acceptable version. Defaults to pkgVersion (lockstep). */
7
+ minVersion?: string;
8
+ /** Installer to fetch. Defaults to the release pinned to pkgVersion. */
9
+ installerUrl?: string;
10
+ /** The host package's own version — only meaningful in lockstep mode. */
11
+ pkgVersion?: string;
12
+ };
13
+ /** Resolve the sharedserver binary, fetching a release when nothing usable is present.
14
+ *
15
+ * Behaviourally identical to plugins/claude/bin/sharedserver — same ladder, floor,
16
+ * lock and degrade-rather-than-die fallback, so a user running both clients gets the
17
+ * same answer to "which sharedserver am I on, and why". */
18
+ export declare function resolveSharedserver(cfg: ResolveConfig, override: string | undefined, env: NodeJS.ProcessEnv, log?: LogFn, toast?: ToastFn): string | undefined;
19
+ //# sourceMappingURL=sharedserver-resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedserver-resolve.d.ts","sourceRoot":"","sources":["../src/sharedserver-resolve.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;AAC/E,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;AAEzF,MAAM,MAAM,aAAa,GAAG;IACxB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAyID;;;;4DAI4D;AAC5D,wBAAgB,mBAAmB,CAC/B,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,GAAG,CAAC,EAAE,KAAK,EACX,KAAK,CAAC,EAAE,OAAO,GAChB,MAAM,GAAG,SAAS,CA4CpB"}
@@ -0,0 +1,188 @@
1
+ // Resolve the `sharedserver` binary, fetching it when none is usable.
2
+ //
3
+ // VENDORED FILE. This is copied byte-identical into the consuming OpenCode plugins
4
+ // (cribsheet, svg-mcp) by their scripts/sync-vendored.sh, so the drift check is a plain
5
+ // diff. There is no way to share it as a dependency without coupling their versions to
6
+ // sharedserver's — see plugins/claude/bin/sharedserver for the same reasoning on the
7
+ // shell side. Edit it HERE; consumers re-sync.
8
+ //
9
+ // Everything repo-specific arrives through ResolveConfig rather than being hardcoded,
10
+ // mirroring bin/sharedserver.conf.
11
+ import { spawnSync } from "node:child_process";
12
+ import { existsSync, mkdirSync, rmSync, statSync, writeFileSync } from "node:fs";
13
+ import { homedir } from "node:os";
14
+ import { join } from "node:path";
15
+ /** Oldest release these plugins are correct against: 0.5.0 added the PID-reuse guard,
16
+ * without which a recycled client PID can hold a server open indefinitely. */
17
+ const HARDCODED_FLOOR = "0.5.0";
18
+ const CANDIDATE_BINARIES = [
19
+ "sharedserver",
20
+ join(homedir(), ".cargo", "bin", "sharedserver"),
21
+ join(homedir(), ".local", "bin", "sharedserver"),
22
+ "/usr/local/bin/sharedserver",
23
+ "/opt/homebrew/bin/sharedserver",
24
+ ];
25
+ function parseVersion(text) {
26
+ const m = text.match(/(\d+)\.(\d+)\.(\d+)/);
27
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : undefined;
28
+ }
29
+ function gte(a, b) {
30
+ for (let i = 0; i < 3; i++)
31
+ if (a[i] !== b[i])
32
+ return a[i] > b[i];
33
+ return true;
34
+ }
35
+ function versionOf(candidate, env) {
36
+ const r = spawnSync(candidate, ["--version"], { env });
37
+ if (r.error)
38
+ return undefined;
39
+ return parseVersion(`${r.stdout?.toString() ?? ""}${r.stderr?.toString() ?? ""}`);
40
+ }
41
+ /** Synchronous sleep — this path runs before anything can be awaited, so the lock wait
42
+ * cannot use timers. Atomics.wait blocks without spinning. */
43
+ function sleepSync(ms) {
44
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
45
+ }
46
+ /** First sharedserver found at ANY version, or undefined. */
47
+ function probeAny(override, env) {
48
+ const candidates = [override, env.SHAREDSERVER_BIN, ...CANDIDATE_BINARIES].filter((v) => typeof v === "string" && v.length > 0);
49
+ for (const candidate of candidates) {
50
+ if (candidate.includes("/")) {
51
+ if (existsSync(candidate))
52
+ return candidate;
53
+ continue;
54
+ }
55
+ // Presence is "spawn did not fail", NOT "exited 0" — a build that rejects some
56
+ // flag is still present.
57
+ if (!spawnSync(candidate, ["--version"], { stdio: "ignore", env }).error)
58
+ return candidate;
59
+ }
60
+ return undefined;
61
+ }
62
+ /** Download and run the cargo-dist installer, then re-probe. */
63
+ function installPinned(cfg, url, what, env, log, toast) {
64
+ // The SAME lock directory as the shell shim — cross-client coordination, so a
65
+ // Claude session and an OpenCode session starting together do not race.
66
+ const lockdir = join(env.TMPDIR || "/tmp", ".sharedserver-install.lock");
67
+ let haveLock = false;
68
+ try {
69
+ mkdirSync(lockdir);
70
+ haveLock = true;
71
+ }
72
+ catch {
73
+ const deadline = Date.now() + 20_000;
74
+ while (existsSync(lockdir) && Date.now() < deadline)
75
+ sleepSync(250);
76
+ const after = probeAny(undefined, env);
77
+ if (after)
78
+ return after;
79
+ try {
80
+ mkdirSync(lockdir);
81
+ haveLock = true;
82
+ }
83
+ catch {
84
+ log?.("warn", `${cfg.label}: another process is installing sharedserver and did not finish; remove the stale lock if this persists: ${lockdir}`);
85
+ return undefined;
86
+ }
87
+ }
88
+ try {
89
+ // Re-probe under the lock: the winner may have finished while we waited.
90
+ const already = probeAny(undefined, env);
91
+ const floor = parseVersion(cfg.minVersion ?? HARDCODED_FLOOR);
92
+ if (already) {
93
+ const v = versionOf(already, env);
94
+ if (v && floor && gte(v, floor))
95
+ return already;
96
+ }
97
+ // Download to a file, then run it. `curl … | sh` would report success on a 404,
98
+ // since a pipeline's status is sh's; spawnSync uses no shell, so this is exact.
99
+ const script = join(lockdir, "installer.sh");
100
+ const dl = spawnSync("curl", ["--proto", "=https", "--tlsv1.2", "-LsSf", url, "-o", script], { env });
101
+ if (dl.error || dl.status !== 0) {
102
+ const msg = `${cfg.label}: could not download the sharedserver installer (${what})`;
103
+ log?.("warn", msg);
104
+ toast?.("warning", msg);
105
+ return undefined;
106
+ }
107
+ if (!existsSync(script) || statSync(script).size === 0) {
108
+ log?.("warn", `${cfg.label}: the downloaded sharedserver installer was empty`);
109
+ return undefined;
110
+ }
111
+ // cargo-dist embeds the expected sha256 but looks up only `sha256sum` and SKIPS
112
+ // verification when missing — i.e. always, on macOS. Give it one (identical
113
+ // output) rather than execute an unverified binary.
114
+ let runEnv = env;
115
+ if (spawnSync("sh", ["-c", "command -v sha256sum"], { stdio: "ignore" }).status !== 0) {
116
+ if (spawnSync("sh", ["-c", "command -v shasum"], { stdio: "ignore" }).status !== 0) {
117
+ log?.("warn", `${cfg.label}: refusing to install sharedserver — no sha256sum or shasum to verify the download`);
118
+ return undefined;
119
+ }
120
+ writeFileSync(join(lockdir, "sha256sum"), '#!/bin/sh\nexec shasum -a 256 "$@"\n', { mode: 0o755 });
121
+ runEnv = { ...env, PATH: `${lockdir}:${env.PATH ?? ""}` };
122
+ }
123
+ const run = spawnSync("sh", [script], { env: runEnv, stdio: "ignore" });
124
+ if (run.error || run.status !== 0) {
125
+ log?.("warn", `${cfg.label}: the sharedserver installer ran but failed`);
126
+ return undefined;
127
+ }
128
+ return probeAny(undefined, env);
129
+ }
130
+ finally {
131
+ if (haveLock) {
132
+ try {
133
+ rmSync(lockdir, { recursive: true, force: true });
134
+ }
135
+ catch {
136
+ /* best effort — a leaked lock costs the next run its bounded wait */
137
+ }
138
+ }
139
+ }
140
+ }
141
+ /** Resolve the sharedserver binary, fetching a release when nothing usable is present.
142
+ *
143
+ * Behaviourally identical to plugins/claude/bin/sharedserver — same ladder, floor,
144
+ * lock and degrade-rather-than-die fallback, so a user running both clients gets the
145
+ * same answer to "which sharedserver am I on, and why". */
146
+ export function resolveSharedserver(cfg, override, env, log, toast) {
147
+ const label = cfg.label ?? "sharedserver";
148
+ const minVersion = cfg.minVersion ?? cfg.pkgVersion ?? HARDCODED_FLOOR;
149
+ const url = cfg.installerUrl ??
150
+ (cfg.pkgVersion
151
+ ? `https://github.com/georgeharker/sharedserver/releases/download/v${cfg.pkgVersion}/sharedserver-installer.sh`
152
+ : "https://github.com/georgeharker/sharedserver/releases/latest/download/sharedserver-installer.sh");
153
+ const what = cfg.installerUrl || !cfg.pkgVersion ? "the latest release" : `v${cfg.pkgVersion}`;
154
+ const resolved = { ...cfg, label, minVersion };
155
+ const floor = parseVersion(minVersion);
156
+ // An explicit binary / SHAREDSERVER_BIN is never second-guessed: the user named a
157
+ // specific one, so quietly downloading a different one is the wrong answer.
158
+ const explicit = override ?? env.SHAREDSERVER_BIN;
159
+ if (explicit) {
160
+ const present = explicit.includes("/")
161
+ ? existsSync(explicit)
162
+ : !spawnSync(explicit, ["--version"], { stdio: "ignore", env }).error;
163
+ if (present) {
164
+ const v = versionOf(explicit, env);
165
+ if (v && floor && !gte(v, floor)) {
166
+ const msg = `${label}: sharedserver at ${explicit} is ${v.join(".")}; this plugin expects >= ${minVersion}. Using it anyway because you set it explicitly.`;
167
+ log?.("warn", msg);
168
+ toast?.("warning", msg);
169
+ }
170
+ return explicit;
171
+ }
172
+ }
173
+ const found = probeAny(override, env);
174
+ if (found) {
175
+ const v = versionOf(found, env);
176
+ if (v && floor && gte(v, floor))
177
+ return found;
178
+ // Too old: fetch, but remember this one — if the download fails we would rather
179
+ // run the old binary than nothing.
180
+ const msg = `${label}: sharedserver at ${found} is ${v?.join(".") ?? "an unknown version"}; this plugin expects >= ${minVersion}. Fetching ${what}. To keep your own build, set SHAREDSERVER_BIN=${found}`;
181
+ log?.("warn", msg);
182
+ toast?.("warning", msg);
183
+ return installPinned(resolved, url, what, env, log, toast) ?? found;
184
+ }
185
+ log?.("info", `${label}: no usable sharedserver found; fetching ${what} (one time). This needs no Rust toolchain.`);
186
+ return installPinned(resolved, url, what, env, log, toast);
187
+ }
188
+ //# sourceMappingURL=sharedserver-resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedserver-resolve.js","sourceRoot":"","sources":["../src/sharedserver-resolve.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,EAAE;AACF,mFAAmF;AACnF,wFAAwF;AACxF,uFAAuF;AACvF,qFAAqF;AACrF,+CAA+C;AAC/C,EAAE;AACF,sFAAsF;AACtF,mCAAmC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAgBhC;+EAC+E;AAC/E,MAAM,eAAe,GAAG,OAAO,CAAA;AAE/B,MAAM,kBAAkB,GAAG;IACvB,cAAc;IACd,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,cAAc,CAAC;IAChD,6BAA6B;IAC7B,gCAAgC;CACnC,CAAA;AAED,SAAS,YAAY,CAAC,IAAY;IAC9B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC3C,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AACrE,CAAC;AAED,SAAS,GAAG,CAAC,CAA2B,EAAE,CAA2B;IACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACjE,OAAO,IAAI,CAAA;AACf,CAAC;AAED,SAAS,SAAS,CAAC,SAAiB,EAAE,GAAsB;IACxD,MAAM,CAAC,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;IACtD,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC7B,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;AACrF,CAAC;AAED;+DAC+D;AAC/D,SAAS,SAAS,CAAC,EAAU;IACzB,OAAO,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;AACpE,CAAC;AAED,6DAA6D;AAC7D,SAAS,QAAQ,CAAC,QAA4B,EAAE,GAAsB;IAClE,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,gBAAgB,EAAE,GAAG,kBAAkB,CAAC,CAAC,MAAM,CAC7E,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAC5D,CAAA;IACD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACjC,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,UAAU,CAAC,SAAS,CAAC;gBAAE,OAAO,SAAS,CAAA;YAC3C,SAAQ;QACZ,CAAC;QACD,+EAA+E;QAC/E,yBAAyB;QACzB,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;IAC9F,CAAC;IACD,OAAO,SAAS,CAAA;AACpB,CAAC;AAED,gEAAgE;AAChE,SAAS,aAAa,CAClB,GAA2D,EAC3D,GAAW,EACX,IAAY,EACZ,GAAsB,EACtB,GAAW,EACX,KAAe;IAEf,8EAA8E;IAC9E,wEAAwE;IACxE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,EAAE,4BAA4B,CAAC,CAAA;IACxE,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,CAAC;QACD,SAAS,CAAC,OAAO,CAAC,CAAA;QAClB,QAAQ,GAAG,IAAI,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACL,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAA;QACpC,OAAO,UAAU,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ;YAAE,SAAS,CAAC,GAAG,CAAC,CAAA;QACnE,MAAM,KAAK,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACtC,IAAI,KAAK;YAAE,OAAO,KAAK,CAAA;QACvB,IAAI,CAAC;YACD,SAAS,CAAC,OAAO,CAAC,CAAA;YAClB,QAAQ,GAAG,IAAI,CAAA;QACnB,CAAC;QAAC,MAAM,CAAC;YACL,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,4GAA4G,OAAO,EAAE,CAAC,CAAA;YAChJ,OAAO,SAAS,CAAA;QACpB,CAAC;IACL,CAAC;IAED,IAAI,CAAC;QACD,yEAAyE;QACzE,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACxC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,UAAU,IAAI,eAAe,CAAC,CAAA;QAC7D,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;YACjC,IAAI,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC;gBAAE,OAAO,OAAO,CAAA;QACnD,CAAC;QAED,gFAAgF;QAChF,gFAAgF;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAA;QAC5C,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAA;QACrG,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK,oDAAoD,IAAI,GAAG,CAAA;YACnF,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;YAClB,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;YACvB,OAAO,SAAS,CAAA;QACpB,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACrD,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,mDAAmD,CAAC,CAAA;YAC9E,OAAO,SAAS,CAAA;QACpB,CAAC;QAED,gFAAgF;QAChF,4EAA4E;QAC5E,oDAAoD;QACpD,IAAI,MAAM,GAAG,GAAG,CAAA;QAChB,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpF,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,mBAAmB,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjF,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,oFAAoF,CAAC,CAAA;gBAC/G,OAAO,SAAS,CAAA;YACpB,CAAC;YACD,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,sCAAsC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAClG,MAAM,GAAG,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,GAAG,OAAO,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,CAAA;QAC7D,CAAC;QAED,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QACvE,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,6CAA6C,CAAC,CAAA;YACxE,OAAO,SAAS,CAAA;QACpB,CAAC;QACD,OAAO,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;IACnC,CAAC;YAAS,CAAC;QACP,IAAI,QAAQ,EAAE,CAAC;YACX,IAAI,CAAC;gBACD,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YACrD,CAAC;YAAC,MAAM,CAAC;gBACL,qEAAqE;YACzE,CAAC;QACL,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;;4DAI4D;AAC5D,MAAM,UAAU,mBAAmB,CAC/B,GAAkB,EAClB,QAA4B,EAC5B,GAAsB,EACtB,GAAW,EACX,KAAe;IAEf,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,cAAc,CAAA;IACzC,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,IAAI,eAAe,CAAA;IACtE,MAAM,GAAG,GACL,GAAG,CAAC,YAAY;QAChB,CAAC,GAAG,CAAC,UAAU;YACX,CAAC,CAAC,mEAAmE,GAAG,CAAC,UAAU,4BAA4B;YAC/G,CAAC,CAAC,iGAAiG,CAAC,CAAA;IAC5G,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAA;IAC9F,MAAM,QAAQ,GAAG,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,CAAA;IAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,UAAU,CAAC,CAAA;IAEtC,kFAAkF;IAClF,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,QAAQ,IAAI,GAAG,CAAC,gBAAgB,CAAA;IACjD,IAAI,QAAQ,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;YAClC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;YACtB,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAA;QACzE,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;YAClC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,GAAG,KAAK,qBAAqB,QAAQ,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,4BAA4B,UAAU,kDAAkD,CAAA;gBAC3J,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;gBAClB,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;YAC3B,CAAC;YACD,OAAO,QAAQ,CAAA;QACnB,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IACrC,IAAI,KAAK,EAAE,CAAC;QACR,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAC/B,IAAI,CAAC,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC;YAAE,OAAO,KAAK,CAAA;QAC7C,gFAAgF;QAChF,mCAAmC;QACnC,MAAM,GAAG,GAAG,GAAG,KAAK,qBAAqB,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,oBAAoB,4BAA4B,UAAU,cAAc,IAAI,kDAAkD,KAAK,EAAE,CAAA;QAC1M,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAClB,KAAK,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;QACvB,OAAO,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,KAAK,CAAA;IACvE,CAAC;IAED,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,4CAA4C,IAAI,4CAA4C,CAAC,CAAA;IACnH,OAAO,aAAa,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AAC9D,CAAC"}