grepmax 0.24.0 → 0.25.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/.claude-plugin/marketplace.json +1 -1
- package/README.md +11 -6
- package/dist/commands/add.js +38 -31
- package/dist/commands/config.js +16 -15
- package/dist/commands/context.js +38 -13
- package/dist/commands/doctor.js +76 -83
- package/dist/commands/extract.js +12 -1
- package/dist/commands/index.js +23 -24
- package/dist/commands/list.js +23 -14
- package/dist/commands/mcp.js +278 -143
- package/dist/commands/peek.js +16 -5
- package/dist/commands/repair.js +54 -120
- package/dist/commands/search-output.js +30 -9
- package/dist/commands/search-run.js +75 -47
- package/dist/commands/search-skeletons.js +28 -18
- package/dist/commands/search.js +45 -49
- package/dist/commands/serve.js +415 -373
- package/dist/commands/setup.js +2 -2
- package/dist/commands/similar.js +5 -5
- package/dist/commands/skeleton.js +67 -41
- package/dist/commands/status.js +5 -2
- package/dist/commands/summarize.js +6 -0
- package/dist/commands/watch.js +102 -38
- package/dist/config.js +3 -0
- package/dist/lib/daemon/daemon.js +1101 -379
- package/dist/lib/daemon/ipc-handler.js +122 -13
- package/dist/lib/daemon/mlx-server-manager.js +268 -125
- package/dist/lib/daemon/process-manager.js +7 -4
- package/dist/lib/daemon/search-handler.js +23 -9
- package/dist/lib/daemon/watcher-manager.js +353 -110
- package/dist/lib/index/batch-processor.js +231 -67
- package/dist/lib/index/embedding-generation.js +109 -0
- package/dist/lib/index/embedding-status.js +23 -0
- package/dist/lib/index/file-policy.js +273 -0
- package/dist/lib/index/ignore-patterns.js +4 -0
- package/dist/lib/index/index-config.js +18 -4
- package/dist/lib/index/syncer.js +256 -79
- package/dist/lib/index/walker.js +66 -86
- package/dist/lib/index/watcher-batch.js +9 -0
- package/dist/lib/index/watcher.js +129 -3
- package/dist/lib/llm/server.js +6 -0
- package/dist/lib/search/searcher.js +30 -19
- package/dist/lib/store/store-lease.js +473 -0
- package/dist/lib/store/vector-db.js +302 -57
- package/dist/lib/utils/blocked-roots.js +63 -0
- package/dist/lib/utils/cross-project.js +7 -3
- package/dist/lib/utils/daemon-client.js +24 -1
- package/dist/lib/utils/daemon-launcher.js +38 -13
- package/dist/lib/utils/doctor-status.js +76 -0
- package/dist/lib/utils/file-utils.js +74 -4
- package/dist/lib/utils/keyed-mutex.js +101 -0
- package/dist/lib/utils/logger.js +57 -1
- package/dist/lib/utils/mlx-hf-cache.js +114 -0
- package/dist/lib/utils/operation-coordinator.js +146 -0
- package/dist/lib/utils/path-containment.js +106 -0
- package/dist/lib/utils/process.js +44 -0
- package/dist/lib/utils/project-registry.js +351 -3
- package/dist/lib/utils/scope-filter.js +3 -9
- package/dist/lib/utils/stale-hint.js +12 -19
- package/dist/lib/utils/watcher-launcher.js +5 -1
- package/dist/lib/utils/watcher-store.js +2 -2
- package/dist/lib/workers/colbert-math.js +15 -12
- package/dist/lib/workers/embeddings/colbert.js +3 -2
- package/dist/lib/workers/embeddings/granite.js +4 -3
- package/dist/lib/workers/embeddings/mlx-client.js +59 -16
- package/dist/lib/workers/orchestrator.js +39 -8
- package/dist/lib/workers/pool.js +146 -82
- package/dist/lib/workers/process-child.js +11 -2
- package/dist/lib/workers/serialized-handler.js +10 -0
- package/dist/lib/workers/worker.js +13 -4
- package/mlx-embed-server/server.py +21 -3
- package/mlx-embed-server/summarizer.py +8 -0
- package/package.json +4 -3
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/start.js +3 -170
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.ProjectFilePolicy = exports.IgnorePolicyReadError = void 0;
|
|
49
|
+
const fs = __importStar(require("node:fs"));
|
|
50
|
+
const path = __importStar(require("node:path"));
|
|
51
|
+
const ignore_1 = __importDefault(require("ignore"));
|
|
52
|
+
const config_1 = require("../../config");
|
|
53
|
+
const file_utils_1 = require("../utils/file-utils");
|
|
54
|
+
const path_containment_1 = require("../utils/path-containment");
|
|
55
|
+
const ignore_patterns_1 = require("./ignore-patterns");
|
|
56
|
+
class IgnorePolicyReadError extends Error {
|
|
57
|
+
constructor(protectedPath, cause) {
|
|
58
|
+
super(`Unable to read ignore policy under ${protectedPath}`);
|
|
59
|
+
this.protectedPath = protectedPath;
|
|
60
|
+
this.cause = cause;
|
|
61
|
+
this.name = "IgnorePolicyReadError";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.IgnorePolicyReadError = IgnorePolicyReadError;
|
|
65
|
+
class ProjectFilePolicy {
|
|
66
|
+
constructor(projectRoot, options = {}) {
|
|
67
|
+
var _a, _b;
|
|
68
|
+
this.ignoreCache = new Map();
|
|
69
|
+
this.projectRoot = path.resolve(projectRoot);
|
|
70
|
+
try {
|
|
71
|
+
this.canonicalRoot = fs.realpathSync(this.projectRoot);
|
|
72
|
+
}
|
|
73
|
+
catch (_c) {
|
|
74
|
+
// Root availability is classified by the walker. Construction must not
|
|
75
|
+
// turn a transient mount/root failure into a permanently wedged watcher.
|
|
76
|
+
this.canonicalRoot = null;
|
|
77
|
+
}
|
|
78
|
+
this.ignoreFiles = (_a = options.ignoreFiles) !== null && _a !== void 0 ? _a : [".gitignore", ".gmaxignore"];
|
|
79
|
+
this.rootFilter = (0, ignore_1.default)().add([
|
|
80
|
+
...ignore_patterns_1.DEFAULT_IGNORE_PATTERNS,
|
|
81
|
+
".git",
|
|
82
|
+
".gmax",
|
|
83
|
+
...((_b = options.additionalPatterns) !== null && _b !== void 0 ? _b : []),
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
isPolicyFile(absPath) {
|
|
87
|
+
return this.ignoreFiles.includes(path.basename(absPath));
|
|
88
|
+
}
|
|
89
|
+
invalidateIgnoreCache() {
|
|
90
|
+
this.ignoreCache.clear();
|
|
91
|
+
}
|
|
92
|
+
isLexicallyContained(absPath) {
|
|
93
|
+
return (0, path_containment_1.isPathWithin)(this.projectRoot, path.resolve(absPath));
|
|
94
|
+
}
|
|
95
|
+
normalizeEventPath(absPath) {
|
|
96
|
+
const resolved = path.resolve(absPath);
|
|
97
|
+
if (this.isLexicallyContained(resolved))
|
|
98
|
+
return resolved;
|
|
99
|
+
if (!this.canonicalRoot || !(0, path_containment_1.isPathWithin)(this.canonicalRoot, resolved)) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return path.resolve(this.projectRoot, path.relative(this.canonicalRoot, resolved));
|
|
103
|
+
}
|
|
104
|
+
relative(absPath) {
|
|
105
|
+
return path.relative(this.projectRoot, absPath).split(path.sep).join("/");
|
|
106
|
+
}
|
|
107
|
+
loadIgnoreScope(dir) {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
109
|
+
const existing = this.ignoreCache.get(dir);
|
|
110
|
+
if (existing)
|
|
111
|
+
return existing;
|
|
112
|
+
const pending = (() => __awaiter(this, void 0, void 0, function* () {
|
|
113
|
+
let filter = null;
|
|
114
|
+
for (const fileName of this.ignoreFiles) {
|
|
115
|
+
try {
|
|
116
|
+
const content = yield fs.promises.readFile(path.join(dir, fileName), "utf8");
|
|
117
|
+
if (!filter)
|
|
118
|
+
filter = (0, ignore_1.default)();
|
|
119
|
+
filter.add(content);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
if (err.code !== "ENOENT") {
|
|
123
|
+
throw new IgnorePolicyReadError(dir, err);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { dir, filter };
|
|
128
|
+
}))();
|
|
129
|
+
this.ignoreCache.set(dir, pending);
|
|
130
|
+
void pending.catch(() => {
|
|
131
|
+
if (this.ignoreCache.get(dir) === pending)
|
|
132
|
+
this.ignoreCache.delete(dir);
|
|
133
|
+
});
|
|
134
|
+
return pending;
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
scopeDirectories(throughDir) {
|
|
138
|
+
const relative = path.relative(this.projectRoot, throughDir);
|
|
139
|
+
if (!relative)
|
|
140
|
+
return [this.projectRoot];
|
|
141
|
+
const parts = relative.split(path.sep).filter(Boolean);
|
|
142
|
+
const dirs = [this.projectRoot];
|
|
143
|
+
let current = this.projectRoot;
|
|
144
|
+
for (const part of parts) {
|
|
145
|
+
current = path.join(current, part);
|
|
146
|
+
dirs.push(current);
|
|
147
|
+
}
|
|
148
|
+
return dirs;
|
|
149
|
+
}
|
|
150
|
+
classifyPath(absPath) {
|
|
151
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
152
|
+
const resolved = path.resolve(absPath);
|
|
153
|
+
if (!this.isLexicallyContained(resolved)) {
|
|
154
|
+
return { status: "excluded", reason: "outside project root" };
|
|
155
|
+
}
|
|
156
|
+
try {
|
|
157
|
+
const stat = yield fs.promises.lstat(resolved);
|
|
158
|
+
const isRoot = resolved === this.projectRoot;
|
|
159
|
+
if (stat.isSymbolicLink() && !isRoot) {
|
|
160
|
+
return { status: "excluded", reason: "symbolic link" };
|
|
161
|
+
}
|
|
162
|
+
const canonical = yield fs.promises.realpath(resolved);
|
|
163
|
+
if (!this.canonicalRoot) {
|
|
164
|
+
this.canonicalRoot = yield fs.promises.realpath(this.projectRoot);
|
|
165
|
+
}
|
|
166
|
+
const expected = path.resolve(this.canonicalRoot, path.relative(this.projectRoot, resolved));
|
|
167
|
+
if (canonical !== expected) {
|
|
168
|
+
return { status: "excluded", reason: "symlinked ancestor" };
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
status: "present",
|
|
172
|
+
stat: isRoot && stat.isSymbolicLink()
|
|
173
|
+
? yield fs.promises.stat(resolved)
|
|
174
|
+
: stat,
|
|
175
|
+
resolved,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
if (err.code === "ENOENT") {
|
|
180
|
+
return { status: "missing" };
|
|
181
|
+
}
|
|
182
|
+
return { status: "error", error: err, protectedPath: resolved };
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
ignoredByPolicy(absPath, isDirectory, loadThroughDir, includeLastScope) {
|
|
187
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
188
|
+
const rootRelative = this.relative(absPath);
|
|
189
|
+
const rootTest = isDirectory ? `${rootRelative}/` : rootRelative;
|
|
190
|
+
if (rootRelative && this.rootFilter.ignores(rootTest)) {
|
|
191
|
+
return "default ignore policy";
|
|
192
|
+
}
|
|
193
|
+
const dirs = this.scopeDirectories(loadThroughDir);
|
|
194
|
+
const scopes = yield Promise.all(dirs.map((dir) => this.loadIgnoreScope(dir)));
|
|
195
|
+
const applicable = includeLastScope ? scopes : scopes.slice(0, -1);
|
|
196
|
+
for (const scope of applicable) {
|
|
197
|
+
if (!scope.filter)
|
|
198
|
+
continue;
|
|
199
|
+
const relative = path
|
|
200
|
+
.relative(scope.dir, absPath)
|
|
201
|
+
.split(path.sep)
|
|
202
|
+
.join("/");
|
|
203
|
+
if (!relative)
|
|
204
|
+
continue;
|
|
205
|
+
const testPath = isDirectory ? `${relative}/` : relative;
|
|
206
|
+
if (scope.filter.ignores(testPath))
|
|
207
|
+
return "project ignore policy";
|
|
208
|
+
}
|
|
209
|
+
return null;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
classifyFile(absPath) {
|
|
213
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
214
|
+
if (this.isPolicyFile(absPath)) {
|
|
215
|
+
return { status: "excluded", reason: "ignore policy file" };
|
|
216
|
+
}
|
|
217
|
+
const classified = yield this.classifyPath(absPath);
|
|
218
|
+
if (classified.status !== "present")
|
|
219
|
+
return classified;
|
|
220
|
+
if (!classified.stat.isFile()) {
|
|
221
|
+
return { status: "excluded", reason: "not a regular file" };
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const ignored = yield this.ignoredByPolicy(classified.resolved, false, path.dirname(classified.resolved), true);
|
|
225
|
+
if (ignored)
|
|
226
|
+
return { status: "excluded", reason: ignored };
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
return {
|
|
230
|
+
status: "error",
|
|
231
|
+
error,
|
|
232
|
+
protectedPath: error instanceof IgnorePolicyReadError
|
|
233
|
+
? error.protectedPath
|
|
234
|
+
: path.dirname(classified.resolved),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (!(0, file_utils_1.isIndexableFile)(classified.resolved, classified.stat.size)) {
|
|
238
|
+
return { status: "excluded", reason: "non-indexable file" };
|
|
239
|
+
}
|
|
240
|
+
if (classified.stat.size === 0 ||
|
|
241
|
+
classified.stat.size > config_1.MAX_FILE_SIZE_BYTES) {
|
|
242
|
+
return { status: "excluded", reason: "invalid file size" };
|
|
243
|
+
}
|
|
244
|
+
return { status: "indexable", stat: classified.stat };
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
classifyDirectory(absPath) {
|
|
248
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
249
|
+
const classified = yield this.classifyPath(absPath);
|
|
250
|
+
if (classified.status !== "present")
|
|
251
|
+
return classified;
|
|
252
|
+
if (!classified.stat.isDirectory()) {
|
|
253
|
+
return { status: "excluded", reason: "not a directory" };
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
const ignored = yield this.ignoredByPolicy(classified.resolved, true, classified.resolved, false);
|
|
257
|
+
if (ignored)
|
|
258
|
+
return { status: "excluded", reason: ignored };
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
return {
|
|
262
|
+
status: "error",
|
|
263
|
+
error,
|
|
264
|
+
protectedPath: error instanceof IgnorePolicyReadError
|
|
265
|
+
? error.protectedPath
|
|
266
|
+
: classified.resolved,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return { status: "traverse" };
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
exports.ProjectFilePolicy = ProjectFilePolicy;
|
|
@@ -25,6 +25,7 @@ exports.DEFAULT_IGNORE_PATTERNS = [
|
|
|
25
25
|
"coverage",
|
|
26
26
|
"venv",
|
|
27
27
|
".venv",
|
|
28
|
+
"site-packages",
|
|
28
29
|
".tox",
|
|
29
30
|
".mypy_cache",
|
|
30
31
|
".pytest_cache",
|
|
@@ -33,6 +34,7 @@ exports.DEFAULT_IGNORE_PATTERNS = [
|
|
|
33
34
|
".gradle",
|
|
34
35
|
".m2",
|
|
35
36
|
"vendor",
|
|
37
|
+
"lancedb",
|
|
36
38
|
".claude",
|
|
37
39
|
".gmax",
|
|
38
40
|
".gmax.json",
|
|
@@ -99,6 +101,8 @@ exports.DEFAULT_IGNORE_PATTERNS = [
|
|
|
99
101
|
"credentials.*",
|
|
100
102
|
// IDE and OS files
|
|
101
103
|
".DS_Store",
|
|
104
|
+
"**/*.tmp.*",
|
|
105
|
+
"**/*.sb-*",
|
|
102
106
|
"**/.idea/**",
|
|
103
107
|
"**/.vscode/**",
|
|
104
108
|
"Thumbs.db",
|
|
@@ -70,8 +70,14 @@ function readGlobalConfig() {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
function writeGlobalConfig(config) {
|
|
73
|
+
const existing = readGlobalConfig();
|
|
74
|
+
const merged = Object.assign(Object.assign({}, existing), config);
|
|
75
|
+
if (config.queryLog === undefined)
|
|
76
|
+
merged.queryLog = existing.queryLog;
|
|
77
|
+
if (config.llmEnabled === undefined)
|
|
78
|
+
merged.llmEnabled = existing.llmEnabled;
|
|
73
79
|
fs.mkdirSync(path.dirname(GLOBAL_CONFIG_PATH), { recursive: true });
|
|
74
|
-
fs.writeFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(
|
|
80
|
+
fs.writeFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(merged, null, 2)}\n`);
|
|
75
81
|
}
|
|
76
82
|
/**
|
|
77
83
|
* Resolve the effective model IDs for a given tier.
|
|
@@ -95,13 +101,13 @@ function readIndexConfig(configPath) {
|
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
103
|
function writeIndexConfig(configPath, extra) {
|
|
98
|
-
var _a;
|
|
104
|
+
var _a, _b, _c, _d, _e;
|
|
99
105
|
const existing = readIndexConfig(configPath);
|
|
100
106
|
const tierName = (_a = existing === null || existing === void 0 ? void 0 : existing.modelTier) !== null && _a !== void 0 ? _a : readGlobalConfig().modelTier;
|
|
101
107
|
const tierIds = getModelIdsForTier(tierName);
|
|
102
108
|
const config = Object.assign({
|
|
103
109
|
// Preserve user preferences from setup
|
|
104
|
-
embedMode: existing === null || existing === void 0 ? void 0 : existing.embedMode, mlxModel: existing === null || existing === void 0 ? void 0 : existing.mlxModel, modelTier: tierName,
|
|
110
|
+
embedMode: (_b = existing === null || existing === void 0 ? void 0 : existing.embedMode) !== null && _b !== void 0 ? _b : readGlobalConfig().embedMode, mlxModel: (_c = existing === null || existing === void 0 ? void 0 : existing.mlxModel) !== null && _c !== void 0 ? _c : readGlobalConfig().mlxModel, modelTier: tierName, queryLog: (_d = existing === null || existing === void 0 ? void 0 : existing.queryLog) !== null && _d !== void 0 ? _d : readGlobalConfig().queryLog, llmEnabled: (_e = existing === null || existing === void 0 ? void 0 : existing.llmEnabled) !== null && _e !== void 0 ? _e : readGlobalConfig().llmEnabled,
|
|
105
111
|
// Model identity from current run
|
|
106
112
|
embedModel: tierIds.embed, colbertModel: tierIds.colbert, vectorDim: tierIds.vectorDim, indexedAt: new Date().toISOString() }, extra);
|
|
107
113
|
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
@@ -112,7 +118,15 @@ function writeIndexConfig(configPath, extra) {
|
|
|
112
118
|
*/
|
|
113
119
|
function writeSetupConfig(configPath, prefs) {
|
|
114
120
|
const existing = readIndexConfig(configPath);
|
|
115
|
-
const config = Object.assign(Object.assign({}, existing), { embedMode: prefs.embedMode
|
|
121
|
+
const config = Object.assign(Object.assign({}, existing), { embedMode: prefs.embedMode });
|
|
122
|
+
if ("mlxModel" in prefs) {
|
|
123
|
+
if (prefs.mlxModel === undefined)
|
|
124
|
+
delete config.mlxModel;
|
|
125
|
+
else
|
|
126
|
+
config.mlxModel = prefs.mlxModel;
|
|
127
|
+
}
|
|
128
|
+
if (prefs.modelTier !== undefined)
|
|
129
|
+
config.modelTier = prefs.modelTier;
|
|
116
130
|
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
117
131
|
}
|
|
118
132
|
function checkModelMismatch(configPath) {
|