patchcord 0.5.121 → 0.5.123
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
|
-
"description": "Cross-machine agent messaging. Messages from other agents
|
|
4
|
-
"version": "0.5.
|
|
3
|
+
"description": "Cross-machine agent messaging. Messages from other agents land in the inbox and wake the agent to reply.",
|
|
4
|
+
"version": "0.5.123",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "ppravdin"
|
|
7
7
|
},
|
package/bin/patchcord.mjs
CHANGED
|
@@ -596,7 +596,7 @@ if (cmd === "subscribe") {
|
|
|
596
596
|
const forceKimi = args.includes("--kimi");
|
|
597
597
|
const intervalArg = args.find((a) => a !== "--kimi") || "30";
|
|
598
598
|
|
|
599
|
-
// Kimi
|
|
599
|
+
// Kimi Code uses polling instead of WebSocket realtime.
|
|
600
600
|
// Force Kimi mode with --kimi flag, or auto-detect from bearer config.
|
|
601
601
|
let isKimi = forceKimi;
|
|
602
602
|
let bearerInfo = null;
|
|
@@ -606,13 +606,15 @@ if (cmd === "subscribe") {
|
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
if (isKimi) {
|
|
609
|
+
const kimiCodeHome = process.env.KIMI_CODE_HOME || join(HOME, ".kimi-code");
|
|
609
610
|
// Remove old combined skill so only patchcord:inbox/subscribe/wait appear
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
611
|
+
for (const oldSkillRoot of [join(kimiCodeHome, "skills", "patchcord"), join(HOME, ".kimi", "skills", "patchcord")]) {
|
|
612
|
+
if (existsSync(oldSkillRoot)) {
|
|
613
|
+
try { rmSync(oldSkillRoot, { recursive: true, force: true }); } catch {}
|
|
614
|
+
}
|
|
613
615
|
}
|
|
614
616
|
|
|
615
|
-
const kimiSubScript = join(
|
|
617
|
+
const kimiSubScript = join(kimiCodeHome, "patchcord-subscribe.sh");
|
|
616
618
|
if (!existsSync(kimiSubScript)) {
|
|
617
619
|
console.error(`Kimi subscribe script not found at ${kimiSubScript}`);
|
|
618
620
|
console.error(`Run npx patchcord@latest to install it.`);
|
|
@@ -835,7 +837,7 @@ if (cmd === "subscribe") {
|
|
|
835
837
|
// ── main flow: global setup + project setup (or just install/agent for back-compat) ──
|
|
836
838
|
// Any --flag enters this branch so equals-form (--token=foo, --tool=foo, --server=foo)
|
|
837
839
|
// works the same as the space-form (--token foo). The internal flag parsing below
|
|
838
|
-
// supports both. Non-flag commands (
|
|
840
|
+
// supports both. Non-flag commands (init, skill, help, plugin-path) have
|
|
839
841
|
// their own branches above and below.
|
|
840
842
|
// ── CLI account auth + orchestrator/team/provisioning/schedule ─────────────
|
|
841
843
|
// These commands act on the user's ACCOUNT, so they require CLI login. The
|
|
@@ -1743,7 +1745,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1743
1745
|
}
|
|
1744
1746
|
}
|
|
1745
1747
|
|
|
1746
|
-
// Kimi
|
|
1748
|
+
// Kimi Code
|
|
1747
1749
|
const hasKimi = run("which kimi");
|
|
1748
1750
|
if (hasKimi) {
|
|
1749
1751
|
let kimiChanged = false;
|
|
@@ -1755,15 +1757,16 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1755
1757
|
copyFileSync(src, dest);
|
|
1756
1758
|
return changed;
|
|
1757
1759
|
};
|
|
1758
|
-
// Kimi
|
|
1760
|
+
// Kimi Code (Python) reads ~/.kimi/skills; Kimi Code (Node) reads
|
|
1759
1761
|
// ~/.kimi-code/skills. Install into BOTH user dirs that exist — a global
|
|
1760
1762
|
// `npx patchcord` must fix whichever Kimi the user runs. Clean up the old
|
|
1761
1763
|
// combined skill AND colon-named flow skills (Kimi requires names to be
|
|
1762
1764
|
// lowercase/digits/hyphens only — a colon kept them out of /flow:, showing
|
|
1763
1765
|
// them only under /skill:). Renamed to patchcord-inbox etc.
|
|
1764
1766
|
const kimiCodeHome = process.env.KIMI_CODE_HOME || join(HOME, ".kimi-code");
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
+
// Kimi Code (Node) reads ~/.kimi-code/skills. The legacy Python kimi-cli
|
|
1768
|
+
// (~/.kimi) is deprecated — install only into Kimi Code's home.
|
|
1769
|
+
const kimiSkillRoots = [join(kimiCodeHome, "skills")];
|
|
1767
1770
|
for (const root of kimiSkillRoots) {
|
|
1768
1771
|
for (const stale of ["patchcord", "patchcord-wait", "patchcord:inbox", "patchcord:wait", "patchcord:subscribe"]) {
|
|
1769
1772
|
const d = join(root, stale);
|
|
@@ -1774,16 +1777,20 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1774
1777
|
kimiChanged = installKimiSkill(join(root, "patchcord-subscribe"), "subscribe") || kimiChanged;
|
|
1775
1778
|
}
|
|
1776
1779
|
|
|
1777
|
-
// Install/update stop hook — fires after each Kimi turn to check inbox
|
|
1780
|
+
// Install/update stop hook — fires after each Kimi turn to check inbox.
|
|
1781
|
+
// Kimi Code (the current product) reads ~/.kimi-code/config.toml and the
|
|
1782
|
+
// hook scripts it points to. The legacy Python kimi-cli home (~/.kimi) is
|
|
1783
|
+
// deprecated, so install into Kimi Code's home and strip any patchcord
|
|
1784
|
+
// artifacts a prior install left in ~/.kimi (see legacy cleanup below).
|
|
1778
1785
|
let hookChanged = false;
|
|
1779
1786
|
const kimiHookSrc = join(pluginRoot, "scripts", "kimi-stop-hook.sh");
|
|
1780
|
-
const kimiHookDest = join(
|
|
1787
|
+
const kimiHookDest = join(kimiCodeHome, "patchcord-stop-hook.sh");
|
|
1781
1788
|
if (existsSync(kimiHookSrc)) {
|
|
1782
|
-
|
|
1789
|
+
mkdirSync(kimiCodeHome, { recursive: true });
|
|
1783
1790
|
copyFileSync(kimiHookSrc, kimiHookDest);
|
|
1784
1791
|
chmodSync(kimiHookDest, 0o755);
|
|
1785
1792
|
|
|
1786
|
-
const kimiConfigPath = join(
|
|
1793
|
+
const kimiConfigPath = join(kimiCodeHome, "config.toml");
|
|
1787
1794
|
let kimiConfig = existsSync(kimiConfigPath) ? readFileSync(kimiConfigPath, "utf-8") : "";
|
|
1788
1795
|
|
|
1789
1796
|
// Remove old inline hooks = [] (conflicts with [[hooks]] array-of-tables)
|
|
@@ -1796,7 +1803,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1796
1803
|
|
|
1797
1804
|
// Install session-start hook
|
|
1798
1805
|
const kimiSessionSrc = join(pluginRoot, "scripts", "kimi-session-start.sh");
|
|
1799
|
-
const kimiSessionDest = join(
|
|
1806
|
+
const kimiSessionDest = join(kimiCodeHome, "patchcord-session-start.sh");
|
|
1800
1807
|
if (existsSync(kimiSessionSrc)) {
|
|
1801
1808
|
copyFileSync(kimiSessionSrc, kimiSessionDest);
|
|
1802
1809
|
chmodSync(kimiSessionDest, 0o755);
|
|
@@ -1807,28 +1814,40 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1807
1814
|
const kept2 = segments2.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-session-start") && !seg.includes("patchcord-prompt-hook"));
|
|
1808
1815
|
kimiConfig = kept2.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
|
|
1809
1816
|
|
|
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
1817
|
// Append new hooks
|
|
1819
1818
|
kimiConfig = kimiConfig.trimEnd() + `\n\n[[hooks]]\nevent = "SessionStart"\ncommand = "${kimiSessionDest}"\ntimeout = 10\n\n[[hooks]]\nevent = "Stop"\ncommand = "${kimiHookDest}"\ntimeout = 10\n`;
|
|
1820
1819
|
|
|
1821
1820
|
mkdirSync(dirname(kimiConfigPath), { recursive: true });
|
|
1822
1821
|
writeFileSync(kimiConfigPath, kimiConfig);
|
|
1823
1822
|
hookChanged = true;
|
|
1823
|
+
|
|
1824
|
+
// Clean up deprecated ~/.kimi patchcord artifacts: stale hook/subscribe
|
|
1825
|
+
// scripts and any [[hooks]] blocks pointing at patchcord in the legacy
|
|
1826
|
+
// config, so the dead Python CLI can't double-fire or reference a script
|
|
1827
|
+
// we no longer maintain there.
|
|
1828
|
+
const legacyKimiHome = join(HOME, ".kimi");
|
|
1829
|
+
for (const f of ["patchcord-stop-hook.sh", "patchcord-session-start.sh", "patchcord-prompt-hook.sh", "patchcord-subscribe.sh"]) {
|
|
1830
|
+
const p = join(legacyKimiHome, f);
|
|
1831
|
+
if (existsSync(p)) { try { rmSync(p, { force: true }); } catch {} }
|
|
1832
|
+
}
|
|
1833
|
+
const legacyConfigPath = join(legacyKimiHome, "config.toml");
|
|
1834
|
+
if (existsSync(legacyConfigPath)) {
|
|
1835
|
+
try {
|
|
1836
|
+
let lc = readFileSync(legacyConfigPath, "utf-8");
|
|
1837
|
+
const segs = lc.split("[[hooks]]");
|
|
1838
|
+
const keptLegacy = segs.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-"));
|
|
1839
|
+
lc = keptLegacy.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
|
|
1840
|
+
writeFileSync(legacyConfigPath, lc ? lc + "\n" : "");
|
|
1841
|
+
} catch {}
|
|
1842
|
+
}
|
|
1824
1843
|
}
|
|
1825
1844
|
|
|
1826
1845
|
// Install/update Kimi subscribe script (background polling)
|
|
1827
1846
|
let subChanged = false;
|
|
1828
1847
|
const kimiSubSrc = join(pluginRoot, "scripts", "kimi-subscribe.sh");
|
|
1829
|
-
const kimiSubDest = join(
|
|
1848
|
+
const kimiSubDest = join(kimiCodeHome, "patchcord-subscribe.sh");
|
|
1830
1849
|
if (existsSync(kimiSubSrc)) {
|
|
1831
|
-
|
|
1850
|
+
mkdirSync(kimiCodeHome, { recursive: true });
|
|
1832
1851
|
copyFileSync(kimiSubSrc, kimiSubDest);
|
|
1833
1852
|
chmodSync(kimiSubDest, 0o755);
|
|
1834
1853
|
subChanged = true;
|
|
@@ -1839,7 +1858,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1839
1858
|
if (hookChanged) kimiParts.push("hooks");
|
|
1840
1859
|
if (subChanged) kimiParts.push("subscribe script");
|
|
1841
1860
|
if (kimiParts.length > 0) {
|
|
1842
|
-
globalChanges.push(`Kimi
|
|
1861
|
+
globalChanges.push(`Kimi Code ${kimiParts.join(" + ")} installed`);
|
|
1843
1862
|
}
|
|
1844
1863
|
}
|
|
1845
1864
|
|
|
@@ -1907,8 +1926,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1907
1926
|
}
|
|
1908
1927
|
|
|
1909
1928
|
if (!hasClaude && !existsSync(codexConfig) && !hasKimi) {
|
|
1910
|
-
console.log(`${dim}No Claude Code, Codex CLI, or Kimi
|
|
1911
|
-
console.log(`${dim} Kimi
|
|
1929
|
+
console.log(`${dim}No Claude Code, Codex CLI, or Kimi Code detected — skipping global setup.${r}`);
|
|
1930
|
+
console.log(`${dim} Kimi Code: https://kimi.moonshot.cn/download${r}`);
|
|
1912
1931
|
}
|
|
1913
1932
|
|
|
1914
1933
|
if (updateOnly) process.exit(0);
|
|
@@ -1981,7 +2000,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1981
2000
|
console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI ${cyan}9.${r} OpenClaw`);
|
|
1982
2001
|
console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code ${cyan}10.${r} Antigravity CLI`);
|
|
1983
2002
|
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
|
|
2003
|
+
console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode ${cyan}12.${r} Kimi Code`);
|
|
1985
2004
|
console.log(` ${cyan}13.${r} Hermes\n`);
|
|
1986
2005
|
choice = (await ask(`${dim}Choose (1-13):${r} `)).trim();
|
|
1987
2006
|
if (!["1","2","3","4","5","6","7","8","9","10","11","12","13"].includes(choice)) {
|
|
@@ -2065,7 +2084,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2065
2084
|
// project setup. Only per-project configs trigger "already configured."
|
|
2066
2085
|
if (existingToken) {
|
|
2067
2086
|
// Figure out which tool is already configured
|
|
2068
|
-
const existingToolName = existingConfigFile.includes(".kimi") ? "Kimi
|
|
2087
|
+
const existingToolName = existingConfigFile.includes(".kimi") ? "Kimi Code"
|
|
2069
2088
|
: existingConfigFile.includes(".codex") ? "Codex"
|
|
2070
2089
|
: existingConfigFile.includes(".agents") ? "Antigravity CLI"
|
|
2071
2090
|
: existingConfigFile.includes("antigravity") ? "Antigravity"
|
|
@@ -2635,7 +2654,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2635
2654
|
console.log(` ${green}✓${r} Skills installed: ${dim}${join(kimiCodeHome, "skills")}${r} ${dim}(/flow:patchcord-inbox)${r}`);
|
|
2636
2655
|
} catch {}
|
|
2637
2656
|
} else if (isKimi) {
|
|
2638
|
-
// Kimi
|
|
2657
|
+
// Kimi Code (Python): per-project .kimi/mcp.json + shell wrapper for --mcp-config-file
|
|
2639
2658
|
const kimiDir = join(cwd, ".kimi");
|
|
2640
2659
|
const kimiPath = join(kimiDir, "mcp.json");
|
|
2641
2660
|
const kimiOk = updateJsonConfig(kimiPath, (obj) => {
|
|
@@ -2649,7 +2668,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2649
2668
|
};
|
|
2650
2669
|
});
|
|
2651
2670
|
if (kimiOk) {
|
|
2652
|
-
console.log(`\n ${green}✓${r} Kimi
|
|
2671
|
+
console.log(`\n ${green}✓${r} Kimi Code configured: ${dim}${kimiPath}${r}`);
|
|
2653
2672
|
console.log(` ${dim}Per-project — use the kimi-pc wrapper (see below) so Kimi loads this config.${r}`);
|
|
2654
2673
|
}
|
|
2655
2674
|
// Install/update global skills. Hyphen names → /flow:patchcord-inbox
|
|
@@ -2968,7 +2987,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2968
2987
|
}
|
|
2969
2988
|
}
|
|
2970
2989
|
|
|
2971
|
-
const toolName = isHermes ? "Hermes" : isKimiCode ? "Kimi Code" : isKimi ? "Kimi
|
|
2990
|
+
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
2991
|
|
|
2973
2992
|
if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isCline && !isKimi && !isHermes) {
|
|
2974
2993
|
console.log(`\n ${dim}To connect a second agent:${r}`);
|
|
@@ -2987,7 +3006,6 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2987
3006
|
process.exit(0);
|
|
2988
3007
|
}
|
|
2989
3008
|
|
|
2990
|
-
// ── channel: spawn the channel MCP server (used by .mcp.json) ──
|
|
2991
3009
|
// ── skill: custom skill from web console ─────────────────────
|
|
2992
3010
|
if (cmd === "skill") {
|
|
2993
3011
|
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
|
|