patchcord 0.5.122 → 0.5.124

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. Messages from other agents land in the inbox and wake the agent to reply.",
4
- "version": "0.5.122",
4
+ "version": "0.5.124",
5
5
  "author": {
6
6
  "name": "ppravdin"
7
7
  },
package/bin/patchcord.mjs CHANGED
@@ -349,18 +349,19 @@ async function _resolveBearer(options = {}) {
349
349
  );
350
350
  })();
351
351
 
352
- // NO global kimi/kimi-code reader. Kimi is a PER-PROJECT identity
353
- // (.kimi-code/mcp.json in the worktree); a global ~/.kimi(-code)/mcp.json would
354
- // make a leftover token hijack every kimi session everywhere. A kimi outside a
352
+ // NO global reader for PER-PROJECT tools. Kimi (.kimi-code/mcp.json) and
353
+ // Antigravity (.agents/mcp_config.json) are per-project identities: a leftover
354
+ // token in a global config (~/.kimi(-code)/mcp.json, ~/.gemini/antigravity/
355
+ // mcp_config.json) would hijack every session everywhere and make the agent
356
+ // "check inbox" in projects it has nothing to do with. Such a tool outside a
355
357
  // patchcord worktree is simply not an agent. (The tools below are global-ONLY
356
- // by nature — Windsurf/Gemini/Zed/etc. store MCP config globally — so they keep
357
- // their global readers.)
358
+ // by nature — Windsurf/Gemini CLI/Zed/etc. store MCP config globally — so they
359
+ // keep their global readers.)
358
360
  const defaultGlobalCandidates = [
359
361
  () => readJsonAt(join(HOME, ".codeium", "windsurf", "mcp_config.json"), ["mcpServers", "patchcord"], "windsurf"),
360
362
  () => readJsonAt(join(HOME, ".gemini", "settings.json"), ["mcpServers", "patchcord"], "gemini"),
361
363
  () => readJsonAt(zedPath, ["context_servers", "patchcord"], "zed"),
362
364
  () => readJsonAt(join(HOME, ".openclaw", "openclaw.json"), ["mcp", "servers", "patchcord"], "openclaw"),
363
- () => readJsonAt(join(HOME, ".gemini", "antigravity", "mcp_config.json"), ["mcpServers", "patchcord"], "antigravity"),
364
365
  () => readHermesShape(join(HOME, ".hermes", "config.yaml")),
365
366
  ...clinePaths.map((p) => () => readJsonAt(p, ["mcpServers", "patchcord"], "cline")),
366
367
  ];
@@ -596,7 +597,7 @@ if (cmd === "subscribe") {
596
597
  const forceKimi = args.includes("--kimi");
597
598
  const intervalArg = args.find((a) => a !== "--kimi") || "30";
598
599
 
599
- // Kimi CLI uses polling instead of WebSocket realtime.
600
+ // Kimi Code uses polling instead of WebSocket realtime.
600
601
  // Force Kimi mode with --kimi flag, or auto-detect from bearer config.
601
602
  let isKimi = forceKimi;
602
603
  let bearerInfo = null;
@@ -606,13 +607,15 @@ if (cmd === "subscribe") {
606
607
  }
607
608
 
608
609
  if (isKimi) {
610
+ const kimiCodeHome = process.env.KIMI_CODE_HOME || join(HOME, ".kimi-code");
609
611
  // Remove old combined skill so only patchcord:inbox/subscribe/wait appear
610
- const oldKimiSkillDir = join(HOME, ".kimi", "skills", "patchcord");
611
- if (existsSync(oldKimiSkillDir)) {
612
- try { rmSync(oldKimiSkillDir, { recursive: true, force: true }); } catch {}
612
+ for (const oldSkillRoot of [join(kimiCodeHome, "skills", "patchcord"), join(HOME, ".kimi", "skills", "patchcord")]) {
613
+ if (existsSync(oldSkillRoot)) {
614
+ try { rmSync(oldSkillRoot, { recursive: true, force: true }); } catch {}
615
+ }
613
616
  }
614
617
 
615
- const kimiSubScript = join(HOME, ".kimi", "patchcord-subscribe.sh");
618
+ const kimiSubScript = join(kimiCodeHome, "patchcord-subscribe.sh");
616
619
  if (!existsSync(kimiSubScript)) {
617
620
  console.error(`Kimi subscribe script not found at ${kimiSubScript}`);
618
621
  console.error(`Run npx patchcord@latest to install it.`);
@@ -835,7 +838,7 @@ if (cmd === "subscribe") {
835
838
  // ── main flow: global setup + project setup (or just install/agent for back-compat) ──
836
839
  // Any --flag enters this branch so equals-form (--token=foo, --tool=foo, --server=foo)
837
840
  // works the same as the space-form (--token foo). The internal flag parsing below
838
- // supports both. Non-flag commands (channel, init, skill, help, plugin-path) have
841
+ // supports both. Non-flag commands (init, skill, help, plugin-path) have
839
842
  // their own branches above and below.
840
843
  // ── CLI account auth + orchestrator/team/provisioning/schedule ─────────────
841
844
  // These commands act on the user's ACCOUNT, so they require CLI login. The
@@ -1667,13 +1670,33 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1667
1670
  if (windsurfChanged) globalChanges.push("Windsurf skills installed");
1668
1671
  }
1669
1672
 
1670
- // Gemini CLI + Antigravity (they SHARE ~/.gemini/skills and ~/.gemini/commands).
1671
- // Seed the patchcord skill ONLY when patchcord MCP is actually configured for
1672
- // one of these surfaces. Otherwise a bare session (esp. Antigravity, which
1673
- // inherits this dir) reads a skill with no backing MCP tool and improvises
1674
- // destructively scavenging other agents' bearer tokens off disk and curling
1675
- // the API. Invariant: skill present patchcord MCP present under ~/.gemini.
1673
+ // Gemini CLI + Antigravity SHARE ~/.gemini/skills and ~/.gemini/commands, but
1674
+ // their MCP config is NOT shared: Gemini CLI stores patchcord globally
1675
+ // (~/.gemini/settings.json) while Antigravity is PER-PROJECT
1676
+ // (<project>/.agents/mcp_config.json). So the shared global skill must be
1677
+ // seeded ONLY off Gemini CLI's global config — never off an Antigravity config.
1678
+ // A patchcord entry in the global ~/.gemini/antigravity(-cli)/mcp_config.json is
1679
+ // a leaked per-project token: it makes agy load the patchcord MCP (and its
1680
+ // "check inbox first" instruction) in EVERY project, and it kept this skill
1681
+ // seeded everywhere. We strip that leak below and gate the skill on Gemini only.
1676
1682
  if (existsSync(join(HOME, ".gemini"))) {
1683
+ // Remove any leaked patchcord server from Antigravity's GLOBAL configs so a
1684
+ // per-project token stops hijacking every agy session. Preserve other MCP
1685
+ // servers; only drop patchcord.
1686
+ for (const agGlobal of [
1687
+ join(HOME, ".gemini", "antigravity", "mcp_config.json"),
1688
+ join(HOME, ".gemini", "antigravity-cli", "mcp_config.json"),
1689
+ ]) {
1690
+ if (!existsSync(agGlobal)) continue;
1691
+ try {
1692
+ const j = JSON.parse(readFileSync(agGlobal, "utf-8"));
1693
+ if (j?.mcpServers?.patchcord) {
1694
+ delete j.mcpServers.patchcord;
1695
+ writeFileSync(agGlobal, JSON.stringify(j, null, 2) + "\n");
1696
+ globalChanges.push("Removed leaked global Antigravity patchcord MCP (agy is per-project)");
1697
+ }
1698
+ } catch {}
1699
+ }
1677
1700
  // true = configured, false = file absent (definitely not), null = unparseable (unknown)
1678
1701
  const hasPatchcordMcp = (p, keyPath) => {
1679
1702
  if (!existsSync(p)) return false;
@@ -1682,8 +1705,6 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1682
1705
  };
1683
1706
  const checks = [
1684
1707
  hasPatchcordMcp(join(HOME, ".gemini", "settings.json"), ["mcpServers", "patchcord"]),
1685
- hasPatchcordMcp(join(HOME, ".gemini", "antigravity", "mcp_config.json"), ["mcpServers", "patchcord"]),
1686
- hasPatchcordMcp(join(HOME, ".gemini", "antigravity-cli", "mcp_config.json"), ["mcpServers", "patchcord"]),
1687
1708
  ];
1688
1709
  const mcpConfigured = checks.some((c) => c === true);
1689
1710
  const mcpUnknown = checks.some((c) => c === null);
@@ -1743,7 +1764,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1743
1764
  }
1744
1765
  }
1745
1766
 
1746
- // Kimi CLI
1767
+ // Kimi Code
1747
1768
  const hasKimi = run("which kimi");
1748
1769
  if (hasKimi) {
1749
1770
  let kimiChanged = false;
@@ -1755,15 +1776,16 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1755
1776
  copyFileSync(src, dest);
1756
1777
  return changed;
1757
1778
  };
1758
- // Kimi CLI (Python) reads ~/.kimi/skills; Kimi Code (Node) reads
1779
+ // Kimi Code (Python) reads ~/.kimi/skills; Kimi Code (Node) reads
1759
1780
  // ~/.kimi-code/skills. Install into BOTH user dirs that exist — a global
1760
1781
  // `npx patchcord` must fix whichever Kimi the user runs. Clean up the old
1761
1782
  // combined skill AND colon-named flow skills (Kimi requires names to be
1762
1783
  // lowercase/digits/hyphens only — a colon kept them out of /flow:, showing
1763
1784
  // them only under /skill:). Renamed to patchcord-inbox etc.
1764
1785
  const kimiCodeHome = process.env.KIMI_CODE_HOME || join(HOME, ".kimi-code");
1765
- const kimiSkillRoots = [join(HOME, ".kimi", "skills")];
1766
- if (existsSync(kimiCodeHome)) kimiSkillRoots.push(join(kimiCodeHome, "skills"));
1786
+ // Kimi Code (Node) reads ~/.kimi-code/skills. The legacy Python kimi-cli
1787
+ // (~/.kimi) is deprecated — install only into Kimi Code's home.
1788
+ const kimiSkillRoots = [join(kimiCodeHome, "skills")];
1767
1789
  for (const root of kimiSkillRoots) {
1768
1790
  for (const stale of ["patchcord", "patchcord-wait", "patchcord:inbox", "patchcord:wait", "patchcord:subscribe"]) {
1769
1791
  const d = join(root, stale);
@@ -1774,16 +1796,20 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1774
1796
  kimiChanged = installKimiSkill(join(root, "patchcord-subscribe"), "subscribe") || kimiChanged;
1775
1797
  }
1776
1798
 
1777
- // Install/update stop hook — fires after each Kimi turn to check inbox
1799
+ // Install/update stop hook — fires after each Kimi turn to check inbox.
1800
+ // Kimi Code (the current product) reads ~/.kimi-code/config.toml and the
1801
+ // hook scripts it points to. The legacy Python kimi-cli home (~/.kimi) is
1802
+ // deprecated, so install into Kimi Code's home and strip any patchcord
1803
+ // artifacts a prior install left in ~/.kimi (see legacy cleanup below).
1778
1804
  let hookChanged = false;
1779
1805
  const kimiHookSrc = join(pluginRoot, "scripts", "kimi-stop-hook.sh");
1780
- const kimiHookDest = join(HOME, ".kimi", "patchcord-stop-hook.sh");
1806
+ const kimiHookDest = join(kimiCodeHome, "patchcord-stop-hook.sh");
1781
1807
  if (existsSync(kimiHookSrc)) {
1782
- const hookAlreadyExisted = existsSync(kimiHookDest);
1808
+ mkdirSync(kimiCodeHome, { recursive: true });
1783
1809
  copyFileSync(kimiHookSrc, kimiHookDest);
1784
1810
  chmodSync(kimiHookDest, 0o755);
1785
1811
 
1786
- const kimiConfigPath = join(HOME, ".kimi", "config.toml");
1812
+ const kimiConfigPath = join(kimiCodeHome, "config.toml");
1787
1813
  let kimiConfig = existsSync(kimiConfigPath) ? readFileSync(kimiConfigPath, "utf-8") : "";
1788
1814
 
1789
1815
  // Remove old inline hooks = [] (conflicts with [[hooks]] array-of-tables)
@@ -1796,7 +1822,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1796
1822
 
1797
1823
  // Install session-start hook
1798
1824
  const kimiSessionSrc = join(pluginRoot, "scripts", "kimi-session-start.sh");
1799
- const kimiSessionDest = join(HOME, ".kimi", "patchcord-session-start.sh");
1825
+ const kimiSessionDest = join(kimiCodeHome, "patchcord-session-start.sh");
1800
1826
  if (existsSync(kimiSessionSrc)) {
1801
1827
  copyFileSync(kimiSessionSrc, kimiSessionDest);
1802
1828
  chmodSync(kimiSessionDest, 0o755);
@@ -1807,28 +1833,40 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1807
1833
  const kept2 = segments2.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-session-start") && !seg.includes("patchcord-prompt-hook"));
1808
1834
  kimiConfig = kept2.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
1809
1835
 
1810
- // Remove the legacy UserPromptSubmit shim script if a prior install left it.
1811
- // Kimi displays stderr to the user but does not feed it to the LLM, so the
1812
- // shim never auto-executed anything — flow skills handle slash invocations.
1813
- const kimiPromptDest = join(HOME, ".kimi", "patchcord-prompt-hook.sh");
1814
- if (existsSync(kimiPromptDest)) {
1815
- try { rmSync(kimiPromptDest, { force: true }); } catch {}
1816
- }
1817
-
1818
1836
  // Append new hooks
1819
1837
  kimiConfig = kimiConfig.trimEnd() + `\n\n[[hooks]]\nevent = "SessionStart"\ncommand = "${kimiSessionDest}"\ntimeout = 10\n\n[[hooks]]\nevent = "Stop"\ncommand = "${kimiHookDest}"\ntimeout = 10\n`;
1820
1838
 
1821
1839
  mkdirSync(dirname(kimiConfigPath), { recursive: true });
1822
1840
  writeFileSync(kimiConfigPath, kimiConfig);
1823
1841
  hookChanged = true;
1842
+
1843
+ // Clean up deprecated ~/.kimi patchcord artifacts: stale hook/subscribe
1844
+ // scripts and any [[hooks]] blocks pointing at patchcord in the legacy
1845
+ // config, so the dead Python CLI can't double-fire or reference a script
1846
+ // we no longer maintain there.
1847
+ const legacyKimiHome = join(HOME, ".kimi");
1848
+ for (const f of ["patchcord-stop-hook.sh", "patchcord-session-start.sh", "patchcord-prompt-hook.sh", "patchcord-subscribe.sh"]) {
1849
+ const p = join(legacyKimiHome, f);
1850
+ if (existsSync(p)) { try { rmSync(p, { force: true }); } catch {} }
1851
+ }
1852
+ const legacyConfigPath = join(legacyKimiHome, "config.toml");
1853
+ if (existsSync(legacyConfigPath)) {
1854
+ try {
1855
+ let lc = readFileSync(legacyConfigPath, "utf-8");
1856
+ const segs = lc.split("[[hooks]]");
1857
+ const keptLegacy = segs.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-"));
1858
+ lc = keptLegacy.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
1859
+ writeFileSync(legacyConfigPath, lc ? lc + "\n" : "");
1860
+ } catch {}
1861
+ }
1824
1862
  }
1825
1863
 
1826
1864
  // Install/update Kimi subscribe script (background polling)
1827
1865
  let subChanged = false;
1828
1866
  const kimiSubSrc = join(pluginRoot, "scripts", "kimi-subscribe.sh");
1829
- const kimiSubDest = join(HOME, ".kimi", "patchcord-subscribe.sh");
1867
+ const kimiSubDest = join(kimiCodeHome, "patchcord-subscribe.sh");
1830
1868
  if (existsSync(kimiSubSrc)) {
1831
- const subAlreadyExisted = existsSync(kimiSubDest);
1869
+ mkdirSync(kimiCodeHome, { recursive: true });
1832
1870
  copyFileSync(kimiSubSrc, kimiSubDest);
1833
1871
  chmodSync(kimiSubDest, 0o755);
1834
1872
  subChanged = true;
@@ -1839,7 +1877,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1839
1877
  if (hookChanged) kimiParts.push("hooks");
1840
1878
  if (subChanged) kimiParts.push("subscribe script");
1841
1879
  if (kimiParts.length > 0) {
1842
- globalChanges.push(`Kimi CLI ${kimiParts.join(" + ")} installed`);
1880
+ globalChanges.push(`Kimi Code ${kimiParts.join(" + ")} installed`);
1843
1881
  }
1844
1882
  }
1845
1883
 
@@ -1907,8 +1945,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1907
1945
  }
1908
1946
 
1909
1947
  if (!hasClaude && !existsSync(codexConfig) && !hasKimi) {
1910
- console.log(`${dim}No Claude Code, Codex CLI, or Kimi CLI detected — skipping global setup.${r}`);
1911
- console.log(`${dim} Kimi CLI: https://kimi.moonshot.cn/download${r}`);
1948
+ console.log(`${dim}No Claude Code, Codex CLI, or Kimi Code detected — skipping global setup.${r}`);
1949
+ console.log(`${dim} Kimi Code: https://kimi.moonshot.cn/download${r}`);
1912
1950
  }
1913
1951
 
1914
1952
  if (updateOnly) process.exit(0);
@@ -1981,7 +2019,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1981
2019
  console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI ${cyan}9.${r} OpenClaw`);
1982
2020
  console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code ${cyan}10.${r} Antigravity CLI`);
1983
2021
  console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed ${cyan}11.${r} Cline`);
1984
- console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode ${cyan}12.${r} Kimi CLI`);
2022
+ console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode ${cyan}12.${r} Kimi Code`);
1985
2023
  console.log(` ${cyan}13.${r} Hermes\n`);
1986
2024
  choice = (await ask(`${dim}Choose (1-13):${r} `)).trim();
1987
2025
  if (!["1","2","3","4","5","6","7","8","9","10","11","12","13"].includes(choice)) {
@@ -2065,7 +2103,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2065
2103
  // project setup. Only per-project configs trigger "already configured."
2066
2104
  if (existingToken) {
2067
2105
  // Figure out which tool is already configured
2068
- const existingToolName = existingConfigFile.includes(".kimi") ? "Kimi CLI"
2106
+ const existingToolName = existingConfigFile.includes(".kimi") ? "Kimi Code"
2069
2107
  : existingConfigFile.includes(".codex") ? "Codex"
2070
2108
  : existingConfigFile.includes(".agents") ? "Antigravity CLI"
2071
2109
  : existingConfigFile.includes("antigravity") ? "Antigravity"
@@ -2635,7 +2673,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2635
2673
  console.log(` ${green}✓${r} Skills installed: ${dim}${join(kimiCodeHome, "skills")}${r} ${dim}(/flow:patchcord-inbox)${r}`);
2636
2674
  } catch {}
2637
2675
  } else if (isKimi) {
2638
- // Kimi CLI (Python): per-project .kimi/mcp.json + shell wrapper for --mcp-config-file
2676
+ // Kimi Code (Python): per-project .kimi/mcp.json + shell wrapper for --mcp-config-file
2639
2677
  const kimiDir = join(cwd, ".kimi");
2640
2678
  const kimiPath = join(kimiDir, "mcp.json");
2641
2679
  const kimiOk = updateJsonConfig(kimiPath, (obj) => {
@@ -2649,7 +2687,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2649
2687
  };
2650
2688
  });
2651
2689
  if (kimiOk) {
2652
- console.log(`\n ${green}✓${r} Kimi CLI configured: ${dim}${kimiPath}${r}`);
2690
+ console.log(`\n ${green}✓${r} Kimi Code configured: ${dim}${kimiPath}${r}`);
2653
2691
  console.log(` ${dim}Per-project — use the kimi-pc wrapper (see below) so Kimi loads this config.${r}`);
2654
2692
  }
2655
2693
  // Install/update global skills. Hyphen names → /flow:patchcord-inbox
@@ -2968,7 +3006,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2968
3006
  }
2969
3007
  }
2970
3008
 
2971
- const toolName = isHermes ? "Hermes" : isKimiCode ? "Kimi Code" : isKimi ? "Kimi CLI" : isAntigravity ? "Antigravity CLI" : isCline ? "Cline" : isOpenClaw ? "OpenClaw" : isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
3009
+ const toolName = isHermes ? "Hermes" : isKimiCode ? "Kimi Code" : isKimi ? "Kimi Code" : isAntigravity ? "Antigravity CLI" : isCline ? "Cline" : isOpenClaw ? "OpenClaw" : isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
2972
3010
 
2973
3011
  if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isCline && !isKimi && !isHermes) {
2974
3012
  console.log(`\n ${dim}To connect a second agent:${r}`);
@@ -2987,7 +3025,6 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2987
3025
  process.exit(0);
2988
3026
  }
2989
3027
 
2990
- // ── channel: spawn the channel MCP server (used by .mcp.json) ──
2991
3028
  // ── skill: custom skill from web console ─────────────────────
2992
3029
  if (cmd === "skill") {
2993
3030
  const sub = process.argv[3];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.122",
3
+ "version": "0.5.124",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "scripts": {
6
6
  "version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin/plugin.json"
@@ -5,13 +5,13 @@ set -euo pipefail
5
5
  # Runs when a Kimi session starts or resumes. Idempotent: the subscribe script
6
6
  # has a pidfile guard that prevents duplicate instances.
7
7
 
8
- KIMI_SUB="${HOME}/.kimi/patchcord-subscribe.sh"
8
+ KIMI_SUB="${KIMI_CODE_HOME:-${HOME}/.kimi-code}/patchcord-subscribe.sh"
9
9
  if [ ! -f "$KIMI_SUB" ]; then
10
10
  exit 0
11
11
  fi
12
12
 
13
13
  # Kimi sends hook metadata on stdin. Use its cwd when present so the
14
- # subscribe script resolves the right per-project .kimi/mcp.json.
14
+ # subscribe script resolves the right per-project .kimi-code/mcp.json.
15
15
  if [ -t 0 ]; then
16
16
  INPUT=""
17
17
  else
@@ -4,8 +4,8 @@ set -euo pipefail
4
4
  # Kimi Stop hook — checks patchcord inbox after each turn.
5
5
  # Installed automatically by `npx patchcord` when Kimi CLI is detected.
6
6
  #
7
- # Supports per-project .kimi/mcp.json (walks up from cwd) and
8
- # falls back to global ~/.kimi/mcp.json.
7
+ # Resolves per-project .kimi-code/mcp.json only (walks up from cwd).
8
+ # No global fallback a Kimi outside a patchcord worktree is not that agent.
9
9
  #
10
10
  # CRITICAL: Kimi v1.44.0 ONLY acts on Stop hooks when they BLOCK (exit code 2).
11
11
  # stdout is silently discarded. stderr becomes the "reason" that triggers a new turn.
@@ -18,7 +18,7 @@ INPUT=$(cat)
18
18
  STOP_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false' 2>/dev/null || echo "false")
19
19
  [ "$STOP_ACTIVE" = "true" ] && exit 0
20
20
 
21
- # Resolve MCP config: PROJECT-scoped ONLY (walk up from cwd for .kimi/mcp.json).
21
+ # Resolve MCP config: PROJECT-scoped ONLY (walk up from cwd for .kimi-code/mcp.json).
22
22
  # NO global ~/.kimi/mcp.json fallback — a Kimi launched outside a patchcord
23
23
  # worktree is not that agent and must not be nagged. No MCP authed in the cwd
24
24
  # tree => no inbox check. (This Stop hook is registered globally in
@@ -9,8 +9,8 @@ set -euo pipefail
9
9
  # Usage: patchcord subscribe (starts with default 30s interval)
10
10
  # patchcord subscribe 10 (starts with 10s interval)
11
11
  #
12
- # Supports per-project .kimi/mcp.json (walks up from cwd) and
13
- # falls back to global ~/.kimi/mcp.json.
12
+ # Resolves per-project .kimi-code/mcp.json only (walks up from cwd).
13
+ # No global fallback.
14
14
 
15
15
  command -v jq >/dev/null 2>&1 || { echo "jq required" >&2; exit 1; }
16
16