patchcord 0.5.64 → 0.5.65

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.
package/README.md CHANGED
@@ -8,7 +8,7 @@ Cross-machine messaging between AI coding agents.
8
8
  npx patchcord@latest
9
9
  ```
10
10
 
11
- One command. Opens browser, configures everything. Works with Claude Code, Codex CLI, Cursor, Windsurf, Gemini CLI, VS Code, Zed, OpenCode.
11
+ One command. Opens browser, configures everything. Works with Claude Code, Codex CLI, Cursor, Windsurf, Gemini CLI, VS Code, Zed, OpenCode, Kimi CLI.
12
12
 
13
13
  Self-hosted:
14
14
 
@@ -23,6 +23,7 @@ npx patchcord@latest --token <token> --server https://patchcord.yourdomain.com
23
23
  - **Stop hook** — checks inbox between turns, notifies of pending messages
24
24
  - **Slash commands** — `/patchcord` and `/patchcord-wait` for Codex and Gemini CLI
25
25
  - **MCP config** — per-project or global config depending on tool
26
+ - **Kimi CLI** — global MCP config plus skills in `~/.kimi/skills/`
26
27
 
27
28
  ## How it works
28
29
 
package/bin/patchcord.mjs CHANGED
@@ -94,9 +94,9 @@ if (cmd === "plugin-path") {
94
94
  }
95
95
 
96
96
  // Shared bearer/base-url resolver. Project-local configs win over globals.
97
- // Supports all 11 installer targets: claude_code, codex, cursor, vscode,
97
+ // Supports all 12 installer targets: claude_code, codex, cursor, vscode,
98
98
  // opencode (per-project) + windsurf, gemini, zed, openclaw, antigravity,
99
- // cline (global). Each tool stores the bearer in its own shape.
99
+ // cline, kimi (global). Each tool stores the bearer in its own shape.
100
100
  async function _resolveBearer() {
101
101
  const { readFileSync } = await import("fs");
102
102
 
@@ -240,6 +240,7 @@ async function _resolveBearer() {
240
240
  () => readJsonAt(join(HOME, ".openclaw", "openclaw.json"), ["mcp", "servers", "patchcord"], "openclaw"),
241
241
  () => readJsonAt(join(HOME, ".gemini", "antigravity", "mcp_config.json"), ["mcpServers", "patchcord"], "antigravity"),
242
242
  ...clinePaths.map((p) => () => readJsonAt(p, ["mcpServers", "patchcord"], "cline")),
243
+ () => readJsonAt(join(HOME, ".kimi", "mcp.json"), ["mcpServers", "patchcord"], "kimi"),
243
244
  ];
244
245
  for (const r of globalCandidates) {
245
246
  const found = r();
@@ -458,7 +459,7 @@ if (cmd === "upload") {
458
459
  // (exits with code 2 + "already running" if another listener is up),
459
460
  // so this command needs zero pre-checks.
460
461
  //
461
- // We resolve the bearer here (all 11 tool configs) and inject it as
462
+ // We resolve the bearer here (all 12 tool configs) and inject it as
462
463
  // env vars so subscribe.mjs works regardless of which MCP client is
463
464
  // running — OpenCode, Codex, Cursor, etc. — not just Claude Code.
464
465
  if (cmd === "subscribe") {
@@ -946,6 +947,25 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
946
947
  if (geminiChanged) globalChanges.push("Gemini CLI skills + commands installed");
947
948
  }
948
949
 
950
+ // Kimi CLI
951
+ const hasKimi = run("which kimi");
952
+ if (hasKimi) {
953
+ const kimiSkillDir = join(HOME, ".kimi", "skills", "patchcord");
954
+ const kimiWaitDir = join(HOME, ".kimi", "skills", "patchcord-wait");
955
+ let kimiChanged = false;
956
+ if (!existsSync(kimiSkillDir)) {
957
+ mkdirSync(kimiSkillDir, { recursive: true });
958
+ cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(kimiSkillDir, "SKILL.md"));
959
+ kimiChanged = true;
960
+ }
961
+ if (!existsSync(kimiWaitDir)) {
962
+ mkdirSync(kimiWaitDir, { recursive: true });
963
+ cpSync(join(pluginRoot, "skills", "wait", "SKILL.md"), join(kimiWaitDir, "SKILL.md"));
964
+ kimiChanged = true;
965
+ }
966
+ if (kimiChanged) globalChanges.push("Kimi CLI skills installed");
967
+ }
968
+
949
969
  // Codex CLI — clean up old settings and install stop hook
950
970
  const codexConfig = join(HOME, ".codex", "config.toml");
951
971
  if (existsSync(codexConfig)) {
@@ -1006,8 +1026,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1006
1026
  }
1007
1027
  }
1008
1028
 
1009
- if (!hasClaude && !existsSync(codexConfig)) {
1010
- console.log(`${dim}No Claude Code or Codex CLI detected — skipping global setup.${r}`);
1029
+ if (!hasClaude && !existsSync(codexConfig) && !hasKimi) {
1030
+ console.log(`${dim}No Claude Code, Codex CLI, or Kimi CLI detected — skipping global setup.${r}`);
1011
1031
  }
1012
1032
 
1013
1033
  if (updateOnly) process.exit(0);
@@ -1025,7 +1045,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1025
1045
  const CLIENT_TYPE_MAP = {
1026
1046
  "claude_code": "1", "codex": "2", "cursor": "3", "windsurf": "4",
1027
1047
  "gemini": "5", "vscode": "6", "zed": "7", "opencode": "8", "openclaw": "9", "antigravity": "10",
1028
- "cline": "11",
1048
+ "cline": "11", "kimi": "12",
1029
1049
  };
1030
1050
 
1031
1051
 
@@ -1077,13 +1097,12 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1077
1097
  // already pre-selected one for us.
1078
1098
  if (!choice) {
1079
1099
  console.log(`\n${bold}Which tool are you setting up?${r}\n`);
1080
- console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI`);
1081
- console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code`);
1082
- console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed`);
1083
- console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode`);
1084
- console.log(` ${cyan}11.${r} Cline ${cyan}9.${r} OpenClaw\n`);
1085
- choice = (await ask(`${dim}Choose (1-9, 11):${r} `)).trim();
1086
- if (!["1","2","3","4","5","6","7","8","9","11"].includes(choice)) {
1100
+ console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI ${cyan}9.${r} OpenClaw`);
1101
+ console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code ${cyan}10.${r} Antigravity`);
1102
+ console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed ${cyan}11.${r} Cline`);
1103
+ console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode ${cyan}12.${r} Kimi CLI\n`);
1104
+ choice = (await ask(`${dim}Choose (1-12):${r} `)).trim();
1105
+ if (!["1","2","3","4","5","6","7","8","9","10","11","12"].includes(choice)) {
1087
1106
  console.error("Invalid choice.");
1088
1107
  rl.close();
1089
1108
  process.exit(1);
@@ -1393,6 +1412,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1393
1412
  const isOpenClaw = choice === "9";
1394
1413
  const isAntigravity = choice === "10";
1395
1414
  const isCline = choice === "11";
1415
+ const isKimi = choice === "12";
1396
1416
 
1397
1417
  const hostname = run("hostname -s") || run("hostname") || "unknown";
1398
1418
 
@@ -1625,6 +1645,31 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1625
1645
  console.log(`\n ${green}✓${r} Cline configured: ${dim}${clinePath}${r}`);
1626
1646
  console.log(` ${yellow}Global config — all Cline projects share this agent.${r}`);
1627
1647
  }
1648
+ } else if (isKimi) {
1649
+ // Kimi CLI: global ~/.kimi/mcp.json
1650
+ const kimiPath = join(HOME, ".kimi", "mcp.json");
1651
+ const kimiOk = updateJsonConfig(kimiPath, (obj) => {
1652
+ obj.mcpServers = obj.mcpServers || {};
1653
+ obj.mcpServers.patchcord = {
1654
+ url: `${serverUrl}/mcp`,
1655
+ headers: {
1656
+ Authorization: `Bearer ${token}`,
1657
+ "X-Patchcord-Machine": hostname,
1658
+ },
1659
+ };
1660
+ });
1661
+ if (kimiOk) {
1662
+ console.log(`\n ${green}✓${r} Kimi CLI configured: ${dim}${kimiPath}${r}`);
1663
+ console.log(` ${yellow}Global config — all Kimi CLI projects share this agent.${r}`);
1664
+ }
1665
+ // Install/update global skills
1666
+ const kimiSkillDir = join(HOME, ".kimi", "skills", "patchcord");
1667
+ const kimiWaitDir = join(HOME, ".kimi", "skills", "patchcord-wait");
1668
+ mkdirSync(kimiSkillDir, { recursive: true });
1669
+ mkdirSync(kimiWaitDir, { recursive: true });
1670
+ cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(kimiSkillDir, "SKILL.md"));
1671
+ cpSync(join(pluginRoot, "skills", "wait", "SKILL.md"), join(kimiWaitDir, "SKILL.md"));
1672
+ console.log(` ${green}✓${r} Skills installed: ${dim}patchcord${r}, ${dim}patchcord-wait${r}`);
1628
1673
  } else if (isVSCode) {
1629
1674
  // VS Code: write .vscode/mcp.json (per-project)
1630
1675
  const vscodeDir = join(cwd, ".vscode");
@@ -1851,7 +1896,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1851
1896
  }
1852
1897
 
1853
1898
  // Warn about gitignore for per-project configs with tokens
1854
- if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline) {
1899
+ if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline && !isKimi) {
1855
1900
  const gitignorePath = join(cwd, ".gitignore");
1856
1901
  const configFile = isCodex ? ".codex/config.toml" : isCursor ? ".cursor/mcp.json" : isVSCode ? ".vscode/mcp.json" : isOpenCode ? "opencode.json" : ".mcp.json";
1857
1902
  let needsWarning = true;
@@ -1869,9 +1914,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1869
1914
  }
1870
1915
  }
1871
1916
 
1872
- const toolName = isAntigravity ? "Antigravity" : isCline ? "Cline" : isOpenClaw ? "OpenClaw" : isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
1917
+ const toolName = isKimi ? "Kimi CLI" : isAntigravity ? "Antigravity" : isCline ? "Cline" : isOpenClaw ? "OpenClaw" : isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
1873
1918
 
1874
- if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline) {
1919
+ if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline && !isKimi) {
1875
1920
  console.log(`\n ${dim}To connect a second agent:${r}`);
1876
1921
  console.log(` ${dim}cd into another project and run${r} ${bold}npx patchcord@latest${r} ${dim}there.${r}`);
1877
1922
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.64",
3
+ "version": "0.5.65",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -55,7 +55,7 @@ function die(msg, code = 1) {
55
55
 
56
56
  function readMcpConfig(cwd) {
57
57
  // Prefer env vars injected by patchcord.mjs, which already ran _resolveBearer()
58
- // and supports all 11 tool configs (Claude Code, OpenCode, Codex, Cursor, etc.).
58
+ // and supports all 12 tool configs (Claude Code, OpenCode, Codex, Cursor, Kimi, etc.).
59
59
  if (process.env.PATCHCORD_BASE_URL && process.env.PATCHCORD_BEARER_TOKEN) {
60
60
  return { baseUrl: process.env.PATCHCORD_BASE_URL, token: process.env.PATCHCORD_BEARER_TOKEN };
61
61
  }