patchcord 0.5.69 → 0.5.70
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 +78 -29
- package/package.json +1 -1
package/bin/patchcord.mjs
CHANGED
|
@@ -709,13 +709,56 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
709
709
|
let wasPluginInstalled = false;
|
|
710
710
|
const { readFileSync, writeFileSync, unlinkSync, rmSync, chmodSync, copyFileSync } = await import("fs");
|
|
711
711
|
|
|
712
|
+
// JSONC-safe comment stripper that preserves content inside string literals.
|
|
713
|
+
// Prevents corrupting URLs like "https://..." which contain "//".
|
|
714
|
+
function _stripJsoncOutsideStrings(str) {
|
|
715
|
+
let out = "";
|
|
716
|
+
let i = 0;
|
|
717
|
+
let inStr = false;
|
|
718
|
+
let strCh = "";
|
|
719
|
+
let prev = "";
|
|
720
|
+
while (i < str.length) {
|
|
721
|
+
const c = str[i];
|
|
722
|
+
if (inStr) {
|
|
723
|
+
out += c;
|
|
724
|
+
if (c === strCh && prev !== "\\") inStr = false;
|
|
725
|
+
prev = c;
|
|
726
|
+
i++;
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
if (c === '"' || c === "'") {
|
|
730
|
+
inStr = true;
|
|
731
|
+
strCh = c;
|
|
732
|
+
out += c;
|
|
733
|
+
prev = c;
|
|
734
|
+
i++;
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
if (c === "/" && str[i + 1] === "/") {
|
|
738
|
+
while (i < str.length && str[i] !== "\n") i++;
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
if (c === "/" && str[i + 1] === "*") {
|
|
742
|
+
i += 2;
|
|
743
|
+
while (i < str.length && !(str[i] === "*" && str[i + 1] === "/")) i++;
|
|
744
|
+
i += 2;
|
|
745
|
+
continue;
|
|
746
|
+
}
|
|
747
|
+
out += c;
|
|
748
|
+
prev = c;
|
|
749
|
+
i++;
|
|
750
|
+
}
|
|
751
|
+
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
752
|
+
}
|
|
753
|
+
|
|
712
754
|
function safeReadJson(filePath) {
|
|
713
755
|
try {
|
|
714
|
-
|
|
715
|
-
//
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
756
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
757
|
+
// Try strict JSON first (avoids corrupting URLs with //)
|
|
758
|
+
try { return JSON.parse(raw); } catch {}
|
|
759
|
+
// Fall back to JSONC stripping for Zed/Gemini-style configs
|
|
760
|
+
const cleaned = _stripJsoncOutsideStrings(raw);
|
|
761
|
+
return cleaned.trim() ? JSON.parse(cleaned) : {};
|
|
719
762
|
} catch { return null; }
|
|
720
763
|
}
|
|
721
764
|
|
|
@@ -729,24 +772,28 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
729
772
|
if (existsSync(filePath)) {
|
|
730
773
|
const raw = readFileSync(filePath, "utf-8");
|
|
731
774
|
try {
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
//
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
775
|
+
// Try strict JSON first (most configs are plain JSON). This avoids
|
|
776
|
+
// corrupting URLs like "https://..." which contain "//".
|
|
777
|
+
parsed = JSON.parse(raw);
|
|
778
|
+
} catch {
|
|
779
|
+
// Fall back to JSONC stripping for Zed/Gemini-style configs.
|
|
780
|
+
// _stripJsoncOutsideStrings preserves content inside string literals
|
|
781
|
+
// so URLs like "https://..." survive.
|
|
782
|
+
try {
|
|
783
|
+
const cleaned = _stripJsoncOutsideStrings(raw);
|
|
784
|
+
parsed = cleaned.trim() ? JSON.parse(cleaned) : {};
|
|
785
|
+
} catch {
|
|
786
|
+
console.log(`\n ${yellow}⚠${r} Skipped ${filePath} — could not parse existing JSON.`);
|
|
787
|
+
console.log(` Fix the file by hand and re-run the installer. We will not`);
|
|
788
|
+
console.log(` overwrite it: that would erase your other servers/settings.`);
|
|
743
789
|
return false;
|
|
744
790
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
console.log(
|
|
791
|
+
}
|
|
792
|
+
// null / arrays / primitives aren't config objects we can merge into;
|
|
793
|
+
// refuse rather than blow them away.
|
|
794
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
795
|
+
console.log(`\n ${yellow}⚠${r} Skipped ${filePath} — existing file is not a JSON object.`);
|
|
796
|
+
console.log(` Replace it with a valid object ({...}) or remove it, then re-run.`);
|
|
750
797
|
return false;
|
|
751
798
|
}
|
|
752
799
|
}
|
|
@@ -1747,12 +1794,14 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1747
1794
|
// Install alias for per-project --mcp-config-file
|
|
1748
1795
|
const aliasLine = `alias kimi-pc='kimi --mcp-config-file .kimi/mcp.json'`;
|
|
1749
1796
|
const aliasComment = "# Patchcord Kimi alias — loads per-project .kimi/mcp.json";
|
|
1750
|
-
const
|
|
1751
|
-
|
|
1752
|
-
join(HOME, ".zshrc"),
|
|
1753
|
-
|
|
1797
|
+
const isZsh = (process.env.SHELL || "").includes("zsh");
|
|
1798
|
+
const shellRcCandidates = isZsh
|
|
1799
|
+
? [join(HOME, ".zshrc"), join(HOME, ".bashrc")]
|
|
1800
|
+
: [join(HOME, ".bashrc"), join(HOME, ".zshrc")];
|
|
1801
|
+
const primaryRc = shellRcCandidates[0];
|
|
1802
|
+
const primaryName = basename(primaryRc);
|
|
1754
1803
|
let aliasInstalled = false;
|
|
1755
|
-
for (const rcFile of
|
|
1804
|
+
for (const rcFile of shellRcCandidates) {
|
|
1756
1805
|
if (!existsSync(rcFile)) continue;
|
|
1757
1806
|
const rcContent = readFileSync(rcFile, "utf-8");
|
|
1758
1807
|
if (rcContent.includes("alias kimi-pc=")) continue; // already present
|
|
@@ -1763,12 +1812,12 @@ if (!cmd || cmd === "install" || cmd === "agent" || cmd?.startsWith("--")) {
|
|
|
1763
1812
|
aliasInstalled = true;
|
|
1764
1813
|
}
|
|
1765
1814
|
if (aliasInstalled) {
|
|
1766
|
-
console.log(`\n ${green}✓${r} Alias installed in
|
|
1815
|
+
console.log(`\n ${green}✓${r} Alias installed in ${primaryName}`);
|
|
1767
1816
|
console.log(` ${dim}Run ${bold}kimi-pc${r}${dim} instead of ${bold}kimi${r}${dim} in project directories.${r}`);
|
|
1768
|
-
console.log(` ${dim}Reload your shell or run ${cyan}source
|
|
1817
|
+
console.log(` ${dim}Reload your shell or run ${cyan}source ~/${primaryName}${r}${dim} to use it now.${r}`);
|
|
1769
1818
|
} else {
|
|
1770
1819
|
console.log(`\n ${yellow}⚠${r} Could not auto-install alias.`);
|
|
1771
|
-
console.log(` ${dim}Add this to your
|
|
1820
|
+
console.log(` ${dim}Add this to your ~/${primaryName} manually:${r}`);
|
|
1772
1821
|
console.log(` ${cyan}${aliasLine}${r}`);
|
|
1773
1822
|
}
|
|
1774
1823
|
} else if (isVSCode) {
|