patchcord 0.3.99 → 0.4.1
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 +87 -18
- package/package.json +1 -1
package/bin/patchcord.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { existsSync, mkdirSync, cpSync, readdirSync } from "fs";
|
|
4
|
-
import { join, dirname } from "path";
|
|
4
|
+
import { join, dirname, basename } from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
7
|
import { homedir } from "os";
|
|
@@ -80,7 +80,8 @@ if (cmd === "plugin-path") {
|
|
|
80
80
|
if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd === "--no-browser" || cmd === "--server") {
|
|
81
81
|
const flags = cmd?.startsWith("--") ? process.argv.slice(2) : process.argv.slice(3);
|
|
82
82
|
const fullStatusline = flags.includes("--full");
|
|
83
|
-
|
|
83
|
+
let wasPluginInstalled = false;
|
|
84
|
+
const { readFileSync, writeFileSync, unlinkSync, rmSync } = await import("fs");
|
|
84
85
|
|
|
85
86
|
function safeReadJson(filePath) {
|
|
86
87
|
try {
|
|
@@ -115,11 +116,18 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
115
116
|
// Claude Code
|
|
116
117
|
const hasClaude = run("which claude");
|
|
117
118
|
if (hasClaude) {
|
|
119
|
+
// Remove legacy npm-cache install (pre-marketplace era) — causes duplicate /patchcord commands.
|
|
120
|
+
const npmCachePatchcord = join(HOME, ".claude", "plugins", "npm-cache", "node_modules", "patchcord");
|
|
121
|
+
if (existsSync(npmCachePatchcord)) {
|
|
122
|
+
try { rmSync(npmCachePatchcord, { recursive: true, force: true }); } catch {}
|
|
123
|
+
}
|
|
124
|
+
|
|
118
125
|
// Always re-add marketplace (copies fresh files from this npx package)
|
|
119
126
|
// and install/update plugin. Claude Code's built-in plugin update
|
|
120
127
|
// doesn't detect new versions from local sources (#37252).
|
|
121
128
|
run(`claude plugin marketplace add "${pluginRoot}"`);
|
|
122
129
|
const installed = run(`claude plugin list`)?.includes("patchcord");
|
|
130
|
+
wasPluginInstalled = !!installed;
|
|
123
131
|
if (installed) {
|
|
124
132
|
run(`claude plugin update patchcord@patchcord-marketplace`);
|
|
125
133
|
globalChanges.push("Claude Code plugin updated");
|
|
@@ -155,12 +163,16 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
155
163
|
}
|
|
156
164
|
}
|
|
157
165
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
// Statusline: enabled later in the Claude Code project-setup branch (prompts user).
|
|
167
|
+
// If --full flag passed non-interactively, install eagerly here so non-Claude-Code
|
|
168
|
+
// flows (e.g. setting up Codex on a machine with Claude Code) still get the upgrade.
|
|
169
|
+
if (fullStatusline) {
|
|
170
|
+
const enableScript = join(pluginRoot, "scripts", "enable-statusline.sh");
|
|
171
|
+
if (existsSync(enableScript)) {
|
|
172
|
+
const slResult = run(`bash "${enableScript}" --full`);
|
|
173
|
+
if (slResult !== null && slResult.includes("statusline")) {
|
|
174
|
+
globalChanges.push("Statusline (full) enabled");
|
|
175
|
+
}
|
|
164
176
|
}
|
|
165
177
|
}
|
|
166
178
|
}
|
|
@@ -218,10 +230,10 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
218
230
|
cpSync(join(pluginRoot, "skills", "patchcord-wait", "SKILL.md"), join(geminiWaitDir, "SKILL.md"));
|
|
219
231
|
geminiChanged = true;
|
|
220
232
|
}
|
|
221
|
-
if (!existsSync(join(geminiCmdDir, "
|
|
233
|
+
if (!existsSync(join(geminiCmdDir, "inbox.toml"))) {
|
|
222
234
|
mkdirSync(geminiCmdDir, { recursive: true });
|
|
223
|
-
cpSync(join(pluginRoot, "commands", "
|
|
224
|
-
cpSync(join(pluginRoot, "commands", "
|
|
235
|
+
cpSync(join(pluginRoot, "commands", "inbox.toml"), join(geminiCmdDir, "inbox.toml"));
|
|
236
|
+
cpSync(join(pluginRoot, "commands", "wait.toml"), join(geminiCmdDir, "wait.toml"));
|
|
225
237
|
geminiChanged = true;
|
|
226
238
|
}
|
|
227
239
|
if (geminiChanged) globalChanges.push("Gemini CLI skills + commands installed");
|
|
@@ -993,14 +1005,71 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd === "--token" || cmd ===
|
|
|
993
1005
|
}
|
|
994
1006
|
console.log(`\n ${green}✓${r} Claude Code configured: ${dim}${mcpPath}${r}`);
|
|
995
1007
|
|
|
996
|
-
//
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1008
|
+
// Statusline: ask whether to enable full mode (unless --full flag passed or already configured).
|
|
1009
|
+
const enableScript = join(pluginRoot, "scripts", "enable-statusline.sh");
|
|
1010
|
+
if (existsSync(enableScript)) {
|
|
1011
|
+
let currentStatusLine = "";
|
|
1012
|
+
const claudeSettingsPath = join(HOME, ".claude", "settings.json");
|
|
1013
|
+
if (existsSync(claudeSettingsPath)) {
|
|
1014
|
+
try {
|
|
1015
|
+
const s = JSON.parse(readFileSync(claudeSettingsPath, "utf-8"));
|
|
1016
|
+
currentStatusLine = s?.statusLine?.command || "";
|
|
1017
|
+
} catch {}
|
|
1002
1018
|
}
|
|
1003
|
-
|
|
1019
|
+
const hasPatchcordStatusLine = currentStatusLine.includes("patchcord");
|
|
1020
|
+
|
|
1021
|
+
let installFull = null; // true = install, null = skip
|
|
1022
|
+
if (fullStatusline) {
|
|
1023
|
+
installFull = true; // already handled in global setup, but re-run is idempotent
|
|
1024
|
+
} else if (!hasPatchcordStatusLine) {
|
|
1025
|
+
// Build preview with user's real values
|
|
1026
|
+
const dirName = basename(cwd) || "project";
|
|
1027
|
+
let branchPart = "";
|
|
1028
|
+
const gitBranch = run(`git -C "${cwd}" symbolic-ref --short HEAD 2>/dev/null`);
|
|
1029
|
+
if (gitBranch) {
|
|
1030
|
+
const dirty = run(`git -C "${cwd}" status --porcelain 2>/dev/null`);
|
|
1031
|
+
const star = dirty ? `${red}*${green}` : "";
|
|
1032
|
+
branchPart = ` ${green}(${gitBranch}${star})${r}`;
|
|
1033
|
+
}
|
|
1034
|
+
const idStr = identity || "your-agent@namespace";
|
|
1035
|
+
const idParts = idStr.split("@");
|
|
1036
|
+
const idPart = idParts.length === 2
|
|
1037
|
+
? `${white}${idParts[0]}${r}${dim}@${idParts[1]}${r}`
|
|
1038
|
+
: `${white}${idStr}${r}`;
|
|
1039
|
+
const machinePart = hostname ? ` ${dim}(${hostname})${r}` : "";
|
|
1040
|
+
const sep = `${dim} │ ${r}`;
|
|
1041
|
+
const blue = "\x1b[38;2;0;153;255m";
|
|
1042
|
+
const example = `${blue}Claude Opus 4.7${r}${sep}${green}0%${r}${sep}${cyan}${dirName}${r}${branchPart}${sep}${idPart}${machinePart}`;
|
|
1043
|
+
|
|
1044
|
+
console.log(``);
|
|
1045
|
+
console.log(` Patchcord can show live agent identity + context in Claude Code's status bar.`);
|
|
1046
|
+
console.log(``);
|
|
1047
|
+
console.log(` Full mode: ${example}`);
|
|
1048
|
+
console.log(``);
|
|
1049
|
+
|
|
1050
|
+
const defaultYes = !wasPluginInstalled;
|
|
1051
|
+
const promptStr = defaultYes
|
|
1052
|
+
? ` ${bold}Install full status bar?${r} ${dim}(Y/n):${r} `
|
|
1053
|
+
: ` ${bold}Install full status bar?${r} ${dim}(y/N):${r} `;
|
|
1054
|
+
const { createInterface: createRLS } = await import("readline");
|
|
1055
|
+
const rlS = createRLS({ input: process.stdin, output: process.stdout });
|
|
1056
|
+
const answer = await new Promise((resolve) => rlS.question(promptStr, resolve));
|
|
1057
|
+
rlS.close();
|
|
1058
|
+
const a = (answer || "").trim().toLowerCase();
|
|
1059
|
+
const yes = defaultYes
|
|
1060
|
+
? !(a === "n" || a === "no")
|
|
1061
|
+
: (a === "y" || a === "yes");
|
|
1062
|
+
if (yes) installFull = true;
|
|
1063
|
+
}
|
|
1064
|
+
// else: existing patchcord statusline — leave it alone
|
|
1065
|
+
|
|
1066
|
+
if (installFull === true) {
|
|
1067
|
+
try {
|
|
1068
|
+
execSync(`bash "${enableScript}" --full`, { stdio: "ignore" });
|
|
1069
|
+
console.log(` ${green}✓${r} Statusline enabled`);
|
|
1070
|
+
} catch {}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1004
1073
|
}
|
|
1005
1074
|
|
|
1006
1075
|
// Warn about gitignore for per-project configs with tokens
|