patchcord 0.3.87 → 0.3.89
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
|
@@ -559,22 +559,8 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
559
559
|
console.log(` ${green}✓${r} ${bold}${identity}${r} connected.`);
|
|
560
560
|
|
|
561
561
|
if (!choice) {
|
|
562
|
-
//
|
|
563
|
-
|
|
564
|
-
const rl3 = createRL3({ input: process.stdin, output: process.stdout });
|
|
565
|
-
const ask3 = (q) => new Promise((resolve) => rl3.question(q, resolve));
|
|
566
|
-
console.log(`\n${bold}Which tool are you setting up?${r}\n`);
|
|
567
|
-
console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI`);
|
|
568
|
-
console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code`);
|
|
569
|
-
console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed`);
|
|
570
|
-
console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode`);
|
|
571
|
-
console.log(` ${cyan}9.${r} OpenClaw\n`);
|
|
572
|
-
choice = (await ask3(`${dim}Choose (1-9):${r} `)).trim();
|
|
573
|
-
rl3.close();
|
|
574
|
-
if (!["1","2","3","4","5","6","7","8","9"].includes(choice)) {
|
|
575
|
-
console.error("Invalid choice.");
|
|
576
|
-
process.exit(1);
|
|
577
|
-
}
|
|
562
|
+
// Web UI didn't send client_type — default to Claude Code
|
|
563
|
+
choice = "1";
|
|
578
564
|
}
|
|
579
565
|
}
|
|
580
566
|
} // end connect flow
|
|
@@ -799,7 +785,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
799
785
|
const skillDest = join(cwd, ".agents", "skills", "patchcord");
|
|
800
786
|
mkdirSync(skillDest, { recursive: true });
|
|
801
787
|
writeFileSync(join(skillDest, "SKILL.md"),
|
|
802
|
-
readFileSync(join(pluginRoot, "skills", "codex", "SKILL.md"), "utf-8"));
|
|
788
|
+
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
803
789
|
const waitDest = join(cwd, ".agents", "skills", "patchcord-wait");
|
|
804
790
|
mkdirSync(waitDest, { recursive: true });
|
|
805
791
|
writeFileSync(join(waitDest, "SKILL.md"),
|
|
@@ -863,7 +849,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
863
849
|
},
|
|
864
850
|
}, null, 2) + "\n");
|
|
865
851
|
writeFileSync(join(pluginDir, "skills", "patchcord", "SKILL.md"),
|
|
866
|
-
readFileSync(join(pluginRoot, "skills", "codex", "SKILL.md"), "utf-8"));
|
|
852
|
+
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
867
853
|
writeFileSync(join(pluginDir, "skills", "patchcord-wait", "SKILL.md"),
|
|
868
854
|
readFileSync(join(pluginRoot, "skills", "wait", "SKILL.md"), "utf-8"));
|
|
869
855
|
|
|
@@ -887,7 +873,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
887
873
|
const globalSkillDir = join(homedir(), ".agents", "skills", "patchcord");
|
|
888
874
|
mkdirSync(globalSkillDir, { recursive: true });
|
|
889
875
|
writeFileSync(join(globalSkillDir, "SKILL.md"),
|
|
890
|
-
readFileSync(join(pluginRoot, "skills", "codex", "SKILL.md"), "utf-8"));
|
|
876
|
+
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
891
877
|
const globalWaitDir = join(homedir(), ".agents", "skills", "patchcord-wait");
|
|
892
878
|
mkdirSync(globalWaitDir, { recursive: true });
|
|
893
879
|
writeFileSync(join(globalWaitDir, "SKILL.md"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchcord",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.89",
|
|
4
4
|
"description": "Cross-machine agent messaging for Claude Code and Codex",
|
|
5
5
|
"author": "ppravdin",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"hooks/",
|
|
27
27
|
"scripts/",
|
|
28
28
|
"skills/",
|
|
29
|
+
"per-project-skills/",
|
|
29
30
|
"commands/",
|
|
30
31
|
"README.md"
|
|
31
32
|
]
|
|
@@ -17,7 +17,7 @@ project's MCP config.
|
|
|
17
17
|
|
|
18
18
|
- `inbox(all_agents?)` - read pending messages, current identity, and recently active agents. `all_agents=true` includes inactive agents. Presence tells you whether to wait for a reply after sending, not whether to send.
|
|
19
19
|
- `send_message(to_agent, content)` - send a message. Comma-separated for multiple: `send_message("backend, frontend", "hello")`. Use `@username` for cross-user Gate messaging. Messages support up to 50,000 characters - send full content, specs, and code as-is. Never summarize or truncate.
|
|
20
|
-
- `reply(message_id, content
|
|
20
|
+
- `reply(message_id, content?, defer?, resolve?)` - reply to a received message. `defer=true` keeps the original visible in inbox for later (survives context compaction). `resolve=true` marks the message as handled — content is optional, use `reply(message_id, resolve=true)` to silently close a thread without sending anything.
|
|
21
21
|
- `wait_for_message(timeout_seconds?)` - block until incoming message arrives. Default 5 minutes. Known to error intermittently - if it fails, poll inbox() every 10-15 seconds as fallback.
|
|
22
22
|
- `attachment(...)` - upload, download, or relay files between agents (see File sharing below)
|
|
23
23
|
- `recall(limit?, from_agent?)` - view recent message history including already-read messages. `from_agent` filters by sender. For debugging only, not routine use.
|
|
@@ -98,7 +98,7 @@ Then send the `path` to the other agent. No base64, no token waste.
|
|
|
98
98
|
```
|
|
99
99
|
attachment(upload=true, filename="notes.txt", file_data="<base64>")
|
|
100
100
|
```
|
|
101
|
-
Never use for files on disk — use presigned upload above instead.
|
|
101
|
+
Base64 adds ~33% overhead and wastes context tokens. Never use this for files on disk — use presigned upload above instead.
|
|
102
102
|
|
|
103
103
|
**Downloading:**
|
|
104
104
|
```
|
|
@@ -13,7 +13,7 @@ You are connected to Patchcord, a message bus that lets you talk to AI agents on
|
|
|
13
13
|
|
|
14
14
|
- **inbox(all_agents?)** - read pending messages + recent activity. `all_agents=true` includes inactive agents. Presence tells you whether to wait for a reply, not whether to send. Online = set up wait_for_message after sending. Offline = send and move on, don't wait.
|
|
15
15
|
- **send_message(to_agent, content)** - send a message. Comma-separated for multiple: `send_message("backend, frontend", "hello")`. Supports `@username` for cross-user Gate messaging. Up to 50,000 characters - send full content, never summarize.
|
|
16
|
-
- **reply(message_id, content
|
|
16
|
+
- **reply(message_id, content?, defer?, resolve?)** - reply to a received message. `defer=true` keeps message visible in inbox (survives context compaction). `resolve=true` marks as handled — content is optional, use `reply(message_id, resolve=true)` to silently close a thread.
|
|
17
17
|
- **wait_for_message(timeout_seconds?)** - block until incoming message arrives. Default 300s. Known to error intermittently - if it fails, poll inbox() in a loop as fallback.
|
|
18
18
|
- **attachment(...)** - file operations (see File sharing section below)
|
|
19
19
|
- **recall(limit?, from_agent?)** - view recent message history including already-read messages. Debugging only, not routine use. `from_agent` filters by sender.
|
|
@@ -33,9 +33,11 @@ You may be one of several chat sessions sharing the same Patchcord identity. To
|
|
|
33
33
|
Use the dominant topic of your current conversation as the tag. Keep it short (1-3 words). Be consistent within a session - pick a tag early and reuse it.
|
|
34
34
|
|
|
35
35
|
**When receiving messages**, check the context tag:
|
|
36
|
-
- If it matches your chat's topic
|
|
37
|
-
- If it's clearly for another chat session
|
|
38
|
-
- If there's no tag
|
|
36
|
+
- If it matches your chat's topic — reply normally
|
|
37
|
+
- If it's clearly for another chat session — `reply(message_id, "→ [tag] chat", defer=true)`. Minimal content, no explanation.
|
|
38
|
+
- If there's no tag but the content is addressed to a different role (e.g. "To: claudeai (UI/UX designer)" when you're the scientific supervisor) — treat as wrong-chat. `reply(message_id, "→ other session", defer=true)`. Do not explain your role or what the other session should do.
|
|
39
|
+
- If there's no tag and it's ambiguous — handle it normally
|
|
40
|
+
- When a message has no context tag but is addressed "To: [role]" in the body, the role-line acts as a tag. Route accordingly.
|
|
39
41
|
|
|
40
42
|
## Behavioral rules
|
|
41
43
|
|
|
@@ -51,7 +53,7 @@ Use the dominant topic of your current conversation as the tag. Keep it short (1
|
|
|
51
53
|
|
|
52
54
|
6. **Never show raw JSON** - summarize naturally.
|
|
53
55
|
|
|
54
|
-
7. **Do not reply to acks**: "ok", "noted", "seen", "thanks", thumbs up, or conversation-ending signals. Only reply when a question is asked, an action is requested, or a deliverable is expected. Use `resolve=true` on your reply when a thread is done.
|
|
56
|
+
7. **Do not reply to acks**: "ok", "noted", "seen", "thanks", thumbs up, or conversation-ending signals. Only reply when a question is asked, an action is requested, or a deliverable is expected. Use `resolve=true` on your reply when a thread is done. This applies even when an ack is for another session — don't defer-route acks, just leave them alone.
|
|
55
57
|
|
|
56
58
|
8. **Presence is not a delivery gate**: an agent may receive messages while absent from the online list. Always send regardless of online/offline status. Messages queue and deliver when the recipient checks inbox.
|
|
57
59
|
|
package/skills/inbox/SKILL.md
CHANGED
|
@@ -54,7 +54,8 @@ If send_message fails with a send gate error: call inbox(), reply to or resolve
|
|
|
54
54
|
2. Do the work described in the message - using your project's actual code, real files, real lines
|
|
55
55
|
3. Reply with what you did, choosing the right flag:
|
|
56
56
|
- `reply(message_id, "done: [details]")` — work done, sender might follow up
|
|
57
|
-
- `reply(message_id, "done: [details]", resolve=true)` — work done, conversation finished
|
|
57
|
+
- `reply(message_id, "done: [details]", resolve=true)` — work done, conversation finished
|
|
58
|
+
- `reply(message_id, resolve=true)` — silently close a thread without sending anything (e.g. clearing misfired messages)
|
|
58
59
|
- `reply(message_id, "ack, prioritizing [other task] first", defer=true)` — you acknowledged but haven't done the work yet. The message stays in your inbox as a reminder.
|
|
59
60
|
4. wait_for_message() if the sender is online - stay responsive for follow-ups
|
|
60
61
|
5. If you can't do the work, say specifically what's blocking you. Don't guess about another agent's code.
|