patchcord 0.3.39 → 0.3.41

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.
Files changed (2) hide show
  1. package/bin/patchcord.mjs +73 -23
  2. package/package.json +1 -1
package/bin/patchcord.mjs CHANGED
@@ -4,6 +4,9 @@ import { existsSync, mkdirSync, cpSync } from "fs";
4
4
  import { join, dirname } from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import { execSync } from "child_process";
7
+ import { homedir } from "os";
8
+
9
+ const HOME = homedir();
7
10
 
8
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
9
12
  const pluginRoot = join(__dirname, "..");
@@ -71,7 +74,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
71
74
  globalChanges.push("Claude Code plugin installed");
72
75
  }
73
76
 
74
- const claudeSettings = join(process.env.HOME || "", ".claude", "settings.json");
77
+ const claudeSettings = join(HOME, ".claude", "settings.json");
75
78
  if (existsSync(claudeSettings)) {
76
79
  try {
77
80
  const settings = JSON.parse(readFileSync(claudeSettings, "utf-8"));
@@ -109,7 +112,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
109
112
  }
110
113
 
111
114
  // Cursor
112
- const cursorSkillsRoot = join(process.env.HOME || "", ".cursor", "skills-cursor");
115
+ const cursorSkillsRoot = join(HOME, ".cursor", "skills-cursor");
113
116
  if (existsSync(cursorSkillsRoot)) {
114
117
  const cursorSkillDir = join(cursorSkillsRoot, "patchcord");
115
118
  const cursorWaitDir = join(cursorSkillsRoot, "patchcord-wait");
@@ -128,9 +131,9 @@ if (!cmd || cmd === "install" || cmd === "agent") {
128
131
  }
129
132
 
130
133
  // Windsurf
131
- if (existsSync(join(process.env.HOME || "", ".codeium", "windsurf"))) {
132
- const windsurfSkillDir = join(process.env.HOME || "", ".codeium", "windsurf", "skills", "patchcord");
133
- const windsurfWaitDir = join(process.env.HOME || "", ".codeium", "windsurf", "skills", "patchcord-wait");
134
+ if (existsSync(join(HOME, ".codeium", "windsurf"))) {
135
+ const windsurfSkillDir = join(HOME, ".codeium", "windsurf", "skills", "patchcord");
136
+ const windsurfWaitDir = join(HOME, ".codeium", "windsurf", "skills", "patchcord-wait");
134
137
  let windsurfChanged = false;
135
138
  if (!existsSync(windsurfSkillDir)) {
136
139
  mkdirSync(windsurfSkillDir, { recursive: true });
@@ -146,10 +149,10 @@ if (!cmd || cmd === "install" || cmd === "agent") {
146
149
  }
147
150
 
148
151
  // Gemini CLI
149
- if (existsSync(join(process.env.HOME || "", ".gemini"))) {
150
- const geminiSkillDir = join(process.env.HOME || "", ".gemini", "skills", "patchcord");
151
- const geminiWaitDir = join(process.env.HOME || "", ".gemini", "skills", "patchcord-wait");
152
- const geminiCmdDir = join(process.env.HOME || "", ".gemini", "commands");
152
+ if (existsSync(join(HOME, ".gemini"))) {
153
+ const geminiSkillDir = join(HOME, ".gemini", "skills", "patchcord");
154
+ const geminiWaitDir = join(HOME, ".gemini", "skills", "patchcord-wait");
155
+ const geminiCmdDir = join(HOME, ".gemini", "commands");
153
156
  let geminiChanged = false;
154
157
  if (!existsSync(geminiSkillDir)) {
155
158
  mkdirSync(geminiSkillDir, { recursive: true });
@@ -171,7 +174,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
171
174
  }
172
175
 
173
176
  // Codex CLI
174
- const codexConfig = join(process.env.HOME || "", ".codex", "config.toml");
177
+ const codexConfig = join(HOME, ".codex", "config.toml");
175
178
  if (existsSync(codexConfig)) {
176
179
  const content = readFileSync(codexConfig, "utf-8");
177
180
  if (!content.includes("[apps.patchcord]")) {
@@ -206,23 +209,25 @@ if (!cmd || cmd === "install" || cmd === "agent") {
206
209
  console.log(` ${cyan}3.${r} Cursor`);
207
210
  console.log(` ${cyan}4.${r} Windsurf`);
208
211
  console.log(` ${cyan}5.${r} Gemini CLI`);
209
- console.log(` ${cyan}6.${r} VS Code (Copilot)\n`);
212
+ console.log(` ${cyan}6.${r} VS Code (Copilot)`);
213
+ console.log(` ${cyan}7.${r} Zed\n`);
210
214
 
211
- const choice = (await ask(`${dim}Choose (1-6):${r} `)).trim();
215
+ const choice = (await ask(`${dim}Choose (1-7):${r} `)).trim();
212
216
  const isCodex = choice === "2";
213
217
  const isCursor = choice === "3";
214
218
  const isWindsurf = choice === "4";
215
219
  const isGemini = choice === "5";
216
220
  const isVSCode = choice === "6";
221
+ const isZed = choice === "7";
217
222
 
218
- if (!["1", "2", "3", "4", "5", "6"].includes(choice)) {
223
+ if (!["1", "2", "3", "4", "5", "6", "7"].includes(choice)) {
219
224
  console.error("Invalid choice.");
220
225
  rl.close();
221
226
  process.exit(1);
222
227
  }
223
228
 
224
- if (isWindsurf || isGemini) {
225
- const toolLabel = isWindsurf ? "Windsurf" : "Gemini CLI";
229
+ if (isWindsurf || isGemini || isZed) {
230
+ const toolLabel = isZed ? "Zed" : isWindsurf ? "Windsurf" : "Gemini CLI";
226
231
  console.log(`\n ${yellow}Note: ${toolLabel} uses global config — applies to all projects.${r}`);
227
232
  } else {
228
233
  console.log(`\n${dim}Project folder:${r} ${bold}${cwd}${r}`);
@@ -271,7 +276,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
271
276
  } catch {}
272
277
  }
273
278
  // Warn about global config conflict
274
- const globalCursor = join(process.env.HOME || "", ".cursor", "mcp.json");
279
+ const globalCursor = join(HOME, ".cursor", "mcp.json");
275
280
  if (existsSync(globalCursor)) {
276
281
  try {
277
282
  const global = JSON.parse(readFileSync(globalCursor, "utf-8"));
@@ -284,7 +289,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
284
289
  } catch {}
285
290
  }
286
291
  } else if (isWindsurf) {
287
- const wsPath = join(process.env.HOME || "", ".codeium", "windsurf", "mcp_config.json");
292
+ const wsPath = join(HOME, ".codeium", "windsurf", "mcp_config.json");
288
293
  if (existsSync(wsPath)) {
289
294
  try {
290
295
  const content = readFileSync(wsPath, "utf-8").trim();
@@ -302,7 +307,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
302
307
  } catch {}
303
308
  }
304
309
  } else if (isGemini) {
305
- const geminiPath = join(process.env.HOME || "", ".gemini", "settings.json");
310
+ const geminiPath = join(HOME, ".gemini", "settings.json");
306
311
  if (existsSync(geminiPath)) {
307
312
  try {
308
313
  const existing = JSON.parse(readFileSync(geminiPath, "utf-8"));
@@ -335,6 +340,25 @@ if (!cmd || cmd === "install" || cmd === "agent") {
335
340
  }
336
341
  } catch {}
337
342
  }
343
+ } else if (isZed) {
344
+ const zedPath = process.platform === "darwin"
345
+ ? join(HOME, "Library", "Application Support", "Zed", "settings.json")
346
+ : join(HOME, ".config", "zed", "settings.json");
347
+ if (existsSync(zedPath)) {
348
+ try {
349
+ const existing = JSON.parse(readFileSync(zedPath, "utf-8"));
350
+ if (existing.context_servers?.patchcord) {
351
+ console.log(`\n ${yellow}⚠ Zed already configured${r}`);
352
+ console.log(` ${dim}${zedPath}${r}`);
353
+ const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
354
+ if (replace !== "y" && replace !== "yes") {
355
+ console.log("Keeping existing config.");
356
+ rl.close();
357
+ process.exit(0);
358
+ }
359
+ }
360
+ } catch {}
361
+ }
338
362
  } else if (isCodex) {
339
363
  const configPath = join(cwd, ".codex", "config.toml");
340
364
  if (existsSync(configPath)) {
@@ -447,7 +471,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
447
471
  console.log(` ${dim}Per-project only — other projects won't see this agent.${r}`);
448
472
  } else if (isWindsurf) {
449
473
  // Windsurf: global only (~/.codeium/windsurf/mcp_config.json)
450
- const wsPath = join(process.env.HOME || "", ".codeium", "windsurf", "mcp_config.json");
474
+ const wsPath = join(HOME, ".codeium", "windsurf", "mcp_config.json");
451
475
  const wsConfig = {
452
476
  mcpServers: {
453
477
  patchcord: {
@@ -475,7 +499,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
475
499
  writeFileSync(wsPath, JSON.stringify(wsConfig, null, 2) + "\n");
476
500
  }
477
501
  } else {
478
- mkdirSync(join(process.env.HOME || "", ".codeium", "windsurf"), { recursive: true });
502
+ mkdirSync(join(HOME, ".codeium", "windsurf"), { recursive: true });
479
503
  writeFileSync(wsPath, JSON.stringify(wsConfig, null, 2) + "\n");
480
504
  }
481
505
  // Install workflows as slash commands (.windsurf/workflows/) — per-project
@@ -488,7 +512,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
488
512
  console.log(` ${yellow}MCP config is global — all Windsurf projects share this agent.${r}`);
489
513
  } else if (isGemini) {
490
514
  // Gemini CLI: global only (~/.gemini/settings.json)
491
- const geminiPath = join(process.env.HOME || "", ".gemini", "settings.json");
515
+ const geminiPath = join(HOME, ".gemini", "settings.json");
492
516
  let geminiSettings = {};
493
517
  if (existsSync(geminiPath)) {
494
518
  try {
@@ -508,10 +532,36 @@ if (!cmd || cmd === "install" || cmd === "agent") {
508
532
  geminiSettings.tools.allowed = geminiSettings.tools.allowed.filter(t => !t.startsWith("mcp_patchcord_"));
509
533
  if (geminiSettings.tools.allowed.length === 0) delete geminiSettings.tools;
510
534
  }
511
- mkdirSync(join(process.env.HOME || "", ".gemini"), { recursive: true });
535
+ mkdirSync(join(HOME, ".gemini"), { recursive: true });
512
536
  writeFileSync(geminiPath, JSON.stringify(geminiSettings, null, 2) + "\n");
513
537
  console.log(`\n ${green}✓${r} Gemini CLI configured: ${dim}${geminiPath}${r}`);
514
538
  console.log(` ${yellow}Global config — all Gemini CLI projects share this agent.${r}`);
539
+ } else if (isZed) {
540
+ // Zed: global settings.json → context_servers
541
+ const zedPath = process.platform === "darwin"
542
+ ? join(HOME, "Library", "Application Support", "Zed", "settings.json")
543
+ : join(HOME, ".config", "zed", "settings.json");
544
+ let zedSettings = {};
545
+ if (existsSync(zedPath)) {
546
+ try {
547
+ zedSettings = JSON.parse(readFileSync(zedPath, "utf-8"));
548
+ } catch {}
549
+ }
550
+ if (!zedSettings.context_servers) zedSettings.context_servers = {};
551
+ zedSettings.context_servers.patchcord = {
552
+ url: `${serverUrl}/mcp`,
553
+ headers: {
554
+ Authorization: `Bearer ${token}`,
555
+ "X-Patchcord-Machine": hostname,
556
+ },
557
+ };
558
+ const zedDir = process.platform === "darwin"
559
+ ? join(HOME, "Library", "Application Support", "Zed")
560
+ : join(HOME, ".config", "zed");
561
+ mkdirSync(zedDir, { recursive: true });
562
+ writeFileSync(zedPath, JSON.stringify(zedSettings, null, 2) + "\n");
563
+ console.log(`\n ${green}✓${r} Zed configured: ${dim}${zedPath}${r}`);
564
+ console.log(` ${yellow}Global config — all Zed projects share this agent.${r}`);
515
565
  } else if (isVSCode) {
516
566
  // VS Code: write .vscode/mcp.json (per-project)
517
567
  const vscodeDir = join(cwd, ".vscode");
@@ -607,7 +657,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
607
657
  console.log(`\n ${green}✓${r} Claude Code configured: ${dim}${mcpPath}${r}`);
608
658
  }
609
659
 
610
- const toolName = isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
660
+ const toolName = isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
611
661
  console.log(`\n${dim}Restart your ${toolName} session, then run:${r} ${bold}inbox()${r}`);
612
662
  process.exit(0);
613
663
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.3.39",
3
+ "version": "0.3.41",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",