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.
package/bin/patchcord.mjs
CHANGED
|
@@ -349,18 +349,19 @@ async function _resolveBearer(options = {}) {
|
|
|
349
349
|
);
|
|
350
350
|
})();
|
|
351
351
|
|
|
352
|
-
// NO global
|
|
353
|
-
// (.
|
|
354
|
-
//
|
|
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
|
|
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
|
|
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
|
|
611
|
-
|
|
612
|
-
|
|
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(
|
|
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 (
|
|
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
|
|
1671
|
-
//
|
|
1672
|
-
//
|
|
1673
|
-
//
|
|
1674
|
-
//
|
|
1675
|
-
//
|
|
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
|
|
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
|
|
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
|
-
|
|
1766
|
-
|
|
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(
|
|
1806
|
+
const kimiHookDest = join(kimiCodeHome, "patchcord-stop-hook.sh");
|
|
1781
1807
|
if (existsSync(kimiHookSrc)) {
|
|
1782
|
-
|
|
1808
|
+
mkdirSync(kimiCodeHome, { recursive: true });
|
|
1783
1809
|
copyFileSync(kimiHookSrc, kimiHookDest);
|
|
1784
1810
|
chmodSync(kimiHookDest, 0o755);
|
|
1785
1811
|
|
|
1786
|
-
const kimiConfigPath = join(
|
|
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(
|
|
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(
|
|
1867
|
+
const kimiSubDest = join(kimiCodeHome, "patchcord-subscribe.sh");
|
|
1830
1868
|
if (existsSync(kimiSubSrc)) {
|
|
1831
|
-
|
|
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
|
|
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
|
|
1911
|
-
console.log(`${dim} Kimi
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
@@ -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
|
-
#
|
|
8
|
-
#
|
|
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
|
-
#
|
|
13
|
-
#
|
|
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
|
|