patchcord 0.3.57 → 0.3.58

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 +33 -223
  2. package/package.json +1 -1
package/bin/patchcord.mjs CHANGED
@@ -77,8 +77,8 @@ if (cmd === "plugin-path") {
77
77
  }
78
78
 
79
79
  // ── main flow: global setup + project setup (or just install/agent for back-compat) ──
80
- if (!cmd || cmd === "install" || cmd === "agent") {
81
- const flags = process.argv.slice(3);
80
+ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd === "--no-browser") {
81
+ const flags = cmd?.startsWith("--") ? process.argv.slice(2) : process.argv.slice(3);
82
82
  const fullStatusline = flags.includes("--full");
83
83
  const { readFileSync, writeFileSync } = await import("fs");
84
84
 
@@ -252,230 +252,15 @@ if (!cmd || cmd === "install" || cmd === "agent") {
252
252
  const rl = createInterface({ input: process.stdin, output: process.stdout });
253
253
  const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
254
254
 
255
- console.log(`\n${bold}Which tool are you setting up?${r}\n`);
256
- console.log(` ${cyan}1.${r} Claude Code`);
257
- console.log(` ${cyan}2.${r} Codex CLI`);
258
- console.log(` ${cyan}3.${r} Cursor`);
259
- console.log(` ${cyan}4.${r} Windsurf`);
260
- console.log(` ${cyan}5.${r} Gemini CLI`);
261
- console.log(` ${cyan}6.${r} VS Code (Copilot)`);
262
- console.log(` ${cyan}7.${r} Zed`);
263
- console.log(` ${cyan}8.${r} OpenCode\n`);
264
-
265
- const choice = (await ask(`${dim}Choose (1-8):${r} `)).trim();
266
- const isCodex = choice === "2";
267
- const isCursor = choice === "3";
268
- const isWindsurf = choice === "4";
269
- const isGemini = choice === "5";
270
- const isVSCode = choice === "6";
271
- const isZed = choice === "7";
272
- const isOpenCode = choice === "8";
255
+ // Tool picker only shown for --token bypass. Browser flow gets tool from web.
256
+ let choice = "";
273
257
 
274
- if (!["1", "2", "3", "4", "5", "6", "7", "8"].includes(choice)) {
275
- console.error("Invalid choice.");
276
- rl.close();
277
- process.exit(1);
278
- }
279
-
280
- if (isWindsurf || isGemini || isZed) {
281
- const toolLabel = isZed ? "Zed" : isWindsurf ? "Windsurf" : "Gemini CLI";
282
- console.log(`\n ${yellow}Note: ${toolLabel} uses global config — applies to all projects.${r}`);
283
- } else {
284
- const folderType = detectFolder(cwd);
285
- const folderName = cwd.split("/").pop() || cwd.split("\\").pop() || cwd;
286
-
287
- if (folderType === "HOME") {
288
- console.log(`\n ${red}✗ You're in your home folder.${r}`);
289
- console.log(` ${yellow}Patchcord must be installed inside a project folder —${r}`);
290
- console.log(` ${yellow}the folder where your agent actually runs.${r}`);
291
- console.log(` ${dim}cd into your project first, then run this again.${r}`);
292
- rl.close();
293
- process.exit(0);
294
- } else if (folderType === "CONTAINER") {
295
- console.log(`\n ${yellow}⚠ This looks like a projects container, not a project.${r}`);
296
- console.log(` ${dim}${cwd}${r}`);
297
- console.log(` ${dim}Patchcord should be installed inside a project, not the folder above it.${r}`);
298
- const proceed = (await ask(` ${dim}Set up here anyway? (y/N):${r} `)).trim().toLowerCase();
299
- if (proceed !== "y" && proceed !== "yes") {
300
- console.log(` ${dim}cd into your project and run this again.${r}`);
301
- rl.close();
302
- process.exit(0);
303
- }
304
- }
305
-
306
- console.log(`\n ${dim}Agent identity:${r} ${bold}${folderName}${r}`);
307
- console.log(` ${dim}Folder:${r} ${cwd}`);
308
- }
258
+ const CLIENT_TYPE_MAP = {
259
+ "claude_code": "1", "codex": "2", "cursor": "3", "windsurf": "4",
260
+ "gemini": "5", "vscode": "6", "zed": "7", "opencode": "8",
261
+ };
309
262
 
310
263
 
311
- // Check if already configured
312
- if (choice === "1") {
313
- const mcpPath = join(cwd, ".mcp.json");
314
- if (existsSync(mcpPath)) {
315
- try {
316
- const existing = JSON.parse(readFileSync(mcpPath, "utf-8"));
317
- if (existing.mcpServers?.patchcord) {
318
- console.log(`\n ${yellow}⚠ Claude Code already configured in this project${r}`);
319
- console.log(` ${dim}${mcpPath}${r}`);
320
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
321
- if (replace !== "y" && replace !== "yes") {
322
- console.log("Keeping existing config.");
323
- rl.close();
324
- process.exit(0);
325
- }
326
- }
327
- } catch {}
328
- }
329
- } else if (isCursor) {
330
- const cursorPath = join(cwd, ".cursor", "mcp.json");
331
- if (existsSync(cursorPath)) {
332
- try {
333
- const existing = JSON.parse(readFileSync(cursorPath, "utf-8"));
334
- if (existing.mcpServers?.patchcord) {
335
- console.log(`\n ${yellow}⚠ Cursor already configured in this project${r}`);
336
- console.log(` ${dim}${cursorPath}${r}`);
337
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
338
- if (replace !== "y" && replace !== "yes") {
339
- console.log("Keeping existing config.");
340
- rl.close();
341
- process.exit(0);
342
- }
343
- }
344
- } catch {}
345
- }
346
- // Warn about global config conflict
347
- const globalCursor = join(HOME, ".cursor", "mcp.json");
348
- if (existsSync(globalCursor)) {
349
- try {
350
- const global = JSON.parse(readFileSync(globalCursor, "utf-8"));
351
- if (global.mcpServers?.patchcord) {
352
- console.log(`\n ${yellow}⚠ Patchcord is also configured globally in Cursor${r}`);
353
- console.log(` ${dim}${globalCursor}${r}`);
354
- console.log(` ${yellow}Having both global AND per-project will cause duplicate tool calls.${r}`);
355
- console.log(` ${dim}Remove patchcord from global config: Cursor Settings → MCP → remove patchcord${r}`);
356
- }
357
- } catch {}
358
- }
359
- } else if (isWindsurf) {
360
- const wsPath = join(HOME, ".codeium", "windsurf", "mcp_config.json");
361
- if (existsSync(wsPath)) {
362
- try {
363
- const content = readFileSync(wsPath, "utf-8").trim();
364
- const existing = content ? JSON.parse(content) : {};
365
- if (existing.mcpServers?.patchcord) {
366
- console.log(`\n ${yellow}⚠ Windsurf already configured${r}`);
367
- console.log(` ${dim}${wsPath}${r}`);
368
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
369
- if (replace !== "y" && replace !== "yes") {
370
- console.log("Keeping existing config.");
371
- rl.close();
372
- process.exit(0);
373
- }
374
- }
375
- } catch {}
376
- }
377
- } else if (isGemini) {
378
- const geminiPath = join(HOME, ".gemini", "settings.json");
379
- if (existsSync(geminiPath)) {
380
- try {
381
- const existing = safeReadJson(geminiPath) || {};
382
- if (existing.mcpServers?.patchcord) {
383
- console.log(`\n ${yellow}⚠ Gemini CLI already configured${r}`);
384
- console.log(` ${dim}${geminiPath}${r}`);
385
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
386
- if (replace !== "y" && replace !== "yes") {
387
- console.log("Keeping existing config.");
388
- rl.close();
389
- process.exit(0);
390
- }
391
- }
392
- } catch {}
393
- }
394
- } else if (isVSCode) {
395
- const vscodePath = join(cwd, ".vscode", "mcp.json");
396
- if (existsSync(vscodePath)) {
397
- try {
398
- const existing = JSON.parse(readFileSync(vscodePath, "utf-8"));
399
- if (existing.servers?.patchcord) {
400
- console.log(`\n ${yellow}⚠ VS Code already configured in this project${r}`);
401
- console.log(` ${dim}${vscodePath}${r}`);
402
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
403
- if (replace !== "y" && replace !== "yes") {
404
- console.log("Keeping existing config.");
405
- rl.close();
406
- process.exit(0);
407
- }
408
- }
409
- } catch {}
410
- }
411
- } else if (isZed) {
412
- const zedPath = process.platform === "darwin"
413
- ? join(HOME, "Library", "Application Support", "Zed", "settings.json")
414
- : join(HOME, ".config", "zed", "settings.json");
415
- if (existsSync(zedPath)) {
416
- try {
417
- const existing = safeReadJson(zedPath) || {};
418
- if (existing.context_servers?.patchcord) {
419
- console.log(`\n ${yellow}⚠ Zed already configured${r}`);
420
- console.log(` ${dim}${zedPath}${r}`);
421
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
422
- if (replace !== "y" && replace !== "yes") {
423
- console.log("Keeping existing config.");
424
- rl.close();
425
- process.exit(0);
426
- }
427
- }
428
- } catch {}
429
- }
430
- } else if (isOpenCode) {
431
- const ocPath = join(cwd, "opencode.json");
432
- if (existsSync(ocPath)) {
433
- try {
434
- const existing = JSON.parse(readFileSync(ocPath, "utf-8"));
435
- if (existing.mcp?.patchcord) {
436
- console.log(`\n ${yellow}⚠ OpenCode already configured in this project${r}`);
437
- console.log(` ${dim}${ocPath}${r}`);
438
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
439
- if (replace !== "y" && replace !== "yes") {
440
- console.log("Keeping existing config.");
441
- rl.close();
442
- process.exit(0);
443
- }
444
- }
445
- } catch {}
446
- }
447
- } else if (isCodex) {
448
- // Check global config for stale patchcord MCP — user may have run installer in ~ by mistake
449
- const globalCodexConfig = join(HOME, ".codex", "config.toml");
450
- if (existsSync(globalCodexConfig)) {
451
- const globalContent = readFileSync(globalCodexConfig, "utf-8");
452
- if (globalContent.includes("[mcp_servers.patchcord-codex]")) {
453
- console.log(`\n ${red}⚠ Patchcord is in your GLOBAL Codex config!${r}`);
454
- console.log(` ${dim}${globalCodexConfig}${r}`);
455
- console.log(` ${yellow}This overrides per-project config and causes conflicts.${r}`);
456
- const cleanGlobal = (await ask(` ${dim}Remove patchcord from global config? (Y/n):${r} `)).trim().toLowerCase();
457
- if (cleanGlobal !== "n" && cleanGlobal !== "no") {
458
- const cleaned = globalContent.replace(/\[mcp_servers\.patchcord\]\n(?:(?!\[)[^\n]*\n?)*/g, "").replace(/\n{3,}/g, "\n\n").trim();
459
- writeFileSync(globalCodexConfig, cleaned + "\n");
460
- console.log(` ${green}✓${r} Removed from global config`);
461
- }
462
- }
463
- }
464
- const configPath = join(cwd, ".codex", "config.toml");
465
- if (existsSync(configPath)) {
466
- const content = readFileSync(configPath, "utf-8");
467
- if (content.includes("[mcp_servers.patchcord-codex]")) {
468
- console.log(`\n ${yellow}⚠ Codex CLI already configured in this project${r}`);
469
- console.log(` ${dim}${configPath}${r}`);
470
- const replace = (await ask(` ${dim}Replace? (y/N):${r} `)).trim().toLowerCase();
471
- if (replace !== "y" && replace !== "yes") {
472
- console.log("Keeping existing config.");
473
- rl.close();
474
- process.exit(0);
475
- }
476
- }
477
- }
478
- }
479
264
 
480
265
  let token = "";
481
266
  let identity = "";
@@ -488,6 +273,18 @@ if (!cmd || cmd === "install" || cmd === "agent") {
488
273
  || (flags.includes("--token") ? flags[flags.indexOf("--token") + 1] : "");
489
274
 
490
275
  if (tokenFlag) {
276
+ // --token bypass: need tool picker in terminal
277
+ console.log(`\n${bold}Which tool are you setting up?${r}\n`);
278
+ console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI`);
279
+ console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code`);
280
+ console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed`);
281
+ console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode\n`);
282
+ choice = (await ask(`${dim}Choose (1-8):${r} `)).trim();
283
+ if (!["1","2","3","4","5","6","7","8"].includes(choice)) {
284
+ console.error("Invalid choice.");
285
+ rl.close();
286
+ process.exit(1);
287
+ }
491
288
  token = tokenFlag.trim();
492
289
  if (!isSafeToken(token)) {
493
290
  console.error("Invalid token format.");
@@ -643,10 +440,23 @@ if (!cmd || cmd === "install" || cmd === "agent") {
643
440
  token = sseResult.token;
644
441
  identity = `${sseResult.agent_id}@${sseResult.namespace_id}`;
645
442
  clientType = sseResult.client_type || "";
443
+ choice = CLIENT_TYPE_MAP[clientType] || "";
444
+ if (!choice) {
445
+ console.error(`Unknown tool type: ${clientType}`);
446
+ process.exit(1);
447
+ }
646
448
  console.log(` ${green}✓${r} ${bold}${identity}${r} connected.`);
647
449
  }
648
450
  }
649
451
 
452
+ const isCodex = choice === "2";
453
+ const isCursor = choice === "3";
454
+ const isWindsurf = choice === "4";
455
+ const isGemini = choice === "5";
456
+ const isVSCode = choice === "6";
457
+ const isZed = choice === "7";
458
+ const isOpenCode = choice === "8";
459
+
650
460
  const hostname = run("hostname -s") || run("hostname") || "unknown";
651
461
 
652
462
  if (isCursor) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.3.57",
3
+ "version": "0.3.58",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",