eminiar 0.10.0 → 0.11.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/plugin.json +1 -1
- package/.cursor-plugin/mcp.json +11 -0
- package/.cursor-plugin/plugin.json +23 -0
- package/README.md +12 -8
- package/dist/cli.js +809 -451
- package/dist/hook.js +848 -504
- package/dist/server.js +247 -57
- package/hooks/cursor.json +36 -0
- package/package.json +7 -4
- package/rules/eminiar.mdc +15 -0
- package/skills/em-docs/SKILL.md +3 -1
package/dist/cli.js
CHANGED
|
@@ -21270,6 +21270,14 @@ function findOnPath(bin) {
|
|
|
21270
21270
|
}
|
|
21271
21271
|
return void 0;
|
|
21272
21272
|
}
|
|
21273
|
+
function requirePreamble(code) {
|
|
21274
|
+
if (!/\brequire\s*\(/.test(code)) return void 0;
|
|
21275
|
+
if (/\b(?:const|let|var|function)\s+require\b/.test(code) || /\bcreateRequire\b/.test(code)) {
|
|
21276
|
+
return void 0;
|
|
21277
|
+
}
|
|
21278
|
+
return `${REQUIRE_PREAMBLE}
|
|
21279
|
+
`;
|
|
21280
|
+
}
|
|
21273
21281
|
function preferredShell() {
|
|
21274
21282
|
const sh = process.env.SHELL ?? "";
|
|
21275
21283
|
if (/\/(zsh|bash)$/.test(sh) && existsSync5(sh)) return sh;
|
|
@@ -21290,13 +21298,14 @@ function availableLanguages() {
|
|
|
21290
21298
|
return { id: l.id, bin };
|
|
21291
21299
|
});
|
|
21292
21300
|
}
|
|
21293
|
-
var require3, tsxPath, LANGUAGES;
|
|
21301
|
+
var require3, REQUIRE_PREAMBLE, tsxPath, LANGUAGES;
|
|
21294
21302
|
var init_languages = __esm({
|
|
21295
21303
|
"src/sandbox/languages.ts"() {
|
|
21296
21304
|
"use strict";
|
|
21297
21305
|
init_esm_shims();
|
|
21298
21306
|
init_paths();
|
|
21299
21307
|
require3 = createRequire2(import.meta.url);
|
|
21308
|
+
REQUIRE_PREAMBLE = 'import { createRequire } from "node:module"; const require = createRequire(process.env.EMINIAR_PROJECT_ROOT ? process.env.EMINIAR_PROJECT_ROOT + "/package.json" : import.meta.url);';
|
|
21300
21309
|
LANGUAGES = [
|
|
21301
21310
|
{
|
|
21302
21311
|
id: "shell",
|
|
@@ -21310,14 +21319,16 @@ var init_languages = __esm({
|
|
|
21310
21319
|
aliases: ["js", "node", "mjs"],
|
|
21311
21320
|
ext: ".mjs",
|
|
21312
21321
|
detect: () => process.execPath,
|
|
21313
|
-
argv: (bin, file3) => [bin, "--no-warnings", file3]
|
|
21322
|
+
argv: (bin, file3) => [bin, "--no-warnings", file3],
|
|
21323
|
+
preamble: requirePreamble
|
|
21314
21324
|
},
|
|
21315
21325
|
{
|
|
21316
21326
|
id: "typescript",
|
|
21317
21327
|
aliases: ["ts"],
|
|
21318
21328
|
ext: ".ts",
|
|
21319
21329
|
detect: () => process.execPath,
|
|
21320
|
-
argv: (bin, file3) => [bin, "--no-warnings", tsxCli(), file3]
|
|
21330
|
+
argv: (bin, file3) => [bin, "--no-warnings", tsxCli(), file3],
|
|
21331
|
+
preamble: requirePreamble
|
|
21321
21332
|
},
|
|
21322
21333
|
{
|
|
21323
21334
|
id: "python",
|
|
@@ -21524,6 +21535,10 @@ var init_terms = __esm({
|
|
|
21524
21535
|
});
|
|
21525
21536
|
|
|
21526
21537
|
// src/storage/sqlite/schema.ts
|
|
21538
|
+
function hasColumn(db, table, column) {
|
|
21539
|
+
const cols = db.pragma(`table_info(${table})`);
|
|
21540
|
+
return cols.some((c) => c.name === column);
|
|
21541
|
+
}
|
|
21527
21542
|
function vecTableSql(dims) {
|
|
21528
21543
|
return `CREATE VIRTUAL TABLE IF NOT EXISTS chunk_vec USING vec0(chunk_id INTEGER PRIMARY KEY, embedding float[${dims}])`;
|
|
21529
21544
|
}
|
|
@@ -21866,7 +21881,6 @@ CREATE TABLE IF NOT EXISTS transcript_files (
|
|
|
21866
21881
|
offset INTEGER NOT NULL DEFAULT 0,
|
|
21867
21882
|
size INTEGER NOT NULL DEFAULT 0,
|
|
21868
21883
|
mtime INTEGER NOT NULL DEFAULT 0,
|
|
21869
|
-
head_hash TEXT,
|
|
21870
21884
|
ingested_at INTEGER NOT NULL
|
|
21871
21885
|
);
|
|
21872
21886
|
|
|
@@ -21894,6 +21908,16 @@ CREATE TABLE IF NOT EXISTS statusline_snapshots (
|
|
|
21894
21908
|
CREATE INDEX IF NOT EXISTS statusline_snapshots_session_ts ON statusline_snapshots(session_id, ts);
|
|
21895
21909
|
CREATE INDEX IF NOT EXISTS statusline_snapshots_ts ON statusline_snapshots(ts);
|
|
21896
21910
|
`
|
|
21911
|
+
},
|
|
21912
|
+
{
|
|
21913
|
+
// transcript_files.head_hash (fingerprint of the file head, so a rewrite with the same
|
|
21914
|
+
// size is noticed) was first added to v5 after v5 had already run on real databases, so
|
|
21915
|
+
// version-5 databases exist both with and without the column. Add it only when missing.
|
|
21916
|
+
version: 6,
|
|
21917
|
+
up(db) {
|
|
21918
|
+
if (!hasColumn(db, "transcript_files", "head_hash"))
|
|
21919
|
+
db.exec("ALTER TABLE transcript_files ADD COLUMN head_hash TEXT");
|
|
21920
|
+
}
|
|
21897
21921
|
}
|
|
21898
21922
|
];
|
|
21899
21923
|
}
|
|
@@ -22013,7 +22037,8 @@ var init_adapter = __esm({
|
|
|
22013
22037
|
if (pending2.length) {
|
|
22014
22038
|
this.transaction(() => {
|
|
22015
22039
|
for (const m of pending2) {
|
|
22016
|
-
this.db.exec(m.sql);
|
|
22040
|
+
if (m.sql) this.db.exec(m.sql);
|
|
22041
|
+
m.up?.(this.db);
|
|
22017
22042
|
this.metaSet("schema_version", String(m.version));
|
|
22018
22043
|
}
|
|
22019
22044
|
});
|
|
@@ -22232,18 +22257,42 @@ var init_adapter = __esm({
|
|
|
22232
22257
|
}
|
|
22233
22258
|
vecSearch(embedding, k, filters) {
|
|
22234
22259
|
if (!this.vectors) return [];
|
|
22235
|
-
const raw = this.db.prepare(
|
|
22236
|
-
"SELECT chunk_id id, distance FROM chunk_vec WHERE embedding MATCH ? AND k = ? ORDER BY distance"
|
|
22237
|
-
).all(embedding, BigInt(filters ? k * 4 : k));
|
|
22238
|
-
if (!filters || !raw.length) return raw.map((r) => ({ chunkId: r.id, distance: r.distance }));
|
|
22239
22260
|
const { where, params } = filterSql(filters);
|
|
22240
|
-
|
|
22241
|
-
|
|
22242
|
-
|
|
22243
|
-
|
|
22244
|
-
|
|
22245
|
-
|
|
22246
|
-
|
|
22261
|
+
if (!where) return this.knn(embedding, k);
|
|
22262
|
+
try {
|
|
22263
|
+
return this.knn(
|
|
22264
|
+
embedding,
|
|
22265
|
+
k,
|
|
22266
|
+
`AND chunk_id IN (SELECT c.id FROM chunks c JOIN documents d ON d.id = c.document_id WHERE 1=1${where})`,
|
|
22267
|
+
params
|
|
22268
|
+
);
|
|
22269
|
+
} catch {
|
|
22270
|
+
return this.vecSearchWidening(embedding, k, where, params);
|
|
22271
|
+
}
|
|
22272
|
+
}
|
|
22273
|
+
knn(embedding, k, extra = "", params = []) {
|
|
22274
|
+
return this.db.prepare(
|
|
22275
|
+
`SELECT chunk_id id, distance FROM chunk_vec WHERE embedding MATCH ? AND k = ? ${extra} ORDER BY distance`
|
|
22276
|
+
).all(embedding, BigInt(k), ...params).map((r) => ({ chunkId: r.id, distance: r.distance }));
|
|
22277
|
+
}
|
|
22278
|
+
/** Fallback filtered KNN: fetch k*4, k*16, ... nearest until k pass the filter or all were seen. */
|
|
22279
|
+
vecSearchWidening(embedding, k, where, params) {
|
|
22280
|
+
const total = this.vecCount();
|
|
22281
|
+
for (let fetch2 = k * 4; ; fetch2 *= 4) {
|
|
22282
|
+
const raw = this.knn(embedding, Math.min(fetch2, total));
|
|
22283
|
+
if (!raw.length) return [];
|
|
22284
|
+
const allowed = /* @__PURE__ */ new Set();
|
|
22285
|
+
for (let i = 0; i < raw.length; i += 400) {
|
|
22286
|
+
const ids = raw.slice(i, i + 400).map((r) => r.chunkId);
|
|
22287
|
+
for (const r of this.db.prepare(
|
|
22288
|
+
`SELECT c.id FROM chunks c JOIN documents d ON d.id = c.document_id
|
|
22289
|
+
WHERE c.id IN (${ids.map(() => "?").join(",")})${where}`
|
|
22290
|
+
).all(...ids, ...params))
|
|
22291
|
+
allowed.add(r.id);
|
|
22292
|
+
}
|
|
22293
|
+
const hits = raw.filter((r) => allowed.has(r.chunkId)).slice(0, k);
|
|
22294
|
+
if (hits.length >= k || fetch2 >= total) return hits;
|
|
22295
|
+
}
|
|
22247
22296
|
}
|
|
22248
22297
|
unembeddedChunkIds(limit) {
|
|
22249
22298
|
return this.db.prepare("SELECT id FROM chunks WHERE embedded = 0 ORDER BY id LIMIT ?").all(limit).map((r) => r.id);
|
|
@@ -22522,6 +22571,26 @@ var init_adapter = __esm({
|
|
|
22522
22571
|
}
|
|
22523
22572
|
return out;
|
|
22524
22573
|
}
|
|
22574
|
+
graphDependentFileCounts(paths2, kinds) {
|
|
22575
|
+
const out = /* @__PURE__ */ new Map();
|
|
22576
|
+
if (!paths2.length || !kinds.length) return out;
|
|
22577
|
+
const kph = kinds.map(() => "?").join(",");
|
|
22578
|
+
for (let i = 0; i < paths2.length; i += 400) {
|
|
22579
|
+
const batch = paths2.slice(i, i + 400);
|
|
22580
|
+
const pph = batch.map(() => "?").join(",");
|
|
22581
|
+
for (const r of this.db.prepare(
|
|
22582
|
+
`SELECT d.path p, COUNT(DISTINCT s.path) n
|
|
22583
|
+
FROM graph_nodes d
|
|
22584
|
+
JOIN graph_edges e ON e.dst = d.id AND e.kind IN (${kph})
|
|
22585
|
+
JOIN graph_nodes s ON s.id = e.src
|
|
22586
|
+
WHERE d.path IN (${pph}) AND s.path IS NOT NULL AND s.path <> d.path
|
|
22587
|
+
GROUP BY d.path`
|
|
22588
|
+
).all(...kinds, ...batch)) {
|
|
22589
|
+
out.set(r.p, r.n);
|
|
22590
|
+
}
|
|
22591
|
+
}
|
|
22592
|
+
return out;
|
|
22593
|
+
}
|
|
22525
22594
|
edgesWhere(col, ids, kinds) {
|
|
22526
22595
|
if (!ids.length) return [];
|
|
22527
22596
|
const out = [];
|
|
@@ -23152,6 +23221,24 @@ var init_storage = __esm({
|
|
|
23152
23221
|
}
|
|
23153
23222
|
});
|
|
23154
23223
|
|
|
23224
|
+
// src/hooks/cursor.ts
|
|
23225
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
23226
|
+
import { homedir as homedir3 } from "os";
|
|
23227
|
+
import { join as join10 } from "path";
|
|
23228
|
+
function cursorDir() {
|
|
23229
|
+
return process.env.CURSOR_CONFIG_DIR || join10(homedir3(), ".cursor");
|
|
23230
|
+
}
|
|
23231
|
+
var PENDING_TTL_MS;
|
|
23232
|
+
var init_cursor = __esm({
|
|
23233
|
+
"src/hooks/cursor.ts"() {
|
|
23234
|
+
"use strict";
|
|
23235
|
+
init_esm_shims();
|
|
23236
|
+
init_context();
|
|
23237
|
+
init_paths();
|
|
23238
|
+
PENDING_TTL_MS = 10 * 6e4;
|
|
23239
|
+
}
|
|
23240
|
+
});
|
|
23241
|
+
|
|
23155
23242
|
// src/install/shell.ts
|
|
23156
23243
|
import { spawnSync } from "child_process";
|
|
23157
23244
|
import { createInterface } from "readline";
|
|
@@ -23200,194 +23287,20 @@ var init_shell = __esm({
|
|
|
23200
23287
|
}
|
|
23201
23288
|
});
|
|
23202
23289
|
|
|
23203
|
-
// src/install/materialize.ts
|
|
23204
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync6, rmSync as rmSync2 } from "fs";
|
|
23205
|
-
import { join as join10 } from "path";
|
|
23206
|
-
function stableRoot() {
|
|
23207
|
-
return join10(paths().plugin, "node_modules", "eminiar");
|
|
23208
|
-
}
|
|
23209
|
-
function stableVersion() {
|
|
23210
|
-
try {
|
|
23211
|
-
return JSON.parse(readFileSync6(join10(stableRoot(), "package.json"), "utf8")).version;
|
|
23212
|
-
} catch {
|
|
23213
|
-
return void 0;
|
|
23214
|
-
}
|
|
23215
|
-
}
|
|
23216
|
-
function materialize(spec, force = false) {
|
|
23217
|
-
const prefix = paths().plugin;
|
|
23218
|
-
mkdirSync5(prefix, { recursive: true });
|
|
23219
|
-
const root = stableRoot();
|
|
23220
|
-
const here = pluginRoot();
|
|
23221
|
-
if (!force && !spec && here === root) return { root, fromSpec: "self" };
|
|
23222
|
-
if (!force && !spec && stableVersion() === version2() && existsSync7(join10(root, "dist", "server.js"))) {
|
|
23223
|
-
log.ok(`stable copy already at v${version2()} (${root})`);
|
|
23224
|
-
return { root, fromSpec: `pack:${here}` };
|
|
23225
|
-
}
|
|
23226
|
-
let target = spec;
|
|
23227
|
-
if (!target) {
|
|
23228
|
-
if (!existsSync7(join10(here, "dist", "server.js"))) {
|
|
23229
|
-
throw new Error(`${here} has no dist/ \u2014 run \`npm run build\` first`);
|
|
23230
|
-
}
|
|
23231
|
-
const dest = paths().tmp;
|
|
23232
|
-
mkdirSync5(dest, { recursive: true });
|
|
23233
|
-
const pack = run(
|
|
23234
|
-
npmCli(),
|
|
23235
|
-
["pack", "--ignore-scripts", "--pack-destination", dest, "--silent"],
|
|
23236
|
-
{ cwd: here }
|
|
23237
|
-
);
|
|
23238
|
-
if (!pack.ok) throw new Error(`npm pack failed: ${pack.stderr || pack.stdout}`);
|
|
23239
|
-
const tarball = pack.stdout.trim().split("\n").pop();
|
|
23240
|
-
target = join10(dest, tarball);
|
|
23241
|
-
}
|
|
23242
|
-
const install2 = run(
|
|
23243
|
-
npmCli(),
|
|
23244
|
-
[
|
|
23245
|
-
"install",
|
|
23246
|
-
"--prefix",
|
|
23247
|
-
prefix,
|
|
23248
|
-
"--omit=dev",
|
|
23249
|
-
"--no-audit",
|
|
23250
|
-
"--no-fund",
|
|
23251
|
-
"--loglevel=error",
|
|
23252
|
-
target
|
|
23253
|
-
],
|
|
23254
|
-
{
|
|
23255
|
-
env: { ...process.env, npm_config_update_notifier: "false" }
|
|
23256
|
-
}
|
|
23257
|
-
);
|
|
23258
|
-
if (!install2.ok) throw new Error(`npm install failed: ${install2.stderr || install2.stdout}`);
|
|
23259
|
-
if (!spec && target.endsWith(".tgz")) rmSync2(target, { force: true });
|
|
23260
|
-
for (const must of [
|
|
23261
|
-
"dist/server.js",
|
|
23262
|
-
"dist/hook.js",
|
|
23263
|
-
"bin/em-hook",
|
|
23264
|
-
".claude-plugin/plugin.json",
|
|
23265
|
-
"hooks/hooks.json"
|
|
23266
|
-
]) {
|
|
23267
|
-
if (!existsSync7(join10(root, must))) throw new Error(`stable copy is missing ${must}`);
|
|
23268
|
-
}
|
|
23269
|
-
log.ok(
|
|
23270
|
-
`installed v${stableVersion()} into ${root} (${readdirSync3(join10(prefix, "node_modules")).length} packages)`
|
|
23271
|
-
);
|
|
23272
|
-
return { root, fromSpec: spec ?? `pack:${here}` };
|
|
23273
|
-
}
|
|
23274
|
-
function nativeCheck(node2, root) {
|
|
23275
|
-
const script = `
|
|
23276
|
-
const { createRequire } = require("node:module");
|
|
23277
|
-
const req = createRequire(${JSON.stringify(join10(root, "package.json"))});
|
|
23278
|
-
const out = [];
|
|
23279
|
-
for (const m of ["better-sqlite3", "sqlite-vec", "web-tree-sitter", "@huggingface/transformers"]) {
|
|
23280
|
-
try { const x = req(m); if (m === "better-sqlite3") { const db = new x(":memory:"); req("sqlite-vec").load(db); db.close(); } }
|
|
23281
|
-
catch (e) { out.push(m + ": " + (e && e.message ? e.message.split("\\n")[0] : e)); }
|
|
23282
|
-
}
|
|
23283
|
-
process.stdout.write(JSON.stringify(out));
|
|
23284
|
-
`;
|
|
23285
|
-
const r = run(node2, ["-e", script], { cwd: root });
|
|
23286
|
-
if (!r.ok) return [`native check could not run: ${r.stderr.trim().split("\n").pop()}`];
|
|
23287
|
-
try {
|
|
23288
|
-
return JSON.parse(r.stdout);
|
|
23289
|
-
} catch {
|
|
23290
|
-
return [`native check returned garbage: ${r.stdout.slice(0, 200)}`];
|
|
23291
|
-
}
|
|
23292
|
-
}
|
|
23293
|
-
function rebuildNative(root) {
|
|
23294
|
-
const r = run(
|
|
23295
|
-
npmCli(),
|
|
23296
|
-
["rebuild", "better-sqlite3", "--prefix", paths().plugin, "--loglevel=error"],
|
|
23297
|
-
{ cwd: root }
|
|
23298
|
-
);
|
|
23299
|
-
return r.ok;
|
|
23300
|
-
}
|
|
23301
|
-
function downloadModel(node2, root, model2) {
|
|
23302
|
-
const script = `
|
|
23303
|
-
(async () => {
|
|
23304
|
-
const tf = await import("@huggingface/transformers");
|
|
23305
|
-
tf.env.cacheDir = ${JSON.stringify(paths().models)};
|
|
23306
|
-
const p = await tf.pipeline("feature-extraction", ${JSON.stringify(model2)}, { dtype: "q8", device: "cpu" });
|
|
23307
|
-
const r = await p(["warm up"], { pooling: "cls", normalize: true });
|
|
23308
|
-
process.stdout.write(String(r.tolist()[0].length));
|
|
23309
|
-
})().catch((e) => { process.stderr.write(String(e && e.message || e)); process.exit(1); });
|
|
23310
|
-
`;
|
|
23311
|
-
const r = run(node2, ["--input-type=module", "-e", script], { cwd: root });
|
|
23312
|
-
return r.ok ? void 0 : r.stderr.trim().split("\n").pop();
|
|
23313
|
-
}
|
|
23314
|
-
var init_materialize = __esm({
|
|
23315
|
-
"src/install/materialize.ts"() {
|
|
23316
|
-
"use strict";
|
|
23317
|
-
init_esm_shims();
|
|
23318
|
-
init_paths();
|
|
23319
|
-
init_version();
|
|
23320
|
-
init_shell();
|
|
23321
|
-
}
|
|
23322
|
-
});
|
|
23323
|
-
|
|
23324
|
-
// src/install/node-resolve.ts
|
|
23325
|
-
import { accessSync as accessSync3, constants as constants3, existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
23326
|
-
import { join as join11 } from "path";
|
|
23327
|
-
function versionOf(bin) {
|
|
23328
|
-
const r = run(bin, ["-p", "process.versions.node"]);
|
|
23329
|
-
return r.ok ? r.stdout.trim() : void 0;
|
|
23330
|
-
}
|
|
23331
|
-
function nodeOk(version3) {
|
|
23332
|
-
const [maj = 0, min = 0] = version3.split(".").map(Number);
|
|
23333
|
-
return maj > 22 || maj === 22 && min >= 12;
|
|
23334
|
-
}
|
|
23335
|
-
function pinNode(explicit) {
|
|
23336
|
-
const candidate = explicit ?? process.execPath;
|
|
23337
|
-
accessSync3(candidate, constants3.X_OK);
|
|
23338
|
-
const version3 = versionOf(candidate);
|
|
23339
|
-
if (!version3) throw new Error(`${candidate} does not look like a node binary`);
|
|
23340
|
-
if (!nodeOk(version3))
|
|
23341
|
-
throw new Error(`node ${version3} at ${candidate} is too old; need >= 22.12`);
|
|
23342
|
-
writeFileSync4(ensureDirs().nodePathFile, candidate);
|
|
23343
|
-
return { path: candidate, version: version3 };
|
|
23344
|
-
}
|
|
23345
|
-
function pinnedNode() {
|
|
23346
|
-
try {
|
|
23347
|
-
const path3 = readFileSync7(ensureDirs().nodePathFile, "utf8").trim();
|
|
23348
|
-
const version3 = versionOf(path3);
|
|
23349
|
-
return version3 ? { path: path3, version: version3 } : void 0;
|
|
23350
|
-
} catch {
|
|
23351
|
-
return void 0;
|
|
23352
|
-
}
|
|
23353
|
-
}
|
|
23354
|
-
function pinRoot(root) {
|
|
23355
|
-
if (!existsSync8(join11(root, "dist", "server.js")))
|
|
23356
|
-
throw new Error(`${root} has no dist/server.js; cannot pin it as the stable root`);
|
|
23357
|
-
writeFileSync4(ensureDirs().rootPathFile, root);
|
|
23358
|
-
return root;
|
|
23359
|
-
}
|
|
23360
|
-
function pinnedRoot() {
|
|
23361
|
-
try {
|
|
23362
|
-
const root = readFileSync7(ensureDirs().rootPathFile, "utf8").trim();
|
|
23363
|
-
return root && existsSync8(join11(root, "dist", "server.js")) ? root : void 0;
|
|
23364
|
-
} catch {
|
|
23365
|
-
return void 0;
|
|
23366
|
-
}
|
|
23367
|
-
}
|
|
23368
|
-
var init_node_resolve = __esm({
|
|
23369
|
-
"src/install/node-resolve.ts"() {
|
|
23370
|
-
"use strict";
|
|
23371
|
-
init_esm_shims();
|
|
23372
|
-
init_paths();
|
|
23373
|
-
init_shell();
|
|
23374
|
-
}
|
|
23375
|
-
});
|
|
23376
|
-
|
|
23377
23290
|
// src/install/register.ts
|
|
23378
23291
|
import { createHash as createHash2 } from "crypto";
|
|
23379
|
-
import { cpSync, existsSync as
|
|
23380
|
-
import { join as
|
|
23292
|
+
import { cpSync, existsSync as existsSync8, mkdirSync as mkdirSync6, readdirSync as readdirSync3, readFileSync as readFileSync7, rmSync as rmSync3 } from "fs";
|
|
23293
|
+
import { join as join11 } from "path";
|
|
23381
23294
|
function fileHash(file3) {
|
|
23382
23295
|
try {
|
|
23383
|
-
return createHash2("sha1").update(
|
|
23296
|
+
return createHash2("sha1").update(readFileSync7(file3)).digest("hex");
|
|
23384
23297
|
} catch {
|
|
23385
23298
|
return void 0;
|
|
23386
23299
|
}
|
|
23387
23300
|
}
|
|
23388
23301
|
function probeServer(root) {
|
|
23389
|
-
const bin =
|
|
23390
|
-
if (!
|
|
23302
|
+
const bin = join11(root, "bin", "em-server");
|
|
23303
|
+
if (!existsSync8(bin)) return "bin/em-server is missing";
|
|
23391
23304
|
const r = run(bin, ["--probe"], { timeoutMs: 2e4 });
|
|
23392
23305
|
if (r.ok && / ok /.test(r.stdout)) return void 0;
|
|
23393
23306
|
const lines = (r.stderr || r.stdout).trim().split("\n").filter(Boolean);
|
|
@@ -23397,11 +23310,11 @@ function probeServer(root) {
|
|
|
23397
23310
|
function pluginCacheStale(stable) {
|
|
23398
23311
|
const cache3 = pluginInstallPath("eminiar@eminiar");
|
|
23399
23312
|
if (!cache3 || cache3 === stable) return void 0;
|
|
23400
|
-
if (!
|
|
23313
|
+
if (!existsSync8(cache3)) return `${cache3} is missing`;
|
|
23401
23314
|
for (const rel of CACHE_FINGERPRINT) {
|
|
23402
|
-
if (fileHash(
|
|
23315
|
+
if (fileHash(join11(cache3, rel)) !== fileHash(join11(stable, rel))) return `${rel} differs`;
|
|
23403
23316
|
}
|
|
23404
|
-
if (
|
|
23317
|
+
if (existsSync8(join11(cache3, ".mcp.json")) && !existsSync8(join11(stable, ".mcp.json")))
|
|
23405
23318
|
return ".mcp.json is present in the cache but not in the stable copy";
|
|
23406
23319
|
const probe3 = probeServer(cache3);
|
|
23407
23320
|
if (probe3) return `cached copy ${probe3}`;
|
|
@@ -23458,7 +23371,7 @@ function isOurs(cmd2, stable) {
|
|
|
23458
23371
|
function registerSettings(stable) {
|
|
23459
23372
|
const settings = readJson2(settingsPath());
|
|
23460
23373
|
const hooks = settings.hooks ?? {};
|
|
23461
|
-
const hookCmd = `"${
|
|
23374
|
+
const hookCmd = `"${join11(stable, "bin", "em-hook")}"`;
|
|
23462
23375
|
for (const ev2 of HOOK_EVENTS) {
|
|
23463
23376
|
const list2 = hooks[ev2] ?? [];
|
|
23464
23377
|
const filtered = list2.filter(
|
|
@@ -23479,17 +23392,17 @@ function registerSettings(stable) {
|
|
|
23479
23392
|
const servers = cj.mcpServers ?? {};
|
|
23480
23393
|
servers.eminiar = {
|
|
23481
23394
|
type: "stdio",
|
|
23482
|
-
command:
|
|
23395
|
+
command: join11(stable, "bin", "em-server"),
|
|
23483
23396
|
args: [],
|
|
23484
23397
|
env: { EMINIAR_PLUGIN_ROOT: stable }
|
|
23485
23398
|
};
|
|
23486
23399
|
cj.mcpServers = servers;
|
|
23487
23400
|
writeJsonWithBackup(claudeJsonPath(), cj);
|
|
23488
23401
|
const skills = [];
|
|
23489
|
-
const skillsDir =
|
|
23402
|
+
const skillsDir = join11(settingsPath(), "..", "skills");
|
|
23490
23403
|
mkdirSync6(skillsDir, { recursive: true });
|
|
23491
|
-
for (const name of
|
|
23492
|
-
cpSync(
|
|
23404
|
+
for (const name of readdirSync3(join11(stable, "skills"))) {
|
|
23405
|
+
cpSync(join11(stable, "skills", name), join11(skillsDir, name), { recursive: true });
|
|
23493
23406
|
skills.push(name);
|
|
23494
23407
|
}
|
|
23495
23408
|
return { hookEvents: HOOK_EVENTS, mcpServer: true, skills };
|
|
@@ -23520,8 +23433,8 @@ function unregisterSettings(stable, wrote) {
|
|
|
23520
23433
|
}
|
|
23521
23434
|
}
|
|
23522
23435
|
for (const name of wrote.skills ?? []) {
|
|
23523
|
-
const dir =
|
|
23524
|
-
if (
|
|
23436
|
+
const dir = join11(settingsPath(), "..", "skills", name);
|
|
23437
|
+
if (existsSync8(dir)) rmSync3(dir, { recursive: true, force: true });
|
|
23525
23438
|
}
|
|
23526
23439
|
}
|
|
23527
23440
|
function setStatusline(stable) {
|
|
@@ -23535,7 +23448,7 @@ function setStatusline(stable) {
|
|
|
23535
23448
|
}
|
|
23536
23449
|
settings.statusLine = {
|
|
23537
23450
|
type: "command",
|
|
23538
|
-
command: `"${
|
|
23451
|
+
command: `"${join11(stable, "bin", "eminiar")}" statusline`
|
|
23539
23452
|
};
|
|
23540
23453
|
writeJsonWithBackup(settingsPath(), settings);
|
|
23541
23454
|
return true;
|
|
@@ -23577,14 +23490,304 @@ var init_register = __esm({
|
|
|
23577
23490
|
}
|
|
23578
23491
|
});
|
|
23579
23492
|
|
|
23493
|
+
// src/install/cursor.ts
|
|
23494
|
+
import { cpSync as cpSync2, existsSync as existsSync9, mkdirSync as mkdirSync7, readdirSync as readdirSync4, readFileSync as readFileSync8, rmSync as rmSync4 } from "fs";
|
|
23495
|
+
import { join as join12 } from "path";
|
|
23496
|
+
function cursorPresent() {
|
|
23497
|
+
return existsSync9(cursorDir()) || existsSync9("/Applications/Cursor.app") || !!findOnPath("cursor") || !!findOnPath("cursor-agent");
|
|
23498
|
+
}
|
|
23499
|
+
function cursorHookCommand(stable) {
|
|
23500
|
+
return `"${join12(stable, "bin", "em-hook")}" --client cursor`;
|
|
23501
|
+
}
|
|
23502
|
+
function registerCursor(stable) {
|
|
23503
|
+
const cfg = readJson2(cursorHooksPath());
|
|
23504
|
+
if (typeof cfg.version !== "number") cfg.version = 1;
|
|
23505
|
+
const hooks = cfg.hooks ?? {};
|
|
23506
|
+
const command = cursorHookCommand(stable);
|
|
23507
|
+
for (const ev2 of CURSOR_HOOK_EVENTS) {
|
|
23508
|
+
const list2 = (Array.isArray(hooks[ev2]) ? hooks[ev2] : []).filter(
|
|
23509
|
+
(h) => !isOurs(h.command, stable)
|
|
23510
|
+
);
|
|
23511
|
+
const entry = { command, timeout: TIMEOUTS[ev2] ?? 5 };
|
|
23512
|
+
if (ev2 === "preToolUse") entry.matcher = CURSOR_PRE_TOOL_MATCHER;
|
|
23513
|
+
list2.push(entry);
|
|
23514
|
+
hooks[ev2] = list2;
|
|
23515
|
+
}
|
|
23516
|
+
cfg.hooks = hooks;
|
|
23517
|
+
writeJsonWithBackup(cursorHooksPath(), cfg);
|
|
23518
|
+
const mcp = readJson2(cursorMcpPath());
|
|
23519
|
+
const servers = mcp.mcpServers ?? {};
|
|
23520
|
+
servers.eminiar = {
|
|
23521
|
+
command: join12(stable, "bin", "em-server"),
|
|
23522
|
+
args: [],
|
|
23523
|
+
env: { EMINIAR_PLUGIN_ROOT: stable }
|
|
23524
|
+
};
|
|
23525
|
+
mcp.mcpServers = servers;
|
|
23526
|
+
writeJsonWithBackup(cursorMcpPath(), mcp);
|
|
23527
|
+
const skills = [];
|
|
23528
|
+
const src = join12(stable, "skills");
|
|
23529
|
+
if (existsSync9(src)) {
|
|
23530
|
+
mkdirSync7(cursorSkillsDir(), { recursive: true });
|
|
23531
|
+
for (const name of readdirSync4(src)) {
|
|
23532
|
+
cpSync2(join12(src, name), join12(cursorSkillsDir(), name), { recursive: true });
|
|
23533
|
+
skills.push(name);
|
|
23534
|
+
}
|
|
23535
|
+
}
|
|
23536
|
+
return { hookEvents: [...CURSOR_HOOK_EVENTS], mcpServer: true, skills };
|
|
23537
|
+
}
|
|
23538
|
+
function unregisterCursor(stable, wrote) {
|
|
23539
|
+
if (!wrote) return;
|
|
23540
|
+
if (wrote.hookEvents.length && existsSync9(cursorHooksPath())) {
|
|
23541
|
+
const cfg = readJson2(cursorHooksPath());
|
|
23542
|
+
const hooks = cfg.hooks ?? {};
|
|
23543
|
+
for (const ev2 of wrote.hookEvents) {
|
|
23544
|
+
if (!Array.isArray(hooks[ev2])) continue;
|
|
23545
|
+
const kept = hooks[ev2].filter((h) => !isOurs(h.command, stable));
|
|
23546
|
+
if (kept.length) hooks[ev2] = kept;
|
|
23547
|
+
else delete hooks[ev2];
|
|
23548
|
+
}
|
|
23549
|
+
cfg.hooks = hooks;
|
|
23550
|
+
writeJsonWithBackup(cursorHooksPath(), cfg);
|
|
23551
|
+
}
|
|
23552
|
+
if (wrote.mcpServer && existsSync9(cursorMcpPath())) {
|
|
23553
|
+
const mcp = readJson2(cursorMcpPath());
|
|
23554
|
+
const servers = mcp.mcpServers;
|
|
23555
|
+
if (servers?.eminiar && isOurs(servers.eminiar.command, stable)) {
|
|
23556
|
+
delete servers.eminiar;
|
|
23557
|
+
writeJsonWithBackup(cursorMcpPath(), mcp);
|
|
23558
|
+
}
|
|
23559
|
+
}
|
|
23560
|
+
for (const name of wrote.skills) {
|
|
23561
|
+
const dir = join12(cursorSkillsDir(), name);
|
|
23562
|
+
if (existsSync9(dir)) rmSync4(dir, { recursive: true, force: true });
|
|
23563
|
+
}
|
|
23564
|
+
}
|
|
23565
|
+
function cursorStatus() {
|
|
23566
|
+
const read2 = (f) => existsSync9(f) ? readFileSync8(f, "utf8") : "";
|
|
23567
|
+
const hooksRaw = read2(cursorHooksPath());
|
|
23568
|
+
let events = [];
|
|
23569
|
+
try {
|
|
23570
|
+
const cfg = hooksRaw ? JSON.parse(hooksRaw) : {};
|
|
23571
|
+
const hooks = cfg.hooks ?? {};
|
|
23572
|
+
events = Object.keys(hooks).filter(
|
|
23573
|
+
(ev2) => Array.isArray(hooks[ev2]) && hooks[ev2].some(
|
|
23574
|
+
(h) => typeof h.command === "string" && h.command.includes("em-hook")
|
|
23575
|
+
)
|
|
23576
|
+
);
|
|
23577
|
+
} catch {
|
|
23578
|
+
}
|
|
23579
|
+
return { hooks: events.length > 0, mcp: read2(cursorMcpPath()).includes("em-server"), events };
|
|
23580
|
+
}
|
|
23581
|
+
var cursorHooksPath, cursorMcpPath, cursorSkillsDir, CURSOR_HOOK_EVENTS, CURSOR_PRE_TOOL_MATCHER, TIMEOUTS;
|
|
23582
|
+
var init_cursor2 = __esm({
|
|
23583
|
+
"src/install/cursor.ts"() {
|
|
23584
|
+
"use strict";
|
|
23585
|
+
init_esm_shims();
|
|
23586
|
+
init_cursor();
|
|
23587
|
+
init_languages();
|
|
23588
|
+
init_claude_config();
|
|
23589
|
+
init_register();
|
|
23590
|
+
cursorHooksPath = () => join12(cursorDir(), "hooks.json");
|
|
23591
|
+
cursorMcpPath = () => join12(cursorDir(), "mcp.json");
|
|
23592
|
+
cursorSkillsDir = () => join12(cursorDir(), "skills");
|
|
23593
|
+
CURSOR_HOOK_EVENTS = [
|
|
23594
|
+
"sessionStart",
|
|
23595
|
+
"beforeSubmitPrompt",
|
|
23596
|
+
"preToolUse",
|
|
23597
|
+
"postToolUse",
|
|
23598
|
+
"postToolUseFailure",
|
|
23599
|
+
"subagentStop",
|
|
23600
|
+
"preCompact",
|
|
23601
|
+
"afterAgentResponse",
|
|
23602
|
+
"sessionEnd"
|
|
23603
|
+
];
|
|
23604
|
+
CURSOR_PRE_TOOL_MATCHER = "Shell|Read|Write|Edit|Grep|Glob|WebFetch|WebSearch|Task";
|
|
23605
|
+
TIMEOUTS = { sessionStart: 10, preCompact: 15, postToolUse: 10 };
|
|
23606
|
+
}
|
|
23607
|
+
});
|
|
23608
|
+
|
|
23609
|
+
// src/install/materialize.ts
|
|
23610
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync8, readdirSync as readdirSync5, readFileSync as readFileSync9, rmSync as rmSync5 } from "fs";
|
|
23611
|
+
import { join as join13 } from "path";
|
|
23612
|
+
function stableRoot() {
|
|
23613
|
+
return join13(paths().plugin, "node_modules", "eminiar");
|
|
23614
|
+
}
|
|
23615
|
+
function stableVersion() {
|
|
23616
|
+
try {
|
|
23617
|
+
return JSON.parse(readFileSync9(join13(stableRoot(), "package.json"), "utf8")).version;
|
|
23618
|
+
} catch {
|
|
23619
|
+
return void 0;
|
|
23620
|
+
}
|
|
23621
|
+
}
|
|
23622
|
+
function materialize(spec, force = false) {
|
|
23623
|
+
const prefix = paths().plugin;
|
|
23624
|
+
mkdirSync8(prefix, { recursive: true });
|
|
23625
|
+
const root = stableRoot();
|
|
23626
|
+
const here = pluginRoot();
|
|
23627
|
+
if (!force && !spec && here === root) return { root, fromSpec: "self" };
|
|
23628
|
+
if (!force && !spec && stableVersion() === version2() && existsSync10(join13(root, "dist", "server.js"))) {
|
|
23629
|
+
log.ok(`stable copy already at v${version2()} (${root})`);
|
|
23630
|
+
return { root, fromSpec: `pack:${here}` };
|
|
23631
|
+
}
|
|
23632
|
+
let target = spec;
|
|
23633
|
+
if (!target) {
|
|
23634
|
+
if (!existsSync10(join13(here, "dist", "server.js"))) {
|
|
23635
|
+
throw new Error(`${here} has no dist/ \u2014 run \`npm run build\` first`);
|
|
23636
|
+
}
|
|
23637
|
+
const dest = paths().tmp;
|
|
23638
|
+
mkdirSync8(dest, { recursive: true });
|
|
23639
|
+
const pack = run(
|
|
23640
|
+
npmCli(),
|
|
23641
|
+
["pack", "--ignore-scripts", "--pack-destination", dest, "--silent"],
|
|
23642
|
+
{ cwd: here }
|
|
23643
|
+
);
|
|
23644
|
+
if (!pack.ok) throw new Error(`npm pack failed: ${pack.stderr || pack.stdout}`);
|
|
23645
|
+
const tarball = pack.stdout.trim().split("\n").pop();
|
|
23646
|
+
target = join13(dest, tarball);
|
|
23647
|
+
}
|
|
23648
|
+
const install2 = run(
|
|
23649
|
+
npmCli(),
|
|
23650
|
+
[
|
|
23651
|
+
"install",
|
|
23652
|
+
"--prefix",
|
|
23653
|
+
prefix,
|
|
23654
|
+
"--omit=dev",
|
|
23655
|
+
"--no-audit",
|
|
23656
|
+
"--no-fund",
|
|
23657
|
+
"--loglevel=error",
|
|
23658
|
+
target
|
|
23659
|
+
],
|
|
23660
|
+
{
|
|
23661
|
+
env: { ...process.env, npm_config_update_notifier: "false" }
|
|
23662
|
+
}
|
|
23663
|
+
);
|
|
23664
|
+
if (!install2.ok) throw new Error(`npm install failed: ${install2.stderr || install2.stdout}`);
|
|
23665
|
+
if (!spec && target.endsWith(".tgz")) rmSync5(target, { force: true });
|
|
23666
|
+
for (const must of [
|
|
23667
|
+
"dist/server.js",
|
|
23668
|
+
"dist/hook.js",
|
|
23669
|
+
"bin/em-hook",
|
|
23670
|
+
".claude-plugin/plugin.json",
|
|
23671
|
+
"hooks/hooks.json"
|
|
23672
|
+
]) {
|
|
23673
|
+
if (!existsSync10(join13(root, must))) throw new Error(`stable copy is missing ${must}`);
|
|
23674
|
+
}
|
|
23675
|
+
log.ok(
|
|
23676
|
+
`installed v${stableVersion()} into ${root} (${readdirSync5(join13(prefix, "node_modules")).length} packages)`
|
|
23677
|
+
);
|
|
23678
|
+
return { root, fromSpec: spec ?? `pack:${here}` };
|
|
23679
|
+
}
|
|
23680
|
+
function nativeCheck(node2, root) {
|
|
23681
|
+
const script = `
|
|
23682
|
+
const { createRequire } = require("node:module");
|
|
23683
|
+
const req = createRequire(${JSON.stringify(join13(root, "package.json"))});
|
|
23684
|
+
const out = [];
|
|
23685
|
+
for (const m of ["better-sqlite3", "sqlite-vec", "web-tree-sitter", "@huggingface/transformers"]) {
|
|
23686
|
+
try { const x = req(m); if (m === "better-sqlite3") { const db = new x(":memory:"); req("sqlite-vec").load(db); db.close(); } }
|
|
23687
|
+
catch (e) { out.push(m + ": " + (e && e.message ? e.message.split("\\n")[0] : e)); }
|
|
23688
|
+
}
|
|
23689
|
+
process.stdout.write(JSON.stringify(out));
|
|
23690
|
+
`;
|
|
23691
|
+
const r = run(node2, ["-e", script], { cwd: root });
|
|
23692
|
+
if (!r.ok) return [`native check could not run: ${r.stderr.trim().split("\n").pop()}`];
|
|
23693
|
+
try {
|
|
23694
|
+
return JSON.parse(r.stdout);
|
|
23695
|
+
} catch {
|
|
23696
|
+
return [`native check returned garbage: ${r.stdout.slice(0, 200)}`];
|
|
23697
|
+
}
|
|
23698
|
+
}
|
|
23699
|
+
function rebuildNative(root) {
|
|
23700
|
+
const r = run(
|
|
23701
|
+
npmCli(),
|
|
23702
|
+
["rebuild", "better-sqlite3", "--prefix", paths().plugin, "--loglevel=error"],
|
|
23703
|
+
{ cwd: root }
|
|
23704
|
+
);
|
|
23705
|
+
return r.ok;
|
|
23706
|
+
}
|
|
23707
|
+
function downloadModel(node2, root, model2) {
|
|
23708
|
+
const script = `
|
|
23709
|
+
(async () => {
|
|
23710
|
+
const tf = await import("@huggingface/transformers");
|
|
23711
|
+
tf.env.cacheDir = ${JSON.stringify(paths().models)};
|
|
23712
|
+
const p = await tf.pipeline("feature-extraction", ${JSON.stringify(model2)}, { dtype: "q8", device: "cpu" });
|
|
23713
|
+
const r = await p(["warm up"], { pooling: "cls", normalize: true });
|
|
23714
|
+
process.stdout.write(String(r.tolist()[0].length));
|
|
23715
|
+
})().catch((e) => { process.stderr.write(String(e && e.message || e)); process.exit(1); });
|
|
23716
|
+
`;
|
|
23717
|
+
const r = run(node2, ["--input-type=module", "-e", script], { cwd: root });
|
|
23718
|
+
return r.ok ? void 0 : r.stderr.trim().split("\n").pop();
|
|
23719
|
+
}
|
|
23720
|
+
var init_materialize = __esm({
|
|
23721
|
+
"src/install/materialize.ts"() {
|
|
23722
|
+
"use strict";
|
|
23723
|
+
init_esm_shims();
|
|
23724
|
+
init_paths();
|
|
23725
|
+
init_version();
|
|
23726
|
+
init_shell();
|
|
23727
|
+
}
|
|
23728
|
+
});
|
|
23729
|
+
|
|
23730
|
+
// src/install/node-resolve.ts
|
|
23731
|
+
import { accessSync as accessSync3, constants as constants3, existsSync as existsSync11, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
23732
|
+
import { join as join14 } from "path";
|
|
23733
|
+
function versionOf(bin) {
|
|
23734
|
+
const r = run(bin, ["-p", "process.versions.node"]);
|
|
23735
|
+
return r.ok ? r.stdout.trim() : void 0;
|
|
23736
|
+
}
|
|
23737
|
+
function nodeOk(version3) {
|
|
23738
|
+
const [maj = 0, min = 0] = version3.split(".").map(Number);
|
|
23739
|
+
return maj > 22 || maj === 22 && min >= 12;
|
|
23740
|
+
}
|
|
23741
|
+
function pinNode(explicit) {
|
|
23742
|
+
const candidate = explicit ?? process.execPath;
|
|
23743
|
+
accessSync3(candidate, constants3.X_OK);
|
|
23744
|
+
const version3 = versionOf(candidate);
|
|
23745
|
+
if (!version3) throw new Error(`${candidate} does not look like a node binary`);
|
|
23746
|
+
if (!nodeOk(version3))
|
|
23747
|
+
throw new Error(`node ${version3} at ${candidate} is too old; need >= 22.12`);
|
|
23748
|
+
writeFileSync5(ensureDirs().nodePathFile, candidate);
|
|
23749
|
+
return { path: candidate, version: version3 };
|
|
23750
|
+
}
|
|
23751
|
+
function pinnedNode() {
|
|
23752
|
+
try {
|
|
23753
|
+
const path3 = readFileSync10(ensureDirs().nodePathFile, "utf8").trim();
|
|
23754
|
+
const version3 = versionOf(path3);
|
|
23755
|
+
return version3 ? { path: path3, version: version3 } : void 0;
|
|
23756
|
+
} catch {
|
|
23757
|
+
return void 0;
|
|
23758
|
+
}
|
|
23759
|
+
}
|
|
23760
|
+
function pinRoot(root) {
|
|
23761
|
+
if (!existsSync11(join14(root, "dist", "server.js")))
|
|
23762
|
+
throw new Error(`${root} has no dist/server.js; cannot pin it as the stable root`);
|
|
23763
|
+
writeFileSync5(ensureDirs().rootPathFile, root);
|
|
23764
|
+
return root;
|
|
23765
|
+
}
|
|
23766
|
+
function pinnedRoot() {
|
|
23767
|
+
try {
|
|
23768
|
+
const root = readFileSync10(ensureDirs().rootPathFile, "utf8").trim();
|
|
23769
|
+
return root && existsSync11(join14(root, "dist", "server.js")) ? root : void 0;
|
|
23770
|
+
} catch {
|
|
23771
|
+
return void 0;
|
|
23772
|
+
}
|
|
23773
|
+
}
|
|
23774
|
+
var init_node_resolve = __esm({
|
|
23775
|
+
"src/install/node-resolve.ts"() {
|
|
23776
|
+
"use strict";
|
|
23777
|
+
init_esm_shims();
|
|
23778
|
+
init_paths();
|
|
23779
|
+
init_shell();
|
|
23780
|
+
}
|
|
23781
|
+
});
|
|
23782
|
+
|
|
23580
23783
|
// src/install/doctor.ts
|
|
23581
23784
|
var doctor_exports = {};
|
|
23582
23785
|
__export(doctor_exports, {
|
|
23583
23786
|
fullDoctor: () => fullDoctor
|
|
23584
23787
|
});
|
|
23585
23788
|
import { spawn } from "child_process";
|
|
23586
|
-
import { existsSync as
|
|
23587
|
-
import { join as
|
|
23789
|
+
import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
|
|
23790
|
+
import { join as join15 } from "path";
|
|
23588
23791
|
function mcpHandshake(bin, ms = 15e3) {
|
|
23589
23792
|
return new Promise((resolve9) => {
|
|
23590
23793
|
const child = spawn(bin, [], { stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -23619,8 +23822,8 @@ function mcpHandshake(bin, ms = 15e3) {
|
|
|
23619
23822
|
async function fullDoctor(opts = {}) {
|
|
23620
23823
|
const rec = readInstallRecord();
|
|
23621
23824
|
const stable = rec?.stableRoot ?? stableRoot();
|
|
23622
|
-
const hasStable =
|
|
23623
|
-
const bins = hasStable ? stable :
|
|
23825
|
+
const hasStable = existsSync12(join15(stable, "dist", "server.js"));
|
|
23826
|
+
const bins = hasStable ? stable : join15(process.argv[1] ?? "", "..", "..");
|
|
23624
23827
|
const fixed = [];
|
|
23625
23828
|
if (opts.fix && hasStable) {
|
|
23626
23829
|
try {
|
|
@@ -23645,7 +23848,7 @@ async function fullDoctor(opts = {}) {
|
|
|
23645
23848
|
checks.push({
|
|
23646
23849
|
name: "install",
|
|
23647
23850
|
ok: !!rec,
|
|
23648
|
-
detail: rec ? `v${rec.version} via ${rec.method} at ${rec.installedAt.slice(0, 10)} (${rec.stableRoot})` : "not installed (run `npx eminiar install`)"
|
|
23851
|
+
detail: rec ? `v${rec.version} via ${rec.method === "none" ? "cursor" : rec.method}${rec.wrote.cursor && rec.method !== "none" ? " + cursor" : ""} at ${rec.installedAt.slice(0, 10)} (${rec.stableRoot})` : "not installed (run `npx eminiar install`)"
|
|
23649
23852
|
});
|
|
23650
23853
|
const pinned = pinnedNode();
|
|
23651
23854
|
checks.push({
|
|
@@ -23682,14 +23885,29 @@ async function fullDoctor(opts = {}) {
|
|
|
23682
23885
|
detail: `${lines.join(" \xB7 ")}${drift}${liveOk ? "" : " \u2014 run `eminiar doctor --fix`, then `eminiar upgrade` if it still fails"}`
|
|
23683
23886
|
});
|
|
23684
23887
|
}
|
|
23685
|
-
} else {
|
|
23686
|
-
const s =
|
|
23888
|
+
} else if (rec.method === "settings") {
|
|
23889
|
+
const s = existsSync12(join15(process.env.HOME ?? "", ".claude", "settings.json")) ? readFileSync11(join15(process.env.HOME ?? "", ".claude", "settings.json"), "utf8") : "";
|
|
23687
23890
|
checks.push({
|
|
23688
23891
|
name: "hooks in settings.json",
|
|
23689
23892
|
ok: s.includes("em-hook"),
|
|
23690
23893
|
detail: s.includes("em-hook") ? "present" : "missing"
|
|
23691
23894
|
});
|
|
23692
23895
|
}
|
|
23896
|
+
if (rec?.wrote.cursor || cursorPresent()) {
|
|
23897
|
+
const cs = cursorStatus();
|
|
23898
|
+
const registered = !!rec?.wrote.cursor;
|
|
23899
|
+
checks.push({
|
|
23900
|
+
name: "Cursor",
|
|
23901
|
+
ok: registered ? cs.hooks && cs.mcp : true,
|
|
23902
|
+
detail: registered ? `${cs.hooks ? `hooks on ${cs.events.length} events` : "hooks missing from ~/.cursor/hooks.json"} \xB7 ${cs.mcp ? "MCP server in ~/.cursor/mcp.json" : "MCP server missing from ~/.cursor/mcp.json"}${cs.hooks && cs.mcp ? "" : " \u2014 run `npx eminiar install --cursor`"}` : cs.hooks || cs.mcp ? "partly configured by hand; `npx eminiar install --cursor` completes and tracks it" : "installed but not registered; `npx eminiar install --cursor` adds hooks, MCP server and skills"
|
|
23903
|
+
});
|
|
23904
|
+
if (registered && rec?.method === "settings")
|
|
23905
|
+
checks.push({
|
|
23906
|
+
name: "Cursor third-party import",
|
|
23907
|
+
ok: false,
|
|
23908
|
+
detail: "Cursor also runs the Claude Code hooks in ~/.claude/settings.json (Settings \u2192 Agents \u2192 Third-Party Imports, on by default), so each event fires twice there; turn that setting off or reinstall Claude Code with `--method plugin`"
|
|
23909
|
+
});
|
|
23910
|
+
}
|
|
23693
23911
|
const failed = needsAuthEntry();
|
|
23694
23912
|
if (failed && opts.fix && clearNeedsAuthEntry()) fixed.push("cached launch failure cleared");
|
|
23695
23913
|
const stillFailed = needsAuthEntry();
|
|
@@ -23700,8 +23918,8 @@ async function fullDoctor(opts = {}) {
|
|
|
23700
23918
|
});
|
|
23701
23919
|
if (opts.fix)
|
|
23702
23920
|
checks.push({ name: "fix", ok: true, detail: fixed.join(", ") || "nothing to fix" });
|
|
23703
|
-
const hookBin =
|
|
23704
|
-
if (
|
|
23921
|
+
const hookBin = join15(bins, "bin", "em-hook");
|
|
23922
|
+
if (existsSync12(hookBin)) {
|
|
23705
23923
|
const r = run(hookBin, ["--selftest"], { env: { ...process.env } });
|
|
23706
23924
|
checks.push({
|
|
23707
23925
|
name: "hook self-test",
|
|
@@ -23709,8 +23927,8 @@ async function fullDoctor(opts = {}) {
|
|
|
23709
23927
|
detail: r.ok ? r.stdout.trim() : r.stderr.trim().slice(-200) || "failed"
|
|
23710
23928
|
});
|
|
23711
23929
|
}
|
|
23712
|
-
const serverBin =
|
|
23713
|
-
if (
|
|
23930
|
+
const serverBin = join15(bins, "bin", "em-server");
|
|
23931
|
+
if (existsSync12(serverBin)) {
|
|
23714
23932
|
const reply = await mcpHandshake(serverBin);
|
|
23715
23933
|
checks.push({ name: "MCP handshake", ok: /^eminiar v|^ok$/.test(reply), detail: reply });
|
|
23716
23934
|
}
|
|
@@ -23722,10 +23940,10 @@ async function fullDoctor(opts = {}) {
|
|
|
23722
23940
|
ok: true,
|
|
23723
23941
|
detail: `${ctx.root} \xB7 ${db.countDocuments()} docs \xB7 ${db.memoryCount()} memories \xB7 graph ${db.graphCounts().nodes} nodes`
|
|
23724
23942
|
});
|
|
23725
|
-
const cfgFile =
|
|
23726
|
-
if (
|
|
23943
|
+
const cfgFile = join15(ctx.root, "eminiar.config.json");
|
|
23944
|
+
if (existsSync12(cfgFile)) {
|
|
23727
23945
|
try {
|
|
23728
|
-
const parsed = ConfigSchema.safeParse(JSON.parse(
|
|
23946
|
+
const parsed = ConfigSchema.safeParse(JSON.parse(readFileSync11(cfgFile, "utf8")));
|
|
23729
23947
|
checks.push({
|
|
23730
23948
|
name: "eminiar.config.json",
|
|
23731
23949
|
ok: parsed.success,
|
|
@@ -23748,9 +23966,9 @@ async function fullDoctor(opts = {}) {
|
|
|
23748
23966
|
ok: true,
|
|
23749
23967
|
detail: live2.length ? `running for this project (pid ${live2.join(", ")})` : "none running for this project right now; enforce routing annotates instead of denying until one connects"
|
|
23750
23968
|
});
|
|
23751
|
-
const projectMcp =
|
|
23752
|
-
if (
|
|
23753
|
-
const raw =
|
|
23969
|
+
const projectMcp = join15(ctx.root, ".mcp.json");
|
|
23970
|
+
if (existsSync12(projectMcp)) {
|
|
23971
|
+
const raw = readFileSync11(projectMcp, "utf8");
|
|
23754
23972
|
const bad = raw.includes(`\${CLAUDE_PLUGIN_ROOT}`) && raw.includes("em-server");
|
|
23755
23973
|
checks.push({
|
|
23756
23974
|
name: "project .mcp.json",
|
|
@@ -23780,6 +23998,7 @@ var init_doctor2 = __esm({
|
|
|
23780
23998
|
init_server_alive();
|
|
23781
23999
|
init_storage();
|
|
23782
24000
|
init_claude_config();
|
|
24001
|
+
init_cursor2();
|
|
23783
24002
|
init_materialize();
|
|
23784
24003
|
init_node_resolve();
|
|
23785
24004
|
init_register();
|
|
@@ -23880,8 +24099,8 @@ __export(install_exports, {
|
|
|
23880
24099
|
install: () => install,
|
|
23881
24100
|
writeTeamFiles: () => writeTeamFiles
|
|
23882
24101
|
});
|
|
23883
|
-
import { existsSync as
|
|
23884
|
-
import { join as
|
|
24102
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync13, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
|
|
24103
|
+
import { join as join16 } from "path";
|
|
23885
24104
|
async function install(opts) {
|
|
23886
24105
|
console.log(`eminiar v${version2()} installer`);
|
|
23887
24106
|
log.step("node");
|
|
@@ -23911,8 +24130,8 @@ async function install(opts) {
|
|
|
23911
24130
|
}
|
|
23912
24131
|
log.step("data directory");
|
|
23913
24132
|
const p = ensureDirs();
|
|
23914
|
-
if (!
|
|
23915
|
-
|
|
24133
|
+
if (!existsSync13(p.configFile))
|
|
24134
|
+
writeFileSync6(p.configFile, `${JSON.stringify(ConfigSchema.parse({}), null, 2)}
|
|
23916
24135
|
`);
|
|
23917
24136
|
globalDb();
|
|
23918
24137
|
log.ok(p.home);
|
|
@@ -23922,18 +24141,23 @@ async function install(opts) {
|
|
|
23922
24141
|
if (err) log.warn(`download failed (${err}); it will be retried lazily on first hybrid search`);
|
|
23923
24142
|
else log.ok("ready");
|
|
23924
24143
|
}
|
|
23925
|
-
|
|
23926
|
-
const
|
|
24144
|
+
const claude = claudeCli();
|
|
24145
|
+
const wantClaude = !opts.cursor || !!claude || !!opts.method;
|
|
24146
|
+
const method = opts.method ?? (claude ? "plugin" : "settings");
|
|
24147
|
+
const targets = [wantClaude ? `Claude Code (${method} method)` : "", opts.cursor ? "Cursor" : ""].filter(Boolean).join(" and ");
|
|
24148
|
+
log.step(`register with ${targets}`);
|
|
24149
|
+
if (opts.cursor && !cursorPresent())
|
|
24150
|
+
log.warn(`${cursorDirHint()} not found; Cursor files are written anyway for its first launch`);
|
|
23927
24151
|
if (!await confirm(
|
|
23928
|
-
`Register eminiar with
|
|
24152
|
+
`Register eminiar with ${targets}? This edits your user-level ${[wantClaude ? "Claude" : "", opts.cursor ? "Cursor" : ""].filter(Boolean).join(" and ")} config.`,
|
|
23929
24153
|
!!opts.yes
|
|
23930
24154
|
)) {
|
|
23931
24155
|
log.warn("skipped registration; re-run with --yes or confirm interactively");
|
|
23932
24156
|
return 1;
|
|
23933
24157
|
}
|
|
23934
24158
|
let wrote = {};
|
|
23935
|
-
let usedMethod = method;
|
|
23936
|
-
if (
|
|
24159
|
+
let usedMethod = wantClaude ? method : "none";
|
|
24160
|
+
if (usedMethod === "plugin") {
|
|
23937
24161
|
const r = registerPlugin(stable);
|
|
23938
24162
|
if (r.ok) {
|
|
23939
24163
|
log.ok(r.detail);
|
|
@@ -23949,15 +24173,27 @@ async function install(opts) {
|
|
|
23949
24173
|
"hooks written to ~/.claude/settings.json, MCP server to ~/.claude.json, skills to ~/.claude/skills"
|
|
23950
24174
|
);
|
|
23951
24175
|
}
|
|
23952
|
-
if (
|
|
23953
|
-
|
|
23954
|
-
|
|
23955
|
-
|
|
23956
|
-
if (
|
|
23957
|
-
|
|
23958
|
-
|
|
24176
|
+
if (wantClaude) {
|
|
24177
|
+
if (needsAuthEntry() && clearNeedsAuthEntry())
|
|
24178
|
+
log.ok("cleared Claude Code's cached connection failure for the plugin server");
|
|
24179
|
+
const wantStatusline = opts.statusline ?? (!!opts.yes && !opts.team);
|
|
24180
|
+
if (wantStatusline) {
|
|
24181
|
+
if (setStatusline(stable)) {
|
|
24182
|
+
wrote.statusline = true;
|
|
24183
|
+
log.ok("statusLine set to `eminiar statusline`");
|
|
24184
|
+
}
|
|
23959
24185
|
}
|
|
23960
24186
|
}
|
|
24187
|
+
if (opts.cursor) {
|
|
24188
|
+
wrote.cursor = registerCursor(stable);
|
|
24189
|
+
log.ok(
|
|
24190
|
+
`hooks written to ${cursorDirHint()}/hooks.json, MCP server to ${cursorDirHint()}/mcp.json, skills to ${cursorDirHint()}/skills`
|
|
24191
|
+
);
|
|
24192
|
+
if (usedMethod === "settings")
|
|
24193
|
+
log.warn(
|
|
24194
|
+
"Cursor also imports Claude Code hooks from ~/.claude/settings.json (Settings \u2192 Agents \u2192 Third-Party Imports); turn that off or each event fires twice in Cursor"
|
|
24195
|
+
);
|
|
24196
|
+
}
|
|
23961
24197
|
writeInstallRecord({
|
|
23962
24198
|
version: version2(),
|
|
23963
24199
|
method: usedMethod,
|
|
@@ -23969,21 +24205,25 @@ async function install(opts) {
|
|
|
23969
24205
|
});
|
|
23970
24206
|
if (opts.team) {
|
|
23971
24207
|
log.step("team defaults");
|
|
23972
|
-
writeTeamFiles(resolveProjectRoot(), opts.marketplace);
|
|
24208
|
+
writeTeamFiles(resolveProjectRoot(), opts.marketplace, { cursor: !!opts.cursor, stable });
|
|
23973
24209
|
}
|
|
23974
24210
|
log.step("doctor");
|
|
23975
24211
|
const checks = await fullDoctor();
|
|
23976
24212
|
console.log(formatDoctor(checks));
|
|
24213
|
+
const restart = [wantClaude ? "Claude Code" : "", opts.cursor ? "Cursor" : ""].filter(Boolean).join(" and ");
|
|
23977
24214
|
console.log(
|
|
23978
24215
|
`
|
|
23979
|
-
Restart
|
|
24216
|
+
Restart ${restart} to load eminiar. Try ${wantClaude ? "/em-doctor, then " : ""}em_execute with an intent.`
|
|
23980
24217
|
);
|
|
23981
24218
|
return checks.every((c) => c.ok) ? 0 : 1;
|
|
23982
24219
|
}
|
|
23983
|
-
function
|
|
23984
|
-
|
|
23985
|
-
|
|
23986
|
-
|
|
24220
|
+
function cursorDirHint() {
|
|
24221
|
+
return process.env.CURSOR_CONFIG_DIR || "~/.cursor";
|
|
24222
|
+
}
|
|
24223
|
+
function writeTeamFiles(root, marketplace, extra = {}) {
|
|
24224
|
+
const cfg = join16(root, "eminiar.config.json");
|
|
24225
|
+
if (!existsSync13(cfg)) {
|
|
24226
|
+
writeFileSync6(
|
|
23987
24227
|
cfg,
|
|
23988
24228
|
`${JSON.stringify(
|
|
23989
24229
|
{
|
|
@@ -24013,7 +24253,7 @@ function writeTeamFiles(root, marketplace) {
|
|
|
24013
24253
|
}
|
|
24014
24254
|
if (marketplace) {
|
|
24015
24255
|
const m = /^github:(.+)$/.exec(marketplace);
|
|
24016
|
-
const file3 =
|
|
24256
|
+
const file3 = join16(root, ".claude", "settings.json");
|
|
24017
24257
|
const settings = readJson2(file3);
|
|
24018
24258
|
const known = settings.extraKnownMarketplaces ?? {};
|
|
24019
24259
|
known.eminiar = m ? { source: { source: "github", repo: m[1] } } : { source: { source: "url", url: marketplace } };
|
|
@@ -24026,7 +24266,19 @@ function writeTeamFiles(root, marketplace) {
|
|
|
24026
24266
|
`${file3}: marketplace + enabledPlugins added \u2014 teammates are prompted to install on next launch`
|
|
24027
24267
|
);
|
|
24028
24268
|
} else {
|
|
24029
|
-
log.info(
|
|
24269
|
+
log.info(
|
|
24270
|
+
`teammates: \`npx eminiar install${extra.cursor ? " --cursor" : ""}\` (reads the committed eminiar.config.json)`
|
|
24271
|
+
);
|
|
24272
|
+
}
|
|
24273
|
+
if (extra.cursor) {
|
|
24274
|
+
const src = join16(extra.stable ?? "", "rules", "eminiar.mdc");
|
|
24275
|
+
const dst = join16(root, ".cursor", "rules", "eminiar.mdc");
|
|
24276
|
+
if (existsSync13(dst)) log.ok(`${dst} already exists`);
|
|
24277
|
+
else if (existsSync13(src)) {
|
|
24278
|
+
mkdirSync9(join16(root, ".cursor", "rules"), { recursive: true });
|
|
24279
|
+
copyFileSync2(src, dst);
|
|
24280
|
+
log.ok(`wrote ${dst} \u2014 commit it`);
|
|
24281
|
+
}
|
|
24030
24282
|
}
|
|
24031
24283
|
}
|
|
24032
24284
|
var init_install = __esm({
|
|
@@ -24040,6 +24292,7 @@ var init_install = __esm({
|
|
|
24040
24292
|
init_global();
|
|
24041
24293
|
init_version();
|
|
24042
24294
|
init_claude_config();
|
|
24295
|
+
init_cursor2();
|
|
24043
24296
|
init_doctor2();
|
|
24044
24297
|
init_materialize();
|
|
24045
24298
|
init_node_resolve();
|
|
@@ -24062,12 +24315,14 @@ async function upgrade() {
|
|
|
24062
24315
|
const fromCheckout = rec.fromSpec.startsWith("pack:") || rec.fromSpec === "self";
|
|
24063
24316
|
return install({
|
|
24064
24317
|
yes: true,
|
|
24065
|
-
|
|
24318
|
+
// "none" means Cursor-only last time; let install() decide again from what is present.
|
|
24319
|
+
method: rec.method === "none" ? void 0 : rec.method,
|
|
24066
24320
|
noModel: false,
|
|
24067
24321
|
spec: fromCheckout ? void 0 : "eminiar@latest",
|
|
24068
24322
|
force: fromCheckout,
|
|
24069
24323
|
node: rec.node,
|
|
24070
|
-
statusline: !!rec.wrote.statusline
|
|
24324
|
+
statusline: !!rec.wrote.statusline,
|
|
24325
|
+
cursor: !!rec.wrote.cursor
|
|
24071
24326
|
});
|
|
24072
24327
|
}
|
|
24073
24328
|
var init_upgrade = __esm({
|
|
@@ -24085,13 +24340,14 @@ var uninstall_exports = {};
|
|
|
24085
24340
|
__export(uninstall_exports, {
|
|
24086
24341
|
uninstall: () => uninstall
|
|
24087
24342
|
});
|
|
24088
|
-
import { existsSync as
|
|
24343
|
+
import { existsSync as existsSync14, rmSync as rmSync6 } from "fs";
|
|
24089
24344
|
async function uninstall(opts) {
|
|
24090
24345
|
const rec = readInstallRecord();
|
|
24091
24346
|
const p = paths();
|
|
24092
24347
|
const plan = [
|
|
24093
24348
|
rec?.method === "plugin" || !rec ? "claude plugin uninstall eminiar@eminiar + marketplace remove" : "",
|
|
24094
24349
|
rec?.method === "settings" ? "remove eminiar hook entries from ~/.claude/settings.json, mcpServers.eminiar from ~/.claude.json, em-* skills" : "",
|
|
24350
|
+
rec?.wrote.cursor ? "remove eminiar hook entries from ~/.cursor/hooks.json, mcpServers.eminiar from ~/.cursor/mcp.json, em-* skills from ~/.cursor/skills" : "",
|
|
24095
24351
|
rec?.wrote.statusline ? "clear the eminiar statusLine" : "",
|
|
24096
24352
|
`delete ${p.plugin}`,
|
|
24097
24353
|
opts.purgeData ? `delete ${p.home} (ALL indexes, memories, stats)` : `keep ${p.home} (indexes, memories, stats)`
|
|
@@ -24102,11 +24358,13 @@ async function uninstall(opts) {
|
|
|
24102
24358
|
const stable = rec?.stableRoot ?? `${p.plugin}/node_modules/eminiar`;
|
|
24103
24359
|
if (!rec || rec.method === "plugin") unregisterPlugin();
|
|
24104
24360
|
if (rec?.method === "settings") unregisterSettings(stable, rec.wrote);
|
|
24361
|
+
if (rec?.wrote.cursor) unregisterCursor(stable, rec.wrote.cursor);
|
|
24105
24362
|
if (rec?.wrote.statusline) clearStatusline(stable);
|
|
24106
|
-
if (
|
|
24107
|
-
if (opts.purgeData)
|
|
24108
|
-
else if (
|
|
24109
|
-
|
|
24363
|
+
if (existsSync14(p.plugin)) rmSync6(p.plugin, { recursive: true, force: true });
|
|
24364
|
+
if (opts.purgeData) rmSync6(p.home, { recursive: true, force: true });
|
|
24365
|
+
else if (existsSync14(p.installFile)) rmSync6(p.installFile, { force: true });
|
|
24366
|
+
const from = [rec?.method !== "none" ? "Claude Code" : "", rec?.wrote.cursor ? "Cursor" : ""].filter(Boolean).join(" and ");
|
|
24367
|
+
log.ok(`eminiar removed from ${from || "Claude Code"}; restart it to finish`);
|
|
24110
24368
|
return 0;
|
|
24111
24369
|
}
|
|
24112
24370
|
var init_uninstall = __esm({
|
|
@@ -24115,6 +24373,7 @@ var init_uninstall = __esm({
|
|
|
24115
24373
|
init_esm_shims();
|
|
24116
24374
|
init_paths();
|
|
24117
24375
|
init_claude_config();
|
|
24376
|
+
init_cursor2();
|
|
24118
24377
|
init_register();
|
|
24119
24378
|
init_shell();
|
|
24120
24379
|
}
|
|
@@ -30413,7 +30672,7 @@ function chunkMarkdown(text3, baseTitle, opts = DEFAULT_CHUNKER) {
|
|
|
30413
30672
|
if (/^\s*(```|~~~)/.test(line)) inFence = !inFence;
|
|
30414
30673
|
const m = !inFence && /^(#{1,6})\s+(.+?)\s*#*\s*$/.exec(line);
|
|
30415
30674
|
if (m) {
|
|
30416
|
-
|
|
30675
|
+
sections.push(current);
|
|
30417
30676
|
const level = m[1].length;
|
|
30418
30677
|
while (stack.length && stack[stack.length - 1].level >= level) stack.pop();
|
|
30419
30678
|
stack.push({ level, text: m[2] });
|
|
@@ -30422,14 +30681,23 @@ function chunkMarkdown(text3, baseTitle, opts = DEFAULT_CHUNKER) {
|
|
|
30422
30681
|
}
|
|
30423
30682
|
current.lines.push(line);
|
|
30424
30683
|
});
|
|
30425
|
-
|
|
30684
|
+
sections.push(current);
|
|
30426
30685
|
const out = [];
|
|
30427
|
-
|
|
30686
|
+
sections.forEach((s, k) => {
|
|
30428
30687
|
const title = s.path.length ? `${baseTitle} > ${s.path.join(" > ")}` : baseTitle;
|
|
30429
30688
|
const body = s.lines.join("\n");
|
|
30689
|
+
if (!body.trim()) {
|
|
30690
|
+
const next = sections[k + 1];
|
|
30691
|
+
const isParent = next !== void 0 && next.path.length > s.path.length && s.path.every((p, j) => next.path[j] === p);
|
|
30692
|
+
if (s.path.length && !isParent) {
|
|
30693
|
+
const heading = s.path[s.path.length - 1];
|
|
30694
|
+
out.push({ title, body: heading, startLine: s.startLine, endLine: s.startLine });
|
|
30695
|
+
}
|
|
30696
|
+
return;
|
|
30697
|
+
}
|
|
30430
30698
|
if (body.length <= opts.maxChars) {
|
|
30431
30699
|
out.push({ title, body, startLine: s.startLine, endLine: s.startLine + s.lines.length - 1 });
|
|
30432
|
-
|
|
30700
|
+
return;
|
|
30433
30701
|
}
|
|
30434
30702
|
let fence = false;
|
|
30435
30703
|
const fenceState = s.lines.map((l) => {
|
|
@@ -30445,7 +30713,7 @@ function chunkMarkdown(text3, baseTitle, opts = DEFAULT_CHUNKER) {
|
|
|
30445
30713
|
s.startLine - 1
|
|
30446
30714
|
)
|
|
30447
30715
|
);
|
|
30448
|
-
}
|
|
30716
|
+
});
|
|
30449
30717
|
return out;
|
|
30450
30718
|
}
|
|
30451
30719
|
var init_markdown = __esm({
|
|
@@ -30553,11 +30821,24 @@ __export(indexer_exports, {
|
|
|
30553
30821
|
indexContent: () => indexContent,
|
|
30554
30822
|
indexPath: () => indexPath
|
|
30555
30823
|
});
|
|
30556
|
-
import { readFileSync as
|
|
30824
|
+
import { readFileSync as readFileSync12, statSync } from "fs";
|
|
30557
30825
|
import { relative, resolve as resolve2 } from "path";
|
|
30558
30826
|
function indexContent(db, input2) {
|
|
30559
30827
|
const kind = input2.kind ?? (input2.contentType === "code" ? "code" : input2.contentType === "json" ? "json" : void 0);
|
|
30560
|
-
const
|
|
30828
|
+
const cut = input2.chunks ? { chunks: finalize2(input2.chunks, input2.contentType ?? "code"), kind: kind ?? "code" } : chunk(input2.content, input2.title, kind, input2.uri);
|
|
30829
|
+
const k = cut.kind;
|
|
30830
|
+
const fallback = cut.chunks.length === 0 && input2.content.trim().length > 0;
|
|
30831
|
+
const chunks = fallback ? finalize2(
|
|
30832
|
+
[
|
|
30833
|
+
{
|
|
30834
|
+
title: input2.title,
|
|
30835
|
+
body: input2.content,
|
|
30836
|
+
startLine: 1,
|
|
30837
|
+
endLine: input2.content.split("\n").length
|
|
30838
|
+
}
|
|
30839
|
+
],
|
|
30840
|
+
kindToContentType(k)
|
|
30841
|
+
) : cut.chunks;
|
|
30561
30842
|
const contentHash = hashText(input2.content);
|
|
30562
30843
|
const existing = input2.uri ? db.findDocumentByUri(input2.uri) : void 0;
|
|
30563
30844
|
if (existing && existing.content_hash === contentHash) {
|
|
@@ -30567,7 +30848,8 @@ function indexContent(db, input2) {
|
|
|
30567
30848
|
created: false,
|
|
30568
30849
|
chunks: chunks.length,
|
|
30569
30850
|
chars: input2.content.length,
|
|
30570
|
-
kind: k
|
|
30851
|
+
kind: k,
|
|
30852
|
+
fallback
|
|
30571
30853
|
};
|
|
30572
30854
|
}
|
|
30573
30855
|
db.deleteDocument(existing.id);
|
|
@@ -30584,11 +30866,25 @@ function indexContent(db, input2) {
|
|
|
30584
30866
|
},
|
|
30585
30867
|
chunks
|
|
30586
30868
|
);
|
|
30587
|
-
return {
|
|
30869
|
+
return {
|
|
30870
|
+
documentId: id,
|
|
30871
|
+
created,
|
|
30872
|
+
chunks: chunks.length,
|
|
30873
|
+
chars: input2.content.length,
|
|
30874
|
+
kind: k,
|
|
30875
|
+
fallback
|
|
30876
|
+
};
|
|
30588
30877
|
}
|
|
30589
30878
|
function indexPath(db, root, target, opts = {}) {
|
|
30590
30879
|
const abs = resolve2(root, target);
|
|
30591
|
-
const summary = {
|
|
30880
|
+
const summary = {
|
|
30881
|
+
files: 0,
|
|
30882
|
+
indexed: 0,
|
|
30883
|
+
unchanged: 0,
|
|
30884
|
+
skipped: [],
|
|
30885
|
+
chunks: 0,
|
|
30886
|
+
fallbacks: 0
|
|
30887
|
+
};
|
|
30592
30888
|
const st = statSync(abs);
|
|
30593
30889
|
const files = st.isDirectory() ? import_fast_glob.default.sync(opts.globs ?? ["**/*.md"], {
|
|
30594
30890
|
cwd: abs,
|
|
@@ -30607,7 +30903,7 @@ function indexPath(db, root, target, opts = {}) {
|
|
|
30607
30903
|
summary.skipped.push({ path: rel, reason: `too large (${size} bytes)` });
|
|
30608
30904
|
continue;
|
|
30609
30905
|
}
|
|
30610
|
-
const content =
|
|
30906
|
+
const content = readFileSync12(file3, "utf8");
|
|
30611
30907
|
if (content.includes("\0")) {
|
|
30612
30908
|
summary.skipped.push({ path: rel, reason: "binary" });
|
|
30613
30909
|
continue;
|
|
@@ -30623,6 +30919,7 @@ function indexPath(db, root, target, opts = {}) {
|
|
|
30623
30919
|
if (r.created) summary.indexed++;
|
|
30624
30920
|
else summary.unchanged++;
|
|
30625
30921
|
summary.chunks += r.chunks;
|
|
30922
|
+
if (r.fallback) summary.fallbacks++;
|
|
30626
30923
|
} catch (err) {
|
|
30627
30924
|
summary.skipped.push({ path: rel, reason: err.message });
|
|
30628
30925
|
}
|
|
@@ -30698,7 +30995,7 @@ var init_em_index = __esm({
|
|
|
30698
30995
|
});
|
|
30699
30996
|
kickEmbedding(ctx, db);
|
|
30700
30997
|
return text(
|
|
30701
|
-
`${r.created ? "indexed" : "unchanged"} "${args.title}" as doc ${r.documentId}: ${r.chunks} chunks, ${r.chars} chars (${r.kind})`
|
|
30998
|
+
`${r.created ? "indexed" : "unchanged"} "${args.title}" as doc ${r.documentId}: ${r.chunks} chunks, ${r.chars} chars (${r.kind})${r.fallback ? " (no sections found; indexed as one chunk)" : ""}`
|
|
30702
30999
|
);
|
|
30703
31000
|
}
|
|
30704
31001
|
if (!args.path) return errorResult("provide `path` or `content`");
|
|
@@ -30708,7 +31005,7 @@ var init_em_index = __esm({
|
|
|
30708
31005
|
recursive: args.recursive ?? true
|
|
30709
31006
|
});
|
|
30710
31007
|
const lines = [
|
|
30711
|
-
`${args.path}: ${s.files} file(s), ${s.indexed} indexed, ${s.unchanged} unchanged, ${s.chunks} chunks`
|
|
31008
|
+
`${args.path}: ${s.files} file(s), ${s.indexed} indexed, ${s.unchanged} unchanged, ${s.chunks} chunks${s.fallbacks ? ` (${s.fallbacks} with no sections found; indexed as one chunk)` : ""}`
|
|
30712
31009
|
];
|
|
30713
31010
|
for (const sk of s.skipped.slice(0, 10)) lines.push(` skipped ${sk.path}: ${sk.reason}`);
|
|
30714
31011
|
if (s.skipped.length > 10) lines.push(` \u2026 ${s.skipped.length - 10} more skipped`);
|
|
@@ -32221,8 +32518,8 @@ var init_routes = __esm({
|
|
|
32221
32518
|
});
|
|
32222
32519
|
|
|
32223
32520
|
// src/graph/languages/parser.ts
|
|
32224
|
-
import { existsSync as
|
|
32225
|
-
import { extname as extname2, join as
|
|
32521
|
+
import { existsSync as existsSync15 } from "fs";
|
|
32522
|
+
import { extname as extname2, join as join17 } from "path";
|
|
32226
32523
|
function grammarFor(path3) {
|
|
32227
32524
|
switch (extname2(path3).toLowerCase()) {
|
|
32228
32525
|
case ".ts":
|
|
@@ -32255,8 +32552,8 @@ async function getParser(grammar) {
|
|
|
32255
32552
|
}
|
|
32256
32553
|
let lang = languages.get(grammar);
|
|
32257
32554
|
if (!lang) {
|
|
32258
|
-
const file3 =
|
|
32259
|
-
if (!
|
|
32555
|
+
const file3 = join17(pluginRoot(), "vendor", "grammars", `${grammar}.wasm`);
|
|
32556
|
+
if (!existsSync15(file3)) throw new Error(`grammar missing: ${file3}`);
|
|
32260
32557
|
lang = await parserMod.Language.load(file3);
|
|
32261
32558
|
languages.set(grammar, lang);
|
|
32262
32559
|
}
|
|
@@ -32314,8 +32611,8 @@ var init_parser = __esm({
|
|
|
32314
32611
|
});
|
|
32315
32612
|
|
|
32316
32613
|
// src/graph/languages/go.ts
|
|
32317
|
-
import { existsSync as
|
|
32318
|
-
import { dirname as dirname4, join as
|
|
32614
|
+
import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
|
|
32615
|
+
import { dirname as dirname4, join as join18, normalize, relative as relative2, resolve as resolve3 } from "path";
|
|
32319
32616
|
function goModule(root, fromAbs) {
|
|
32320
32617
|
let dir = dirname4(fromAbs);
|
|
32321
32618
|
while (dir.startsWith(root)) {
|
|
@@ -32323,9 +32620,9 @@ function goModule(root, fromAbs) {
|
|
|
32323
32620
|
if (hit !== void 0) {
|
|
32324
32621
|
if (hit) return hit;
|
|
32325
32622
|
} else {
|
|
32326
|
-
const file3 =
|
|
32327
|
-
if (
|
|
32328
|
-
const m = /^module\s+(\S+)/m.exec(
|
|
32623
|
+
const file3 = join18(dir, "go.mod");
|
|
32624
|
+
if (existsSync16(file3)) {
|
|
32625
|
+
const m = /^module\s+(\S+)/m.exec(readFileSync13(file3, "utf8"));
|
|
32329
32626
|
const info = m ? { module: m[1], dir } : null;
|
|
32330
32627
|
goModCache.set(dir, info);
|
|
32331
32628
|
if (info) return info;
|
|
@@ -32342,11 +32639,11 @@ function resolveGoPackage(root, fromRel, importPath) {
|
|
|
32342
32639
|
let dir;
|
|
32343
32640
|
if (importPath === mod.module) dir = mod.dir;
|
|
32344
32641
|
else if (importPath.startsWith(`${mod.module}/`))
|
|
32345
|
-
dir =
|
|
32346
|
-
if (!dir || !
|
|
32642
|
+
dir = join18(mod.dir, importPath.slice(mod.module.length + 1));
|
|
32643
|
+
if (!dir || !existsSync16(dir)) return [];
|
|
32347
32644
|
try {
|
|
32348
|
-
return
|
|
32349
|
-
(f) => normalize(relative2(root,
|
|
32645
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).sort().map(
|
|
32646
|
+
(f) => normalize(relative2(root, join18(dir, f))).split("\\").join("/")
|
|
32350
32647
|
);
|
|
32351
32648
|
} catch {
|
|
32352
32649
|
return [];
|
|
@@ -32748,13 +33045,13 @@ var init_go = __esm({
|
|
|
32748
33045
|
});
|
|
32749
33046
|
|
|
32750
33047
|
// src/graph/languages/php.ts
|
|
32751
|
-
import { readdirSync as
|
|
32752
|
-
import { dirname as dirname5, join as
|
|
33048
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync2 } from "fs";
|
|
33049
|
+
import { dirname as dirname5, join as join19, normalize as normalize2, relative as relative3, resolve as resolve4 } from "path";
|
|
32753
33050
|
function readComposer(dir) {
|
|
32754
|
-
const file3 =
|
|
33051
|
+
const file3 = join19(dir, "composer.json");
|
|
32755
33052
|
if (!isFile(file3)) return null;
|
|
32756
33053
|
try {
|
|
32757
|
-
const json3 = JSON.parse(
|
|
33054
|
+
const json3 = JSON.parse(readFileSync14(file3, "utf8"));
|
|
32758
33055
|
const info = { dir, psr4: [], psr0: [], classmap: [], files: [], require: [] };
|
|
32759
33056
|
for (const key of ["autoload", "autoload-dev"]) {
|
|
32760
33057
|
const section = json3[key];
|
|
@@ -32796,7 +33093,7 @@ function phpFilesUnder(abs, budget) {
|
|
|
32796
33093
|
if (isFile(abs)) return abs.endsWith(".php") ? [abs] : [];
|
|
32797
33094
|
let entries;
|
|
32798
33095
|
try {
|
|
32799
|
-
entries =
|
|
33096
|
+
entries = readdirSync7(abs, { recursive: true, encoding: "utf8" });
|
|
32800
33097
|
} catch {
|
|
32801
33098
|
return [];
|
|
32802
33099
|
}
|
|
@@ -32804,7 +33101,7 @@ function phpFilesUnder(abs, budget) {
|
|
|
32804
33101
|
for (const e of entries) {
|
|
32805
33102
|
if (budget.left <= 0) break;
|
|
32806
33103
|
if (!e.endsWith(".php") || e.split(/[\\/]/).includes("vendor")) continue;
|
|
32807
|
-
out.push(
|
|
33104
|
+
out.push(join19(abs, e));
|
|
32808
33105
|
budget.left--;
|
|
32809
33106
|
}
|
|
32810
33107
|
return out;
|
|
@@ -32814,11 +33111,11 @@ function classmapClasses(root, auto) {
|
|
|
32814
33111
|
const classes = /* @__PURE__ */ new Map();
|
|
32815
33112
|
const budget = { left: CLASSMAP_MAX_FILES };
|
|
32816
33113
|
for (const entry of auto.classmap) {
|
|
32817
|
-
for (const f of phpFilesUnder(
|
|
33114
|
+
for (const f of phpFilesUnder(join19(auto.dir, entry), budget)) {
|
|
32818
33115
|
if (relative3(root, f).startsWith("..")) continue;
|
|
32819
33116
|
let code;
|
|
32820
33117
|
try {
|
|
32821
|
-
code =
|
|
33118
|
+
code = readFileSync14(f, "utf8");
|
|
32822
33119
|
} catch {
|
|
32823
33120
|
continue;
|
|
32824
33121
|
}
|
|
@@ -32838,11 +33135,11 @@ function autoloadedFunctions(root, auto) {
|
|
|
32838
33135
|
if (auto.functions) return auto.functions;
|
|
32839
33136
|
const functions = /* @__PURE__ */ new Map();
|
|
32840
33137
|
for (const entry of auto.files) {
|
|
32841
|
-
const f =
|
|
33138
|
+
const f = join19(auto.dir, entry);
|
|
32842
33139
|
if (!isFile(f) || relative3(root, f).startsWith("..")) continue;
|
|
32843
33140
|
let code;
|
|
32844
33141
|
try {
|
|
32845
|
-
code =
|
|
33142
|
+
code = readFileSync14(f, "utf8");
|
|
32846
33143
|
} catch {
|
|
32847
33144
|
continue;
|
|
32848
33145
|
}
|
|
@@ -32862,14 +33159,14 @@ function resolvePhpClass(root, fromRel, fqcn) {
|
|
|
32862
33159
|
for (const { prefix, dirs } of auto.psr4) {
|
|
32863
33160
|
if (!name.startsWith(prefix)) continue;
|
|
32864
33161
|
const rest2 = name.slice(prefix.length).split("\\");
|
|
32865
|
-
for (const d of dirs) candidates2.push(
|
|
33162
|
+
for (const d of dirs) candidates2.push(join19(auto.dir, d, ...rest2));
|
|
32866
33163
|
}
|
|
32867
33164
|
for (const { prefix, dirs } of auto.psr0) {
|
|
32868
33165
|
if (!name.startsWith(prefix)) continue;
|
|
32869
33166
|
const cut = name.lastIndexOf("\\");
|
|
32870
33167
|
const ns = cut === -1 ? [] : name.slice(0, cut).split("\\");
|
|
32871
33168
|
const cls = name.slice(cut + 1).split("_");
|
|
32872
|
-
for (const d of dirs) candidates2.push(
|
|
33169
|
+
for (const d of dirs) candidates2.push(join19(auto.dir, d, ...ns, ...cls));
|
|
32873
33170
|
}
|
|
32874
33171
|
} else {
|
|
32875
33172
|
const parts = name.split("\\");
|
|
@@ -33106,7 +33403,7 @@ async function parsePhp(root, rel, code) {
|
|
|
33106
33403
|
for (let i = left.includes("__FILE__") ? 1 : 0; i < Number(up[1] ?? 1); i++)
|
|
33107
33404
|
base = dirname5(base);
|
|
33108
33405
|
}
|
|
33109
|
-
if (base && right !== void 0) candidates2.push(
|
|
33406
|
+
if (base && right !== void 0) candidates2.push(join19(base, right));
|
|
33110
33407
|
}
|
|
33111
33408
|
const hit = candidates2.find((c) => isFile(c) && !relative3(root, c).startsWith(".."));
|
|
33112
33409
|
if (!hit) continue;
|
|
@@ -33815,25 +34112,25 @@ var init_php = __esm({
|
|
|
33815
34112
|
});
|
|
33816
34113
|
|
|
33817
34114
|
// src/graph/languages/python.ts
|
|
33818
|
-
import { existsSync as
|
|
33819
|
-
import { dirname as dirname6, join as
|
|
34115
|
+
import { existsSync as existsSync17, statSync as statSync3 } from "fs";
|
|
34116
|
+
import { dirname as dirname6, join as join20, normalize as normalize3, relative as relative4, resolve as resolve5 } from "path";
|
|
33820
34117
|
function resolvePython(root, fromRel, module, level) {
|
|
33821
34118
|
const parts = module ? module.split(".") : [];
|
|
33822
34119
|
const candidates2 = [];
|
|
33823
34120
|
if (level > 0) {
|
|
33824
34121
|
let base = dirname6(resolve5(root, fromRel));
|
|
33825
34122
|
for (let i = 1; i < level; i++) base = dirname6(base);
|
|
33826
|
-
candidates2.push(
|
|
34123
|
+
candidates2.push(join20(base, ...parts));
|
|
33827
34124
|
} else {
|
|
33828
34125
|
candidates2.push(resolve5(root, ...parts), resolve5(root, "src", ...parts));
|
|
33829
34126
|
let dir = dirname6(resolve5(root, fromRel));
|
|
33830
34127
|
while (dir.startsWith(root) && dir !== root) {
|
|
33831
|
-
candidates2.push(
|
|
34128
|
+
candidates2.push(join20(dir, ...parts));
|
|
33832
34129
|
dir = dirname6(dir);
|
|
33833
34130
|
}
|
|
33834
34131
|
}
|
|
33835
34132
|
for (const c of candidates2) {
|
|
33836
|
-
for (const f of [`${c}.py`,
|
|
34133
|
+
for (const f of [`${c}.py`, join20(c, "__init__.py"), `${c}.pyi`]) {
|
|
33837
34134
|
if (isFile2(f) && !relative4(root, f).startsWith(".."))
|
|
33838
34135
|
return normalize3(relative4(root, f)).split("\\").join("/");
|
|
33839
34136
|
}
|
|
@@ -33872,7 +34169,7 @@ async function parsePython(root, rel, code) {
|
|
|
33872
34169
|
walkRefs(stmt);
|
|
33873
34170
|
}
|
|
33874
34171
|
edges.push(...refs.edges());
|
|
33875
|
-
if (!
|
|
34172
|
+
if (!existsSync17(join20(root, rel))) {
|
|
33876
34173
|
}
|
|
33877
34174
|
const errors = tree.rootNode.hasError ? tree.rootNode.descendantsOfType("ERROR").length : 0;
|
|
33878
34175
|
fileNode.meta = {
|
|
@@ -34219,16 +34516,16 @@ var init_python = __esm({
|
|
|
34219
34516
|
});
|
|
34220
34517
|
|
|
34221
34518
|
// src/graph/resolve.ts
|
|
34222
|
-
import { existsSync as
|
|
34223
|
-
import { dirname as dirname7, join as
|
|
34519
|
+
import { existsSync as existsSync18, readdirSync as readdirSync8, readFileSync as readFileSync15, statSync as statSync4 } from "fs";
|
|
34520
|
+
import { dirname as dirname7, join as join21, normalize as normalize4, relative as relative5, resolve as resolve6 } from "path";
|
|
34224
34521
|
function loadTsPaths(root) {
|
|
34225
34522
|
const hit = tsPathsCache.get(root);
|
|
34226
34523
|
if (hit !== void 0) return hit;
|
|
34227
34524
|
let out = null;
|
|
34228
34525
|
try {
|
|
34229
|
-
const file3 =
|
|
34230
|
-
if (
|
|
34231
|
-
const raw =
|
|
34526
|
+
const file3 = join21(root, "tsconfig.json");
|
|
34527
|
+
if (existsSync18(file3)) {
|
|
34528
|
+
const raw = readFileSync15(file3, "utf8").replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
|
|
34232
34529
|
const cfg = JSON.parse(raw);
|
|
34233
34530
|
const co = cfg.compilerOptions ?? {};
|
|
34234
34531
|
if (co.paths) {
|
|
@@ -34266,16 +34563,16 @@ function probe(abs) {
|
|
|
34266
34563
|
if (tryFile(abs + ext)) return abs + ext;
|
|
34267
34564
|
}
|
|
34268
34565
|
for (const ext of EXTS) {
|
|
34269
|
-
const idx =
|
|
34566
|
+
const idx = join21(abs, `index${ext}`);
|
|
34270
34567
|
if (tryFile(idx)) return idx;
|
|
34271
34568
|
}
|
|
34272
34569
|
return void 0;
|
|
34273
34570
|
}
|
|
34274
34571
|
function readPackageJson(dir) {
|
|
34275
34572
|
try {
|
|
34276
|
-
const file3 =
|
|
34277
|
-
if (!
|
|
34278
|
-
return JSON.parse(
|
|
34573
|
+
const file3 = join21(dir, "package.json");
|
|
34574
|
+
if (!existsSync18(file3)) return void 0;
|
|
34575
|
+
return JSON.parse(readFileSync15(file3, "utf8"));
|
|
34279
34576
|
} catch {
|
|
34280
34577
|
return void 0;
|
|
34281
34578
|
}
|
|
@@ -34291,9 +34588,9 @@ function loadWorkspaces(root) {
|
|
|
34291
34588
|
if (Array.isArray(ws)) globs.push(...ws);
|
|
34292
34589
|
else if (ws?.packages) globs.push(...ws.packages);
|
|
34293
34590
|
try {
|
|
34294
|
-
const yaml =
|
|
34295
|
-
if (
|
|
34296
|
-
for (const m of
|
|
34591
|
+
const yaml = join21(root, "pnpm-workspace.yaml");
|
|
34592
|
+
if (existsSync18(yaml)) {
|
|
34593
|
+
for (const m of readFileSync15(yaml, "utf8").matchAll(/^\s*-\s*['"]?([^'"\n#]+?)['"]?\s*$/gm))
|
|
34297
34594
|
globs.push(m[1].trim());
|
|
34298
34595
|
}
|
|
34299
34596
|
} catch {
|
|
@@ -34306,8 +34603,8 @@ function loadWorkspaces(root) {
|
|
|
34306
34603
|
else {
|
|
34307
34604
|
const base = resolve6(root, g.slice(0, star));
|
|
34308
34605
|
try {
|
|
34309
|
-
for (const d of
|
|
34310
|
-
if (d.isDirectory()) dirs.push(
|
|
34606
|
+
for (const d of readdirSync8(base, { withFileTypes: true })) {
|
|
34607
|
+
if (d.isDirectory()) dirs.push(join21(base, d.name));
|
|
34311
34608
|
}
|
|
34312
34609
|
} catch {
|
|
34313
34610
|
}
|
|
@@ -35450,8 +35747,8 @@ var init_link = __esm({
|
|
|
35450
35747
|
});
|
|
35451
35748
|
|
|
35452
35749
|
// src/graph/reindex.ts
|
|
35453
|
-
import { readFileSync as
|
|
35454
|
-
import { join as
|
|
35750
|
+
import { readFileSync as readFileSync16, statSync as statSync5 } from "fs";
|
|
35751
|
+
import { join as join22 } from "path";
|
|
35455
35752
|
function listCodeFiles(ctx) {
|
|
35456
35753
|
return import_fast_glob2.default.sync(ctx.config.graph.include, {
|
|
35457
35754
|
cwd: ctx.root,
|
|
@@ -35462,7 +35759,7 @@ function listCodeFiles(ctx) {
|
|
|
35462
35759
|
});
|
|
35463
35760
|
}
|
|
35464
35761
|
async function indexOne(ctx, db, rel, force) {
|
|
35465
|
-
const abs =
|
|
35762
|
+
const abs = join22(ctx.root, rel);
|
|
35466
35763
|
const st = statSync5(abs);
|
|
35467
35764
|
const backend = getCodeBackend(ctx);
|
|
35468
35765
|
const language = backend.languageOf(rel) ?? null;
|
|
@@ -35482,7 +35779,7 @@ async function indexOne(ctx, db, rel, force) {
|
|
|
35482
35779
|
}
|
|
35483
35780
|
return "skipped";
|
|
35484
35781
|
}
|
|
35485
|
-
const code =
|
|
35782
|
+
const code = readFileSync16(abs, "utf8");
|
|
35486
35783
|
const hash2 = hashText(code);
|
|
35487
35784
|
const prev = db.fileIndexGet(rel);
|
|
35488
35785
|
if (!force && prev?.hash === hash2 && prev.status !== "skipped") return "unchanged";
|
|
@@ -35563,7 +35860,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
35563
35860
|
summary.unsupported++;
|
|
35564
35861
|
if (db.fileIndexGet(rel)?.status === "unsupported") continue;
|
|
35565
35862
|
try {
|
|
35566
|
-
const st = statSync5(
|
|
35863
|
+
const st = statSync5(join22(ctx.root, rel));
|
|
35567
35864
|
db.fileIndexSet({
|
|
35568
35865
|
path: rel,
|
|
35569
35866
|
hash: "",
|
|
@@ -35579,7 +35876,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
35579
35876
|
}
|
|
35580
35877
|
for (const rel of targets) {
|
|
35581
35878
|
try {
|
|
35582
|
-
if (!statSafe(
|
|
35879
|
+
if (!statSafe(join22(ctx.root, rel))) {
|
|
35583
35880
|
if (db.fileIndexGet(rel)) {
|
|
35584
35881
|
removeOne(db, rel);
|
|
35585
35882
|
summary.removed++;
|
|
@@ -35591,7 +35888,7 @@ async function reindexCode(ctx, db, opts = {}) {
|
|
|
35591
35888
|
const error62 = err.message;
|
|
35592
35889
|
summary.errors.push({ path: rel, error: error62 });
|
|
35593
35890
|
try {
|
|
35594
|
-
const st = statSync5(
|
|
35891
|
+
const st = statSync5(join22(ctx.root, rel));
|
|
35595
35892
|
db.fileIndexSet({
|
|
35596
35893
|
path: rel,
|
|
35597
35894
|
hash: "",
|
|
@@ -35694,10 +35991,10 @@ function indexFreshness(ctx, db) {
|
|
|
35694
35991
|
const dirty = [];
|
|
35695
35992
|
for (const r of rows.slice(0, 400)) {
|
|
35696
35993
|
try {
|
|
35697
|
-
const abs =
|
|
35994
|
+
const abs = join22(ctx.root, r.path);
|
|
35698
35995
|
const st = statSync5(abs);
|
|
35699
35996
|
if (r.mtime !== null && Math.abs(st.mtimeMs - r.mtime) < 1 && st.size === r.size) continue;
|
|
35700
|
-
if (hashText(
|
|
35997
|
+
if (hashText(readFileSync16(abs, "utf8")) !== r.hash) dirty.push(r.path);
|
|
35701
35998
|
} catch {
|
|
35702
35999
|
dirty.push(r.path);
|
|
35703
36000
|
}
|
|
@@ -35731,10 +36028,10 @@ var init_reindex = __esm({
|
|
|
35731
36028
|
});
|
|
35732
36029
|
|
|
35733
36030
|
// src/session/current.ts
|
|
35734
|
-
import { readFileSync as
|
|
35735
|
-
import { join as
|
|
36031
|
+
import { readFileSync as readFileSync17, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
36032
|
+
import { join as join23 } from "path";
|
|
35736
36033
|
function file2(ctx) {
|
|
35737
|
-
return
|
|
36034
|
+
return join23(projectDir(ctx.id), "current-session");
|
|
35738
36035
|
}
|
|
35739
36036
|
function getCurrentSession(ctx) {
|
|
35740
36037
|
if (process.env.EMINIAR_SESSION_ID) return process.env.EMINIAR_SESSION_ID;
|
|
@@ -35746,7 +36043,7 @@ function getCurrentSession(ctx) {
|
|
|
35746
36043
|
return "unknown";
|
|
35747
36044
|
}
|
|
35748
36045
|
if (cached4 && cached4.file === f && cached4.mtimeMs === mtimeMs) return cached4.id;
|
|
35749
|
-
const id =
|
|
36046
|
+
const id = readFileSync17(f, "utf8").trim() || "unknown";
|
|
35750
36047
|
cached4 = { file: f, mtimeMs, id };
|
|
35751
36048
|
return id;
|
|
35752
36049
|
}
|
|
@@ -35917,15 +36214,15 @@ __export(store_exports, {
|
|
|
35917
36214
|
write: () => write
|
|
35918
36215
|
});
|
|
35919
36216
|
import {
|
|
35920
|
-
existsSync as
|
|
35921
|
-
mkdirSync as
|
|
35922
|
-
readFileSync as
|
|
36217
|
+
existsSync as existsSync19,
|
|
36218
|
+
mkdirSync as mkdirSync10,
|
|
36219
|
+
readFileSync as readFileSync18,
|
|
35923
36220
|
renameSync,
|
|
35924
36221
|
statSync as statSync7,
|
|
35925
36222
|
unlinkSync,
|
|
35926
|
-
writeFileSync as
|
|
36223
|
+
writeFileSync as writeFileSync8
|
|
35927
36224
|
} from "fs";
|
|
35928
|
-
import { dirname as dirname8, join as
|
|
36225
|
+
import { dirname as dirname8, join as join24, relative as relative6, sep } from "path";
|
|
35929
36226
|
function isStatus(s) {
|
|
35930
36227
|
return typeof s === "string" && MEMORY_STATUSES.includes(s);
|
|
35931
36228
|
}
|
|
@@ -35939,13 +36236,13 @@ function memoriesRel(ctx) {
|
|
|
35939
36236
|
return ctx.config.memories.dir.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
35940
36237
|
}
|
|
35941
36238
|
function memoriesDir(ctx) {
|
|
35942
|
-
return
|
|
36239
|
+
return join24(ctx.root, memoriesRel(ctx));
|
|
35943
36240
|
}
|
|
35944
36241
|
function relOf(ctx, name) {
|
|
35945
36242
|
return `${memoriesRel(ctx)}/${name}.md`;
|
|
35946
36243
|
}
|
|
35947
36244
|
function absOf(ctx, name) {
|
|
35948
|
-
return
|
|
36245
|
+
return join24(ctx.root, relOf(ctx, name));
|
|
35949
36246
|
}
|
|
35950
36247
|
function nameOfFile(ctx, abs) {
|
|
35951
36248
|
const rel = relative6(memoriesDir(ctx), abs).split(sep).join("/");
|
|
@@ -36003,7 +36300,7 @@ function impliedFileLinks(root, body, skipPrefix) {
|
|
|
36003
36300
|
if (!p || p.startsWith("..") || out.has(p) || skipPrefix && p.startsWith(`${skipPrefix}/`))
|
|
36004
36301
|
continue;
|
|
36005
36302
|
try {
|
|
36006
|
-
if (statSync7(
|
|
36303
|
+
if (statSync7(join24(root, p)).isFile()) out.add(p);
|
|
36007
36304
|
} catch {
|
|
36008
36305
|
}
|
|
36009
36306
|
if (out.size >= 30) break;
|
|
@@ -36012,8 +36309,8 @@ function impliedFileLinks(root, body, skipPrefix) {
|
|
|
36012
36309
|
}
|
|
36013
36310
|
function writeMemoryFile(ctx, name, meta4, body) {
|
|
36014
36311
|
const abs = absOf(ctx, name);
|
|
36015
|
-
|
|
36016
|
-
|
|
36312
|
+
mkdirSync10(dirname8(abs), { recursive: true });
|
|
36313
|
+
writeFileSync8(abs, serializeMemoryFile(meta4, `
|
|
36017
36314
|
${body.trim()}
|
|
36018
36315
|
`));
|
|
36019
36316
|
}
|
|
@@ -36051,13 +36348,13 @@ function forgetInDb(db, name, rel) {
|
|
|
36051
36348
|
function syncFile(ctx, db, name, opts = {}) {
|
|
36052
36349
|
const abs = absOf(ctx, name);
|
|
36053
36350
|
const rel = relOf(ctx, name);
|
|
36054
|
-
if (!
|
|
36351
|
+
if (!existsSync19(abs)) return void 0;
|
|
36055
36352
|
let st = statSync7(abs);
|
|
36056
36353
|
const row = db.memoryGetByName(name);
|
|
36057
36354
|
const mtime = Math.floor(st.mtimeMs);
|
|
36058
36355
|
if (!opts.force && row && row.file_mtime === mtime && row.file_size === st.size)
|
|
36059
36356
|
return { changed: false, row };
|
|
36060
|
-
let text3 =
|
|
36357
|
+
let text3 = readFileSync18(abs, "utf8");
|
|
36061
36358
|
let hash2 = hashText(text3);
|
|
36062
36359
|
if (!opts.force && row && row.file_hash === hash2) {
|
|
36063
36360
|
db.memoryUpsertByName({
|
|
@@ -36095,7 +36392,7 @@ function syncFile(ctx, db, name, opts = {}) {
|
|
|
36095
36392
|
parsed.hadFrontmatter ? parsed.body : `
|
|
36096
36393
|
${parsed.body.replace(/^\s*\n/, "")}`
|
|
36097
36394
|
);
|
|
36098
|
-
|
|
36395
|
+
writeFileSync8(abs, text3);
|
|
36099
36396
|
st = statSync7(abs);
|
|
36100
36397
|
hash2 = hashText(text3);
|
|
36101
36398
|
}
|
|
@@ -36137,15 +36434,15 @@ tags: ${tags.join(", ")}` : ""}`,
|
|
|
36137
36434
|
}
|
|
36138
36435
|
function setMeta(ctx, db, name, patch) {
|
|
36139
36436
|
const abs = absOf(ctx, name);
|
|
36140
|
-
if (!
|
|
36141
|
-
const parsed = parseMemoryFile(
|
|
36437
|
+
if (!existsSync19(abs)) return false;
|
|
36438
|
+
const parsed = parseMemoryFile(readFileSync18(abs, "utf8"));
|
|
36142
36439
|
const meta4 = { ...parsed.meta };
|
|
36143
36440
|
for (const [k, v] of Object.entries(patch)) {
|
|
36144
36441
|
if (v === void 0) delete meta4[k];
|
|
36145
36442
|
else meta4[k] = v;
|
|
36146
36443
|
}
|
|
36147
36444
|
meta4.updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
36148
|
-
|
|
36445
|
+
writeFileSync8(abs, serializeMemoryFile(meta4, parsed.body));
|
|
36149
36446
|
syncFile(ctx, db, name, { force: true });
|
|
36150
36447
|
return true;
|
|
36151
36448
|
}
|
|
@@ -36154,10 +36451,10 @@ function migrateLegacy(ctx, db) {
|
|
|
36154
36451
|
for (const row of db.memoryLegacyRows()) {
|
|
36155
36452
|
const kind = isKind(row.kind) ? row.kind : "note";
|
|
36156
36453
|
const base = `${kind}/${slugify2(row.content)}`;
|
|
36157
|
-
const taken =
|
|
36454
|
+
const taken = existsSync19(absOf(ctx, base)) || !!db.memoryGetByName(base);
|
|
36158
36455
|
const name = taken ? `${base}-${row.id}` : base;
|
|
36159
36456
|
const created = new Date(row.created_at).toISOString();
|
|
36160
|
-
if (!
|
|
36457
|
+
if (!existsSync19(absOf(ctx, name))) {
|
|
36161
36458
|
writeMemoryFile(
|
|
36162
36459
|
ctx,
|
|
36163
36460
|
name,
|
|
@@ -36182,7 +36479,7 @@ function reconcile(ctx, db) {
|
|
|
36182
36479
|
const out = { files: 0, synced: 0, removed: 0, migrated: 0, skipped: [] };
|
|
36183
36480
|
out.migrated = migrateLegacy(ctx, db);
|
|
36184
36481
|
const dir = memoriesDir(ctx);
|
|
36185
|
-
const files =
|
|
36482
|
+
const files = existsSync19(dir) ? import_fast_glob3.default.sync("**/*.md", { cwd: dir, absolute: true, onlyFiles: true, dot: true }) : [];
|
|
36186
36483
|
const seen = /* @__PURE__ */ new Set();
|
|
36187
36484
|
for (const f of files) {
|
|
36188
36485
|
const name = nameOfFile(ctx, f);
|
|
@@ -36210,7 +36507,7 @@ function write(ctx, db, input2) {
|
|
|
36210
36507
|
);
|
|
36211
36508
|
const abs = absOf(ctx, name);
|
|
36212
36509
|
const prev = db.memoryGetByName(name);
|
|
36213
|
-
const exists = !!prev ||
|
|
36510
|
+
const exists = !!prev || existsSync19(abs);
|
|
36214
36511
|
if (exists && !input2.replace)
|
|
36215
36512
|
throw new Error(
|
|
36216
36513
|
`memory "${name}" already exists; pass replace: true to overwrite it, or em_memory {action: "edit"} to change part of it`
|
|
@@ -36219,7 +36516,7 @@ function write(ctx, db, input2) {
|
|
|
36219
36516
|
let extra = {};
|
|
36220
36517
|
if (exists) {
|
|
36221
36518
|
try {
|
|
36222
|
-
extra = parseMemoryFile(
|
|
36519
|
+
extra = parseMemoryFile(readFileSync18(abs, "utf8")).meta;
|
|
36223
36520
|
} catch {
|
|
36224
36521
|
}
|
|
36225
36522
|
}
|
|
@@ -36246,7 +36543,7 @@ function write(ctx, db, input2) {
|
|
|
36246
36543
|
function read(ctx, db, name) {
|
|
36247
36544
|
const synced = syncFile(ctx, db, name);
|
|
36248
36545
|
if (!synced) return void 0;
|
|
36249
|
-
const parsed = parseMemoryFile(
|
|
36546
|
+
const parsed = parseMemoryFile(readFileSync18(absOf(ctx, name), "utf8"));
|
|
36250
36547
|
return {
|
|
36251
36548
|
name,
|
|
36252
36549
|
kind: synced.row.kind,
|
|
@@ -36271,14 +36568,14 @@ function escapeRe(s) {
|
|
|
36271
36568
|
}
|
|
36272
36569
|
function edit(ctx, db, name, opts) {
|
|
36273
36570
|
const abs = absOf(ctx, name);
|
|
36274
|
-
if (!
|
|
36571
|
+
if (!existsSync19(abs)) throw new Error(`memory "${name}" does not exist`);
|
|
36275
36572
|
syncFile(ctx, db, name);
|
|
36276
|
-
const parsed = parseMemoryFile(
|
|
36573
|
+
const parsed = parseMemoryFile(readFileSync18(abs, "utf8"));
|
|
36277
36574
|
const re = new RegExp(opts.regex ? opts.find : escapeRe(opts.find), "g");
|
|
36278
36575
|
const count = (parsed.body.match(re) ?? []).length;
|
|
36279
36576
|
if (!count) return 0;
|
|
36280
36577
|
const body = parsed.body.replace(re, opts.replace);
|
|
36281
|
-
|
|
36578
|
+
writeFileSync8(
|
|
36282
36579
|
abs,
|
|
36283
36580
|
serializeMemoryFile({ ...parsed.meta, updated: (/* @__PURE__ */ new Date()).toISOString() }, body)
|
|
36284
36581
|
);
|
|
@@ -36289,12 +36586,12 @@ function rename(ctx, db, from, to) {
|
|
|
36289
36586
|
if (!isValidName(to)) throw new Error(`invalid memory name "${to}"`);
|
|
36290
36587
|
const absFrom = absOf(ctx, from);
|
|
36291
36588
|
const absTo = absOf(ctx, to);
|
|
36292
|
-
if (!
|
|
36293
|
-
if (
|
|
36294
|
-
|
|
36589
|
+
if (!existsSync19(absFrom)) throw new Error(`memory "${from}" does not exist`);
|
|
36590
|
+
if (existsSync19(absTo) || db.memoryGetByName(to)) throw new Error(`memory "${to}" already exists`);
|
|
36591
|
+
mkdirSync10(dirname8(absTo), { recursive: true });
|
|
36295
36592
|
renameSync(absFrom, absTo);
|
|
36296
|
-
const parsed = parseMemoryFile(
|
|
36297
|
-
|
|
36593
|
+
const parsed = parseMemoryFile(readFileSync18(absTo, "utf8"));
|
|
36594
|
+
writeFileSync8(
|
|
36298
36595
|
absTo,
|
|
36299
36596
|
serializeMemoryFile(
|
|
36300
36597
|
{ ...parsed.meta, name: to, updated: (/* @__PURE__ */ new Date()).toISOString() },
|
|
@@ -36308,11 +36605,11 @@ function rename(ctx, db, from, to) {
|
|
|
36308
36605
|
for (const row of db.memoryList({ limit: 1e5 })) {
|
|
36309
36606
|
if (!row.name || row.name === to) continue;
|
|
36310
36607
|
const abs = absOf(ctx, row.name);
|
|
36311
|
-
if (!
|
|
36312
|
-
const text3 =
|
|
36608
|
+
if (!existsSync19(abs)) continue;
|
|
36609
|
+
const text3 = readFileSync18(abs, "utf8");
|
|
36313
36610
|
if (!ref.test(text3)) continue;
|
|
36314
36611
|
ref.lastIndex = 0;
|
|
36315
|
-
|
|
36612
|
+
writeFileSync8(abs, text3.replace(ref, `mem:${to}`));
|
|
36316
36613
|
syncFile(ctx, db, row.name, { force: true });
|
|
36317
36614
|
refsUpdated++;
|
|
36318
36615
|
}
|
|
@@ -36320,19 +36617,19 @@ function rename(ctx, db, from, to) {
|
|
|
36320
36617
|
}
|
|
36321
36618
|
function remove(ctx, db, name) {
|
|
36322
36619
|
const abs = absOf(ctx, name);
|
|
36323
|
-
const existed =
|
|
36324
|
-
if (
|
|
36620
|
+
const existed = existsSync19(abs) || !!db.memoryGetByName(name);
|
|
36621
|
+
if (existsSync19(abs)) unlinkSync(abs);
|
|
36325
36622
|
forgetInDb(db, name, relOf(ctx, name));
|
|
36326
36623
|
return existed;
|
|
36327
36624
|
}
|
|
36328
36625
|
function gitignoreHint(ctx) {
|
|
36329
36626
|
if (hinted.has(ctx.root)) return void 0;
|
|
36330
36627
|
hinted.add(ctx.root);
|
|
36331
|
-
const file3 =
|
|
36332
|
-
if (!
|
|
36628
|
+
const file3 = join24(ctx.root, ".gitignore");
|
|
36629
|
+
if (!existsSync19(file3)) return void 0;
|
|
36333
36630
|
const dir = memoriesRel(ctx);
|
|
36334
36631
|
const top2 = dir.split("/")[0];
|
|
36335
|
-
const ignored =
|
|
36632
|
+
const ignored = readFileSync18(file3, "utf8").split(/\r?\n/).map((l) => l.trim().replace(/^\//, "").replace(/\/$/, "")).some((l) => l === top2 || l === dir || l === `${top2}/**` || l === `${dir}/**`);
|
|
36336
36633
|
return ignored ? `note: .gitignore ignores ${dir}, so memories stay local to this machine (remove that line to share them with the team)` : void 0;
|
|
36337
36634
|
}
|
|
36338
36635
|
var import_fast_glob3, MEMORY_KINDS, SEGMENT, NAME_RE, MEM_LINK_RE, PATH_RE, hinted;
|
|
@@ -36962,12 +37259,12 @@ var init_em_graph_changes = __esm({
|
|
|
36962
37259
|
});
|
|
36963
37260
|
|
|
36964
37261
|
// src/graph/architecture.ts
|
|
36965
|
-
import { existsSync as
|
|
36966
|
-
import { join as
|
|
37262
|
+
import { existsSync as existsSync20, readFileSync as readFileSync19 } from "fs";
|
|
37263
|
+
import { join as join25 } from "path";
|
|
36967
37264
|
function pkgJson(root) {
|
|
36968
37265
|
try {
|
|
36969
|
-
const f =
|
|
36970
|
-
return
|
|
37266
|
+
const f = join25(root, "package.json");
|
|
37267
|
+
return existsSync20(f) ? JSON.parse(readFileSync19(f, "utf8")) : {};
|
|
36971
37268
|
} catch {
|
|
36972
37269
|
return {};
|
|
36973
37270
|
}
|
|
@@ -38319,11 +38616,14 @@ var init_catalog = __esm({
|
|
|
38319
38616
|
});
|
|
38320
38617
|
|
|
38321
38618
|
// src/docs/manifest.ts
|
|
38322
|
-
import { existsSync as
|
|
38323
|
-
import { dirname as dirname9, join as
|
|
38619
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync20, writeFileSync as writeFileSync9 } from "fs";
|
|
38620
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
38324
38621
|
function docsTag(name) {
|
|
38325
38622
|
return `${DOCS_PREFIX}${name}`;
|
|
38326
38623
|
}
|
|
38624
|
+
function nameFromTag(tag) {
|
|
38625
|
+
return tag.startsWith(DOCS_PREFIX) ? tag.slice(DOCS_PREFIX.length) : void 0;
|
|
38626
|
+
}
|
|
38327
38627
|
function isValidName2(name) {
|
|
38328
38628
|
return NAME_RE2.test(name);
|
|
38329
38629
|
}
|
|
@@ -38332,7 +38632,7 @@ function slugify3(input2) {
|
|
|
38332
38632
|
return (s || "source").slice(0, 64);
|
|
38333
38633
|
}
|
|
38334
38634
|
function manifestPathAt(root, rel = ".eminiar/docs.json") {
|
|
38335
|
-
return
|
|
38635
|
+
return join26(root, rel);
|
|
38336
38636
|
}
|
|
38337
38637
|
function manifestPath(ctx) {
|
|
38338
38638
|
return manifestPathAt(ctx.root, ctx.config.docs.manifest);
|
|
@@ -38360,9 +38660,9 @@ function normalize5(raw) {
|
|
|
38360
38660
|
return { version: 1, sources: out };
|
|
38361
38661
|
}
|
|
38362
38662
|
function readManifestAt(file3) {
|
|
38363
|
-
if (!
|
|
38663
|
+
if (!existsSync21(file3)) return empty();
|
|
38364
38664
|
try {
|
|
38365
|
-
return normalize5(JSON.parse(
|
|
38665
|
+
return normalize5(JSON.parse(readFileSync20(file3, "utf8")));
|
|
38366
38666
|
} catch {
|
|
38367
38667
|
return empty();
|
|
38368
38668
|
}
|
|
@@ -38372,12 +38672,12 @@ function readManifest(ctx) {
|
|
|
38372
38672
|
}
|
|
38373
38673
|
function writeManifest(ctx, m) {
|
|
38374
38674
|
const file3 = manifestPath(ctx);
|
|
38375
|
-
|
|
38675
|
+
mkdirSync11(dirname9(file3), { recursive: true });
|
|
38376
38676
|
const sorted = {
|
|
38377
38677
|
version: 1,
|
|
38378
38678
|
sources: [...m.sources].sort((a, b) => a.name.localeCompare(b.name))
|
|
38379
38679
|
};
|
|
38380
|
-
|
|
38680
|
+
writeFileSync9(file3, `${JSON.stringify(sorted, null, 2)}
|
|
38381
38681
|
`);
|
|
38382
38682
|
return file3;
|
|
38383
38683
|
}
|
|
@@ -38473,11 +38773,11 @@ var init_manifest = __esm({
|
|
|
38473
38773
|
});
|
|
38474
38774
|
|
|
38475
38775
|
// src/docs/discover.ts
|
|
38476
|
-
import { existsSync as
|
|
38477
|
-
import { basename, join as
|
|
38776
|
+
import { existsSync as existsSync22, readFileSync as readFileSync21, statSync as statSync8 } from "fs";
|
|
38777
|
+
import { basename, join as join27, relative as relative7 } from "path";
|
|
38478
38778
|
function readText(file3) {
|
|
38479
38779
|
try {
|
|
38480
|
-
return
|
|
38780
|
+
return readFileSync21(file3, "utf8");
|
|
38481
38781
|
} catch {
|
|
38482
38782
|
return void 0;
|
|
38483
38783
|
}
|
|
@@ -38531,7 +38831,7 @@ function findProjects(root, opts) {
|
|
|
38531
38831
|
const found = /* @__PURE__ */ new Set();
|
|
38532
38832
|
for (const m of markers) {
|
|
38533
38833
|
for (const f of glob(root, [`*/${m}`, `*/*/${m}`], 3)) {
|
|
38534
|
-
const dir =
|
|
38834
|
+
const dir = join27(f, "..");
|
|
38535
38835
|
const rel = relative7(root, dir);
|
|
38536
38836
|
if (!rel || rel.split("/").some((p) => p.startsWith(".") || p === "node_modules")) continue;
|
|
38537
38837
|
found.add(dir);
|
|
@@ -38540,7 +38840,7 @@ function findProjects(root, opts) {
|
|
|
38540
38840
|
const max = opts.maxProjects ?? 40;
|
|
38541
38841
|
const seenNames = /* @__PURE__ */ new Set();
|
|
38542
38842
|
const nameOf = (dir) => {
|
|
38543
|
-
const pkg = readJson3(
|
|
38843
|
+
const pkg = readJson3(join27(dir, "package.json"));
|
|
38544
38844
|
return typeof pkg?.name === "string" ? pkg.name : void 0;
|
|
38545
38845
|
};
|
|
38546
38846
|
const rootName = nameOf(root);
|
|
@@ -38558,7 +38858,7 @@ function findProjects(root, opts) {
|
|
|
38558
38858
|
return out;
|
|
38559
38859
|
}
|
|
38560
38860
|
function npmSignals(dir, includeDev, project) {
|
|
38561
|
-
const pkg = readJson3(
|
|
38861
|
+
const pkg = readJson3(join27(dir, "package.json"));
|
|
38562
38862
|
if (!pkg) return [];
|
|
38563
38863
|
const sections = ["dependencies", ...includeDev ? ["devDependencies"] : []];
|
|
38564
38864
|
const out = [];
|
|
@@ -38575,13 +38875,13 @@ function npmSignals(dir, includeDev, project) {
|
|
|
38575
38875
|
}
|
|
38576
38876
|
function pythonSignals(dir, project) {
|
|
38577
38877
|
const out = [];
|
|
38578
|
-
const py = readText(
|
|
38878
|
+
const py = readText(join27(dir, "pyproject.toml"));
|
|
38579
38879
|
if (py) {
|
|
38580
38880
|
const block = /dependencies\s*=\s*\[([\s\S]*?)\]/.exec(py)?.[1] ?? "";
|
|
38581
38881
|
for (const m of block.matchAll(/["']([A-Za-z0-9_.-]+)/g))
|
|
38582
38882
|
out.push({ kind: "pypi", key: m[1].toLowerCase(), project });
|
|
38583
38883
|
}
|
|
38584
|
-
const req = readText(
|
|
38884
|
+
const req = readText(join27(dir, "requirements.txt"));
|
|
38585
38885
|
if (req) {
|
|
38586
38886
|
for (const line of req.split("\n")) {
|
|
38587
38887
|
const name = /^\s*([A-Za-z0-9_.-]+)/.exec(line)?.[1];
|
|
@@ -38592,7 +38892,7 @@ function pythonSignals(dir, project) {
|
|
|
38592
38892
|
return out;
|
|
38593
38893
|
}
|
|
38594
38894
|
function goSignals(dir, project) {
|
|
38595
|
-
const mod = readText(
|
|
38895
|
+
const mod = readText(join27(dir, "go.mod"));
|
|
38596
38896
|
if (!mod) return [];
|
|
38597
38897
|
const out = [];
|
|
38598
38898
|
const block = /require\s*\(([\s\S]*?)\)/g;
|
|
@@ -38789,8 +39089,8 @@ function localCandidates(root, dir, project, isRegistered) {
|
|
|
38789
39089
|
why: "project readme and top-level guides"
|
|
38790
39090
|
});
|
|
38791
39091
|
for (const d of ["docs", "doc", "documentation"]) {
|
|
38792
|
-
const abs =
|
|
38793
|
-
if (!
|
|
39092
|
+
const abs = join27(dir, d);
|
|
39093
|
+
if (!existsSync22(abs)) continue;
|
|
38794
39094
|
const files = glob(abs, ["**/*.md", "**/*.mdx", "**/*.rst", "**/*.txt"]).filter(
|
|
38795
39095
|
(f) => !SKIP_EXT.has(f.slice(f.lastIndexOf(".")))
|
|
38796
39096
|
);
|
|
@@ -38813,8 +39113,8 @@ function localCandidates(root, dir, project, isRegistered) {
|
|
|
38813
39113
|
"docs/decisions",
|
|
38814
39114
|
"decisions"
|
|
38815
39115
|
]) {
|
|
38816
|
-
const abs =
|
|
38817
|
-
if (!
|
|
39116
|
+
const abs = join27(dir, d);
|
|
39117
|
+
if (!existsSync22(abs)) continue;
|
|
38818
39118
|
if (out.some((c) => c.path && rel(abs).startsWith(`${c.path}/`))) break;
|
|
38819
39119
|
const files = glob(abs, ["**/*.md"]);
|
|
38820
39120
|
push({
|
|
@@ -39611,7 +39911,7 @@ var init_category = __esm({
|
|
|
39611
39911
|
});
|
|
39612
39912
|
|
|
39613
39913
|
// src/docs/graph.ts
|
|
39614
|
-
import { existsSync as
|
|
39914
|
+
import { existsSync as existsSync23, statSync as statSync9 } from "fs";
|
|
39615
39915
|
import { dirname as dirname10, posix, relative as relative8, sep as sep2 } from "path";
|
|
39616
39916
|
function manifestRel(ctx) {
|
|
39617
39917
|
return relative8(ctx.root, manifestPath(ctx)).split(sep2).join("/");
|
|
@@ -39709,7 +40009,7 @@ function localDocPages(ctx, db) {
|
|
|
39709
40009
|
}
|
|
39710
40010
|
function stampOf(ctx, db) {
|
|
39711
40011
|
const file3 = manifestPath(ctx);
|
|
39712
|
-
const st =
|
|
40012
|
+
const st = existsSync23(file3) ? statSync9(file3) : void 0;
|
|
39713
40013
|
const counts = db.graphNodeCounts();
|
|
39714
40014
|
const syncs = readManifest(ctx).sources.map((s) => syncState(db, s.name)?.at ?? 0).join(",");
|
|
39715
40015
|
return `${st ? `${Math.floor(st.mtimeMs)}:${st.size}` : "none"}|${counts.file ?? 0}|${counts.package ?? 0}|${syncs}`;
|
|
@@ -40848,7 +41148,7 @@ function removeDocSource(ctx, db, name) {
|
|
|
40848
41148
|
const removed = removeSource(ctx, name);
|
|
40849
41149
|
const documents = db.deleteDocumentsBySource(docsTag(name));
|
|
40850
41150
|
clearSyncState(db, name);
|
|
40851
|
-
if (removed) syncDocsGraphQuietly(ctx, db);
|
|
41151
|
+
if (removed || documents) syncDocsGraphQuietly(ctx, db);
|
|
40852
41152
|
return { removed, documents };
|
|
40853
41153
|
}
|
|
40854
41154
|
function formatAdd(o) {
|
|
@@ -40903,7 +41203,8 @@ var init_add = __esm({
|
|
|
40903
41203
|
var em_docs_exports = {};
|
|
40904
41204
|
__export(em_docs_exports, {
|
|
40905
41205
|
emDocs: () => emDocs,
|
|
40906
|
-
formatDiscovery: () => formatDiscovery
|
|
41206
|
+
formatDiscovery: () => formatDiscovery,
|
|
41207
|
+
orphanedDocSources: () => orphanedDocSources
|
|
40907
41208
|
});
|
|
40908
41209
|
function toInput(a) {
|
|
40909
41210
|
return {
|
|
@@ -40930,6 +41231,26 @@ function ago(ts) {
|
|
|
40930
41231
|
if (s < 172800) return `${Math.round(s / 3600)}h ago`;
|
|
40931
41232
|
return `${Math.round(s / 86400)}d ago`;
|
|
40932
41233
|
}
|
|
41234
|
+
function orphanedDocSources(db, registered, stats = db.documentSourceStats(DOCS_PREFIX)) {
|
|
41235
|
+
const known = new Set(registered);
|
|
41236
|
+
const out = [];
|
|
41237
|
+
for (const s of stats) {
|
|
41238
|
+
const name = nameFromTag(s.source);
|
|
41239
|
+
if (name === void 0 || known.has(name)) continue;
|
|
41240
|
+
out.push({ name, documents: s.documents, chunks: s.chunks, latest: s.latest });
|
|
41241
|
+
}
|
|
41242
|
+
return out;
|
|
41243
|
+
}
|
|
41244
|
+
function formatOrphans(orphans2) {
|
|
41245
|
+
const names = orphans2.map((o) => o.name);
|
|
41246
|
+
return [
|
|
41247
|
+
`# Orphaned in the index (${orphans2.length}; pages without a manifest entry)`,
|
|
41248
|
+
...orphans2.map(
|
|
41249
|
+
(o) => `- ${o.name} \xB7 ${o.documents} doc(s) \xB7 ${o.chunks} chunks \xB7 indexed ${ago(o.latest)}`
|
|
41250
|
+
),
|
|
41251
|
+
`em_docs {action:"remove", names:${JSON.stringify(names)}} drops them; {action:"add", pick:"recommended"} or {action:"add", name, url|path} re-registers.`
|
|
41252
|
+
];
|
|
41253
|
+
}
|
|
40933
41254
|
function formatDiscovery(d, max = 40) {
|
|
40934
41255
|
const lines = [];
|
|
40935
41256
|
lines.push(
|
|
@@ -41112,19 +41433,30 @@ var init_em_docs = __esm({
|
|
|
41112
41433
|
case "remove": {
|
|
41113
41434
|
const names = [...args.name ? [args.name] : [], ...args.names ?? []];
|
|
41114
41435
|
if (!names.length) return errorResult("remove needs `name` or `names`");
|
|
41436
|
+
let unknown2 = 0;
|
|
41115
41437
|
const lines = names.map((n) => {
|
|
41116
41438
|
const r = removeDocSource(ctx, db, n);
|
|
41117
|
-
|
|
41439
|
+
if (r.removed) return `removed ${n} (${r.documents} document(s) dropped)`;
|
|
41440
|
+
if (r.documents) return `removed ${n} (orphaned; ${r.documents} document(s) dropped)`;
|
|
41441
|
+
unknown2++;
|
|
41442
|
+
return `${n}: not registered and not in the index; em_docs {action:"list"} shows both`;
|
|
41118
41443
|
});
|
|
41119
|
-
|
|
41444
|
+
const out = lines.join("\n");
|
|
41445
|
+
return unknown2 === names.length ? errorResult(out) : done(out);
|
|
41120
41446
|
}
|
|
41121
41447
|
case "list": {
|
|
41122
41448
|
const m = readManifest(ctx);
|
|
41123
|
-
|
|
41124
|
-
|
|
41125
|
-
|
|
41126
|
-
)
|
|
41127
|
-
|
|
41449
|
+
const sourceStats = db.documentSourceStats(DOCS_PREFIX);
|
|
41450
|
+
const orphans2 = orphanedDocSources(
|
|
41451
|
+
db,
|
|
41452
|
+
m.sources.map((s) => s.name),
|
|
41453
|
+
sourceStats
|
|
41454
|
+
);
|
|
41455
|
+
if (!m.sources.length) {
|
|
41456
|
+
const none = `no documentation sources registered (${manifestPath(ctx)}). em_docs {action:"discover"} finds local docs and the libraries, services and APIs this project uses.`;
|
|
41457
|
+
return done(orphans2.length ? [none, "", ...formatOrphans(orphans2)].join("\n") : none);
|
|
41458
|
+
}
|
|
41459
|
+
const stats = new Map(sourceStats.map((s) => [s.source, s]));
|
|
41128
41460
|
const catalog = mergedCatalog(ctx.config.docs.catalog);
|
|
41129
41461
|
const categorised = m.sources.map((s) => ({
|
|
41130
41462
|
s,
|
|
@@ -41155,9 +41487,10 @@ var init_em_docs = __esm({
|
|
|
41155
41487
|
`- ${s.name} [${s.kind}]${s.provider ? ` \u2190 ${s.provider}` : ""}${s.tags?.length ? ` (${s.tags.join(", ")})` : ""} \xB7 ${st?.documents ?? 0} doc(s) \xB7 ${st?.chunks ?? 0} chunks \xB7 ${state} \xB7 ${where}`
|
|
41156
41488
|
);
|
|
41157
41489
|
}
|
|
41490
|
+
if (orphans2.length) lines.push("", ...formatOrphans(orphans2));
|
|
41158
41491
|
lines.push(
|
|
41159
41492
|
"",
|
|
41160
|
-
`${m.sources.length} source(s); em_docs {action:"lookup", query} searches them all, {action:"sync"} refreshes.`
|
|
41493
|
+
`${m.sources.length} source(s)${orphans2.length ? ` + ${orphans2.length} orphaned` : ""}; em_docs {action:"lookup", query} searches them all, {action:"sync"} refreshes.`
|
|
41161
41494
|
);
|
|
41162
41495
|
return done(lines.join("\n"));
|
|
41163
41496
|
}
|
|
@@ -41203,10 +41536,18 @@ ${r.urls.map((u) => ` ${u}`).join("\n")}
|
|
|
41203
41536
|
raw += r.hits.reduce((n, h) => n + h.chunk.body.length, 0);
|
|
41204
41537
|
responses.push(r);
|
|
41205
41538
|
}
|
|
41206
|
-
|
|
41207
|
-
|
|
41208
|
-
|
|
41539
|
+
let out = formatResults(responses, args.max_tokens ?? ctx.config.search.defaultMaxTokens);
|
|
41540
|
+
const hitSources = new Set(
|
|
41541
|
+
responses.flatMap((r) => r.hits.map((h) => h.chunk.document.source))
|
|
41209
41542
|
);
|
|
41543
|
+
const orphaned = orphanedDocSources(
|
|
41544
|
+
db,
|
|
41545
|
+
m.sources.map((s) => s.name)
|
|
41546
|
+
).filter((o) => hitSources.has(docsTag(o.name)));
|
|
41547
|
+
if (orphaned.length)
|
|
41548
|
+
out += `
|
|
41549
|
+
|
|
41550
|
+
note: ${orphaned.map((o) => o.name).join(", ")} ${orphaned.length === 1 ? "is" : "are"} not in the manifest (orphaned pages); em_docs {action:"list"} explains`;
|
|
41210
41551
|
recordStat(ctx, "em_docs", {
|
|
41211
41552
|
rawChars: raw,
|
|
41212
41553
|
returnedChars: out.length,
|
|
@@ -42467,6 +42808,9 @@ function memoriesForFile(db, rel, opts = {}) {
|
|
|
42467
42808
|
trace
|
|
42468
42809
|
};
|
|
42469
42810
|
}
|
|
42811
|
+
function dependentFiles(db, paths2) {
|
|
42812
|
+
return db.graphDependentFileCounts(paths2, DEPENDENCY_KINDS);
|
|
42813
|
+
}
|
|
42470
42814
|
function riskLine(path3, f) {
|
|
42471
42815
|
if (f.risk < RISKY && !f.bugOrigins) return void 0;
|
|
42472
42816
|
const parts = [`${f.fixes}/${f.commits} commits were fixes`];
|
|
@@ -42494,10 +42838,10 @@ function fileContext(db, rel, opts = {}) {
|
|
|
42494
42838
|
}
|
|
42495
42839
|
const fanKey = `fanin:${rel}`;
|
|
42496
42840
|
if (opts.edit && !seen.has(fanKey)) {
|
|
42497
|
-
const
|
|
42498
|
-
if (
|
|
42841
|
+
const dependents = dependentFiles(db, [rel]).get(rel) ?? 0;
|
|
42842
|
+
if (dependents >= FAN_IN) {
|
|
42499
42843
|
lines.push(
|
|
42500
|
-
`eminiar graph: ${rel} is imported by ${
|
|
42844
|
+
`eminiar graph: ${rel} is imported by ${dependents} files; em_graph_impact {node:"${fileId(rel)}"} lists them before you change an exported signature.`
|
|
42501
42845
|
);
|
|
42502
42846
|
keys.push(fanKey);
|
|
42503
42847
|
}
|
|
@@ -42554,6 +42898,7 @@ var init_recall = __esm({
|
|
|
42554
42898
|
"use strict";
|
|
42555
42899
|
init_esm_shims();
|
|
42556
42900
|
init_ids();
|
|
42901
|
+
init_metrics();
|
|
42557
42902
|
init_model();
|
|
42558
42903
|
init_pipeline();
|
|
42559
42904
|
init_query();
|
|
@@ -44231,14 +44576,14 @@ __export(ingest_exports, {
|
|
|
44231
44576
|
usageEnabled: () => usageEnabled
|
|
44232
44577
|
});
|
|
44233
44578
|
import { createHash as createHash4 } from "crypto";
|
|
44234
|
-
import { closeSync, existsSync as
|
|
44235
|
-
import { homedir as
|
|
44236
|
-
import { basename as basename2, dirname as dirname11, join as
|
|
44579
|
+
import { closeSync, existsSync as existsSync24, openSync, readdirSync as readdirSync9, readSync, statSync as statSync10 } from "fs";
|
|
44580
|
+
import { homedir as homedir4 } from "os";
|
|
44581
|
+
import { basename as basename2, dirname as dirname11, join as join28, resolve as resolve7, sep as sep3 } from "path";
|
|
44237
44582
|
function isValidSessionId(id) {
|
|
44238
44583
|
return SESSION_ID_RE.test(id);
|
|
44239
44584
|
}
|
|
44240
44585
|
function claudeDir2() {
|
|
44241
|
-
return process.env.EMINIAR_CLAUDE_DIR ||
|
|
44586
|
+
return process.env.EMINIAR_CLAUDE_DIR || join28(homedir4(), ".claude");
|
|
44242
44587
|
}
|
|
44243
44588
|
function insideDir(path3, dir) {
|
|
44244
44589
|
const d = resolve7(dir);
|
|
@@ -44257,7 +44602,7 @@ function transcriptSlug(root) {
|
|
|
44257
44602
|
return root.replace(/[^A-Za-z0-9]/g, "-");
|
|
44258
44603
|
}
|
|
44259
44604
|
function transcriptDirFor(root) {
|
|
44260
|
-
return
|
|
44605
|
+
return join28(claudeDir2(), "projects", transcriptSlug(root));
|
|
44261
44606
|
}
|
|
44262
44607
|
function usageEnabled(ctx) {
|
|
44263
44608
|
return ctx.config.usage.enabled !== false;
|
|
@@ -44427,7 +44772,7 @@ function add(a, b) {
|
|
|
44427
44772
|
}
|
|
44428
44773
|
function listJsonl(dir) {
|
|
44429
44774
|
try {
|
|
44430
|
-
return
|
|
44775
|
+
return readdirSync9(dir).filter((f) => f.endsWith(".jsonl")).map((f) => join28(dir, f));
|
|
44431
44776
|
} catch {
|
|
44432
44777
|
return [];
|
|
44433
44778
|
}
|
|
@@ -44447,7 +44792,7 @@ function firstEntrySessionId(path3) {
|
|
|
44447
44792
|
function sidechainFilesFor(db, dir, sessionId) {
|
|
44448
44793
|
if (!isValidSessionId(sessionId)) return [];
|
|
44449
44794
|
const inside = (p) => insideDir(p, dir) && p.endsWith(".jsonl");
|
|
44450
|
-
const out = listJsonl(
|
|
44795
|
+
const out = listJsonl(join28(dir, sessionId, "subagents")).filter(inside);
|
|
44451
44796
|
for (const path3 of listJsonl(dir)) {
|
|
44452
44797
|
if (!inside(path3) || !basename2(path3).startsWith("agent-")) continue;
|
|
44453
44798
|
const known = db.transcriptFileGet(path3)?.session_id;
|
|
@@ -44491,11 +44836,11 @@ function ingestSession(db, root, sessionId, transcriptPath, opts = {}) {
|
|
|
44491
44836
|
function ingestProject(db, root, opts = {}) {
|
|
44492
44837
|
const dir = transcriptDirFor(root);
|
|
44493
44838
|
const files = new Set(listJsonl(dir));
|
|
44494
|
-
if (
|
|
44839
|
+
if (existsSync24(dir)) {
|
|
44495
44840
|
try {
|
|
44496
|
-
for (const entry of
|
|
44841
|
+
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
44497
44842
|
if (entry.isDirectory())
|
|
44498
|
-
for (const sub of listJsonl(
|
|
44843
|
+
for (const sub of listJsonl(join28(dir, entry.name, "subagents"))) files.add(sub);
|
|
44499
44844
|
}
|
|
44500
44845
|
} catch {
|
|
44501
44846
|
}
|
|
@@ -44546,12 +44891,17 @@ function usageLine(ctx, sessionId) {
|
|
|
44546
44891
|
if (!usageEnabled(ctx)) return void 0;
|
|
44547
44892
|
try {
|
|
44548
44893
|
const db = getStorage(ctx);
|
|
44549
|
-
|
|
44894
|
+
let failed;
|
|
44895
|
+
try {
|
|
44896
|
+
ingestSession(db, ctx.root, sessionId, void 0, { overrides: ctx.config.usage.pricing });
|
|
44897
|
+
} catch (err) {
|
|
44898
|
+
failed = `usage: ingest failed: ${err.message}`;
|
|
44899
|
+
}
|
|
44550
44900
|
const b = usageBrief(db, ctx, { sessionId });
|
|
44551
|
-
|
|
44552
|
-
return
|
|
44553
|
-
} catch {
|
|
44554
|
-
return
|
|
44901
|
+
const line = b.todayUsd || b.sessionUsd ? `usage: today ${formatUsd(b.todayUsd)} \xB7 session ${formatUsd(b.sessionUsd)} \xB7 see em_usage` : void 0;
|
|
44902
|
+
return [line, failed].filter((s) => s).join("\n") || void 0;
|
|
44903
|
+
} catch (err) {
|
|
44904
|
+
return `usage: unavailable: ${err.message}`;
|
|
44555
44905
|
}
|
|
44556
44906
|
}
|
|
44557
44907
|
function mergeByTool(rows) {
|
|
@@ -45825,7 +46175,10 @@ var init_em_search = __esm({
|
|
|
45825
46175
|
}
|
|
45826
46176
|
}
|
|
45827
46177
|
const out = formatResults(responses, args.max_tokens ?? ctx.config.search.defaultMaxTokens);
|
|
45828
|
-
|
|
46178
|
+
let note = mode !== "lexical" && mode !== "regex" && !vectorSearch && ctx.config.embeddings.enabled ? "\n\n(embeddings: model still loading \u2014 lexical results only this time)" : "";
|
|
46179
|
+
const sources = Array.isArray(args.source) ? args.source : args.source ? [args.source] : [];
|
|
46180
|
+
if (mode === "semantic" && !ctx.config.docs.embed && sources.some((s) => s.startsWith("docs:")) && responses.every((r) => r.hits.length === 0))
|
|
46181
|
+
note += '\n\n(docs:* pages are indexed without vectors because docs.embed is off; use mode "hybrid" or "lexical", or set docs.embed: true in eminiar.config.json and em_docs {action:"sync", force:true})';
|
|
45829
46182
|
recordStat(ctx, "em_search", {
|
|
45830
46183
|
rawChars: responses.reduce(
|
|
45831
46184
|
(a, r) => a + r.hits.reduce((b, h) => b + h.chunk.body.length, 0),
|
|
@@ -45841,14 +46194,14 @@ var init_em_search = __esm({
|
|
|
45841
46194
|
});
|
|
45842
46195
|
|
|
45843
46196
|
// src/ui/api.ts
|
|
45844
|
-
import { existsSync as
|
|
45845
|
-
import { join as
|
|
46197
|
+
import { existsSync as existsSync25, readdirSync as readdirSync10 } from "fs";
|
|
46198
|
+
import { join as join29, relative as relative9 } from "path";
|
|
45846
46199
|
function listProjects() {
|
|
45847
46200
|
const dir = paths().projects;
|
|
45848
46201
|
const out = [];
|
|
45849
|
-
for (const id of
|
|
46202
|
+
for (const id of readdirSync10(dir, { withFileTypes: true })) {
|
|
45850
46203
|
if (!id.isDirectory()) continue;
|
|
45851
|
-
const db =
|
|
46204
|
+
const db = join29(dir, id.name, "eminiar.db");
|
|
45852
46205
|
try {
|
|
45853
46206
|
const a = new SqliteAdapter(db, { vectors: false });
|
|
45854
46207
|
out.push({ id: id.name, root: a.sessionLatest()?.project_root ?? null });
|
|
@@ -45874,8 +46227,8 @@ function statsPayload(ctx) {
|
|
|
45874
46227
|
const db = getStorage(ctx);
|
|
45875
46228
|
const sessionId = getCurrentSession(ctx);
|
|
45876
46229
|
const g = globalDb();
|
|
45877
|
-
const onboardingDir =
|
|
45878
|
-
const onboarding =
|
|
46230
|
+
const onboardingDir = join29(memoriesDir(ctx), "onboarding");
|
|
46231
|
+
const onboarding = existsSync25(onboardingDir) ? readdirSync10(onboardingDir).filter((f) => f.endsWith(".md")).map((f) => f.slice(0, -3)) : [];
|
|
45879
46232
|
return {
|
|
45880
46233
|
project: ctx.root,
|
|
45881
46234
|
projectId: ctx.id,
|
|
@@ -46477,8 +46830,8 @@ var init_namepath = __esm({
|
|
|
46477
46830
|
});
|
|
46478
46831
|
|
|
46479
46832
|
// src/code/symbols.ts
|
|
46480
|
-
import { existsSync as
|
|
46481
|
-
import { join as
|
|
46833
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
|
|
46834
|
+
import { join as join30 } from "path";
|
|
46482
46835
|
function isExported2(n) {
|
|
46483
46836
|
if (!n.meta) return false;
|
|
46484
46837
|
try {
|
|
@@ -46514,7 +46867,7 @@ var init_symbols2 = __esm({
|
|
|
46514
46867
|
});
|
|
46515
46868
|
|
|
46516
46869
|
// src/ui/graph-api.ts
|
|
46517
|
-
import { readFileSync as
|
|
46870
|
+
import { readFileSync as readFileSync23, realpathSync as realpathSync2, statSync as statSync11 } from "fs";
|
|
46518
46871
|
import { relative as relative10, resolve as resolve8 } from "path";
|
|
46519
46872
|
function metaOf2(row) {
|
|
46520
46873
|
if (!row?.meta) return {};
|
|
@@ -46600,7 +46953,7 @@ function filePayload(ctx, rel) {
|
|
|
46600
46953
|
}));
|
|
46601
46954
|
if (st.size > MAX_CODE_BYTES)
|
|
46602
46955
|
return { path: clean, tooLarge: true, size: st.size, status: row?.status ?? null, symbols };
|
|
46603
|
-
const content =
|
|
46956
|
+
const content = readFileSync23(real, "utf8");
|
|
46604
46957
|
return {
|
|
46605
46958
|
path: clean,
|
|
46606
46959
|
size: st.size,
|
|
@@ -47286,8 +47639,8 @@ var init_lineage = __esm({
|
|
|
47286
47639
|
});
|
|
47287
47640
|
|
|
47288
47641
|
// src/ui/history-graph-api.ts
|
|
47289
|
-
import { existsSync as
|
|
47290
|
-
import { join as
|
|
47642
|
+
import { existsSync as existsSync27 } from "fs";
|
|
47643
|
+
import { join as join31 } from "path";
|
|
47291
47644
|
function parseList(raw) {
|
|
47292
47645
|
if (!raw) return [];
|
|
47293
47646
|
try {
|
|
@@ -47526,7 +47879,7 @@ function buildHistoryGraph(ctx, db, m, opts = {}) {
|
|
|
47526
47879
|
path: p,
|
|
47527
47880
|
line: null,
|
|
47528
47881
|
root: id === focusId,
|
|
47529
|
-
missing:
|
|
47882
|
+
missing: existsSync27(join31(ctx.root, p)) ? void 0 : true,
|
|
47530
47883
|
risk: h?.risk,
|
|
47531
47884
|
fixes: h?.fixes
|
|
47532
47885
|
});
|
|
@@ -47885,9 +48238,9 @@ __export(server_exports, {
|
|
|
47885
48238
|
uiDir: () => uiDir
|
|
47886
48239
|
});
|
|
47887
48240
|
import { spawn as spawn2 } from "child_process";
|
|
47888
|
-
import { existsSync as
|
|
48241
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, statSync as statSync12 } from "fs";
|
|
47889
48242
|
import { createServer } from "http";
|
|
47890
|
-
import { extname as extname3, join as
|
|
48243
|
+
import { extname as extname3, join as join32, normalize as normalize6 } from "path";
|
|
47891
48244
|
import { URL as URL2 } from "url";
|
|
47892
48245
|
function json2(res, status, body) {
|
|
47893
48246
|
res.writeHead(status, {
|
|
@@ -47909,7 +48262,7 @@ function strList(v) {
|
|
|
47909
48262
|
return void 0;
|
|
47910
48263
|
}
|
|
47911
48264
|
function uiDir() {
|
|
47912
|
-
return process.env.EMINIAR_UI_DIR ||
|
|
48265
|
+
return process.env.EMINIAR_UI_DIR || join32(pluginRoot(), "dist", "ui");
|
|
47913
48266
|
}
|
|
47914
48267
|
function originAllowed(req, port) {
|
|
47915
48268
|
const host = req.headers.host ?? "";
|
|
@@ -47933,25 +48286,25 @@ function originAllowed(req, port) {
|
|
|
47933
48286
|
function serveStatic(res, p) {
|
|
47934
48287
|
const dir = uiDir();
|
|
47935
48288
|
const rel = p === "/" ? "index.html" : p.replace(/^\/+/, "");
|
|
47936
|
-
const file3 = normalize6(
|
|
48289
|
+
const file3 = normalize6(join32(dir, rel));
|
|
47937
48290
|
if (!file3.startsWith(normalize6(dir))) return false;
|
|
47938
|
-
if (!
|
|
48291
|
+
if (!existsSync28(file3) || !statSync12(file3).isFile()) return false;
|
|
47939
48292
|
const type = MIME[extname3(file3).toLowerCase()] ?? "application/octet-stream";
|
|
47940
48293
|
if (rel === "index.html") {
|
|
47941
48294
|
const stamp = (name) => {
|
|
47942
48295
|
try {
|
|
47943
|
-
return `/${name}?v=${Math.floor(statSync12(
|
|
48296
|
+
return `/${name}?v=${Math.floor(statSync12(join32(dir, name)).mtimeMs)}`;
|
|
47944
48297
|
} catch {
|
|
47945
48298
|
return `/${name}`;
|
|
47946
48299
|
}
|
|
47947
48300
|
};
|
|
47948
|
-
const html =
|
|
48301
|
+
const html = readFileSync24(file3, "utf8").replace('"/app.global.js"', `"${stamp("app.global.js")}"`).replace('"/styles.css"', `"${stamp("styles.css")}"`);
|
|
47949
48302
|
res.writeHead(200, { "content-type": type, "cache-control": "no-store" });
|
|
47950
48303
|
res.end(html);
|
|
47951
48304
|
return true;
|
|
47952
48305
|
}
|
|
47953
48306
|
res.writeHead(200, { "content-type": type, "cache-control": "no-cache" });
|
|
47954
|
-
res.end(
|
|
48307
|
+
res.end(readFileSync24(file3));
|
|
47955
48308
|
return true;
|
|
47956
48309
|
}
|
|
47957
48310
|
async function serve(opts) {
|
|
@@ -48390,7 +48743,7 @@ __export(statusline_exports, {
|
|
|
48390
48743
|
renderStatusline: () => renderStatusline,
|
|
48391
48744
|
usageSegments: () => usageSegments
|
|
48392
48745
|
});
|
|
48393
|
-
import { existsSync as
|
|
48746
|
+
import { existsSync as existsSync29, readFileSync as readFileSync25, writeFileSync as writeFileSync10 } from "fs";
|
|
48394
48747
|
function epochMs(v) {
|
|
48395
48748
|
if (typeof v === "number" && Number.isFinite(v)) return v < 1e12 ? v * 1e3 : v;
|
|
48396
48749
|
if (typeof v === "string") {
|
|
@@ -48452,8 +48805,8 @@ function renderStatusline(raw) {
|
|
|
48452
48805
|
const key = cacheKey(input2);
|
|
48453
48806
|
const cache3 = paths().statuslineCache;
|
|
48454
48807
|
try {
|
|
48455
|
-
if (
|
|
48456
|
-
const c = JSON.parse(
|
|
48808
|
+
if (existsSync29(cache3)) {
|
|
48809
|
+
const c = JSON.parse(readFileSync25(cache3, "utf8"));
|
|
48457
48810
|
if (Date.now() - c.at < CACHE_TTL_MS && c.key === key) return c.line;
|
|
48458
48811
|
}
|
|
48459
48812
|
} catch {
|
|
@@ -48484,7 +48837,7 @@ function renderStatusline(raw) {
|
|
|
48484
48837
|
line = `eminiar \xB7 unavailable (${err.message.slice(0, 40)})`;
|
|
48485
48838
|
}
|
|
48486
48839
|
try {
|
|
48487
|
-
|
|
48840
|
+
writeFileSync10(cache3, JSON.stringify({ at: Date.now(), line, key }));
|
|
48488
48841
|
} catch {
|
|
48489
48842
|
}
|
|
48490
48843
|
return line;
|
|
@@ -48518,9 +48871,11 @@ var USAGE = `eminiar v${version2()} \u2014 local-first context, memory & knowled
|
|
|
48518
48871
|
Usage: eminiar <command> [options]
|
|
48519
48872
|
|
|
48520
48873
|
Setup
|
|
48521
|
-
install [--no-model] [--method plugin|settings] [--team] [--yes] [--force]
|
|
48874
|
+
install [--no-model] [--method plugin|settings] [--cursor] [--team] [--yes] [--force]
|
|
48875
|
+
Install into Claude Code; --cursor also registers with Cursor
|
|
48876
|
+
(hooks, MCP server, skills under ~/.cursor)
|
|
48522
48877
|
upgrade Update to the latest version and re-register
|
|
48523
|
-
uninstall [--purge-data] Remove from Claude Code (data kept unless --purge-data)
|
|
48878
|
+
uninstall [--purge-data] Remove from Claude Code and Cursor (data kept unless --purge-data)
|
|
48524
48879
|
doctor [--json] [--fix] Check installation health; --fix re-pins node/root and clears
|
|
48525
48880
|
Claude Code's cached launch failure
|
|
48526
48881
|
replace-context-mode [--yes] Remove the context-mode plugin after parity sign-off
|
|
@@ -48548,7 +48903,7 @@ Use
|
|
|
48548
48903
|
ui [--port 7331] [--no-open] Web dashboard: stats, memories, graph, search, sessions, actions
|
|
48549
48904
|
(alias: serve)
|
|
48550
48905
|
statusline Claude Code statusLine command (reads JSON on stdin)
|
|
48551
|
-
hook [--event E]
|
|
48906
|
+
hook [--event E] [--client claude|cursor] Run the hook handler manually (reads JSON on stdin)
|
|
48552
48907
|
version | help
|
|
48553
48908
|
`;
|
|
48554
48909
|
function text2(r) {
|
|
@@ -48578,6 +48933,7 @@ var commands = {
|
|
|
48578
48933
|
node: { type: "string" },
|
|
48579
48934
|
yes: { type: "boolean" },
|
|
48580
48935
|
statusline: { type: "boolean" },
|
|
48936
|
+
cursor: { type: "boolean" },
|
|
48581
48937
|
force: { type: "boolean" }
|
|
48582
48938
|
},
|
|
48583
48939
|
strict: false
|
|
@@ -48585,6 +48941,7 @@ var commands = {
|
|
|
48585
48941
|
const { install: install2 } = await Promise.resolve().then(() => (init_install(), install_exports));
|
|
48586
48942
|
return install2({
|
|
48587
48943
|
force: !!values.force,
|
|
48944
|
+
cursor: !!values.cursor,
|
|
48588
48945
|
noModel: !!values["no-model"],
|
|
48589
48946
|
method: values.method === "settings" ? "settings" : values.method === "plugin" ? "plugin" : void 0,
|
|
48590
48947
|
team: !!values.team,
|
|
@@ -49037,7 +49394,8 @@ try {
|
|
|
49037
49394
|
} catch (err) {
|
|
49038
49395
|
console.error(`eminiar ${cmd} failed: ${err.message}`);
|
|
49039
49396
|
if (process.env.EMINIAR_DEBUG) console.error(err.stack);
|
|
49040
|
-
if (cmd
|
|
49397
|
+
if (cmd === "usage") console.error("run `eminiar doctor` to check the installation");
|
|
49398
|
+
else if (cmd !== "doctor") console.error(formatDoctor(runDoctor()));
|
|
49041
49399
|
process.exit(1);
|
|
49042
49400
|
}
|
|
49043
49401
|
/*! Bundled license information:
|