patchcord 0.5.61 → 0.5.63

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/patchcord.mjs CHANGED
@@ -457,16 +457,26 @@ if (cmd === "upload") {
457
457
  // of a wall of bash. subscribe.mjs handles its own pidfile guard
458
458
  // (exits with code 2 + "already running" if another listener is up),
459
459
  // so this command needs zero pre-checks.
460
+ //
461
+ // We resolve the bearer here (all 11 tool configs) and inject it as
462
+ // env vars so subscribe.mjs works regardless of which MCP client is
463
+ // running — OpenCode, Codex, Cursor, etc. — not just Claude Code.
460
464
  if (cmd === "subscribe") {
461
465
  const subscribeScript = join(pluginRoot, "scripts", "subscribe.mjs");
462
466
  if (!existsSync(subscribeScript)) {
463
467
  console.error(`subscribe.mjs not found at ${subscribeScript}`);
464
468
  process.exit(1);
465
469
  }
470
+ const bearerInfo = await _resolveBearer();
471
+ const spawnEnv = { ...process.env };
472
+ if (bearerInfo) {
473
+ spawnEnv.PATCHCORD_BASE_URL = bearerInfo.baseUrl;
474
+ spawnEnv.PATCHCORD_BEARER_TOKEN = bearerInfo.token;
475
+ }
466
476
  const { spawnSync } = await import("child_process");
467
477
  const result = spawnSync(process.execPath, [subscribeScript], {
468
478
  stdio: "inherit",
469
- env: process.env,
479
+ env: spawnEnv,
470
480
  });
471
481
  process.exit(result.status ?? (result.signal ? 1 : 0));
472
482
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.61",
3
+ "version": "0.5.63",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -11,6 +11,7 @@ import { readFileSync, writeFileSync, unlinkSync, existsSync } from "node:fs";
11
11
  import { request as httpsRequest } from "node:https";
12
12
  import { request as httpRequest } from "node:http";
13
13
  import { URL } from "node:url";
14
+ import { dirname } from "node:path";
14
15
  import { connect as wsConnect } from "./lib/ws.mjs";
15
16
 
16
17
  const JWT_REFRESH_SAFETY_MARGIN_SEC = 120;
@@ -53,24 +54,36 @@ function die(msg, code = 1) {
53
54
  }
54
55
 
55
56
  function readMcpConfig(cwd) {
56
- const path = `${cwd}/.mcp.json`;
57
- if (!existsSync(path)) die(`no .mcp.json in ${cwd}`);
58
- let json;
59
- try {
60
- json = JSON.parse(readFileSync(path, "utf8"));
61
- } catch (e) {
62
- die(`.mcp.json parse error: ${e.message}`);
57
+ // Prefer env vars injected by patchcord.mjs, which already ran _resolveBearer()
58
+ // and supports all 11 tool configs (Claude Code, OpenCode, Codex, Cursor, etc.).
59
+ if (process.env.PATCHCORD_BASE_URL && process.env.PATCHCORD_BEARER_TOKEN) {
60
+ return { baseUrl: process.env.PATCHCORD_BASE_URL, token: process.env.PATCHCORD_BEARER_TOKEN };
63
61
  }
64
- const pc = json?.mcpServers?.patchcord;
65
- if (!pc?.url || !pc?.headers?.Authorization) {
66
- die(".mcp.json missing mcpServers.patchcord.url or Authorization");
62
+ // Fallback: direct invocation — try .mcp.json walking up from cwd.
63
+ let dir = cwd;
64
+ while (dir && dir !== "/") {
65
+ const path = `${dir}/.mcp.json`;
66
+ if (existsSync(path)) {
67
+ let json;
68
+ try {
69
+ json = JSON.parse(readFileSync(path, "utf8"));
70
+ } catch (e) {
71
+ die(`.mcp.json parse error: ${e.message}`);
72
+ }
73
+ const pc = json?.mcpServers?.patchcord;
74
+ if (!pc?.url || !pc?.headers?.Authorization) {
75
+ die(".mcp.json missing mcpServers.patchcord.url or Authorization");
76
+ }
77
+ let baseUrl = pc.url.replace(/\/mcp\/bearer$/, "").replace(/\/mcp$/, "");
78
+ const auth = pc.headers.Authorization;
79
+ const token = auth.startsWith("Bearer ") ? auth.slice(7) : auth;
80
+ return { baseUrl, token };
81
+ }
82
+ const parent = dirname(dir);
83
+ if (parent === dir) break;
84
+ dir = parent;
67
85
  }
68
- let baseUrl = pc.url;
69
- // Strip known MCP path suffixes to get the API base
70
- baseUrl = baseUrl.replace(/\/mcp\/bearer$/, "").replace(/\/mcp$/, "");
71
- const auth = pc.headers.Authorization;
72
- const token = auth.startsWith("Bearer ") ? auth.slice(7) : auth;
73
- return { baseUrl, token };
86
+ die(`no patchcord config found — run from a project directory or use 'patchcord subscribe'`);
74
87
  }
75
88
 
76
89
  function httpJson(urlStr, { method = "GET", headers = {}, body = null } = {}) {
@@ -419,8 +432,10 @@ function runOnce(ticket, baseUrl, token, refreshTicket) {
419
432
  return;
420
433
  }
421
434
  // Successful subscribe ack — log once for confirmation, then quiet.
435
+ // Replace Supabase's "Subscribed to PostgreSQL" with a user-facing label.
422
436
  if (status === "ok" && message) {
423
- logErr(`subscribe: system ok on ${frame.topic}: ${message}`);
437
+ const displayMsg = message.replace(/PostgreSQL/g, "Patchcord");
438
+ logErr(`subscribe: system ok on ${frame.topic}: ${displayMsg}`);
424
439
  }
425
440
  return;
426
441
  }