patchcord 0.6.14 → 0.6.15

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "patchcord",
3
3
  "description": "Cross-machine agent messaging. Messages from other agents land in the inbox and wake the agent to reply.",
4
- "version": "0.6.14",
4
+ "version": "0.6.15",
5
5
  "author": {
6
6
  "name": "ppravdin"
7
7
  },
package/bin/patchcord.mjs CHANGED
@@ -43,6 +43,59 @@ function isSafeId(s) {
43
43
  return /^[A-Za-z0-9_\-]+$/.test(s) && s.length < 100;
44
44
  }
45
45
 
46
+ /** Undo 0.6.14 mistake: Claude Code uses /mcp (not /mcp/bearer). */
47
+ function revertClaudeMcpBearerUrl(mcpPath) {
48
+ if (!existsSync(mcpPath)) return false;
49
+ try {
50
+ const obj = JSON.parse(readFileSync(mcpPath, "utf-8"));
51
+ const pt = obj?.mcpServers?.patchcord;
52
+ const url = pt?.url;
53
+ if (!url || !url.endsWith("/mcp/bearer")) return false;
54
+ pt.url = url.replace(/\/mcp\/bearer$/, "/mcp");
55
+ writeFileSync(mcpPath, JSON.stringify(obj, null, 2) + "\n");
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ /** Patchcord uses project .mcp.json only — drop stale local-scope duplicates. */
63
+ function dedupeClaudePatchcordMcp(cwd) {
64
+ if (run("which claude")) {
65
+ run("claude mcp remove patchcord -s local");
66
+ }
67
+ const claudeJson = join(HOME, ".claude.json");
68
+ if (!existsSync(claudeJson)) return false;
69
+ try {
70
+ const obj = JSON.parse(readFileSync(claudeJson, "utf-8"));
71
+ let changed = false;
72
+ if (obj.mcpServers?.patchcord) {
73
+ delete obj.mcpServers.patchcord;
74
+ if (Object.keys(obj.mcpServers).length === 0) delete obj.mcpServers;
75
+ changed = true;
76
+ }
77
+ const proj = obj.projects?.[cwd];
78
+ if (proj?.mcpServers?.patchcord) {
79
+ delete proj.mcpServers.patchcord;
80
+ if (Object.keys(proj.mcpServers).length === 0) delete proj.mcpServers;
81
+ changed = true;
82
+ }
83
+ if (changed) {
84
+ writeFileSync(claudeJson, JSON.stringify(obj, null, 2) + "\n");
85
+ }
86
+ return changed;
87
+ } catch {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ function fixClaudePatchcordMcp(cwd) {
93
+ const mcpPath = join(cwd, ".mcp.json");
94
+ const reverted = revertClaudeMcpBearerUrl(mcpPath);
95
+ const deduped = dedupeClaudePatchcordMcp(cwd);
96
+ return { reverted, deduped };
97
+ }
98
+
46
99
  // A trailing --help/-h on ANY subcommand must show help and exit — never run the
47
100
  // command. (patchcord orchestrator --help used to PROVISION an orchestrator;
48
101
  // patchcord login --help hung on the browser login. Side-effecting --help is a
@@ -708,6 +761,8 @@ if (cmd === "subscribe") {
708
761
  const forceKimi = args.includes("--kimi");
709
762
  const intervalArg = args.find((a) => a !== "--kimi") || "30";
710
763
 
764
+ fixClaudePatchcordMcp(process.cwd());
765
+
711
766
  // Kimi Code uses polling instead of WebSocket realtime.
712
767
  // Force Kimi mode with --kimi flag, or auto-detect from bearer config.
713
768
  let isKimi = forceKimi;
@@ -1172,13 +1227,9 @@ if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "
1172
1227
  // default: claude_code. type:"http" is REQUIRED — without it Claude Code
1173
1228
  // defaults to stdio transport and rejects the entry ("command: expected
1174
1229
  // string, received undefined").
1175
- // Use /mcp/bearer (not /mcp): Claude Code v2.1.113+ follows RFC 9728 OAuth
1176
- // discovery on /mcp, drops the static bearer header, and stalls on "Needs
1177
- // authentication". /mcp/bearer serves bearer-only resource metadata — same
1178
- // path Cursor and Kimi Code already use.
1179
1230
  return writeJson(join(dir, ".mcp.json"), (o) => {
1180
1231
  o.mcpServers = o.mcpServers || {};
1181
- o.mcpServers.patchcord = { type: "http", url: `${baseUrl}/mcp/bearer`, headers: hdr };
1232
+ o.mcpServers.patchcord = { type: "http", url: `${baseUrl}/mcp`, headers: hdr };
1182
1233
  });
1183
1234
  };
1184
1235
 
@@ -1665,22 +1716,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1665
1716
  return out.replace(/,(\s*[}\]])/g, "$1");
1666
1717
  }
1667
1718
 
1668
- // Claude Code v2.1.113+ OAuth discovery on plain /mcp breaks bearer MCP.
1669
- // Rewrite legacy project configs to /mcp/bearer (Cursor/Kimi already use it).
1670
- function _migrateClaudeMcpBearerUrl(mcpPath) {
1671
- if (!existsSync(mcpPath)) return false;
1672
- try {
1673
- const obj = JSON.parse(readFileSync(mcpPath, "utf-8"));
1674
- const pt = obj?.mcpServers?.patchcord;
1675
- const url = pt?.url;
1676
- if (!url || !/\/mcp$/.test(url) || url.endsWith("/mcp/bearer")) return false;
1677
- pt.url = url.replace(/\/mcp$/, "/mcp/bearer");
1678
- writeFileSync(mcpPath, JSON.stringify(obj, null, 2) + "\n");
1679
- return true;
1680
- } catch {
1681
- return false;
1682
- }
1683
- }
1719
+ // dedupeClaudePatchcordMcp + revertClaudeMcpBearerUrl live at module scope.
1684
1720
 
1685
1721
  // Read+merge+write a JSON config file. If the file exists but its contents
1686
1722
  // can't be parsed, REFUSE to write — silently overwriting would erase
@@ -1740,8 +1776,13 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1740
1776
  const bold = "\x1b[1m";
1741
1777
  const r = "\x1b[0m";
1742
1778
 
1743
- if (_migrateClaudeMcpBearerUrl(join(process.cwd(), ".mcp.json"))) {
1744
- console.log(` ${green}✓${r} Claude Code MCP URL migrated to /mcp/bearer`);
1779
+ const _installCwd = process.cwd();
1780
+ const _mcpFix = fixClaudePatchcordMcp(_installCwd);
1781
+ if (_mcpFix.reverted) {
1782
+ console.log(` ${green}✓${r} Claude Code MCP URL reverted to /mcp (0.6.14 /mcp/bearer was wrong for CC)`);
1783
+ }
1784
+ if (_mcpFix.deduped) {
1785
+ console.log(` ${green}✓${r} Removed stale local-scope patchcord MCP (use project .mcp.json only)`);
1745
1786
  }
1746
1787
 
1747
1788
  // ── Purge stale npx cache entries ────────────────────────────
@@ -3276,7 +3317,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
3276
3317
  mcpServers: {
3277
3318
  patchcord: {
3278
3319
  type: "http",
3279
- url: `${serverUrl}/mcp/bearer`,
3320
+ url: `${serverUrl}/mcp`,
3280
3321
  headers: {
3281
3322
  Authorization: `Bearer ${token}`,
3282
3323
  "X-Patchcord-Machine": hostname,
@@ -3295,6 +3336,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
3295
3336
  // their JSON and re-runs.
3296
3337
  process.exit(1);
3297
3338
  }
3339
+ dedupeClaudePatchcordMcp(cwd);
3298
3340
  console.log(`\n ${green}✓${r} Claude Code configured: ${dim}${mcpPath}${r}`);
3299
3341
 
3300
3342
  // Statusline: ask whether to enable full mode (unless --full flag passed or already configured).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "scripts": {
6
6
  "version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin/plugin.json"