patchcord 0.5.81 → 0.5.83

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
@@ -1106,24 +1106,19 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1106
1106
 
1107
1107
  // Remove existing patchcord session-start hook blocks
1108
1108
  const segments2 = kimiConfig.split("[[hooks]]");
1109
- const kept2 = segments2.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-session-start"));
1109
+ const kept2 = segments2.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-session-start") && !seg.includes("patchcord-prompt-hook"));
1110
1110
  kimiConfig = kept2.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
1111
1111
 
1112
- // Install UserPromptSubmit hook legacy compatibility for /skill:patchcord:*
1113
- const kimiPromptSrc = join(pluginRoot, "scripts", "kimi-prompt-hook.sh");
1112
+ // Remove the legacy UserPromptSubmit shim script if a prior install left it.
1113
+ // Kimi displays stderr to the user but does not feed it to the LLM, so the
1114
+ // shim never auto-executed anything — flow skills handle slash invocations.
1114
1115
  const kimiPromptDest = join(HOME, ".kimi", "patchcord-prompt-hook.sh");
1115
- if (existsSync(kimiPromptSrc)) {
1116
- copyFileSync(kimiPromptSrc, kimiPromptDest);
1117
- chmodSync(kimiPromptDest, 0o755);
1116
+ if (existsSync(kimiPromptDest)) {
1117
+ try { rmSync(kimiPromptDest, { force: true }); } catch {}
1118
1118
  }
1119
1119
 
1120
- // Remove existing patchcord prompt hook blocks
1121
- const segments3 = kimiConfig.split("[[hooks]]");
1122
- const kept3 = segments3.filter((seg, idx) => idx === 0 || !seg.includes("patchcord-prompt-hook"));
1123
- kimiConfig = kept3.join("[[hooks]]").replace(/\n{3,}/g, "\n\n").trim();
1124
-
1125
1120
  // Append new hooks
1126
- kimiConfig = kimiConfig.trimEnd() + `\n\n[[hooks]]\nevent = "UserPromptSubmit"\ncommand = "${kimiPromptDest}"\ntimeout = 5\n\n[[hooks]]\nevent = "SessionStart"\ncommand = "${kimiSessionDest}"\ntimeout = 10\n\n[[hooks]]\nevent = "Stop"\ncommand = "${kimiHookDest}"\ntimeout = 10\n`;
1121
+ kimiConfig = kimiConfig.trimEnd() + `\n\n[[hooks]]\nevent = "SessionStart"\ncommand = "${kimiSessionDest}"\ntimeout = 10\n\n[[hooks]]\nevent = "Stop"\ncommand = "${kimiHookDest}"\ntimeout = 10\n`;
1127
1122
 
1128
1123
  mkdirSync(dirname(kimiConfigPath), { recursive: true });
1129
1124
  writeFileSync(kimiConfigPath, kimiConfig);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.81",
3
+ "version": "0.5.83",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -1,15 +1,12 @@
1
1
  ---
2
2
  name: patchcord:inbox
3
3
  description: Read Patchcord inbox and reply to messages
4
+ type: flow
4
5
  ---
5
6
 
6
- 1. Run `inbox()`
7
- 2. For each pending message: do the work, then `reply(message_id, "what I did")`
8
- 3. Re-arm listener:
9
- ```
10
- Shell:
11
- command: patchcord subscribe --kimi 5
12
- run_in_background: true
13
- description: Patchcord inbox polling
14
- timeout: 86400
7
+ ```mermaid
8
+ flowchart TD
9
+ A([BEGIN]) --> B[Call the inbox MCP tool. For each pending message: do the work it asks for, then call reply with the message_id and a concrete summary of what you did.]
10
+ B --> C[Use the Shell tool to run `patchcord subscribe --kimi 5` with run_in_background=true and timeout=86400 to re-arm the listener.]
11
+ C --> D([END])
15
12
  ```
@@ -1,24 +1,11 @@
1
1
  ---
2
2
  name: patchcord:subscribe
3
- description: >
4
- Start a background polling task that wakes Kimi when new Patchcord messages
5
- arrive. Use when the user asks about notifications, background listening,
6
- or when you need to re-arm the listener after reading messages.
3
+ description: Start the Patchcord background polling listener
4
+ type: flow
7
5
  ---
8
6
 
9
- # patchcord:subscribe
10
-
11
- Run this exact background Shell task:
12
-
7
+ ```mermaid
8
+ flowchart TD
9
+ A([BEGIN]) --> B[Use the Shell tool to run `patchcord subscribe --kimi 5` with run_in_background=true and timeout=86400. Then tell the user in one sentence: Patchcord listener active.]
10
+ B --> C([END])
13
11
  ```
14
- Shell:
15
- command: patchcord subscribe --kimi 5
16
- run_in_background: true
17
- description: Patchcord inbox polling
18
- timeout: 86400
19
- ```
20
-
21
- - `command: patchcord subscribe --kimi 5` — forces Kimi polling mode and polls inbox every **5 seconds**
22
- - `timeout: 86400` — runs for **24 hours** (maximum). Always 86400, never anything else.
23
- - One-shot: exits with code 2 when messages found, triggering Kimi auto-run
24
- - Must re-arm after every `inbox()` or `wait_for_message()` call by running the exact same command again
@@ -1,31 +1,15 @@
1
1
  ---
2
2
  name: patchcord:wait
3
- description: >
4
- Block this turn for up to 5 minutes waiting for one incoming Patchcord
5
- message via the wait_for_message MCP tool. Single blocking call, no
6
- background process. Use ONLY when the user explicitly runs /patchcord:wait
7
- or asks you to wait for a patchcord message.
3
+ description: Wait for one incoming Patchcord message
4
+ type: flow
8
5
  ---
9
6
 
10
- # patchcord:wait
11
-
12
- User invoked /patchcord:wait or asked you to wait for a Patchcord message. Use `wait_for_message()` only. Do NOT spawn a background listener.
13
-
14
- Call `wait_for_message()` to block until a message arrives (up to 5 minutes).
15
-
16
- When a message arrives:
17
-
18
- 1. Read it — the tool returns from, content, and message_id. If it belongs to a thread, `thread` and `thread_id` will be set.
19
- 2. **Re-arm the background listener** — see `patchcord:subscribe` skill for how to run `patchcord subscribe --kimi 5` so the next message will also wake you up.
20
- 3. Do the work described in the message first. Update the file, write the code, fix the bug — whatever it asks.
21
- 4. Reply with what you did: `reply(message_id, "here's what I changed: [concrete details]")`. Thread is auto-inherited. Use `resolve=true` to close the thread when the task is fully done.
22
- 5. Tell the human who wrote and what you did about it
23
- 6. Call `wait_for_message()` again to keep listening
24
-
25
- Loop until timeout or the human interrupts.
26
-
27
- If `wait_for_message()` errors, fall back to polling `inbox()` every 10-15 seconds instead of stopping the loop.
28
-
29
- Do not ask the human for permission to reply — just do the work, reply with results, then report.
30
-
31
- **No ack chains.** If the arriving message is a clear ack ("Noted", "Got it", "Thanks", "Keep running") — close it silently with `reply(id, resolve=true)`, no content, and keep listening. Never text-reply to an ack. Never send "Noted" + resolve=true — that creates a new pending message the other side will feel compelled to answer.
7
+ ```mermaid
8
+ flowchart TD
9
+ A([BEGIN]) --> B[Call the wait_for_message MCP tool to block until a message arrives or 5 minutes elapse.]
10
+ B --> C{Message arrived?}
11
+ C -->|Yes| D[Do the work the message asks for, then call reply with the message_id and a concrete summary.]
12
+ C -->|No| E([END])
13
+ D --> F[Use the Shell tool to run `patchcord subscribe --kimi 5` with run_in_background=true and timeout=86400 to re-arm the listener.]
14
+ F --> E
15
+ ```
@@ -60,12 +60,14 @@ fi
60
60
  PIDFILE="/tmp/patchcord_subscribe_${NAMESPACE_ID}_${AGENT_ID}.pid"
61
61
  NOTIFY_FILE="${HOME}/.kimi/patchcord-subscribe-notify.txt"
62
62
 
63
- # Pidfile guard: exit if another instance is running
63
+ # Pidfile guard: if another instance is already running, that's the desired
64
+ # state (typically the SessionStart hook armed the listener). Exit 0 so flow
65
+ # skill invocations don't surface as "background task failed".
64
66
  if [ -f "$PIDFILE" ]; then
65
67
  OLD_PID=$(cat "$PIDFILE" 2>/dev/null || echo "")
66
68
  if [ -n "$OLD_PID" ] && kill -0 "$OLD_PID" 2>/dev/null; then
67
- echo "Already running (pid $OLD_PID)" >&2
68
- exit 2
69
+ echo "Patchcord listener already running (pid $OLD_PID)"
70
+ exit 0
69
71
  fi
70
72
  fi
71
73
  echo $$ > "$PIDFILE"
@@ -1,39 +0,0 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
-
4
- # UserPromptSubmit hook for Kimi CLI — intercepts legacy /skill:patchcord:*
5
- # prompts and gives Kimi a concrete correction. This is a compatibility shim;
6
- # SessionStart + Stop hooks are the primary Kimi integration.
7
- #
8
- # Kimi silently discards stdout from UserPromptSubmit hooks, but exit 2 + stderr
9
- # is fed back to the LLM as a correction. We exploit this to turn /skill: into
10
- # direct command execution.
11
-
12
- command -v jq >/dev/null 2>&1 || exit 0
13
-
14
- if [ -t 0 ]; then
15
- INPUT=""
16
- else
17
- INPUT=$(cat)
18
- fi
19
- PROMPT=$(echo "$INPUT" | jq -r '.prompt // ""' 2>/dev/null || echo "")
20
-
21
- # Map /skill:patchcord:* to direct command corrections. Kimi Skills are
22
- # documentation, not executable slash commands.
23
- case "$PROMPT" in
24
- */skill:patchcord:subscribe*)
25
- echo "Start the Patchcord listener immediately as a background Shell task: command 'patchcord subscribe --kimi 5', run_in_background true, timeout 86400. Do not run it in the foreground." >&2
26
- exit 2
27
- ;;
28
- */skill:patchcord:inbox*)
29
- echo "Execute immediately: call inbox(), do the requested work for each pending message, reply(), then re-arm Patchcord with a background Shell task: patchcord subscribe --kimi 5." >&2
30
- exit 2
31
- ;;
32
- */skill:patchcord:wait*)
33
- echo "Execute immediately: call wait_for_message() once. If a message arrives, do the work, reply(), then re-arm Patchcord with a background Shell task: patchcord subscribe --kimi 5." >&2
34
- exit 2
35
- ;;
36
- *)
37
- exit 0
38
- ;;
39
- esac