diff --git a/core/config/load.ts b/core/config/load.ts index dfea7c17d6..ad5a07734d 100644 --- a/core/config/load.ts +++ b/core/config/load.ts @@ -1,3 +1,4 @@ +import * as JSONC from "comment-json"; import * as fs from "fs"; import path from "path"; import { @@ -57,7 +58,7 @@ const { execSync } = require("child_process"); function resolveSerializedConfig(filepath: string): SerializedContinueConfig { let content = fs.readFileSync(filepath, "utf8"); - const config = JSON.parse(content) as SerializedContinueConfig; + const config = JSONC.parse(content) as unknown as SerializedContinueConfig; if (config.env && Array.isArray(config.env)) { const env = { ...process.env, @@ -74,7 +75,7 @@ function resolveSerializedConfig(filepath: string): SerializedContinueConfig { }); } - return JSON.parse(content); + return JSONC.parse(content) as unknown as SerializedContinueConfig; } const configMergeKeys = { diff --git a/core/config/util.ts b/core/config/util.ts index f47635c40a..1b2c397b71 100644 --- a/core/config/util.ts +++ b/core/config/util.ts @@ -1,6 +1,5 @@ -import { readFileSync, writeFileSync } from "fs"; import { ModelDescription } from "../index.js"; -import { editConfigJson, getConfigJsonPath } from "../util/paths.js"; +import { editConfigJson } from "../util/paths.js"; function stringify(obj: any, indentation?: number): string { return JSON.stringify( @@ -13,21 +12,17 @@ function stringify(obj: any, indentation?: number): string { } export function addModel(model: ModelDescription) { - const config = readFileSync(getConfigJsonPath(), "utf8"); - const configJson = JSON.parse(config); + editConfigJson((config) => { + if (config.models?.some((m: any) => stringify(m) === stringify(model))) { + return config; + } + if (config.models?.some((m: any) => m?.title === model.title)) { + model.title = `${model.title} (1)`; + } - // De-duplicate - if (configJson.models?.some((m: any) => stringify(m) === stringify(model))) { + config.models.push(model); return config; - } - if (configJson.models?.some((m: any) => m?.title === model.title)) { - model.title = `${model.title} (1)`; - } - - configJson.models.push(model); - const newConfigString = stringify(configJson, 2); - writeFileSync(getConfigJsonPath(), newConfigString); - return newConfigString; + }); } export function addOpenAIKey(key: string) { diff --git a/core/core.ts b/core/core.ts index cc91a70d2e..fbbfdbf787 100644 --- a/core/core.ts +++ b/core/core.ts @@ -27,7 +27,7 @@ import { DevDataSqliteDb } from "./util/devdataSqlite.js"; import { fetchwithRequestOptions } from "./util/fetchWithOptions.js"; import historyManager from "./util/history.js"; import type { IMessenger, Message } from "./util/messenger"; -import { editConfigJson, getConfigJsonPath } from "./util/paths.js"; +import { editConfigJson } from "./util/paths.js"; import { Telemetry } from "./util/posthog.js"; import { streamDiffLines } from "./util/verticalEdit.js"; @@ -179,37 +179,8 @@ export class Core { // Edit config on("config/addModel", (msg) => { const model = msg.data.model; - const newConfigString = addModel(model); + addModel(model); this.configHandler.reloadConfig(); - this.ide.openFile(getConfigJsonPath()); - - // Find the range where it was added and highlight - const lines = newConfigString.split("\n"); - let startLine: number | undefined; - let endLine: number | undefined; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - - if (!startLine) { - if (line.trim() === `"title": "${model.title}",`) { - startLine = i - 1; - } - } else { - if (line.startsWith(" }")) { - endLine = i; - break; - } - } - } - - if (startLine && endLine) { - this.ide.showLines( - getConfigJsonPath(), - startLine, - endLine, - // "#fff1" - ); - } }); on("config/addOpenAiKey", (msg) => { addOpenAIKey(msg.data); diff --git a/core/package-lock.json b/core/package-lock.json index 5aea48e3f6..1ff3584a6f 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -22,6 +22,7 @@ "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", "commander": "^12.0.0", + "comment-json": "^4.2.3", "dbinfoz": "^0.1.4", "dotenv": "^16.3.1", "fastest-levenshtein": "^1.0.16", @@ -5285,6 +5286,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==" + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -6201,6 +6207,26 @@ "node": ">=18" } }, + "node_modules/comment-json": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.3.tgz", + "integrity": "sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw==", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/comment-json/node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7231,7 +7257,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -8067,6 +8092,14 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -11260,7 +11293,6 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "peer": true, "engines": { "node": ">=0.10" } diff --git a/core/package.json b/core/package.json index bc54da2523..da77c644dc 100644 --- a/core/package.json +++ b/core/package.json @@ -42,6 +42,7 @@ "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", "commander": "^12.0.0", + "comment-json": "^4.2.3", "dbinfoz": "^0.1.4", "dotenv": "^16.3.1", "fastest-levenshtein": "^1.0.16", diff --git a/core/util/paths.ts b/core/util/paths.ts index 12838c1be2..0c6cb6948e 100644 --- a/core/util/paths.ts +++ b/core/util/paths.ts @@ -1,3 +1,4 @@ +import * as JSONC from "comment-json"; import dotenv from "dotenv"; import * as fs from "fs"; import * as os from "os"; @@ -152,12 +153,16 @@ export function getDevDataFilePath(fileName: string): string { export function editConfigJson( callback: (config: SerializedContinueConfig) => SerializedContinueConfig, -) { +): void { const config = fs.readFileSync(getConfigJsonPath(), "utf8"); - let configJson = JSON.parse(config); - configJson = callback(configJson); - fs.writeFileSync(getConfigJsonPath(), JSON.stringify(configJson, null, 2)); - return configJson; + let configJson = JSONC.parse(config); + // Check if it's an object + if (typeof configJson === "object" && configJson !== null) { + configJson = callback(configJson as any) as any; + fs.writeFileSync(getConfigJsonPath(), JSONC.stringify(configJson, null, 2)); + } else { + console.warn("config.json is not a valid object"); + } } function getMigrationsFolderPath(): string { diff --git a/extensions/vscode/package-lock.json b/extensions/vscode/package-lock.json index 379234dc8e..ae1349e888 100644 --- a/extensions/vscode/package-lock.json +++ b/extensions/vscode/package-lock.json @@ -104,6 +104,7 @@ "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", "commander": "^12.0.0", + "comment-json": "^4.2.3", "dbinfoz": "^0.1.4", "dotenv": "^16.3.1", "fastest-levenshtein": "^1.0.16", diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index afee8b02ed..ff7afdc30e 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -53,6 +53,15 @@ "main": "./out/extension.js", "browser": "./out/extension.js", "contributes": { + "languages": [ + { + "filenames": [ + "config.json", + ".continuerc.json" + ], + "id": "jsonc" + } + ], "configuration": { "title": "Continue", "properties": { diff --git a/gui/package-lock.json b/gui/package-lock.json index a5786fb30c..9c96e041be 100644 --- a/gui/package-lock.json +++ b/gui/package-lock.json @@ -99,6 +99,7 @@ "axios": "^1.6.7", "cheerio": "^1.0.0-rc.12", "commander": "^12.0.0", + "comment-json": "^4.2.3", "dbinfoz": "^0.1.4", "dotenv": "^16.3.1", "fastest-levenshtein": "^1.0.16",