patchcord 0.6.40 → 0.6.42
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/.claude-plugin/plugin.json +1 -1
- package/bin/patchcord.mjs +138 -21
- package/harnesses.json +228 -0
- package/package.json +3 -2
package/bin/patchcord.mjs
CHANGED
|
@@ -993,7 +993,27 @@ if (cmd === "subscribe") {
|
|
|
993
993
|
spawnEnv.PATCHCORD_BEARER_TOKEN = bearerInfo.token;
|
|
994
994
|
}
|
|
995
995
|
const { spawnSync } = await import("child_process");
|
|
996
|
-
|
|
996
|
+
// FORWARD argv. This used to spawn [subscribeScript] with no arguments, so
|
|
997
|
+
// every flag a user typed was silently thrown away between the wrapper and
|
|
998
|
+
// the script that reads it.
|
|
999
|
+
//
|
|
1000
|
+
// What that broke: subscribe.mjs gates its Hermes webhook bridge on
|
|
1001
|
+
// `process.argv.includes("--hermes")` — its OWN argv. Our Hermes skill tells
|
|
1002
|
+
// the human to run `PATCHCORD_HERMES_WEBHOOK=<url> patchcord subscribe
|
|
1003
|
+
// --hermes`. The env var arrived, the flag did not, and the flag is the gate.
|
|
1004
|
+
// notify() then took the `!HERMES_MODE` branch and wrote to a stdout no
|
|
1005
|
+
// Hermes gateway reads. The listener ran. Nothing was ever woken. No error.
|
|
1006
|
+
// The `--hermes <url>` inline form was worse: it has no env fallback at all.
|
|
1007
|
+
//
|
|
1008
|
+
// Forward everything rather than allow-listing `--hermes`. An allow-list
|
|
1009
|
+
// fixes today and leaves the trap armed: the next person adds a child-side
|
|
1010
|
+
// flag, reads subscribe.mjs, sees it handled, and never looks at these eight
|
|
1011
|
+
// lines. Same silent failure, new flag name. Reported by lead@mux-v2, who
|
|
1012
|
+
// asked for the fix in this shape rather than the narrow one.
|
|
1013
|
+
//
|
|
1014
|
+
// `--kimi` never hit this because the kimi branch above parses it here in the
|
|
1015
|
+
// parent and re-passes the interval explicitly. That was luck, not design.
|
|
1016
|
+
const result = spawnSync(process.execPath, [subscribeScript, ...args], {
|
|
997
1017
|
stdio: "inherit",
|
|
998
1018
|
env: spawnEnv,
|
|
999
1019
|
});
|
|
@@ -4037,21 +4057,71 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
4037
4057
|
console.log(` ${green}✓${r} Cleaned PATCHCORD_TOKEN from .env`);
|
|
4038
4058
|
}
|
|
4039
4059
|
}
|
|
4040
|
-
//
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4060
|
+
// We do NOT touch .codex/prompts/ — not the project one, not the home one.
|
|
4061
|
+
//
|
|
4062
|
+
// We used to write /patchcord and /patchcord-wait there, then a later commit
|
|
4063
|
+
// deleted them on every install. Both halves were wrong to keep.
|
|
4064
|
+
//
|
|
4065
|
+
// Writing them is pointless: Codex stopped loading $CODEX_HOME/prompts
|
|
4066
|
+
// entirely. Verified on 0.145 — a probe file at ~/.codex/prompts/pctest.md
|
|
4067
|
+
// and at ./.codex/prompts/pcproj.md both give "no matches" in the slash
|
|
4068
|
+
// menu, while /us still filters to /usage, so the menu itself works.
|
|
4069
|
+
// OpenAI marks custom prompts deprecated and says "use skills instead";
|
|
4070
|
+
// openai/codex#15941 reports the 0.117 break and was closed "not planned".
|
|
4071
|
+
//
|
|
4072
|
+
// Deleting them is worse than pointless. A user still on Codex < 0.117 has
|
|
4073
|
+
// WORKING slash commands, and the delete loop took them away on the next
|
|
4074
|
+
// install. It gave that user nothing back. `@patchcord` is the replacement
|
|
4075
|
+
// and it is installed below via the skills path.
|
|
4076
|
+
//
|
|
4077
|
+
// If you are tempted to re-add either half, run the probe first. Do not
|
|
4078
|
+
// trust this comment and do not trust the docs.
|
|
4079
|
+
|
|
4047
4080
|
// Clean up old per-project skill (now installed as global plugin)
|
|
4048
4081
|
const oldSkillPath = join(cwd, ".agents", "skills", "patchcord", "SKILL.md");
|
|
4049
4082
|
if (existsSync(oldSkillPath)) { unlinkSync(oldSkillPath); }
|
|
4050
4083
|
|
|
4051
|
-
// Install Codex plugin
|
|
4052
|
-
|
|
4084
|
+
// Install the Codex plugin.
|
|
4085
|
+
//
|
|
4086
|
+
// TWO DIFFERENT DIRECTORIES, and putting them in one place is the bug this
|
|
4087
|
+
// replaces. The marketplace FILE lives at ~/.agents/plugins/marketplace.json.
|
|
4088
|
+
// The plugin BODY lives at ~/plugins/patchcord. A `source.path` in that file
|
|
4089
|
+
// resolves against HOME — NOT against the directory holding the file.
|
|
4090
|
+
//
|
|
4091
|
+
// We previously wrote the body to ~/.agents/plugins/patchcord and pointed at
|
|
4092
|
+
// "./patchcord". Codex read that as ~/patchcord, which never existed, so:
|
|
4093
|
+
//
|
|
4094
|
+
// $ codex plugin list
|
|
4095
|
+
// patchcord@patchcord not installed /home/now/patchcord
|
|
4096
|
+
//
|
|
4097
|
+
// The plugin has never once installed. Only the ~/.agents/skills/ copy
|
|
4098
|
+
// written further down kept @patchcord alive, which is why nobody noticed.
|
|
4099
|
+
//
|
|
4100
|
+
// The layout below is OpenAI's own, from the bundled plugin-creator skill
|
|
4101
|
+
// (~/.codex/skills/.system/plugin-creator/): the scaffold writes bodies to
|
|
4102
|
+
// ~/plugins/<name>, and its SKILL.md states "In either location, the
|
|
4103
|
+
// generated source path remains ./plugins/<plugin-name>".
|
|
4104
|
+
//
|
|
4105
|
+
// Verify with `codex plugin list` after changing this. STATUS must not say
|
|
4106
|
+
// "not installed", and PATH must be a directory that exists.
|
|
4107
|
+
// Codex caches an installed plugin BY VERSION under ~/.codex/plugins/cache/.
|
|
4108
|
+
// Re-running the installer on the same release therefore reinstalls nothing,
|
|
4109
|
+
// and re-running it is the normal way people pick up a fix. So append the
|
|
4110
|
+
// cachebuster suffix Codex defines for exactly this case — the format is
|
|
4111
|
+
// `+codex.<token>`, per the bundled plugin-creator helper
|
|
4112
|
+
// (~/.codex/skills/.system/plugin-creator/scripts/update_plugin_cachebuster.py).
|
|
4113
|
+
const basePluginVersion = JSON.parse(readFileSync(join(pluginRoot, "package.json"), "utf-8")).version;
|
|
4114
|
+
const pluginVersion = `${basePluginVersion}+codex.${new Date().toISOString().replace(/[-:T]/g, "").slice(0, 14)}`;
|
|
4053
4115
|
const marketplaceDir = join(homedir(), ".agents", "plugins");
|
|
4054
|
-
const pluginDir = join(
|
|
4116
|
+
const pluginDir = join(homedir(), "plugins", "patchcord");
|
|
4117
|
+
|
|
4118
|
+
// Remove the body from the old, never-loadable location. Leaving it behind
|
|
4119
|
+
// makes `plugin list` ambiguous and keeps a stale copy of the skills on disk.
|
|
4120
|
+
const deadPluginDir = join(marketplaceDir, "patchcord");
|
|
4121
|
+
if (existsSync(join(deadPluginDir, ".codex-plugin", "plugin.json"))) {
|
|
4122
|
+
try { rmSync(deadPluginDir, { recursive: true, force: true }); } catch {}
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4055
4125
|
mkdirSync(join(pluginDir, ".codex-plugin"), { recursive: true });
|
|
4056
4126
|
mkdirSync(join(pluginDir, "skills", "patchcord"), { recursive: true });
|
|
4057
4127
|
mkdirSync(join(pluginDir, "skills", "patchcord-wait"), { recursive: true });
|
|
@@ -4081,7 +4151,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
4081
4151
|
writeFileSync(join(pluginDir, "skills", "patchcord-wait", "SKILL.md"),
|
|
4082
4152
|
readFileSync(join(pluginRoot, "skills", "wait", "SKILL.md"), "utf-8"));
|
|
4083
4153
|
|
|
4084
|
-
// Personal marketplace entry
|
|
4154
|
+
// Personal marketplace entry. `path` is relative to HOME, not to this file.
|
|
4085
4155
|
const marketplacePath = join(marketplaceDir, "marketplace.json");
|
|
4086
4156
|
updateJsonConfig(marketplacePath, (obj) => {
|
|
4087
4157
|
if (!obj.name) obj.name = "patchcord";
|
|
@@ -4089,24 +4159,71 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
4089
4159
|
obj.plugins = (obj.plugins || []).filter(p => p.name !== "patchcord");
|
|
4090
4160
|
obj.plugins.push({
|
|
4091
4161
|
name: "patchcord",
|
|
4092
|
-
source: { source: "local", path: "./patchcord" },
|
|
4162
|
+
source: { source: "local", path: "./plugins/patchcord" },
|
|
4093
4163
|
policy: { installation: "INSTALLED_BY_DEFAULT", authentication: "ON_INSTALL" },
|
|
4094
4164
|
category: "Productivity",
|
|
4095
4165
|
});
|
|
4096
4166
|
});
|
|
4097
4167
|
|
|
4098
|
-
//
|
|
4168
|
+
// Writing the marketplace entry does NOT install the plugin. Codex leaves it
|
|
4169
|
+
// at "not installed" until this runs, `INSTALLED_BY_DEFAULT` notwithstanding.
|
|
4170
|
+
// We never ran it, which is the second half of why the plugin was dead.
|
|
4171
|
+
// The command is `plugin add`, not `plugin install` — see
|
|
4172
|
+
// ~/.codex/skills/.system/plugin-creator/references/installing-and-updating.md.
|
|
4173
|
+
//
|
|
4174
|
+
// Not run() — run() has no timeout, and this is the one call here that talks
|
|
4175
|
+
// to another program's install path. The marketplace entry sets
|
|
4176
|
+
// authentication ON_INSTALL, so a future Codex could decide to ask. An
|
|
4177
|
+
// installer that hangs forever is worse than one that skips the plugin, and
|
|
4178
|
+
// skipping is survivable: the ~/.agents/skills/ fallback below covers it.
|
|
4179
|
+
let pluginAdded = false;
|
|
4180
|
+
try {
|
|
4181
|
+
execSync(`codex plugin add patchcord@patchcord`,
|
|
4182
|
+
{ stdio: "pipe", encoding: "utf-8", timeout: 30_000 });
|
|
4183
|
+
pluginAdded = true;
|
|
4184
|
+
} catch { pluginAdded = false; }
|
|
4185
|
+
|
|
4186
|
+
// ~/.agents/skills/ holds the SAME two skills as a fallback. Codex reads that
|
|
4187
|
+
// tree directly, with no marketplace and no install step, so @patchcord works
|
|
4188
|
+
// there even when the plugin does not load.
|
|
4189
|
+
//
|
|
4190
|
+
// EXACTLY ONE of the two may exist at a time. Codex reads both and shows both.
|
|
4191
|
+
// With the plugin installed AND the fallback present, `@patchcord` lists:
|
|
4192
|
+
//
|
|
4193
|
+
// Patchcord Cross-machine agent messaging Plugin
|
|
4194
|
+
// patchcord Cross-agent messaging for Codex … Skill
|
|
4195
|
+
// patchcord (patchcord) Cross-agent messaging for Codex … Skill
|
|
4196
|
+
// patchcord-wait Block this turn for up to 5 minutes … Skill
|
|
4197
|
+
// patchcord:wait (patchcord) Block this turn for up to 5 minutes … Skill
|
|
4198
|
+
//
|
|
4199
|
+
// Five entries for two skills. Observed, not predicted — an earlier version
|
|
4200
|
+
// of this comment asserted they would not collide, and that was wrong.
|
|
4099
4201
|
const globalSkillDir = join(homedir(), ".agents", "skills", "patchcord");
|
|
4100
|
-
mkdirSync(globalSkillDir, { recursive: true });
|
|
4101
|
-
writeFileSync(join(globalSkillDir, "SKILL.md"),
|
|
4102
|
-
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
4103
4202
|
const globalWaitDir = join(homedir(), ".agents", "skills", "patchcord-wait");
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4203
|
+
if (pluginAdded) {
|
|
4204
|
+
for (const d of [globalSkillDir, globalWaitDir]) {
|
|
4205
|
+
if (existsSync(d)) { try { rmSync(d, { recursive: true, force: true }); } catch {} }
|
|
4206
|
+
}
|
|
4207
|
+
} else {
|
|
4208
|
+
mkdirSync(globalSkillDir, { recursive: true });
|
|
4209
|
+
writeFileSync(join(globalSkillDir, "SKILL.md"),
|
|
4210
|
+
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
4211
|
+
mkdirSync(globalWaitDir, { recursive: true });
|
|
4212
|
+
writeFileSync(join(globalWaitDir, "SKILL.md"),
|
|
4213
|
+
readFileSync(join(pluginRoot, "skills", "wait", "SKILL.md"), "utf-8"));
|
|
4214
|
+
}
|
|
4107
4215
|
|
|
4108
4216
|
console.log(`\n ${green}✓${r} Codex configured: ${dim}${configPath}${r}`);
|
|
4109
|
-
|
|
4217
|
+
if (pluginAdded) {
|
|
4218
|
+
console.log(` ${green}✓${r} Plugin installed: ${dim}${pluginDir}${r}`);
|
|
4219
|
+
} else {
|
|
4220
|
+
// Say it plainly. A silent failure here still leaves @patchcord working
|
|
4221
|
+
// through ~/.agents/skills/, so this is a downgrade, not a breakage.
|
|
4222
|
+
console.log(` ${yellow}!${r} Codex plugin did not install (${dim}codex plugin add patchcord@patchcord${r})`);
|
|
4223
|
+
console.log(` ${dim}Skills still work. Check with: codex plugin list${r}`);
|
|
4224
|
+
}
|
|
4225
|
+
console.log(` ${green}✓${r} Type ${dim}@patchcord${r} or ${dim}@patchcord-wait${r} in Codex`);
|
|
4226
|
+
console.log(` ${dim}Codex dropped custom slash commands — @ is the picker now.${r}`);
|
|
4110
4227
|
} else {
|
|
4111
4228
|
// Claude Code: write .mcp.json
|
|
4112
4229
|
const mcpPath = join(cwd, ".mcp.json");
|
package/harnesses.json
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": [
|
|
3
|
+
"Machine-readable harness capability registry. Consumed by mux (lead@mux-v2) to decide",
|
|
4
|
+
"whether a seat can hold a Patchcord listener and whether two seats may share a host.",
|
|
5
|
+
"",
|
|
6
|
+
"TWO SCOPE FIELDS ON PURPOSE. `installer_scope` is where OUR installer writes.",
|
|
7
|
+
"`harness_scope` is what the HARNESS itself supports. They are not the same question and",
|
|
8
|
+
"conflating them is what this file exists to prevent: in one thread I answered three",
|
|
9
|
+
"harness-capability questions with installer behaviour and was wrong all three times.",
|
|
10
|
+
"hermes is the worked example — our installer writes one global file, and hermes supports",
|
|
11
|
+
"many isolated profiles. 'Our installer writes X' never implies 'the harness only does X'.",
|
|
12
|
+
"",
|
|
13
|
+
"EVIDENCE IS EARNED, NOT TYPED. This file may only ever say \"declared\" or \"absent\".",
|
|
14
|
+
"\"tested\" is not a legal value here — it lives in tests/test-harness-registry.mjs, in a",
|
|
15
|
+
"list that names what was observed and by whom. A writer can type a confident guess into",
|
|
16
|
+
"a data file; a writer cannot type an observation into a test they did not run. If you",
|
|
17
|
+
"believe a row deserves \"tested\", add it there with the observation, not here.",
|
|
18
|
+
"",
|
|
19
|
+
"Any row whose listener.wake is not \"none\" MUST have a real subscribe path on disk, or",
|
|
20
|
+
"carry blocked_reason saying why not. hermes is why: it HAS a subscribe skill directory",
|
|
21
|
+
"and, until 0.6.41, could not actually be armed. Directory presence is necessary, never",
|
|
22
|
+
"sufficient."
|
|
23
|
+
],
|
|
24
|
+
"version": 1,
|
|
25
|
+
"harnesses": [
|
|
26
|
+
{
|
|
27
|
+
"id": "claude_code",
|
|
28
|
+
"aliases": ["claude"],
|
|
29
|
+
"cli": "claude",
|
|
30
|
+
"kind": "terminal",
|
|
31
|
+
"installer_scope": "project",
|
|
32
|
+
"installer_config": ".mcp.json",
|
|
33
|
+
"harness_scope": "project",
|
|
34
|
+
"listener": {
|
|
35
|
+
"wake": "realtime",
|
|
36
|
+
"mechanism": "subscribe-skill-under-monitor",
|
|
37
|
+
"self_arm": true,
|
|
38
|
+
"survives_wake": true,
|
|
39
|
+
"evidence": "declared"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "codex",
|
|
44
|
+
"aliases": [],
|
|
45
|
+
"cli": "codex",
|
|
46
|
+
"kind": "terminal",
|
|
47
|
+
"installer_scope": "project",
|
|
48
|
+
"installer_config": ".codex/config.toml",
|
|
49
|
+
"harness_scope": "project",
|
|
50
|
+
"listener": {
|
|
51
|
+
"wake": "none",
|
|
52
|
+
"mechanism": "stop-hook-nudge-only",
|
|
53
|
+
"self_arm": false,
|
|
54
|
+
"survives_wake": null,
|
|
55
|
+
"evidence": "declared",
|
|
56
|
+
"note": "A stop hook fires at the END of a turn. An idle codex seat hears nothing. No subscribe skill exists for codex in this package."
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"id": "cursor",
|
|
61
|
+
"aliases": [],
|
|
62
|
+
"cli": "cursor-agent",
|
|
63
|
+
"kind": "terminal",
|
|
64
|
+
"installer_scope": "project",
|
|
65
|
+
"installer_config": ".cursor/mcp.json",
|
|
66
|
+
"harness_scope": "unknown",
|
|
67
|
+
"listener": {
|
|
68
|
+
"wake": "realtime",
|
|
69
|
+
"mechanism": "subscribe-skill-background-shell",
|
|
70
|
+
"self_arm": true,
|
|
71
|
+
"survives_wake": null,
|
|
72
|
+
"evidence": "declared",
|
|
73
|
+
"note": "The skill claims it wakes the agent. Nobody in this repo has watched it happen."
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "grok",
|
|
78
|
+
"aliases": ["grok_cli", "grok_build"],
|
|
79
|
+
"cli": "grok",
|
|
80
|
+
"kind": "terminal",
|
|
81
|
+
"installer_scope": "project",
|
|
82
|
+
"installer_config": ".grok/config.toml",
|
|
83
|
+
"harness_scope": "project",
|
|
84
|
+
"listener": {
|
|
85
|
+
"wake": "realtime",
|
|
86
|
+
"mechanism": "subscribe-skill",
|
|
87
|
+
"self_arm": true,
|
|
88
|
+
"survives_wake": null,
|
|
89
|
+
"evidence": "declared",
|
|
90
|
+
"note": "Grok resolves configs from cwd up to the git root, so per-seat identity works. Wake is claimed by the skill, not observed."
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"id": "opencode",
|
|
95
|
+
"aliases": [],
|
|
96
|
+
"cli": "opencode",
|
|
97
|
+
"kind": "terminal",
|
|
98
|
+
"installer_scope": "project",
|
|
99
|
+
"installer_config": "opencode.json",
|
|
100
|
+
"harness_scope": "unknown",
|
|
101
|
+
"listener": {
|
|
102
|
+
"wake": "realtime",
|
|
103
|
+
"mechanism": "installed-plugin",
|
|
104
|
+
"self_arm": true,
|
|
105
|
+
"survives_wake": true,
|
|
106
|
+
"evidence": "declared",
|
|
107
|
+
"note": "The installer writes .opencode/plugins/patchcord.js, which spawns `patchcord subscribe` and calls client.session.prompt() on each message. It prompts on the realtime event rather than session.idle deliberately: session.idle re-prompting has a teardown race in headless `opencode run`."
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "kimi",
|
|
112
|
+
"aliases": [],
|
|
113
|
+
"cli": "kimi",
|
|
114
|
+
"kind": "terminal",
|
|
115
|
+
"installer_scope": "project",
|
|
116
|
+
"installer_config": ".kimi-code/mcp.json",
|
|
117
|
+
"harness_scope": "unknown",
|
|
118
|
+
"listener": {
|
|
119
|
+
"wake": "poll",
|
|
120
|
+
"mechanism": "poll-script",
|
|
121
|
+
"self_arm": true,
|
|
122
|
+
"survives_wake": false,
|
|
123
|
+
"evidence": "declared",
|
|
124
|
+
"note": "NOT realtime. patchcord-subscribe.sh polls /api/inbox and EXITS 0 on a pending count; Kimi starts a turn when a background task reaches a terminal state. So the listener dies on every delivery and the agent must re-arm it. Re-arm is the failure point: an agent that skips it is silently deaf from then on."
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "hermes",
|
|
129
|
+
"aliases": [],
|
|
130
|
+
"cli": "hermes",
|
|
131
|
+
"kind": "terminal",
|
|
132
|
+
"installer_scope": "global",
|
|
133
|
+
"installer_config": "~/.hermes/config.yaml",
|
|
134
|
+
"harness_scope": "per-profile",
|
|
135
|
+
"installer_defect": "The path is hardcoded to ~/.hermes/config.yaml. The installer never calls `hermes config path` and does not know profiles exist, so installing while a non-default profile is active writes the DEFAULT profile's config — the wrong file, silently. Not fixed as of 0.6.41.",
|
|
136
|
+
"listener": {
|
|
137
|
+
"wake": "realtime",
|
|
138
|
+
"mechanism": "webhook-bridge",
|
|
139
|
+
"self_arm": false,
|
|
140
|
+
"survives_wake": true,
|
|
141
|
+
"evidence": "declared",
|
|
142
|
+
"note": "`patchcord subscribe --hermes` POSTs to a Hermes gateway webhook per message; the gateway injects a prompt. No re-arm needed. self_arm is false: a human creates the route and starts the bridge once. A deploy that waits N seconds for a SEAT-started listener will fail hermes forever while hermes is fully push-capable.",
|
|
143
|
+
"blocked_until": "0.6.41",
|
|
144
|
+
"blocked_reason": "Before 0.6.41 the `patchcord subscribe` wrapper spawned subscribe.mjs with no arguments, so --hermes never reached the child that gates on it. The env var arrived, the flag did not, the flag is the gate. The bridge was unreachable by its own documented command and failed silently. Fixed; not yet observed end to end."
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "antigravity",
|
|
149
|
+
"aliases": ["agy"],
|
|
150
|
+
"cli": "antigravity",
|
|
151
|
+
"kind": "terminal",
|
|
152
|
+
"installer_scope": "project",
|
|
153
|
+
"installer_config": ".agents/mcp_config.json",
|
|
154
|
+
"harness_scope": "unknown",
|
|
155
|
+
"listener": {
|
|
156
|
+
"wake": "none",
|
|
157
|
+
"mechanism": null,
|
|
158
|
+
"self_arm": false,
|
|
159
|
+
"survives_wake": null,
|
|
160
|
+
"evidence": "declared",
|
|
161
|
+
"note": "No subscribe skill of any kind in this package."
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"id": "openclaw",
|
|
166
|
+
"aliases": [],
|
|
167
|
+
"cli": "openclaw",
|
|
168
|
+
"kind": "terminal",
|
|
169
|
+
"installer_scope": "unknown",
|
|
170
|
+
"installer_config": "~/.openclaw/openclaw.json",
|
|
171
|
+
"harness_scope": "unknown",
|
|
172
|
+
"listener": {
|
|
173
|
+
"wake": "none",
|
|
174
|
+
"mechanism": null,
|
|
175
|
+
"self_arm": false,
|
|
176
|
+
"survives_wake": null,
|
|
177
|
+
"evidence": "absent",
|
|
178
|
+
"note": "installer_scope is unknown, not global. We PREFER `openclaw mcp set patchcord`, so openclaw decides where the entry lands; the ~/.openclaw path is only our fallback when that CLI is missing. Nobody here has openclaw installed. Do not refuse a second openclaw seat on the strength of this row — refuse on a test or not at all."
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"id": "windsurf",
|
|
183
|
+
"aliases": [],
|
|
184
|
+
"cli": null,
|
|
185
|
+
"kind": "editor",
|
|
186
|
+
"installer_scope": "global",
|
|
187
|
+
"installer_config": "~/.codeium/windsurf/mcp_config.json",
|
|
188
|
+
"harness_scope": "unknown",
|
|
189
|
+
"listener": { "wake": "none", "mechanism": null, "self_arm": false, "survives_wake": null, "evidence": "declared" }
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"id": "vscode",
|
|
193
|
+
"aliases": [],
|
|
194
|
+
"cli": null,
|
|
195
|
+
"kind": "editor",
|
|
196
|
+
"installer_scope": "project",
|
|
197
|
+
"installer_config": ".vscode/mcp.json",
|
|
198
|
+
"harness_scope": "unknown",
|
|
199
|
+
"listener": { "wake": "none", "mechanism": null, "self_arm": false, "survives_wake": null, "evidence": "declared" }
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"id": "zed",
|
|
203
|
+
"aliases": [],
|
|
204
|
+
"cli": null,
|
|
205
|
+
"kind": "editor",
|
|
206
|
+
"installer_scope": "global",
|
|
207
|
+
"installer_config": "~/.config/zed/settings.json",
|
|
208
|
+
"harness_scope": "unknown",
|
|
209
|
+
"listener": { "wake": "none", "mechanism": null, "self_arm": false, "survives_wake": null, "evidence": "declared" }
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"id": "cline",
|
|
213
|
+
"aliases": [],
|
|
214
|
+
"cli": null,
|
|
215
|
+
"kind": "editor",
|
|
216
|
+
"installer_scope": "global",
|
|
217
|
+
"installer_config": "cline_mcp_settings.json (VS Code globalStorage)",
|
|
218
|
+
"harness_scope": "unknown",
|
|
219
|
+
"listener": { "wake": "none", "mechanism": null, "self_arm": false, "survives_wake": null, "evidence": "declared" }
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
"retired": [
|
|
223
|
+
{
|
|
224
|
+
"id": "gemini",
|
|
225
|
+
"reason": "Retired as an install target; Antigravity covers Google's agent. CLIENT_TYPE_MAP slot \"5\" is left UNASSIGNED rather than reused, so a stale connect page sending client_type=gemini falls through to no choice instead of silently configuring a different harness and writing someone's token to the wrong file. Do not mirror the gap as a bug and do not fill it."
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchcord",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.42",
|
|
4
4
|
"description": "Cross-machine agent messaging for Claude Code and Codex",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"version": "node scripts/sync-plugin-version.mjs && git add .claude-plugin/plugin.json"
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"per-project-skills/",
|
|
33
33
|
"commands/",
|
|
34
34
|
"README.md",
|
|
35
|
-
"plugins/"
|
|
35
|
+
"plugins/",
|
|
36
|
+
"harnesses.json"
|
|
36
37
|
]
|
|
37
38
|
}
|