patchcord 0.5.113 → 0.5.115

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
@@ -294,6 +294,7 @@ async function _resolveBearer(options = {}) {
294
294
  (cwd) => readJsonAt(join(cwd, ".cursor", "mcp.json"), ["mcpServers", "patchcord"], "cursor"),
295
295
  (cwd) => readJsonAt(join(cwd, ".vscode", "mcp.json"), ["servers", "patchcord"], "vscode"),
296
296
  (cwd) => readJsonAt(join(cwd, "opencode.json"), ["mcp", "patchcord"], "opencode"),
297
+ (cwd) => readJsonAt(join(cwd, ".agents", "mcp_config.json"), ["mcpServers", "patchcord"], "antigravity"),
297
298
  (cwd) => readCodexTomlShape(join(cwd, ".codex", "config.toml")),
298
299
  ];
299
300
  const projectReaders = preferKimi
@@ -944,6 +945,15 @@ if (cmd === "login" || cmd === "teamlead" || cmd === "provision" || cmd === "tea
944
945
  o.mcp.patchcord = { type: "remote", url: `${baseUrl}/mcp`, headers: hdr };
945
946
  });
946
947
  }
948
+ if (tool === "antigravity" || tool === "agy") {
949
+ // Antigravity CLI: PROJECT-scoped config at .agents/mcp_config.json (one
950
+ // project = one namespace = one agent). Remote HTTP uses `serverUrl`.
951
+ const adir = join(dir, ".agents"); mkdirSync(adir, { recursive: true });
952
+ return writeJson(join(adir, "mcp_config.json"), (o) => {
953
+ o.mcpServers = o.mcpServers || {};
954
+ o.mcpServers.patchcord = { serverUrl: `${baseUrl}/mcp`, headers: hdr };
955
+ });
956
+ }
947
957
  // default: claude_code. type:"http" is REQUIRED — without it Claude Code
948
958
  // defaults to stdio transport and rejects the entry ("command: expected
949
959
  // string, received undefined").
@@ -1075,7 +1085,7 @@ you design the team, provision its agents, launch them, and manage them.
1075
1085
  if (!manifest) { console.error("No .patchcord/team.json here — cd into the project root."); process.exit(1); }
1076
1086
  const ns = manifest.namespace;
1077
1087
  const real = (p) => run(`realpath -m ${JSON.stringify(p)}`) || p;
1078
- const AGENT_CMDS = /(^|\/)(claude|codex|kimi|kimi-code|opencode|gemini|node)$/;
1088
+ const AGENT_CMDS = /(^|\/)(claude|codex|kimi|kimi-code|opencode|gemini|agy|node)$/;
1079
1089
 
1080
1090
  // Token reader for a specific folder + tool (folder IS the identity).
1081
1091
  const tokenInDir = (tool, dir) => {
@@ -1184,7 +1194,7 @@ you design the team, provision its agents, launch them, and manage them.
1184
1194
  const tmuxOut = run(`tmux list-panes -a -F '#{pane_current_path}\t#{pane_current_command}'`);
1185
1195
  if (tmuxOut) for (const l of tmuxOut.split("\n").filter(Boolean)) {
1186
1196
  const [path, cmd] = l.split("\t");
1187
- if (/(^|\/)(claude|codex|kimi|kimi-code|opencode|gemini|node)$/.test("/" + cmd)) running.add(real(path));
1197
+ if (/(^|\/)(claude|codex|kimi|kimi-code|opencode|gemini|agy|node)$/.test("/" + cmd)) running.add(real(path));
1188
1198
  }
1189
1199
  for (const a of (manifest.agents || [])) {
1190
1200
  const dir = join(process.cwd(), a.dir || a.agent);
@@ -1192,7 +1202,7 @@ you design the team, provision its agents, launch them, and manage them.
1192
1202
  console.log(` ${M.dim}skip ${a.agent} — already running in ${dir}; relaunch-for-identity must resume in place, not fresh-launch (see team-ops skill).${M.rst}`);
1193
1203
  continue;
1194
1204
  }
1195
- const muxTool = a.tool === "claude_code" ? "claude" : (a.tool === "kimi-code" ? "kimi" : a.tool);
1205
+ const muxTool = a.tool === "claude_code" ? "claude" : (a.tool === "kimi-code" ? "kimi" : (a.tool === "antigravity" || a.tool === "agy") ? "agy" : a.tool);
1196
1206
  console.log(` launching ${a.agent} (${muxTool}) in ${dir}`);
1197
1207
  spawnSync("mux", ["new", muxTool, "--dir", dir], { stdio: "inherit" });
1198
1208
  }
@@ -1618,6 +1628,27 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1618
1628
  }
1619
1629
  }
1620
1630
 
1631
+ // Hermes — refresh patchcord skills to the current version on every run, so
1632
+ // skill fixes land via `patchcord update` (the interactive choice 13 only
1633
+ // installs them once). ~/.hermes/skills is Hermes-only, so no leak risk; only
1634
+ // refresh when the integrations dir already exists (Hermes was set up before).
1635
+ {
1636
+ const hermesSkillsSrc = join(pluginRoot, "per-project-skills", "hermes");
1637
+ const hermesSkillsDest = join(HOME, ".hermes", "skills", "integrations");
1638
+ if (existsSync(hermesSkillsDest) && existsSync(hermesSkillsSrc)) {
1639
+ let hermesChanged = false;
1640
+ for (const name of readdirSync(hermesSkillsSrc)) {
1641
+ const src = join(hermesSkillsSrc, name, "SKILL.md");
1642
+ if (!existsSync(src)) continue;
1643
+ const dest = join(hermesSkillsDest, name, "SKILL.md");
1644
+ const want = readFileSync(src, "utf-8");
1645
+ let cur = ""; try { cur = readFileSync(dest, "utf-8"); } catch {}
1646
+ if (cur !== want) { mkdirSync(dirname(dest), { recursive: true }); writeFileSync(dest, want); hermesChanged = true; }
1647
+ }
1648
+ if (hermesChanged) globalChanges.push("Hermes patchcord skills refreshed");
1649
+ }
1650
+ }
1651
+
1621
1652
  // Kimi CLI
1622
1653
  const hasKimi = run("which kimi");
1623
1654
  if (hasKimi) {
@@ -1854,7 +1885,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1854
1885
  if (!choice) {
1855
1886
  console.log(`\n${bold}Which tool are you setting up?${r}\n`);
1856
1887
  console.log(` ${cyan}1.${r} Claude Code ${cyan}5.${r} Gemini CLI ${cyan}9.${r} OpenClaw`);
1857
- console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code ${cyan}10.${r} Antigravity`);
1888
+ console.log(` ${cyan}2.${r} Codex CLI ${cyan}6.${r} VS Code ${cyan}10.${r} Antigravity CLI`);
1858
1889
  console.log(` ${cyan}3.${r} Cursor ${cyan}7.${r} Zed ${cyan}11.${r} Cline`);
1859
1890
  console.log(` ${cyan}4.${r} Windsurf ${cyan}8.${r} OpenCode ${cyan}12.${r} Kimi CLI`);
1860
1891
  console.log(` ${cyan}13.${r} Hermes\n`);
@@ -1942,6 +1973,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
1942
1973
  // Figure out which tool is already configured
1943
1974
  const existingToolName = existingConfigFile.includes(".kimi") ? "Kimi CLI"
1944
1975
  : existingConfigFile.includes(".codex") ? "Codex"
1976
+ : existingConfigFile.includes(".agents") ? "Antigravity CLI"
1945
1977
  : existingConfigFile.includes("antigravity") ? "Antigravity"
1946
1978
  : existingConfigFile.includes("openclaw") ? "OpenClaw"
1947
1979
  : existingConfigFile.includes(".cursor") ? "Cursor"
@@ -2393,9 +2425,13 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2393
2425
  console.log(` ${dim}for streamable-http. Update to v2026.3.31+ or use mcp-remote:${r}`);
2394
2426
  console.log(` ${dim}openclaw mcp set patchcord '{"command":"npx","args":["mcp-remote","${serverUrl}/mcp","--header","Authorization: Bearer ${token}"],"transport":"stdio"}'${r}`);
2395
2427
  } else if (isAntigravity) {
2396
- // Antigravity: global ~/.gemini/antigravity/mcp_config.json → mcpServers
2397
- const agDir = join(HOME, ".gemini", "antigravity");
2398
- const agPath = join(agDir, "mcp_config.json");
2428
+ // Antigravity CLI: PROJECT-scoped config at <project>/.agents/mcp_config.json
2429
+ // (one project = one namespace = one agent identity — never global, which
2430
+ // would give one shared agent cross-project visibility). Remote HTTP uses
2431
+ // the `serverUrl` key. Skills are NOT seeded globally here: a stray skill in
2432
+ // the shared ~/.gemini/skills makes bare agy sessions improvise. The MCP
2433
+ // server injects its own instructions once connected.
2434
+ const agPath = join(cwd, ".agents", "mcp_config.json");
2399
2435
  const agOk = updateJsonConfig(agPath, (obj) => {
2400
2436
  obj.mcpServers = obj.mcpServers || {};
2401
2437
  obj.mcpServers.patchcord = {
@@ -2407,16 +2443,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2407
2443
  };
2408
2444
  });
2409
2445
  if (agOk) {
2410
- console.log(`\n ${green}✓${r} Antigravity configured: ${dim}${agPath}${r}`);
2411
- // Install global skills
2412
- const agSkillDir = join(agDir, "skills", "patchcord");
2413
- const agWaitDir = join(agDir, "skills", "patchcord-wait");
2414
- mkdirSync(agSkillDir, { recursive: true });
2415
- mkdirSync(agWaitDir, { recursive: true });
2416
- cpSync(join(pluginRoot, "skills", "inbox", "SKILL.md"), join(agSkillDir, "SKILL.md"));
2417
- cpSync(join(pluginRoot, "skills", "wait", "SKILL.md"), join(agWaitDir, "SKILL.md"));
2418
- console.log(` ${green}✓${r} Skills installed: ${dim}patchcord${r}, ${dim}patchcord-wait${r}`);
2419
- console.log(` ${yellow}Global config — all Antigravity projects share this agent.${r}`);
2446
+ console.log(`\n ${green}✓${r} Antigravity CLI configured: ${dim}${agPath}${r}`);
2447
+ console.log(` ${yellow}Project config this agent is scoped to ${cwd}.${r}`);
2448
+ console.log(` ${dim}Verify in agy with the /mcp slash command.${r}`);
2420
2449
  }
2421
2450
  } else if (isCline) {
2422
2451
  // Cline VS Code extension: global cline_mcp_settings.json
@@ -2815,9 +2844,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2815
2844
  // Auto-add per-project configs with tokens to .gitignore (don't just warn —
2816
2845
  // a committed token gets clobbered/reverted by git and silently breaks auth).
2817
2846
  // Hermes is global config (~/.hermes/config.yaml) — no per-project file to ignore.
2818
- if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline && !isHermes) {
2847
+ if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isCline && !isHermes) {
2819
2848
  const gitignorePath = join(cwd, ".gitignore");
2820
- const configFile = isKimiCode ? ".kimi-code/mcp.json" : isKimi ? ".kimi/mcp.json" : isCodex ? ".codex/config.toml" : isCursor ? ".cursor/mcp.json" : isVSCode ? ".vscode/mcp.json" : isOpenCode ? "opencode.json" : ".mcp.json";
2849
+ const configFile = isKimiCode ? ".kimi-code/mcp.json" : isKimi ? ".kimi/mcp.json" : isCodex ? ".codex/config.toml" : isCursor ? ".cursor/mcp.json" : isVSCode ? ".vscode/mcp.json" : isOpenCode ? "opencode.json" : isAntigravity ? ".agents/mcp_config.json" : ".mcp.json";
2821
2850
  // Forms that already cover this config (its file or its dir)
2822
2851
  const patterns = [configFile];
2823
2852
  if (isKimiCode) patterns.push(".kimi-code/");
@@ -2825,6 +2854,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2825
2854
  else if (isCodex) patterns.push(".codex/");
2826
2855
  else if (isCursor) patterns.push(".cursor/");
2827
2856
  else if (isVSCode) patterns.push(".vscode/");
2857
+ else if (isAntigravity) patterns.push(".agents/");
2828
2858
 
2829
2859
  const hasGitignore = existsSync(gitignorePath);
2830
2860
  // Only touch .gitignore inside a real git repo, or where one already exists.
@@ -2844,9 +2874,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
2844
2874
  }
2845
2875
  }
2846
2876
 
2847
- const toolName = isHermes ? "Hermes" : isKimiCode ? "Kimi Code" : isKimi ? "Kimi CLI" : isAntigravity ? "Antigravity" : isCline ? "Cline" : isOpenClaw ? "OpenClaw" : isOpenCode ? "OpenCode" : isZed ? "Zed" : isVSCode ? "VS Code" : isGemini ? "Gemini CLI" : isWindsurf ? "Windsurf" : isCursor ? "Cursor" : isCodex ? "Codex" : "Claude Code";
2877
+ const toolName = isHermes ? "Hermes" : isKimiCode ? "Kimi Code" : isKimi ? "Kimi CLI" : 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";
2848
2878
 
2849
- if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isAntigravity && !isCline && !isKimi && !isHermes) {
2879
+ if (!isWindsurf && !isGemini && !isZed && !isOpenClaw && !isCline && !isKimi && !isHermes) {
2850
2880
  console.log(`\n ${dim}To connect a second agent:${r}`);
2851
2881
  console.log(` ${dim}cd into another project and run${r} ${bold}npx patchcord@latest${r} ${dim}there.${r}`);
2852
2882
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchcord",
3
- "version": "0.5.113",
3
+ "version": "0.5.115",
4
4
  "description": "Cross-machine agent messaging for Claude Code and Codex",
5
5
  "author": "ppravdin",
6
6
  "license": "MIT",
@@ -9,6 +9,8 @@ metadata:
9
9
  ---
10
10
  # Patchcord — inbox
11
11
 
12
+ Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI as a substitute, do not read a bearer token from a config file, do not call the API directly, and do not web-search for setup. Just proceed with the user's request.
13
+
12
14
  ## When to use
13
15
  The user mentions patchcord / other agents / checking messages, or a Patchcord webhook fired ("new Patchcord messages").
14
16
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: patchcord-subscribe
3
- description: Set up real-time Patchcord delivery so new messages wake this agent automatically via the gateway webhook bridge.
4
- version: 1.0.0
3
+ description: Real-time Patchcord delivery options for Hermes. Hermes has no in-session listener, so this starts nothing in-turn — it drains the inbox and tells the human the optional one-time push setup.
4
+ version: 2.0.0
5
5
  platforms: [macos, linux]
6
6
  metadata:
7
7
  hermes:
@@ -10,21 +10,19 @@ metadata:
10
10
  ---
11
11
  # Patchcord — subscribe (real-time)
12
12
 
13
- Hermes has no per-turn background-listener tool. Real-time delivery uses the
14
- gateway webhook plus the patchcord bridge: the bridge holds one realtime
15
- connection and POSTs to a Hermes webhook on each new message, and the always-on
16
- gateway injects a prompt that wakes the agent. No re-arm.
13
+ Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI, do not read tokens from config files, do not call the API directly.
17
14
 
18
- ## One-time setup
19
- 1. Register a webhook route on the gateway:
20
- `hermes webhook subscribe patchcord --prompt "You have new Patchcord messages. Run /patchcord-inbox now."`
21
- Note the route URL it prints (e.g. `https://<gateway-host>/webhooks/patchcord`).
22
- 2. Start the bridge under the gateway/tmux/systemd:
23
- `PATCHCORD_HERMES_WEBHOOK=<route-url> patchcord subscribe --hermes`
24
- It self-reconnects and survives JWT cycles — leave it running.
15
+ **Hermes has no per-turn background-listener tool. There is nothing to start in this turn.** Do NOT web-search, do NOT fetch docs, do NOT guess or invent `hermes ...` commands.
25
16
 
26
- ## When the webhook fires
27
- The gateway injects the prompt → run the **patchcord-inbox** skill: read inbox, reply to each message, report to the user.
17
+ When invoked, do exactly this and stop:
18
+ 1. Run the **patchcord-inbox** skill now (drain anything pending).
19
+ 2. Tell the human: "Hermes can't hold a live listener — I'll check the inbox at the start of each session. For push delivery there's a one-time bridge the human sets up; want the steps?"
20
+ 3. Do not configure anything yourself.
28
21
 
29
- ## No webhook available
30
- Fall back to polling: `hermes cron create` a job that runs `/patchcord-inbox` every few minutes.
22
+ ## One-time push setup (the HUMAN runs this, only if they ask)
23
+ Real-time needs the patchcord bridge holding one realtime connection and POSTing to a Hermes webhook the human controls. Hand these to the human — never run them or invent command names yourself:
24
+ - In Hermes, create a webhook route that, when it fires, injects the prompt: `You have new Patchcord messages. Run /patchcord-inbox now.` (Use whatever the installed Hermes version calls this — the human knows their CLI.)
25
+ - Start the bridge pointed at that route URL and leave it running:
26
+ `PATCHCORD_HERMES_WEBHOOK=<route-url> patchcord subscribe --hermes`
27
+
28
+ Once the bridge runs, each new message fires the webhook → the gateway wakes the agent → run **patchcord-inbox**. If the human doesn't want the bridge, checking inbox at session start is the whole feature — that's fine.
@@ -9,6 +9,8 @@ metadata:
9
9
  ---
10
10
  # Patchcord — wait
11
11
 
12
+ Applies only when the patchcord MCP tools (`mcp_patchcord_*`) are available this session. If they are not, do nothing — do not run the CLI, read tokens from config files, call the API directly, or web-search for setup. Proceed with the user's request.
13
+
12
14
  ## When to use
13
15
  You sent a message and expect a reply, or the user asks you to wait for an incoming Patchcord message.
14
16