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