patchcord 0.6.11 → 0.6.13
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 +82 -1
- package/package.json +1 -1
package/bin/patchcord.mjs
CHANGED
|
@@ -177,7 +177,84 @@ function _purgeLegacyKimiProjectConfig(dir) {
|
|
|
177
177
|
} catch {}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
//
|
|
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.
|
|
185
|
+
function _purgeCursorSkillDuplicates() {
|
|
186
|
+
const staleCursorOnly = [
|
|
187
|
+
"patchcord",
|
|
188
|
+
"patchcordinbox",
|
|
189
|
+
"patchcordwait",
|
|
190
|
+
"patchcordsubscribe",
|
|
191
|
+
"patchcord:inbox",
|
|
192
|
+
"patchcord:wait",
|
|
193
|
+
"patchcord:subscribe",
|
|
194
|
+
];
|
|
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 {}
|
|
200
|
+
}
|
|
201
|
+
// cursor-agent ships patchcord@* with Claude plugin skills/ — Cursor must not
|
|
202
|
+
// index those; only per-project skills-cursor copies are valid for Cursor CLI.
|
|
203
|
+
const cursorAgentRoot = join(HOME, ".local", "share", "cursor-agent");
|
|
204
|
+
if (existsSync(cursorAgentRoot)) {
|
|
205
|
+
const walk = (dir, depth = 0) => {
|
|
206
|
+
if (depth > 8) return;
|
|
207
|
+
let entries;
|
|
208
|
+
try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return; }
|
|
209
|
+
for (const ent of entries) {
|
|
210
|
+
const p = join(dir, ent.name);
|
|
211
|
+
if (ent.isDirectory()) {
|
|
212
|
+
if (ent.name === "patchcord" && dir.endsWith("node_modules")) {
|
|
213
|
+
for (const pluginSkill of ["inbox", "wait", "subscribe"]) {
|
|
214
|
+
const sd = join(p, "skills", pluginSkill);
|
|
215
|
+
if (existsSync(sd)) {
|
|
216
|
+
try { rmSync(sd, { recursive: true, force: true }); } catch {}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
walk(p, depth + 1);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
walk(cursorAgentRoot);
|
|
226
|
+
}
|
|
227
|
+
const syncManifest = join(HOME, ".cursor", "skills-cursor", ".sync-manifest.json");
|
|
228
|
+
if (existsSync(syncManifest)) {
|
|
229
|
+
try {
|
|
230
|
+
const obj = JSON.parse(readFileSync(syncManifest, "utf-8"));
|
|
231
|
+
if (obj?.skills) {
|
|
232
|
+
for (const stale of ["patchcord", "patchcordinbox", "patchcordwait", "patchcordsubscribe", "patchcord:inbox", "patchcord:wait", "patchcord:subscribe"]) {
|
|
233
|
+
delete obj.skills[stale];
|
|
234
|
+
}
|
|
235
|
+
writeFileSync(syncManifest, JSON.stringify(obj, null, 2) + "\n");
|
|
236
|
+
}
|
|
237
|
+
} catch {}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
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
|
+
|
|
181
258
|
// preserving the rest of the user's YAML. Block-style only (what Hermes writes).
|
|
182
259
|
function upsertHermesConfig(existing, url, token) {
|
|
183
260
|
const block = [
|
|
@@ -1782,6 +1859,7 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1782
1859
|
const cursorSkillsRoot = join(HOME, ".cursor", "skills-cursor");
|
|
1783
1860
|
const hasCursorAgent = run("which cursor-agent");
|
|
1784
1861
|
if (hasCursorAgent || existsSync(cursorSkillsRoot)) {
|
|
1862
|
+
_purgeCursorSkillDuplicates();
|
|
1785
1863
|
mkdirSync(cursorSkillsRoot, { recursive: true });
|
|
1786
1864
|
const cursorInboxDir = join(cursorSkillsRoot, "patchcord-inbox");
|
|
1787
1865
|
const cursorWaitDir = join(cursorSkillsRoot, "patchcord-wait");
|
|
@@ -2182,6 +2260,9 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
2182
2260
|
globalChanges.push(`Codex stop hook ${hookAlreadyExisted ? "updated" : "installed"}`);
|
|
2183
2261
|
}
|
|
2184
2262
|
|
|
2263
|
+
_restoreCodexGlobalSkills();
|
|
2264
|
+
globalChanges.push("Codex global skills refreshed");
|
|
2265
|
+
|
|
2185
2266
|
writeFileSync(codexConfig, globalCodexContent);
|
|
2186
2267
|
}
|
|
2187
2268
|
|
package/package.json
CHANGED