grepmax 0.26.35 → 0.26.36
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 +3 -1
- package/dist/commands/config.js +76 -2
- package/dist/commands/status.js +115 -18
- package/dist/config.js +70 -23
- package/dist/lib/daemon/daemon.js +6 -0
- package/dist/lib/daemon/ipc-handler.js +3 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "grepmax",
|
|
11
11
|
"source": "./plugins/grepmax",
|
|
12
12
|
"description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
|
|
13
|
-
"version": "0.26.
|
|
13
|
+
"version": "0.26.36",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
package/README.md
CHANGED
|
@@ -50,6 +50,7 @@ No setup required — gmax auto-detects your platform (GPU on Apple Silicon, CPU
|
|
|
50
50
|
gmax setup # Interactive wizard (models, embedding mode, plugins)
|
|
51
51
|
gmax config # View current settings
|
|
52
52
|
gmax config --embed-mode gpu # Switch to GPU (Apple Silicon)
|
|
53
|
+
gmax config --worker-threads 2 # Cap worker processes (auto = default); applies on daemon restart
|
|
53
54
|
gmax doctor # Health check
|
|
54
55
|
gmax doctor --fix # Auto-repair (compact, prune, remove stale locks)
|
|
55
56
|
```
|
|
@@ -85,6 +86,7 @@ gmax context src/lib/auth.ts --budget 4000 # Deterministic file/path context
|
|
|
85
86
|
gmax project # Languages, structure, key symbols
|
|
86
87
|
gmax related src/lib/auth.ts # Dependencies + dependents
|
|
87
88
|
gmax status # All indexed projects + chunk counts
|
|
89
|
+
gmax status --json # The same plus daemon, settings and workers, as JSON
|
|
88
90
|
```
|
|
89
91
|
|
|
90
92
|
In our public benchmarks, `grepmax` can save about 20% of your LLM tokens and deliver a 30% speedup.
|
|
@@ -423,7 +425,7 @@ fixtures/
|
|
|
423
425
|
| Variable | Description | Default |
|
|
424
426
|
| --- | --- | --- |
|
|
425
427
|
| `GMAX_EMBED_MODE` | Force `cpu` or `gpu` | Auto-detect |
|
|
426
|
-
| `GMAX_WORKER_THREADS` | Worker
|
|
428
|
+
| `GMAX_WORKER_THREADS` | Worker processes for embedding; overrides `gmax config --worker-threads` | `min(4, max(2, cores/2))` |
|
|
427
429
|
| `GMAX_WORKER_RSS_RECYCLE_MB` | Recycle workers that remain above this RSS; `0` disables the check | `1536` |
|
|
428
430
|
| `GMAX_DEBUG` | Debug logging | Off |
|
|
429
431
|
| `GMAX_SUMMARIZER` | Enable summarizer auto-start (`1`) | Off |
|
package/dist/commands/config.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
36
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
37
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -10,6 +43,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
43
|
};
|
|
11
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
45
|
exports.config = void 0;
|
|
46
|
+
const os = __importStar(require("node:os"));
|
|
13
47
|
const commander_1 = require("commander");
|
|
14
48
|
const config_1 = require("../config");
|
|
15
49
|
const embedding_status_1 = require("../lib/index/embedding-status");
|
|
@@ -22,12 +56,15 @@ exports.config = new commander_1.Command("config")
|
|
|
22
56
|
.option("--embed-mode <mode>", "Set embedding mode: cpu or gpu")
|
|
23
57
|
.option("--model-tier <tier>", "Set model tier: small (384d) or standard (768d)")
|
|
24
58
|
.option("--query-log <on|off>", "Enable/disable query logging to ~/.gmax/logs/queries.jsonl")
|
|
59
|
+
.option("--worker-threads <n|auto>", "Set the number of embedding worker processes, or auto for the default")
|
|
25
60
|
.addHelpText("after", `
|
|
26
61
|
Examples:
|
|
27
62
|
gmax config Show current configuration
|
|
28
63
|
gmax config --embed-mode cpu Switch to CPU embeddings
|
|
29
64
|
gmax config --model-tier standard Switch to standard model (768d)
|
|
30
65
|
gmax config --query-log on Enable query logging
|
|
66
|
+
gmax config --worker-threads 2 Run at most 2 worker processes
|
|
67
|
+
gmax config --worker-threads auto Back to the computed default
|
|
31
68
|
`)
|
|
32
69
|
.action((_opts, cmd) => __awaiter(void 0, void 0, void 0, function* () {
|
|
33
70
|
var _a, _b, _c, _d, _e;
|
|
@@ -37,7 +74,8 @@ Examples:
|
|
|
37
74
|
const project = (0, project_registry_1.getProject)((_a = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _a !== void 0 ? _a : process.cwd());
|
|
38
75
|
const hasUpdates = options.embedMode !== undefined ||
|
|
39
76
|
options.modelTier !== undefined ||
|
|
40
|
-
options.queryLog !== undefined
|
|
77
|
+
options.queryLog !== undefined ||
|
|
78
|
+
options.workerThreads !== undefined;
|
|
41
79
|
if (!hasUpdates) {
|
|
42
80
|
// Show current config
|
|
43
81
|
const tier = (_b = config_1.MODEL_TIERS[globalConfig.modelTier]) !== null && _b !== void 0 ? _b : config_1.MODEL_TIERS.small;
|
|
@@ -57,10 +95,15 @@ Examples:
|
|
|
57
95
|
}
|
|
58
96
|
}
|
|
59
97
|
console.log(` Query log: ${globalConfig.queryLog ? "on" : "off"}`);
|
|
98
|
+
const threads = (0, config_1.resolveWorkerThreads)({
|
|
99
|
+
env: process.env.GMAX_WORKER_THREADS,
|
|
100
|
+
configValue: globalConfig.workerThreads,
|
|
101
|
+
});
|
|
102
|
+
console.log(` Worker threads: ${threads.value} (${threads.source})`);
|
|
60
103
|
if (project === null || project === void 0 ? void 0 : project.lastIndexed) {
|
|
61
104
|
console.log(` Last indexed: ${project.lastIndexed}`);
|
|
62
105
|
}
|
|
63
|
-
console.log(`\nTo change: gmax config --embed-mode <cpu|gpu> --model-tier <small|standard> --query-log <on|off>`);
|
|
106
|
+
console.log(`\nTo change: gmax config --embed-mode <cpu|gpu> --model-tier <small|standard> --query-log <on|off> --worker-threads <n|auto>`);
|
|
64
107
|
yield (0, exit_1.gracefulExit)();
|
|
65
108
|
return;
|
|
66
109
|
}
|
|
@@ -75,6 +118,36 @@ Examples:
|
|
|
75
118
|
yield (0, exit_1.gracefulExit)(1);
|
|
76
119
|
return;
|
|
77
120
|
}
|
|
121
|
+
if (options.workerThreads !== undefined) {
|
|
122
|
+
const cores = os.cpus().length || 1;
|
|
123
|
+
const raw = options.workerThreads.trim().toLowerCase();
|
|
124
|
+
const value = raw === "auto" ? undefined : (0, config_1.parseWorkerThreads)(raw, cores);
|
|
125
|
+
if (value === null) {
|
|
126
|
+
console.error(`Invalid worker threads: ${options.workerThreads} (use a whole number from 1 to ${cores}, or auto)`);
|
|
127
|
+
yield (0, exit_1.gracefulExit)(1);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
(0, index_config_1.writeGlobalConfig)(Object.assign(Object.assign({}, globalConfig), { workerThreads: value }));
|
|
131
|
+
globalConfig.workerThreads = value;
|
|
132
|
+
const effective = (0, config_1.resolveWorkerThreads)({
|
|
133
|
+
env: process.env.GMAX_WORKER_THREADS,
|
|
134
|
+
configValue: value,
|
|
135
|
+
cores,
|
|
136
|
+
});
|
|
137
|
+
console.log(value === undefined
|
|
138
|
+
? `Worker threads set to auto (${(0, config_1.defaultWorkerThreads)(cores)} on this machine).`
|
|
139
|
+
: `Worker threads set to ${value}.`);
|
|
140
|
+
if (effective.source === "env") {
|
|
141
|
+
console.log(`GMAX_WORKER_THREADS=${process.env.GMAX_WORKER_THREADS} is set in this shell and overrides it here.`);
|
|
142
|
+
}
|
|
143
|
+
console.log("Takes effect when the gmax daemon restarts: gmax watch stop, then gmax watch --daemon -b.");
|
|
144
|
+
if (options.queryLog === undefined &&
|
|
145
|
+
!options.embedMode &&
|
|
146
|
+
!options.modelTier) {
|
|
147
|
+
yield (0, exit_1.gracefulExit)();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
78
151
|
// Handle query-log toggle (independent of model/embed changes)
|
|
79
152
|
if (options.queryLog !== undefined) {
|
|
80
153
|
if (!["on", "off"].includes(options.queryLog)) {
|
|
@@ -103,6 +176,7 @@ Examples:
|
|
|
103
176
|
embedMode: newMode,
|
|
104
177
|
mlxModel: newMode === "gpu" ? tier.mlxModel : undefined,
|
|
105
178
|
queryLog: globalConfig.queryLog,
|
|
179
|
+
workerThreads: globalConfig.workerThreads,
|
|
106
180
|
});
|
|
107
181
|
(0, index_config_1.writeSetupConfig)(paths.configPath, {
|
|
108
182
|
embedMode: newMode,
|
package/dist/commands/status.js
CHANGED
|
@@ -43,6 +43,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.status = void 0;
|
|
46
|
+
exports.buildStatusJson = buildStatusJson;
|
|
47
|
+
const node_child_process_1 = require("node:child_process");
|
|
46
48
|
const os = __importStar(require("node:os"));
|
|
47
49
|
const commander_1 = require("commander");
|
|
48
50
|
const config_1 = require("../config");
|
|
@@ -89,7 +91,17 @@ function loadStatusView(projects) {
|
|
|
89
91
|
chunkCounts.set(project.root, stats.chunks);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
|
-
|
|
94
|
+
const daemon = {
|
|
95
|
+
pid: typeof resp.pid === "number" ? resp.pid : null,
|
|
96
|
+
uptimeSec: typeof resp.uptime === "number" ? resp.uptime : null,
|
|
97
|
+
// Older daemons do not report these.
|
|
98
|
+
workers: typeof resp.workers === "number" ? resp.workers : null,
|
|
99
|
+
workerThreads: resp.workerThreads &&
|
|
100
|
+
typeof resp.workerThreads.value === "number"
|
|
101
|
+
? resp.workerThreads.value
|
|
102
|
+
: null,
|
|
103
|
+
};
|
|
104
|
+
return { watchers, chunkCounts, daemon };
|
|
93
105
|
}),
|
|
94
106
|
inProcess: () => __awaiter(this, void 0, void 0, function* () {
|
|
95
107
|
(0, watcher_store_1.listWatchers)(); // cleans stale entries as side effect
|
|
@@ -129,6 +141,86 @@ function loadStatusView(projects) {
|
|
|
129
141
|
});
|
|
130
142
|
});
|
|
131
143
|
}
|
|
144
|
+
/** State shown per project; shared by --agent and --json. */
|
|
145
|
+
function projectState(project, watcher) {
|
|
146
|
+
var _a;
|
|
147
|
+
const projectStatus = (_a = project.status) !== null && _a !== void 0 ? _a : "indexed";
|
|
148
|
+
if (projectStatus === "pending")
|
|
149
|
+
return "pending";
|
|
150
|
+
if (projectStatus === "error")
|
|
151
|
+
return "error";
|
|
152
|
+
if ((watcher === null || watcher === void 0 ? void 0 : watcher.status) === "syncing")
|
|
153
|
+
return "indexing";
|
|
154
|
+
if (watcher)
|
|
155
|
+
return "watching";
|
|
156
|
+
return "idle";
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Worker processes under the daemon, from the process table. Used only when
|
|
160
|
+
* the daemon is too old to report its pool size.
|
|
161
|
+
*/
|
|
162
|
+
function countWorkerProcesses(daemonPid) {
|
|
163
|
+
try {
|
|
164
|
+
const out = (0, node_child_process_1.execFileSync)("ps", ["-axo", "ppid=,command="], {
|
|
165
|
+
encoding: "utf8",
|
|
166
|
+
timeout: 2000,
|
|
167
|
+
});
|
|
168
|
+
let n = 0;
|
|
169
|
+
for (const line of out.split("\n")) {
|
|
170
|
+
const m = line.trim().match(/^(\d+)\s+(\S+)/);
|
|
171
|
+
if (m && Number(m[1]) === daemonPid && m[2] === "gmax-worker")
|
|
172
|
+
n++;
|
|
173
|
+
}
|
|
174
|
+
return n;
|
|
175
|
+
}
|
|
176
|
+
catch (_a) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function toMs(iso) {
|
|
181
|
+
if (!iso)
|
|
182
|
+
return null;
|
|
183
|
+
const t = Date.parse(iso);
|
|
184
|
+
return Number.isFinite(t) ? t : null;
|
|
185
|
+
}
|
|
186
|
+
function buildStatusJson(input) {
|
|
187
|
+
var _a, _b, _c, _d, _e;
|
|
188
|
+
const now = (_a = input.now) !== null && _a !== void 0 ? _a : Date.now();
|
|
189
|
+
const { view, globalConfig } = input;
|
|
190
|
+
const d = view.daemon;
|
|
191
|
+
let workersRunning = null;
|
|
192
|
+
if (d) {
|
|
193
|
+
workersRunning = (_b = d.workers) !== null && _b !== void 0 ? _b : (d.pid !== null
|
|
194
|
+
? ((_c = input.countWorkers) !== null && _c !== void 0 ? _c : countWorkerProcesses)(d.pid)
|
|
195
|
+
: null);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
daemon: {
|
|
199
|
+
running: d !== undefined,
|
|
200
|
+
pid: (_d = d === null || d === void 0 ? void 0 : d.pid) !== null && _d !== void 0 ? _d : null,
|
|
201
|
+
since: (d === null || d === void 0 ? void 0 : d.uptimeSec) != null ? now - d.uptimeSec * 1000 : null,
|
|
202
|
+
workerThreads: (_e = d === null || d === void 0 ? void 0 : d.workerThreads) !== null && _e !== void 0 ? _e : null,
|
|
203
|
+
},
|
|
204
|
+
settings: {
|
|
205
|
+
embedMode: globalConfig.embedMode,
|
|
206
|
+
modelTier: globalConfig.modelTier,
|
|
207
|
+
vectorDim: globalConfig.vectorDim,
|
|
208
|
+
queryLog: globalConfig.queryLog === true,
|
|
209
|
+
workerThreads: input.workerThreads,
|
|
210
|
+
},
|
|
211
|
+
workersRunning,
|
|
212
|
+
indexing: input.indexing,
|
|
213
|
+
projects: input.projects.map((project) => { var _a, _b; return ({
|
|
214
|
+
name: project.name,
|
|
215
|
+
root: project.root,
|
|
216
|
+
chunks: (_b = (_a = view.chunkCounts.get(project.root)) !== null && _a !== void 0 ? _a : project.chunkCount) !== null && _b !== void 0 ? _b : 0,
|
|
217
|
+
indexedAt: toMs(project.lastIndexed),
|
|
218
|
+
state: projectState(project, view.watchers.get(project.root)),
|
|
219
|
+
embedding: (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig).state,
|
|
220
|
+
}); }),
|
|
221
|
+
at: now,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
132
224
|
const style = {
|
|
133
225
|
bold: (s) => `\x1b[1m${s}\x1b[22m`,
|
|
134
226
|
dim: (s) => `\x1b[2m${s}\x1b[22m`,
|
|
@@ -169,12 +261,14 @@ function formatChunks(n) {
|
|
|
169
261
|
exports.status = new commander_1.Command("status")
|
|
170
262
|
.description("Show gmax index status for all projects")
|
|
171
263
|
.option("--agent", "Compact output for AI agents", false)
|
|
264
|
+
.option("--json", "Machine-readable status: daemon, settings, projects", false)
|
|
172
265
|
.addHelpText("after", `
|
|
173
266
|
Examples:
|
|
174
267
|
gmax status Show status of all indexed projects
|
|
268
|
+
gmax status --json The same, plus daemon and settings, as JSON
|
|
175
269
|
`)
|
|
176
270
|
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
177
|
-
var _a, _b, _c
|
|
271
|
+
var _a, _b, _c;
|
|
178
272
|
const globalConfig = (0, index_config_1.readGlobalConfig)();
|
|
179
273
|
const projects = (0, project_registry_1.listProjects)();
|
|
180
274
|
const indexing = (0, lock_1.isLocked)(config_1.PATHS.globalRoot);
|
|
@@ -192,6 +286,21 @@ Examples:
|
|
|
192
286
|
throw err;
|
|
193
287
|
}
|
|
194
288
|
const { watchers, chunkCounts } = view;
|
|
289
|
+
if (opts.json) {
|
|
290
|
+
const json = buildStatusJson({
|
|
291
|
+
view,
|
|
292
|
+
projects,
|
|
293
|
+
globalConfig,
|
|
294
|
+
indexing,
|
|
295
|
+
workerThreads: (0, config_1.resolveWorkerThreads)({
|
|
296
|
+
env: process.env.GMAX_WORKER_THREADS,
|
|
297
|
+
configValue: globalConfig.workerThreads,
|
|
298
|
+
}),
|
|
299
|
+
});
|
|
300
|
+
console.log(JSON.stringify(json));
|
|
301
|
+
yield (0, exit_1.gracefulExit)();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
195
304
|
if (!opts.agent) {
|
|
196
305
|
// Header
|
|
197
306
|
console.log(`\n${style.bold("gmax")} · ${globalConfig.modelTier} (${globalConfig.vectorDim}d, ${globalConfig.embedMode})${indexing ? style.yellow(" · indexing...") : ""}`);
|
|
@@ -208,21 +317,9 @@ Examples:
|
|
|
208
317
|
}
|
|
209
318
|
if (opts.agent) {
|
|
210
319
|
for (const project of projects) {
|
|
211
|
-
const
|
|
212
|
-
const projectStatus = (_a = project.status) !== null && _a !== void 0 ? _a : "indexed";
|
|
213
|
-
let st;
|
|
214
|
-
if (projectStatus === "pending")
|
|
215
|
-
st = "pending";
|
|
216
|
-
else if (projectStatus === "error")
|
|
217
|
-
st = "error";
|
|
218
|
-
else if ((watcher === null || watcher === void 0 ? void 0 : watcher.status) === "syncing")
|
|
219
|
-
st = "indexing";
|
|
220
|
-
else if (watcher)
|
|
221
|
-
st = "watching";
|
|
222
|
-
else
|
|
223
|
-
st = "idle";
|
|
320
|
+
const st = projectState(project, watchers.get(project.root));
|
|
224
321
|
const isCurrent = project.root === currentRoot;
|
|
225
|
-
const count = (
|
|
322
|
+
const count = (_a = chunkCounts.get(project.root)) !== null && _a !== void 0 ? _a : project.chunkCount;
|
|
226
323
|
const identity = (0, embedding_status_1.projectEmbeddingStatus)(project, globalConfig);
|
|
227
324
|
console.log(`${project.name}\t${formatChunks(count)}\t${formatAge(project.lastIndexed)}\t${st}\tembedding=${identity.state}${isCurrent ? "\tcurrent" : ""}`);
|
|
228
325
|
}
|
|
@@ -240,7 +337,7 @@ Examples:
|
|
|
240
337
|
const watcher = watchers.get(project.root);
|
|
241
338
|
// Status column
|
|
242
339
|
let statusStr;
|
|
243
|
-
const projectStatus = (
|
|
340
|
+
const projectStatus = (_b = project.status) !== null && _b !== void 0 ? _b : "indexed";
|
|
244
341
|
if (projectStatus === "pending") {
|
|
245
342
|
statusStr = style.yellow("pending");
|
|
246
343
|
}
|
|
@@ -257,7 +354,7 @@ Examples:
|
|
|
257
354
|
statusStr = style.dim("idle");
|
|
258
355
|
}
|
|
259
356
|
// Chunks column
|
|
260
|
-
const count = (
|
|
357
|
+
const count = (_c = chunkCounts.get(project.root)) !== null && _c !== void 0 ? _c : project.chunkCount;
|
|
261
358
|
const chunks = `${formatChunks(count)} chunks`;
|
|
262
359
|
// Age column
|
|
263
360
|
const age = formatAge(project.lastIndexed);
|
package/dist/config.js
CHANGED
|
@@ -33,11 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.INDEXABLE_EXTENSIONS = exports.STALE_TEMP_FILE_AGE_MS = exports.VERSION_PRUNE_THRESHOLD = exports.FRAGMENT_COMPACT_THRESHOLD = exports.DISK_LOW_BYTES = exports.DISK_CRITICAL_BYTES = exports.MAX_FILE_SIZE_BYTES = exports.PATHS = exports.MAX_WORKER_MEMORY_MB = exports.WORKER_BOOT_TIMEOUT_MS = exports.WORKER_TIMEOUT_MS = exports.REBUILD_COMMAND = exports.CHUNKER_VERSION_HISTORY = exports.CONFIG = exports.MODEL_IDS = exports.DEFAULT_MODEL_TIER = exports.MODEL_TIERS = void 0;
|
|
36
|
+
exports.INDEXABLE_EXTENSIONS = exports.STALE_TEMP_FILE_AGE_MS = exports.VERSION_PRUNE_THRESHOLD = exports.FRAGMENT_COMPACT_THRESHOLD = exports.DISK_LOW_BYTES = exports.DISK_CRITICAL_BYTES = exports.MAX_FILE_SIZE_BYTES = exports.PATHS = exports.MAX_WORKER_MEMORY_MB = exports.WORKER_BOOT_TIMEOUT_MS = exports.WORKER_TIMEOUT_MS = exports.REBUILD_COMMAND = exports.CHUNKER_VERSION_HISTORY = exports.CONFIG = exports.WORKER_THREADS_SETTING = exports.MODEL_IDS = exports.DEFAULT_MODEL_TIER = exports.MODEL_TIERS = void 0;
|
|
37
|
+
exports.defaultWorkerThreads = defaultWorkerThreads;
|
|
38
|
+
exports.parseWorkerThreads = parseWorkerThreads;
|
|
39
|
+
exports.resolveWorkerThreads = resolveWorkerThreads;
|
|
37
40
|
exports.describeChunkerGap = describeChunkerGap;
|
|
38
41
|
exports.describeEmbeddingGap = describeEmbeddingGap;
|
|
39
42
|
exports.describeSchemaDimGap = describeSchemaDimGap;
|
|
40
43
|
exports.schemaDimAgentRow = schemaDimAgentRow;
|
|
44
|
+
const fs = __importStar(require("node:fs"));
|
|
41
45
|
const os = __importStar(require("node:os"));
|
|
42
46
|
const path = __importStar(require("node:path"));
|
|
43
47
|
exports.MODEL_TIERS = {
|
|
@@ -63,27 +67,79 @@ exports.MODEL_IDS = {
|
|
|
63
67
|
embed: exports.MODEL_TIERS[exports.DEFAULT_MODEL_TIER].onnxModel,
|
|
64
68
|
colbert: "ryandono/mxbai-edge-colbert-v0-17m-onnx-int8",
|
|
65
69
|
};
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
const HOME = os.homedir();
|
|
71
|
+
// Models, grammars and the pinned HF cache are shared by every store and always
|
|
72
|
+
// live on the internal disk. GMAX_HOME moves only the data root: a secondary
|
|
73
|
+
// store on an external drive (see src/lib/utils/stores.ts) sets it before this
|
|
74
|
+
// module loads, so a project's index can live on the drive with its files.
|
|
75
|
+
const SHARED_ROOT = path.join(HOME, ".gmax");
|
|
76
|
+
const GLOBAL_ROOT = process.env.GMAX_HOME
|
|
77
|
+
? path.resolve(process.env.GMAX_HOME)
|
|
78
|
+
: SHARED_ROOT;
|
|
79
|
+
function coreCount() {
|
|
80
|
+
return os.cpus().length || 1;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Each worker is a separate process that loads the ONNX models, peaking at
|
|
84
|
+
* ~800 MB-1 GB. The old max(4, cores/2) let a 14-core host run 7 of them;
|
|
85
|
+
* together with the daemon that froze a 48 GB machine. Four is the ceiling;
|
|
86
|
+
* two is the floor where the cores exist, so one worker can stay free for
|
|
87
|
+
* search.
|
|
88
|
+
*/
|
|
89
|
+
function defaultWorkerThreads(cores = coreCount()) {
|
|
77
90
|
const target = Math.min(4, Math.max(2, Math.floor(cores * 0.5)));
|
|
78
91
|
return Math.max(1, Math.min(target, cores));
|
|
79
|
-
}
|
|
92
|
+
}
|
|
93
|
+
/** A stored or typed worker count is a whole number from 1 to the core count. */
|
|
94
|
+
function parseWorkerThreads(value, cores = coreCount()) {
|
|
95
|
+
const n = typeof value === "number"
|
|
96
|
+
? value
|
|
97
|
+
: typeof value === "string" && /^\d+$/.test(value.trim())
|
|
98
|
+
? Number(value.trim())
|
|
99
|
+
: Number.NaN;
|
|
100
|
+
if (!Number.isInteger(n) || n < 1 || n > cores)
|
|
101
|
+
return null;
|
|
102
|
+
return n;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* GMAX_WORKER_THREADS wins, then `workerThreads` in ~/.gmax/config.json
|
|
106
|
+
* (`gmax config --worker-threads`), then the computed default. The env var
|
|
107
|
+
* keeps its old meaning (any positive whole number); a stored value outside
|
|
108
|
+
* 1..cores is ignored.
|
|
109
|
+
*/
|
|
110
|
+
function resolveWorkerThreads(opts) {
|
|
111
|
+
var _a, _b;
|
|
112
|
+
const cores = (_a = opts.cores) !== null && _a !== void 0 ? _a : coreCount();
|
|
113
|
+
const fromEnv = Number.parseInt((_b = opts.env) !== null && _b !== void 0 ? _b : "", 10);
|
|
114
|
+
if (Number.isFinite(fromEnv) && fromEnv > 0) {
|
|
115
|
+
return { value: fromEnv, source: "env" };
|
|
116
|
+
}
|
|
117
|
+
const fromConfig = parseWorkerThreads(opts.configValue, cores);
|
|
118
|
+
if (fromConfig !== null)
|
|
119
|
+
return { value: fromConfig, source: "config" };
|
|
120
|
+
return { value: defaultWorkerThreads(cores), source: "default" };
|
|
121
|
+
}
|
|
122
|
+
function storedWorkerThreads() {
|
|
123
|
+
try {
|
|
124
|
+
const raw = fs.readFileSync(path.join(GLOBAL_ROOT, "config.json"), "utf-8");
|
|
125
|
+
return JSON.parse(raw).workerThreads;
|
|
126
|
+
}
|
|
127
|
+
catch (_a) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Read once at load: a running daemon keeps the value it started with. */
|
|
132
|
+
exports.WORKER_THREADS_SETTING = resolveWorkerThreads({
|
|
133
|
+
env: process.env.GMAX_WORKER_THREADS,
|
|
134
|
+
configValue: storedWorkerThreads(),
|
|
135
|
+
});
|
|
80
136
|
exports.CONFIG = {
|
|
81
137
|
VECTOR_DIM: 384,
|
|
82
138
|
COLBERT_DIM: 48,
|
|
83
139
|
MAX_CHUNK_CHARS: 2000,
|
|
84
140
|
MAX_CHUNK_LINES: 75,
|
|
85
141
|
EMBED_BATCH_SIZE: 24,
|
|
86
|
-
WORKER_THREADS:
|
|
142
|
+
WORKER_THREADS: exports.WORKER_THREADS_SETTING.value,
|
|
87
143
|
QUERY_PREFIX: "",
|
|
88
144
|
// Bump when chunk metadata semantics change in a way that requires a full
|
|
89
145
|
// reindex to take effect. Must equal the latest entry's `v` in
|
|
@@ -217,15 +273,6 @@ exports.MAX_WORKER_MEMORY_MB = (() => {
|
|
|
217
273
|
const HARD_CEILING = 4096; // 4GB max per worker regardless of system RAM
|
|
218
274
|
return Math.min(HARD_CEILING, Math.max(2048, Math.floor((os.totalmem() / 1024 / 1024) * 0.5)));
|
|
219
275
|
})();
|
|
220
|
-
const HOME = os.homedir();
|
|
221
|
-
// Models, grammars and the pinned HF cache are shared by every store and always
|
|
222
|
-
// live on the internal disk. GMAX_HOME moves only the data root: a secondary
|
|
223
|
-
// store on an external drive (see src/lib/utils/stores.ts) sets it before this
|
|
224
|
-
// module loads, so a project's index can live on the drive with its files.
|
|
225
|
-
const SHARED_ROOT = path.join(HOME, ".gmax");
|
|
226
|
-
const GLOBAL_ROOT = process.env.GMAX_HOME
|
|
227
|
-
? path.resolve(process.env.GMAX_HOME)
|
|
228
|
-
: SHARED_ROOT;
|
|
229
276
|
exports.PATHS = {
|
|
230
277
|
globalRoot: GLOBAL_ROOT,
|
|
231
278
|
sharedRoot: SHARED_ROOT,
|
|
@@ -844,6 +844,12 @@ class Daemon {
|
|
|
844
844
|
uptime() {
|
|
845
845
|
return Math.floor((Date.now() - this.startTime) / 1000);
|
|
846
846
|
}
|
|
847
|
+
/** Worker processes alive in the pool right now (0 before it exists). */
|
|
848
|
+
workerCount() {
|
|
849
|
+
var _a;
|
|
850
|
+
var _b;
|
|
851
|
+
return (_b = (_a = this.workerPool) === null || _a === void 0 ? void 0 : _a.getWorkerPids().length) !== null && _b !== void 0 ? _b : 0;
|
|
852
|
+
}
|
|
847
853
|
/** True once shared resources (LanceDB + MetaCache) are open. */
|
|
848
854
|
isReady() {
|
|
849
855
|
return this.ready;
|
|
@@ -49,6 +49,7 @@ exports.startHeartbeat = startHeartbeat;
|
|
|
49
49
|
exports.handleCommand = handleCommand;
|
|
50
50
|
const fs = __importStar(require("node:fs"));
|
|
51
51
|
const path = __importStar(require("node:path"));
|
|
52
|
+
const config_1 = require("../../config");
|
|
52
53
|
const logger_1 = require("../utils/logger");
|
|
53
54
|
const operation_coordinator_1 = require("../utils/operation-coordinator");
|
|
54
55
|
const path_containment_1 = require("../utils/path-containment");
|
|
@@ -183,6 +184,8 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
183
184
|
leases: daemon.listWatchLeases(),
|
|
184
185
|
diskPressure: daemon.getDiskPressure(),
|
|
185
186
|
mlx: daemon.getMlxStatus(),
|
|
187
|
+
workers: daemon.workerCount(),
|
|
188
|
+
workerThreads: config_1.WORKER_THREADS_SETTING,
|
|
186
189
|
};
|
|
187
190
|
case "optimize":
|
|
188
191
|
// Keeps compaction single-writer: see Daemon.runOptimize.
|
package/package.json
CHANGED