patchcord 0.5.111 → 0.5.112

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
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync, mkdirSync, cpSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
3
+ import { existsSync, mkdirSync, cpSync, readdirSync, readFileSync, writeFileSync, unlinkSync, rmSync } from "fs";
4
4
  import { join, dirname, basename } from "path";
5
5
  import { fileURLToPath } from "url";
6
6
  import { execSync } from "child_process";
@@ -1563,29 +1563,60 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1563
1563
  if (windsurfChanged) globalChanges.push("Windsurf skills installed");
1564
1564
  }
1565
1565
 
1566
- // Gemini CLI
1566
+ // Gemini CLI + Antigravity (they SHARE ~/.gemini/skills and ~/.gemini/commands).
1567
+ // Seed the patchcord skill ONLY when patchcord MCP is actually configured for
1568
+ // one of these surfaces. Otherwise a bare session (esp. Antigravity, which
1569
+ // inherits this dir) reads a skill with no backing MCP tool and improvises
1570
+ // destructively — scavenging other agents' bearer tokens off disk and curling
1571
+ // the API. Invariant: skill present ⟺ patchcord MCP present under ~/.gemini.
1567
1572
  if (existsSync(join(HOME, ".gemini"))) {
1573
+ // true = configured, false = file absent (definitely not), null = unparseable (unknown)
1574
+ const hasPatchcordMcp = (p, keyPath) => {
1575
+ if (!existsSync(p)) return false;
1576
+ try { return !!keyPath.reduce((o, k) => o?.[k], JSON.parse(readFileSync(p, "utf-8"))); }
1577
+ catch { return null; }
1578
+ };
1579
+ const checks = [
1580
+ hasPatchcordMcp(join(HOME, ".gemini", "settings.json"), ["mcpServers", "patchcord"]),
1581
+ hasPatchcordMcp(join(HOME, ".gemini", "antigravity", "mcp_config.json"), ["mcpServers", "patchcord"]),
1582
+ hasPatchcordMcp(join(HOME, ".gemini", "antigravity-cli", "mcp_config.json"), ["mcpServers", "patchcord"]),
1583
+ ];
1584
+ const mcpConfigured = checks.some((c) => c === true);
1585
+ const mcpUnknown = checks.some((c) => c === null);
1568
1586
  const geminiSkillDir = join(HOME, ".gemini", "skills", "patchcord");
1569
1587
  const geminiWaitDir = join(HOME, ".gemini", "skills", "patchcord-wait");
1570
1588
  const geminiCmdDir = join(HOME, ".gemini", "commands");
1571
- let geminiChanged = false;
1572
- if (!existsSync(geminiSkillDir)) {
1573
- mkdirSync(geminiSkillDir, { recursive: true });
1574
- cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(geminiSkillDir, "SKILL.md"));
1575
- geminiChanged = true;
1576
- }
1577
- if (!existsSync(geminiWaitDir)) {
1578
- mkdirSync(geminiWaitDir, { recursive: true });
1579
- cpSync(join(pluginRoot, "skills", "wait", "SKILL.md"), join(geminiWaitDir, "SKILL.md"));
1580
- geminiChanged = true;
1581
- }
1582
- if (!existsSync(join(geminiCmdDir, "inbox.toml"))) {
1583
- mkdirSync(geminiCmdDir, { recursive: true });
1584
- cpSync(join(pluginRoot, "commands", "inbox.toml"), join(geminiCmdDir, "inbox.toml"));
1585
- cpSync(join(pluginRoot, "commands", "wait.toml"), join(geminiCmdDir, "wait.toml"));
1586
- geminiChanged = true;
1587
- }
1588
- if (geminiChanged) globalChanges.push("Gemini CLI skills + commands installed");
1589
+ if (mcpConfigured) {
1590
+ let geminiChanged = false;
1591
+ if (!existsSync(geminiSkillDir)) {
1592
+ mkdirSync(geminiSkillDir, { recursive: true });
1593
+ cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(geminiSkillDir, "SKILL.md"));
1594
+ geminiChanged = true;
1595
+ }
1596
+ if (!existsSync(geminiWaitDir)) {
1597
+ mkdirSync(geminiWaitDir, { recursive: true });
1598
+ cpSync(join(pluginRoot, "skills", "wait", "SKILL.md"), join(geminiWaitDir, "SKILL.md"));
1599
+ geminiChanged = true;
1600
+ }
1601
+ if (!existsSync(join(geminiCmdDir, "inbox.toml"))) {
1602
+ mkdirSync(geminiCmdDir, { recursive: true });
1603
+ cpSync(join(pluginRoot, "commands", "inbox.toml"), join(geminiCmdDir, "inbox.toml"));
1604
+ cpSync(join(pluginRoot, "commands", "wait.toml"), join(geminiCmdDir, "wait.toml"));
1605
+ geminiChanged = true;
1606
+ }
1607
+ if (geminiChanged) globalChanges.push("Gemini CLI skills + commands installed");
1608
+ } else if (!mcpUnknown) {
1609
+ // Definitively no patchcord MCP under ~/.gemini → remove any previously
1610
+ // seeded skill so a bare Gemini/Antigravity session has nothing to act on.
1611
+ let removed = false;
1612
+ for (const d of [geminiSkillDir, geminiWaitDir]) {
1613
+ if (existsSync(d)) { try { rmSync(d, { recursive: true, force: true }); removed = true; } catch {} }
1614
+ }
1615
+ for (const f of [join(geminiCmdDir, "inbox.toml"), join(geminiCmdDir, "wait.toml")]) {
1616
+ if (existsSync(f)) { try { unlinkSync(f); removed = true; } catch {} }
1617
+ }
1618
+ if (removed) globalChanges.push("Removed stale Gemini/Antigravity patchcord skills (no patchcord MCP configured there)");
1619
+ }
1589
1620
  }
1590
1621
 
1591
1622
  // Kimi CLI
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.111",
3
+ "version": "0.5.112",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -10,6 +10,18 @@ description: >
10
10
 
11
11
  7 MCP tools: inbox, send_message, reply, wait_for_message, attachment, recall, unsend.
12
12
 
13
+ ## Applies ONLY when the patchcord MCP tools are loaded this session
14
+
15
+ This skill governs those 7 MCP tools. It applies only if they are actually available in the current session.
16
+
17
+ **If the patchcord MCP tools are NOT present, this skill does not apply — do nothing with it. Specifically:**
18
+ - Do NOT call inbox() at session start or at any other time.
19
+ - Do NOT run the `patchcord` CLI as a substitute for the missing tools.
20
+ - Do NOT read a bearer token out of `.mcp.json`, `settings.json`, `mcp_config.json`, or any other config file, and do NOT call the patchcord HTTP API (`/api/inbox`, etc.) directly. A token belongs to the one agent it was issued to; using another agent's token — or any token you found on disk — is never correct.
21
+ - Just proceed with the user's actual request.
22
+
23
+ A missing tool means patchcord is not configured for this agent. That is a normal, silent state, not a problem to work around.
24
+
13
25
  ## Do the work, never just acknowledge
14
26
 
15
27
  When you receive a message from another agent:
@@ -117,7 +129,7 @@ Always send the storage path (not the file content) to the other agent.
117
129
 
118
130
  ## Identity (`patchcord whoami` / `patchcord agents`)
119
131
 
120
- `whoami` and `agents` are CLI commands, not MCP tools. They use the bearer token from the project's `.mcp.json` — same namespace scope, no extra setup. Cheap to call (input tokens only), don't bloat MCP.
132
+ `whoami` and `agents` are CLI commands, not MCP tools. Run them only when the patchcord MCP tools are present (see the gate at the top of this skill). They read the bearer token from the **current project's own** `.mcp.json` automatically — same namespace scope, no extra setup. Never go hunting for a token in another project's config or another agent's file, and never pass a token on the command line. Cheap to call (input tokens only), don't bloat MCP.
121
133
 
122
134
  - **Run `patchcord whoami` once per session.** Returns your `agent`, `namespace`, project summary, and your 300-char `self` description. Use it on first turn after `/clear` or a fresh session to orient.
123
135
  - **Run `patchcord agents`** to see the full roster (every peer's whoami). One call, ~3KB, complete picture of the namespace.
@@ -8,6 +8,8 @@ description: >
8
8
  ---
9
9
  # patchcord:wait
10
10
 
11
+ Applies ONLY when the patchcord MCP tools are loaded this session. If `wait_for_message` is not available, this skill does not apply — do nothing, do not substitute the CLI or direct HTTP calls, and never read a bearer token out of a config file. Proceed with the user's request.
12
+
11
13
  User invoked /patchcord:wait — do NOT substitute /patchcord:subscribe or spawn any background listener. Use `wait_for_message()` only.
12
14
 
13
15
  Call `wait_for_message()` to block until a message arrives (up to 5 minutes).