patchcord 0.3.71 → 0.3.72

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 +56 -2
  2. package/package.json +1 -1
package/bin/patchcord.mjs CHANGED
@@ -321,8 +321,61 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
321
321
  }
322
322
  rl.close();
323
323
  } else {
324
+ // Check if patchcord is already configured — offer to update URL without re-auth
325
+ let existingToken = "";
326
+ let existingConfigFile = "";
327
+ const mcpJsonPath = join(cwd, ".mcp.json");
328
+ const codexTomlPath = join(cwd, ".codex", "config.toml");
329
+ if (existsSync(mcpJsonPath)) {
330
+ try {
331
+ const existing = JSON.parse(readFileSync(mcpJsonPath, "utf-8"));
332
+ const pt = existing?.mcpServers?.patchcord;
333
+ if (pt?.headers?.Authorization) {
334
+ existingToken = pt.headers.Authorization.replace(/^Bearer\s+/i, "");
335
+ existingConfigFile = mcpJsonPath;
336
+ }
337
+ } catch {}
338
+ }
339
+ if (!existingToken && existsSync(codexTomlPath)) {
340
+ try {
341
+ const content = readFileSync(codexTomlPath, "utf-8");
342
+ const match = content.match(/Bearer\s+([^\s"]+)/);
343
+ if (match) {
344
+ existingToken = match[1];
345
+ existingConfigFile = codexTomlPath;
346
+ }
347
+ } catch {}
348
+ }
349
+ if (existingToken) {
350
+ console.log(`\n ${dim}Existing patchcord token found in ${existingConfigFile}${r}`);
351
+ const { createInterface: createRLU } = await import("readline");
352
+ const rlU = createRLU({ input: process.stdin, output: process.stdout });
353
+ const askU = (q) => new Promise((resolve) => rlU.question(q, resolve));
354
+ const answer = (await askU(` ${bold}Update config and keep existing token? (Y/n):${r} `)).trim().toLowerCase();
355
+ rlU.close();
356
+ if (answer !== "n" && answer !== "no") {
357
+ token = existingToken;
358
+ // Validate existing token
359
+ const validateResp = run(`curl -sf --max-time 5 -H "Authorization: Bearer ${token}" "${serverUrl}/api/inbox?limit=0&count_only=1"`);
360
+ if (validateResp) {
361
+ try {
362
+ const data = JSON.parse(validateResp);
363
+ identity = `${data.agent_id}@${data.namespace_id}`;
364
+ clientType = data.client_type || "";
365
+ choice = CLIENT_TYPE_MAP[clientType] || "";
366
+ console.log(` ${green}✓${r} ${bold}${identity}${r} — token valid`);
367
+ } catch {}
368
+ }
369
+ if (!identity) {
370
+ console.log(` ${yellow}⚠${r} Token expired or invalid. Starting fresh setup.`);
371
+ token = "";
372
+ }
373
+ }
374
+ }
375
+
376
+ if (!token) {
324
377
  // Browser connect flow
325
- rl.close();
378
+ if (rl) rl.close();
326
379
 
327
380
  function canOpenBrowser() {
328
381
  if (process.env.SSH_CLIENT || process.env.SSH_TTY) return false;
@@ -475,7 +528,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
475
528
  }
476
529
  }
477
530
  }
478
- }
531
+ } // end connect flow
532
+ } // end if (!token)
479
533
 
480
534
  const isCodex = choice === "2";
481
535
  const isCursor = choice === "3";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.3.71",
3
+ "version": "0.3.72",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",