patchcord 0.3.24 → 0.3.26

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 with auto-inbox checking. Agents automatically respond to messages from other agents without human intervention.",
4
- "version": "0.3.24",
4
+ "version": "0.3.26",
5
5
  "author": {
6
6
  "name": "ppravdin"
7
7
  },
package/bin/patchcord.mjs CHANGED
@@ -117,6 +117,15 @@ if (!cmd || cmd === "install" || cmd === "agent") {
117
117
  globalChanges.push("Cursor skill installed");
118
118
  }
119
119
 
120
+ // Windsurf
121
+ const windsurfSkillDir = join(process.env.HOME || "", ".codeium", "windsurf", "skills", "patchcord");
122
+ const windsurfSkillsRoot = join(process.env.HOME || "", ".codeium", "windsurf", "skills");
123
+ if (existsSync(join(process.env.HOME || "", ".codeium", "windsurf")) && !existsSync(windsurfSkillDir)) {
124
+ mkdirSync(windsurfSkillDir, { recursive: true });
125
+ cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(windsurfSkillDir, "SKILL.md"));
126
+ globalChanges.push("Windsurf skill installed");
127
+ }
128
+
120
129
  // Codex CLI
121
130
  const codexConfig = join(process.env.HOME || "", ".codex", "config.toml");
122
131
  if (existsSync(codexConfig)) {
@@ -159,13 +168,15 @@ if (!cmd || cmd === "install" || cmd === "agent") {
159
168
  console.log(`\n${bold}Which tool are you setting up?${r}\n`);
160
169
  console.log(` ${cyan}1.${r} Claude Code`);
161
170
  console.log(` ${cyan}2.${r} Codex CLI`);
162
- console.log(` ${cyan}3.${r} Cursor\n`);
171
+ console.log(` ${cyan}3.${r} Cursor`);
172
+ console.log(` ${cyan}4.${r} Windsurf\n`);
163
173
 
164
- const choice = (await ask(`${dim}Choose (1/2/3):${r} `)).trim();
174
+ const choice = (await ask(`${dim}Choose (1/2/3/4):${r} `)).trim();
165
175
  const isCodex = choice === "2";
166
176
  const isCursor = choice === "3";
177
+ const isWindsurf = choice === "4";
167
178
 
168
- if (!["1", "2", "3"].includes(choice)) {
179
+ if (!["1", "2", "3", "4"].includes(choice)) {
169
180
  console.error("Invalid choice.");
170
181
  rl.close();
171
182
  process.exit(1);
@@ -221,6 +232,37 @@ if (!cmd || cmd === "install" || cmd === "agent") {
221
232
  }
222
233
  } catch {}
223
234
  }
235
+ } else if (isWindsurf) {
236
+ // Check per-project config
237
+ const wsPath = join(cwd, ".windsurf", "mcp.json");
238
+ if (existsSync(wsPath)) {
239
+ try {
240
+ const existing = JSON.parse(readFileSync(wsPath, "utf-8"));
241
+ if (existing.mcpServers?.patchcord) {
242
+ console.log(`\n ${yellow}⚠ Windsurf already configured in this project${r}`);
243
+ console.log(` ${dim}${wsPath}${r}`);
244
+ const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
245
+ if (replace !== "y" && replace !== "yes") {
246
+ console.log("Keeping existing config.");
247
+ rl.close();
248
+ process.exit(0);
249
+ }
250
+ }
251
+ } catch {}
252
+ }
253
+ // Warn about global config conflict
254
+ const globalWs = join(process.env.HOME || "", ".codeium", "windsurf", "mcp_config.json");
255
+ if (existsSync(globalWs)) {
256
+ try {
257
+ const global = JSON.parse(readFileSync(globalWs, "utf-8"));
258
+ if (global.mcpServers?.patchcord) {
259
+ console.log(`\n ${yellow}⚠ Patchcord is also configured globally in Windsurf${r}`);
260
+ console.log(` ${dim}${globalWs}${r}`);
261
+ console.log(` ${yellow}Having both global AND per-project will cause duplicate tool calls.${r}`);
262
+ console.log(` ${dim}Remove patchcord from global: edit ~/.codeium/windsurf/mcp_config.json${r}`);
263
+ }
264
+ } catch {}
265
+ }
224
266
  } else {
225
267
  const configPath = join(cwd, ".codex", "config.toml");
226
268
  if (existsSync(configPath)) {
@@ -327,6 +369,39 @@ if (!cmd || cmd === "install" || cmd === "agent") {
327
369
  }
328
370
  console.log(`\n ${green}✓${r} Cursor configured: ${dim}${cursorPath}${r}`);
329
371
  console.log(` ${dim}Per-project only — other projects won't see this agent.${r}`);
372
+ } else if (isWindsurf) {
373
+ // Windsurf: write .windsurf/mcp.json (per-project)
374
+ const wsDir = join(cwd, ".windsurf");
375
+ mkdirSync(wsDir, { recursive: true });
376
+ const wsPath = join(wsDir, "mcp.json");
377
+ const wsConfig = {
378
+ mcpServers: {
379
+ patchcord: {
380
+ command: "npx",
381
+ args: [
382
+ "-y", "mcp-remote",
383
+ serverUrl,
384
+ "--header",
385
+ `Authorization: Bearer ${token}`,
386
+ ],
387
+ },
388
+ },
389
+ };
390
+
391
+ if (existsSync(wsPath)) {
392
+ try {
393
+ const existing = JSON.parse(readFileSync(wsPath, "utf-8"));
394
+ existing.mcpServers = existing.mcpServers || {};
395
+ existing.mcpServers.patchcord = wsConfig.mcpServers.patchcord;
396
+ writeFileSync(wsPath, JSON.stringify(existing, null, 2) + "\n");
397
+ } catch {
398
+ writeFileSync(wsPath, JSON.stringify(wsConfig, null, 2) + "\n");
399
+ }
400
+ } else {
401
+ writeFileSync(wsPath, JSON.stringify(wsConfig, null, 2) + "\n");
402
+ }
403
+ console.log(`\n ${green}✓${r} Windsurf configured: ${dim}${wsPath}${r}`);
404
+ console.log(` ${dim}Per-project only — other projects won't see this agent.${r}`);
330
405
  } else if (isCodex) {
331
406
  // Codex: copy skill + write config
332
407
  const dest = join(cwd, ".agents", "skills", "patchcord");
@@ -373,7 +448,7 @@ if (!cmd || cmd === "install" || cmd === "agent") {
373
448
  console.log(`\n ${green}✓${r} Claude Code configured: ${dim}${mcpPath}${r}`);
374
449
  }
375
450
 
376
- const toolName = isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
451
+ const toolName = isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
377
452
  console.log(`\n${dim}Restart your ${toolName} session, then run:${r} ${bold}inbox()${r}`);
378
453
  process.exit(0);
379
454
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.3.24",
3
+ "version": "0.3.26",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -89,4 +89,3 @@ Deferred messages survive context compaction — the agent won't forget them.
89
89
  - send_message() is blocked by unread inbox items, not by offline status. If sending is blocked, clear actionable inbox items first.
90
90
  - Resolve machine names to agent_ids from inbox() results.
91
91
  - Do NOT reply to messages that don't need a response: acks, "ok", "noted", "seen", "👍", confirmations, thumbs up, "thanks", or anything that is clearly a conversation-ending signal. Just read them and move on. Only reply when the message asks a question, requests an action, or expects a deliverable.
92
- - NEVER use `mcp__claude_ai_*` tools for patchcord. These are web interface OAuth tools with wrong identity. Always use `mcp__patchcord__*` (project-level). If only `claude_ai` tools are visible, diagnose the config: check `.mcp.json`, run `claude mcp get patchcord`, check `~/.claude/settings.json` deny rule.