Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/app/api/cli-tools/claude-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ const readSettings = async () => {
try {
const settingsPath = getClaudeSettingsPath();
const content = await fs.readFile(settingsPath, "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") {
return null;
}
throw error;
return null;
}
};

Expand Down
8 changes: 5 additions & 3 deletions src/app/api/cli-tools/cline-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ const checkInstalled = async () => {
const readJson = async (filePath) => {
try {
const content = await fs.readFile(filePath, "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
return null;
}
};

Expand Down
8 changes: 5 additions & 3 deletions src/app/api/cli-tools/copilot-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const getConfigPath = () => {
const readConfig = async () => {
try {
const content = await fs.readFile(getConfigPath(), "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
return null;
}
};

Expand Down
24 changes: 16 additions & 8 deletions src/app/api/cli-tools/cowork-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,14 @@ const get1pRoot = () => {
const get1pConfigPath = () => path.join(get1pRoot(), "claude_desktop_config.json");

const read1pConfig = async () => {
try { return JSON.parse(await fs.readFile(get1pConfigPath(), "utf-8")) || {}; }
catch (error) {
if (error.code === "ENOENT") return {};
throw error;
try {
const content = await fs.readFile(get1pConfigPath(), "utf-8");
// Tolerate JSONC (trailing commas) and treat unparseable files as empty config
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped) || {};
} catch (error) {
return {};
}
};

Expand Down Expand Up @@ -193,10 +197,14 @@ const checkInstalled = async () => {
};

const readJson = async (filePath) => {
try { return JSON.parse(await fs.readFile(filePath, "utf-8")); }
catch (error) {
if (error.code === "ENOENT") return null;
throw error;
try {
const content = await fs.readFile(filePath, "utf-8");
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
return null;
}
};

Expand Down
8 changes: 5 additions & 3 deletions src/app/api/cli-tools/droid-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ const readSettings = async () => {
try {
const settingsPath = getDroidSettingsPath();
const content = await fs.readFile(settingsPath, "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
return null;
}
};

Expand Down
8 changes: 5 additions & 3 deletions src/app/api/cli-tools/kilo-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ const checkInstalled = async () => {
const readJson = async (filePath) => {
try {
const content = await fs.readFile(filePath, "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
return null;
}
};

Expand Down
8 changes: 5 additions & 3 deletions src/app/api/cli-tools/openclaw-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ const readSettings = async () => {
try {
const settingsPath = getOpenClawSettingsPath();
const content = await fs.readFile(settingsPath, "utf-8");
return JSON.parse(content);
// Tolerate JSONC (trailing commas) and treat unparseable files as "no config"
// rather than throwing a 500 that the UI misreads as "tool not installed".
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
return null;
}
};

Expand Down
10 changes: 8 additions & 2 deletions src/app/api/cli-tools/opencode-settings/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,16 @@ const checkOpenCodeInstalled = async () => {
const readConfig = async () => {
try {
const content = await fs.readFile(getConfigPath(), "utf-8");
return JSON.parse(content);
// opencode config files may use JSONC format (trailing commas, comments).
// Strip trailing commas before parsing to avoid SyntaxError on valid JSONC.
const stripped = content.replace(/,(\s*[}\]])/g, "$1");
return JSON.parse(stripped);
} catch (error) {
if (error.code === "ENOENT") return null;
throw error;
// If the config file exists but is unparseable (corrupted, exotic JSONC),
// treat it as "no config" rather than throwing a 500 that the UI
// misinterprets as "opencode not installed".
return null;
}
};

Expand Down