patchcord 0.6.12 → 0.6.14
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 +58 -19
- package/package.json +1 -1
package/bin/patchcord.mjs
CHANGED
|
@@ -177,16 +177,14 @@ function _purgeLegacyKimiProjectConfig(dir) {
|
|
|
177
177
|
} catch {}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
// Cursor
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
180
|
+
// Cursor slash menu duplicates come from (a) stale combined/no-hyphen dirs under
|
|
181
|
+
// skills-cursor and (b) Claude colon-named plugin skills bundled inside
|
|
182
|
+
// cursor-agent's node_modules/patchcord. NEVER touch ~/.agents/skills — that tree
|
|
183
|
+
// is Codex/Antigravity-owned (global + per-project); Cursor update must not
|
|
184
|
+
// delete other harnesses' skills.
|
|
184
185
|
function _purgeCursorSkillDuplicates() {
|
|
185
|
-
const
|
|
186
|
+
const staleCursorOnly = [
|
|
186
187
|
"patchcord",
|
|
187
|
-
"patchcord-inbox",
|
|
188
|
-
"patchcord-wait",
|
|
189
|
-
"patchcord-subscribe",
|
|
190
188
|
"patchcordinbox",
|
|
191
189
|
"patchcordwait",
|
|
192
190
|
"patchcordsubscribe",
|
|
@@ -194,15 +192,11 @@ function _purgeCursorSkillDuplicates() {
|
|
|
194
192
|
"patchcord:wait",
|
|
195
193
|
"patchcord:subscribe",
|
|
196
194
|
];
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
join(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const d = join(root, name);
|
|
203
|
-
if (!existsSync(d)) continue;
|
|
204
|
-
try { rmSync(d, { recursive: true, force: true }); } catch {}
|
|
205
|
-
}
|
|
195
|
+
const cursorSkillsRoot = join(HOME, ".cursor", "skills-cursor");
|
|
196
|
+
for (const name of staleCursorOnly) {
|
|
197
|
+
const d = join(cursorSkillsRoot, name);
|
|
198
|
+
if (!existsSync(d)) continue;
|
|
199
|
+
try { rmSync(d, { recursive: true, force: true }); } catch {}
|
|
206
200
|
}
|
|
207
201
|
// cursor-agent ships patchcord@* with Claude plugin skills/ — Cursor must not
|
|
208
202
|
// index those; only per-project skills-cursor copies are valid for Cursor CLI.
|
|
@@ -244,6 +238,23 @@ function _purgeCursorSkillDuplicates() {
|
|
|
244
238
|
}
|
|
245
239
|
}
|
|
246
240
|
|
|
241
|
+
// Codex global skills live at ~/.agents/skills/ (not Cursor). Refresh on
|
|
242
|
+
// update so a mistaken Cursor-only purge cannot leave Codex without @patchcord.
|
|
243
|
+
function _restoreCodexGlobalSkills() {
|
|
244
|
+
const codexConfig = join(HOME, ".codex", "config.toml");
|
|
245
|
+
if (!existsSync(codexConfig)) return;
|
|
246
|
+
const globalSkillDir = join(HOME, ".agents", "skills", "patchcord");
|
|
247
|
+
const globalWaitDir = join(HOME, ".agents", "skills", "patchcord-wait");
|
|
248
|
+
try {
|
|
249
|
+
mkdirSync(globalSkillDir, { recursive: true });
|
|
250
|
+
writeFileSync(join(globalSkillDir, "SKILL.md"),
|
|
251
|
+
readFileSync(join(pluginRoot, "per-project-skills", "codex", "SKILL.md"), "utf-8"));
|
|
252
|
+
mkdirSync(globalWaitDir, { recursive: true });
|
|
253
|
+
writeFileSync(join(globalWaitDir, "SKILL.md"),
|
|
254
|
+
readFileSync(join(pluginRoot, "skills", "wait", "SKILL.md"), "utf-8"));
|
|
255
|
+
} catch {}
|
|
256
|
+
}
|
|
257
|
+
|
|
247
258
|
// preserving the rest of the user's YAML. Block-style only (what Hermes writes).
|
|
248
259
|
function upsertHermesConfig(existing, url, token) {
|
|
249
260
|
const block = [
|
|
@@ -1161,9 +1172,13 @@ if (cmd === "login" || cmd === "orchestrator" || cmd === "teamlead" || cmd === "
|
|
|
1161
1172
|
// default: claude_code. type:"http" is REQUIRED — without it Claude Code
|
|
1162
1173
|
// defaults to stdio transport and rejects the entry ("command: expected
|
|
1163
1174
|
// string, received undefined").
|
|
1175
|
+
// Use /mcp/bearer (not /mcp): Claude Code v2.1.113+ follows RFC 9728 OAuth
|
|
1176
|
+
// discovery on /mcp, drops the static bearer header, and stalls on "Needs
|
|
1177
|
+
// authentication". /mcp/bearer serves bearer-only resource metadata — same
|
|
1178
|
+
// path Cursor and Kimi Code already use.
|
|
1164
1179
|
return writeJson(join(dir, ".mcp.json"), (o) => {
|
|
1165
1180
|
o.mcpServers = o.mcpServers || {};
|
|
1166
|
-
o.mcpServers.patchcord = { type: "http", url: `${baseUrl}/mcp`, headers: hdr };
|
|
1181
|
+
o.mcpServers.patchcord = { type: "http", url: `${baseUrl}/mcp/bearer`, headers: hdr };
|
|
1167
1182
|
});
|
|
1168
1183
|
};
|
|
1169
1184
|
|
|
@@ -1650,6 +1665,23 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1650
1665
|
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
1651
1666
|
}
|
|
1652
1667
|
|
|
1668
|
+
// Claude Code v2.1.113+ OAuth discovery on plain /mcp breaks bearer MCP.
|
|
1669
|
+
// Rewrite legacy project configs to /mcp/bearer (Cursor/Kimi already use it).
|
|
1670
|
+
function _migrateClaudeMcpBearerUrl(mcpPath) {
|
|
1671
|
+
if (!existsSync(mcpPath)) return false;
|
|
1672
|
+
try {
|
|
1673
|
+
const obj = JSON.parse(readFileSync(mcpPath, "utf-8"));
|
|
1674
|
+
const pt = obj?.mcpServers?.patchcord;
|
|
1675
|
+
const url = pt?.url;
|
|
1676
|
+
if (!url || !/\/mcp$/.test(url) || url.endsWith("/mcp/bearer")) return false;
|
|
1677
|
+
pt.url = url.replace(/\/mcp$/, "/mcp/bearer");
|
|
1678
|
+
writeFileSync(mcpPath, JSON.stringify(obj, null, 2) + "\n");
|
|
1679
|
+
return true;
|
|
1680
|
+
} catch {
|
|
1681
|
+
return false;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1653
1685
|
// Read+merge+write a JSON config file. If the file exists but its contents
|
|
1654
1686
|
// can't be parsed, REFUSE to write — silently overwriting would erase
|
|
1655
1687
|
// unrelated MCP servers, settings, or hand-edits the user has in there.
|
|
@@ -1708,6 +1740,10 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1708
1740
|
const bold = "\x1b[1m";
|
|
1709
1741
|
const r = "\x1b[0m";
|
|
1710
1742
|
|
|
1743
|
+
if (_migrateClaudeMcpBearerUrl(join(process.cwd(), ".mcp.json"))) {
|
|
1744
|
+
console.log(` ${green}✓${r} Claude Code MCP URL migrated to /mcp/bearer`);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1711
1747
|
// ── Purge stale npx cache entries ────────────────────────────
|
|
1712
1748
|
// npx never auto-updates a cached package. Users with an old `npx patchcord`
|
|
1713
1749
|
// entry get the stale binary indefinitely. On every install we sweep
|
|
@@ -2249,6 +2285,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2249
2285
|
globalChanges.push(`Codex stop hook ${hookAlreadyExisted ? "updated" : "installed"}`);
|
|
2250
2286
|
}
|
|
2251
2287
|
|
|
2288
|
+
_restoreCodexGlobalSkills();
|
|
2289
|
+
globalChanges.push("Codex global skills refreshed");
|
|
2290
|
+
|
|
2252
2291
|
writeFileSync(codexConfig, globalCodexContent);
|
|
2253
2292
|
}
|
|
2254
2293
|
|
|
@@ -3237,7 +3276,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
3237
3276
|
mcpServers: {
|
|
3238
3277
|
patchcord: {
|
|
3239
3278
|
type: "http",
|
|
3240
|
-
url: `${serverUrl}/mcp`,
|
|
3279
|
+
url: `${serverUrl}/mcp/bearer`,
|
|
3241
3280
|
headers: {
|
|
3242
3281
|
Authorization: `Bearer ${token}`,
|
|
3243
3282
|
"X-Patchcord-Machine": hostname,
|
package/package.json
CHANGED