@strvmarv/total-recall 0.6.8-beta.4 → 0.6.8-beta.7
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/README.md +2 -0
- package/dist/eval/ci-smoke.js +3 -2
- package/dist/index.js +234 -143
- package/package.json +3 -2
- package/scripts/mcp-smoke-test.mjs +388 -0
- package/scripts/postinstall.js +25 -0
package/dist/index.js
CHANGED
|
@@ -6803,7 +6803,8 @@ import { randomUUID as randomUUID8 } from "crypto";
|
|
|
6803
6803
|
|
|
6804
6804
|
// src/config.ts
|
|
6805
6805
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
6806
|
-
import { join } from "path";
|
|
6806
|
+
import { join, isAbsolute } from "path";
|
|
6807
|
+
import { homedir } from "os";
|
|
6807
6808
|
import { createHash, randomUUID } from "crypto";
|
|
6808
6809
|
|
|
6809
6810
|
// node_modules/smol-toml/dist/error.js
|
|
@@ -7640,7 +7641,40 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
|
|
|
7640
7641
|
// src/config.ts
|
|
7641
7642
|
var DEFAULTS_PATH = new URL("./defaults.toml", import.meta.url);
|
|
7642
7643
|
function getDataDir() {
|
|
7643
|
-
return process.env.TOTAL_RECALL_HOME ?? join(
|
|
7644
|
+
return process.env.TOTAL_RECALL_HOME ?? join(homedir(), ".total-recall");
|
|
7645
|
+
}
|
|
7646
|
+
var SqliteDbPathError = class extends Error {
|
|
7647
|
+
constructor(message) {
|
|
7648
|
+
super(message);
|
|
7649
|
+
this.name = "SqliteDbPathError";
|
|
7650
|
+
}
|
|
7651
|
+
};
|
|
7652
|
+
function getDbPath() {
|
|
7653
|
+
const raw = process.env.TOTAL_RECALL_DB_PATH;
|
|
7654
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
7655
|
+
return join(getDataDir(), "total-recall.db");
|
|
7656
|
+
}
|
|
7657
|
+
const trimmed = raw.trim();
|
|
7658
|
+
if (trimmed.endsWith("/") || trimmed.endsWith("\\")) {
|
|
7659
|
+
throw new SqliteDbPathError(
|
|
7660
|
+
`TOTAL_RECALL_DB_PATH must be a file path, not a directory. Got: "${trimmed}"`
|
|
7661
|
+
);
|
|
7662
|
+
}
|
|
7663
|
+
if (trimmed === "~") {
|
|
7664
|
+
throw new SqliteDbPathError(
|
|
7665
|
+
`TOTAL_RECALL_DB_PATH must be a file path, not a directory. Got: "~"`
|
|
7666
|
+
);
|
|
7667
|
+
}
|
|
7668
|
+
let expanded = trimmed;
|
|
7669
|
+
if (trimmed.startsWith("~/")) {
|
|
7670
|
+
expanded = join(homedir(), trimmed.slice(2));
|
|
7671
|
+
}
|
|
7672
|
+
if (!isAbsolute(expanded)) {
|
|
7673
|
+
throw new SqliteDbPathError(
|
|
7674
|
+
`TOTAL_RECALL_DB_PATH must be absolute or start with ~/. Got: "${trimmed}"`
|
|
7675
|
+
);
|
|
7676
|
+
}
|
|
7677
|
+
return expanded;
|
|
7644
7678
|
}
|
|
7645
7679
|
function loadConfig() {
|
|
7646
7680
|
const defaultsText = readFileSync(DEFAULTS_PATH, "utf-8");
|
|
@@ -7734,9 +7768,9 @@ function deepMerge(target, source) {
|
|
|
7734
7768
|
}
|
|
7735
7769
|
|
|
7736
7770
|
// src/db/connection.ts
|
|
7737
|
-
import { Database } from "bun:sqlite";
|
|
7738
|
-
import { mkdirSync as mkdirSync2
|
|
7739
|
-
import {
|
|
7771
|
+
import { Database as Database2 } from "bun:sqlite";
|
|
7772
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
7773
|
+
import { dirname } from "path";
|
|
7740
7774
|
|
|
7741
7775
|
// node_modules/sqlite-vec/index.mjs
|
|
7742
7776
|
import { fileURLToPath } from "url";
|
|
@@ -7988,16 +8022,55 @@ function initSchema(db) {
|
|
|
7988
8022
|
migrate();
|
|
7989
8023
|
}
|
|
7990
8024
|
|
|
8025
|
+
// src/db/sqlite-bootstrap.ts
|
|
8026
|
+
import { Database } from "bun:sqlite";
|
|
8027
|
+
import { existsSync as existsSync2 } from "fs";
|
|
8028
|
+
var DARWIN_SQLITE_CANDIDATES = [
|
|
8029
|
+
"/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib",
|
|
8030
|
+
// Apple Silicon brew
|
|
8031
|
+
"/usr/local/opt/sqlite/lib/libsqlite3.dylib"
|
|
8032
|
+
// Intel brew
|
|
8033
|
+
];
|
|
8034
|
+
var SqliteExtensionError = class extends Error {
|
|
8035
|
+
constructor(message) {
|
|
8036
|
+
super(message);
|
|
8037
|
+
this.name = "SqliteExtensionError";
|
|
8038
|
+
}
|
|
8039
|
+
};
|
|
8040
|
+
var _bootstrapped = false;
|
|
8041
|
+
function bootstrapSqlite() {
|
|
8042
|
+
if (_bootstrapped) return;
|
|
8043
|
+
_bootstrapped = true;
|
|
8044
|
+
if (process.platform !== "darwin") return;
|
|
8045
|
+
for (const candidate of DARWIN_SQLITE_CANDIDATES) {
|
|
8046
|
+
if (existsSync2(candidate)) {
|
|
8047
|
+
Database.setCustomSQLite(candidate);
|
|
8048
|
+
return;
|
|
8049
|
+
}
|
|
8050
|
+
}
|
|
8051
|
+
throw new SqliteExtensionError(
|
|
8052
|
+
[
|
|
8053
|
+
"total-recall: no extension-capable libsqlite3 found on this Mac.",
|
|
8054
|
+
"",
|
|
8055
|
+
"macOS ships /usr/lib/libsqlite3.dylib without SQLITE_ENABLE_LOAD_EXTENSION,",
|
|
8056
|
+
"so sqlite-vec cannot be loaded. Install Homebrew sqlite to fix:",
|
|
8057
|
+
"",
|
|
8058
|
+
" brew install sqlite",
|
|
8059
|
+
"",
|
|
8060
|
+
"total-recall will automatically pick it up from:",
|
|
8061
|
+
...DARWIN_SQLITE_CANDIDATES.map((p) => ` - ${p}`)
|
|
8062
|
+
].join("\n")
|
|
8063
|
+
);
|
|
8064
|
+
}
|
|
8065
|
+
|
|
7991
8066
|
// src/db/connection.ts
|
|
7992
8067
|
var _db = null;
|
|
7993
8068
|
function getDb() {
|
|
7994
8069
|
if (_db) return _db;
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7999
|
-
const dbPath = join2(dataDir, "total-recall.db");
|
|
8000
|
-
_db = new Database(dbPath);
|
|
8070
|
+
bootstrapSqlite();
|
|
8071
|
+
const dbPath = getDbPath();
|
|
8072
|
+
mkdirSync2(dirname(dbPath), { recursive: true });
|
|
8073
|
+
_db = new Database2(dbPath);
|
|
8001
8074
|
load(_db);
|
|
8002
8075
|
initSchema(_db);
|
|
8003
8076
|
return _db;
|
|
@@ -8011,30 +8084,30 @@ function closeDb() {
|
|
|
8011
8084
|
|
|
8012
8085
|
// src/embedding/embedder.ts
|
|
8013
8086
|
import { readFile as readFile2 } from "fs/promises";
|
|
8014
|
-
import { join as
|
|
8087
|
+
import { join as join5 } from "path";
|
|
8015
8088
|
import * as ort from "onnxruntime-node";
|
|
8016
8089
|
|
|
8017
8090
|
// src/embedding/bootstrap.ts
|
|
8018
8091
|
import { mkdirSync as mkdirSync4 } from "fs";
|
|
8019
|
-
import { join as
|
|
8092
|
+
import { join as join4 } from "path";
|
|
8020
8093
|
|
|
8021
8094
|
// src/embedding/registry.ts
|
|
8022
8095
|
import { readFileSync as readFileSync2 } from "fs";
|
|
8023
8096
|
|
|
8024
8097
|
// src/pkg-root.ts
|
|
8025
8098
|
import { existsSync as existsSync3 } from "fs";
|
|
8026
|
-
import { dirname, join as
|
|
8099
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
8027
8100
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8028
8101
|
var cached = null;
|
|
8029
8102
|
function getPackageRoot() {
|
|
8030
8103
|
if (cached) return cached;
|
|
8031
|
-
let dir =
|
|
8104
|
+
let dir = dirname2(fileURLToPath2(import.meta.url));
|
|
8032
8105
|
for (let i = 0; i < 10; i++) {
|
|
8033
|
-
if (existsSync3(
|
|
8106
|
+
if (existsSync3(join2(dir, "package.json"))) {
|
|
8034
8107
|
cached = dir;
|
|
8035
8108
|
return dir;
|
|
8036
8109
|
}
|
|
8037
|
-
const parent =
|
|
8110
|
+
const parent = dirname2(dir);
|
|
8038
8111
|
if (parent === dir) break;
|
|
8039
8112
|
dir = parent;
|
|
8040
8113
|
}
|
|
@@ -8043,7 +8116,7 @@ function getPackageRoot() {
|
|
|
8043
8116
|
);
|
|
8044
8117
|
}
|
|
8045
8118
|
function pkgPath(...segments) {
|
|
8046
|
-
return
|
|
8119
|
+
return join2(getPackageRoot(), ...segments);
|
|
8047
8120
|
}
|
|
8048
8121
|
|
|
8049
8122
|
// src/embedding/registry.ts
|
|
@@ -8096,14 +8169,14 @@ import { Readable } from "stream";
|
|
|
8096
8169
|
import { pipeline } from "stream/promises";
|
|
8097
8170
|
import { createWriteStream } from "fs";
|
|
8098
8171
|
import { createHash as createHash2 } from "crypto";
|
|
8099
|
-
import { join as
|
|
8172
|
+
import { join as join3, dirname as dirname3 } from "path";
|
|
8100
8173
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8101
8174
|
function getBundledModelPath(modelName) {
|
|
8102
|
-
const distDir =
|
|
8103
|
-
return
|
|
8175
|
+
const distDir = dirname3(fileURLToPath3(import.meta.url));
|
|
8176
|
+
return join3(distDir, "..", "models", modelName);
|
|
8104
8177
|
}
|
|
8105
8178
|
function getUserModelPath(modelName) {
|
|
8106
|
-
return
|
|
8179
|
+
return join3(getDataDir(), "models", modelName);
|
|
8107
8180
|
}
|
|
8108
8181
|
function getModelPath(modelName) {
|
|
8109
8182
|
const bundled = getBundledModelPath(modelName);
|
|
@@ -8206,10 +8279,10 @@ async function downloadModel(modelName, options = {}) {
|
|
|
8206
8279
|
const fileCount = fileEntries.length;
|
|
8207
8280
|
for (let i = 0; i < fileEntries.length; i++) {
|
|
8208
8281
|
const { file: file2, url: url2 } = fileEntries[i];
|
|
8209
|
-
const finalPath =
|
|
8282
|
+
const finalPath = join3(target, file2);
|
|
8210
8283
|
await downloadFile(url2, finalPath, file2, i, fileCount, options, maxRetries);
|
|
8211
8284
|
}
|
|
8212
|
-
const onnxPath =
|
|
8285
|
+
const onnxPath = join3(target, "model.onnx");
|
|
8213
8286
|
const actualHash = await sha256File(onnxPath);
|
|
8214
8287
|
if (actualHash !== spec.sha256) {
|
|
8215
8288
|
try {
|
|
@@ -8220,7 +8293,7 @@ async function downloadModel(modelName, options = {}) {
|
|
|
8220
8293
|
`sha256 mismatch for model.onnx: expected ${spec.sha256}, actual ${actualHash}`
|
|
8221
8294
|
);
|
|
8222
8295
|
}
|
|
8223
|
-
const sidecarPath =
|
|
8296
|
+
const sidecarPath = join3(target, ".verified");
|
|
8224
8297
|
await writeFileAtomic(sidecarPath, spec.sha256);
|
|
8225
8298
|
return target;
|
|
8226
8299
|
}
|
|
@@ -8255,11 +8328,11 @@ async function writeFileAtomic(dest, data) {
|
|
|
8255
8328
|
function isModelStructurallyValid(modelPath, spec) {
|
|
8256
8329
|
if (!existsSync4(modelPath)) return false;
|
|
8257
8330
|
for (const file2 of Object.keys(spec.files)) {
|
|
8258
|
-
const p =
|
|
8331
|
+
const p = join3(modelPath, file2);
|
|
8259
8332
|
if (!existsSync4(p)) return false;
|
|
8260
8333
|
}
|
|
8261
8334
|
try {
|
|
8262
|
-
const onnx =
|
|
8335
|
+
const onnx = join3(modelPath, "model.onnx");
|
|
8263
8336
|
const size = statSync(onnx).size;
|
|
8264
8337
|
return size === spec.sizeBytes;
|
|
8265
8338
|
} catch {
|
|
@@ -8267,7 +8340,7 @@ function isModelStructurallyValid(modelPath, spec) {
|
|
|
8267
8340
|
}
|
|
8268
8341
|
}
|
|
8269
8342
|
async function isModelChecksumValid(modelPath, spec) {
|
|
8270
|
-
const sidecarPath =
|
|
8343
|
+
const sidecarPath = join3(modelPath, ".verified");
|
|
8271
8344
|
if (existsSync4(sidecarPath)) {
|
|
8272
8345
|
try {
|
|
8273
8346
|
const cached4 = (await readFile(sidecarPath, "utf8")).trim();
|
|
@@ -8275,7 +8348,7 @@ async function isModelChecksumValid(modelPath, spec) {
|
|
|
8275
8348
|
} catch {
|
|
8276
8349
|
}
|
|
8277
8350
|
}
|
|
8278
|
-
const onnxPath =
|
|
8351
|
+
const onnxPath = join3(modelPath, "model.onnx");
|
|
8279
8352
|
if (!existsSync4(onnxPath)) return false;
|
|
8280
8353
|
let computed;
|
|
8281
8354
|
try {
|
|
@@ -8316,7 +8389,7 @@ import * as lockfile from "proper-lockfile";
|
|
|
8316
8389
|
var defaultAcquireLock = async (targetDir) => {
|
|
8317
8390
|
mkdirSync4(targetDir, { recursive: true });
|
|
8318
8391
|
const release = await lockfile.lock(targetDir, {
|
|
8319
|
-
lockfilePath:
|
|
8392
|
+
lockfilePath: join4(targetDir, ".bootstrap.lock"),
|
|
8320
8393
|
retries: { retries: 60, minTimeout: 1e3, maxTimeout: 1e3 }
|
|
8321
8394
|
});
|
|
8322
8395
|
return { release: async () => {
|
|
@@ -8579,9 +8652,9 @@ var Embedder = class {
|
|
|
8579
8652
|
}
|
|
8580
8653
|
}
|
|
8581
8654
|
const modelPath = await this.bootstrap.ensureReady();
|
|
8582
|
-
const onnxPath =
|
|
8655
|
+
const onnxPath = join5(modelPath, "model.onnx");
|
|
8583
8656
|
this.session = await ort.InferenceSession.create(onnxPath);
|
|
8584
|
-
const tokenizerPath =
|
|
8657
|
+
const tokenizerPath = join5(modelPath, "tokenizer.json");
|
|
8585
8658
|
const tokenizerText = await readFile2(tokenizerPath, "utf-8");
|
|
8586
8659
|
const tokenizerJson = JSON.parse(tokenizerText);
|
|
8587
8660
|
this.tokenizer = new WordPieceTokenizer(tokenizerJson.model.vocab);
|
|
@@ -23515,7 +23588,6 @@ async function handleMemoryTool(name, args, ctx) {
|
|
|
23515
23588
|
|
|
23516
23589
|
// src/tools/system-tools.ts
|
|
23517
23590
|
import { statSync as statSync2 } from "fs";
|
|
23518
|
-
import { join as join7 } from "path";
|
|
23519
23591
|
|
|
23520
23592
|
// src/ingestion/hierarchical-index.ts
|
|
23521
23593
|
function rowToEntry2(row) {
|
|
@@ -23644,8 +23716,7 @@ function handleSystemTool(name, args, ctx) {
|
|
|
23644
23716
|
const key = `${tier}_${type === "memory" ? "memories" : "knowledge"}`;
|
|
23645
23717
|
tierSizes[key] = countEntries(ctx.db, tier, type);
|
|
23646
23718
|
}
|
|
23647
|
-
const
|
|
23648
|
-
const dbPath = join7(dataDir, "total-recall.db");
|
|
23719
|
+
const dbPath = getDbPath();
|
|
23649
23720
|
let dbSizeBytes = null;
|
|
23650
23721
|
try {
|
|
23651
23722
|
dbSizeBytes = statSync2(dbPath).size;
|
|
@@ -23742,7 +23813,7 @@ import { statSync as statSync4 } from "fs";
|
|
|
23742
23813
|
|
|
23743
23814
|
// src/ingestion/ingest.ts
|
|
23744
23815
|
import { readFileSync as readFileSync3, readdirSync, statSync as statSync3 } from "fs";
|
|
23745
|
-
import { join as
|
|
23816
|
+
import { join as join6, dirname as dirname4, basename, extname } from "path";
|
|
23746
23817
|
|
|
23747
23818
|
// src/ingestion/markdown-parser.ts
|
|
23748
23819
|
function estimateTokens(text) {
|
|
@@ -24215,7 +24286,7 @@ async function ingestFile(db, embed, filePath, collectionId) {
|
|
|
24215
24286
|
const chunks = chunkFile(content, filePath, { maxTokens: 512, overlapTokens: 50 });
|
|
24216
24287
|
let resolvedCollectionId = collectionId;
|
|
24217
24288
|
if (!resolvedCollectionId) {
|
|
24218
|
-
const dirPath =
|
|
24289
|
+
const dirPath = dirname4(filePath);
|
|
24219
24290
|
const dirName = basename(dirPath);
|
|
24220
24291
|
resolvedCollectionId = await createCollection(db, embed, {
|
|
24221
24292
|
name: dirName,
|
|
@@ -24262,7 +24333,7 @@ function walkDirectory(dirPath) {
|
|
|
24262
24333
|
}
|
|
24263
24334
|
for (const entry of entries) {
|
|
24264
24335
|
if (entry.startsWith(".") || entry === "node_modules") continue;
|
|
24265
|
-
const fullPath =
|
|
24336
|
+
const fullPath = join6(dirPath, entry);
|
|
24266
24337
|
let stat;
|
|
24267
24338
|
try {
|
|
24268
24339
|
stat = statSync3(fullPath);
|
|
@@ -24581,7 +24652,7 @@ function registerKbTools() {
|
|
|
24581
24652
|
}
|
|
24582
24653
|
|
|
24583
24654
|
// src/tools/eval-tools.ts
|
|
24584
|
-
import { resolve as resolve3, dirname as
|
|
24655
|
+
import { resolve as resolve3, dirname as dirname6, basename as basename3 } from "path";
|
|
24585
24656
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
24586
24657
|
|
|
24587
24658
|
// src/eval/benchmark-runner.ts
|
|
@@ -24662,9 +24733,9 @@ async function runBenchmark(db, embed, opts) {
|
|
|
24662
24733
|
// src/eval/benchmark-candidates.ts
|
|
24663
24734
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
24664
24735
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
24665
|
-
import { resolve as resolve2, dirname as
|
|
24736
|
+
import { resolve as resolve2, dirname as dirname5, basename as basename2 } from "path";
|
|
24666
24737
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
24667
|
-
var __dirname =
|
|
24738
|
+
var __dirname = dirname5(fileURLToPath4(import.meta.url));
|
|
24668
24739
|
var PACKAGE_ROOT = basename2(__dirname) === "dist" ? resolve2(__dirname, "..") : resolve2(__dirname, "..", "..");
|
|
24669
24740
|
function writeCandidates(db, misses, contexts) {
|
|
24670
24741
|
const contextMap = new Map(contexts.map((c) => [c.query, c]));
|
|
@@ -24911,7 +24982,7 @@ function computeCompactionHealth(rows) {
|
|
|
24911
24982
|
}
|
|
24912
24983
|
|
|
24913
24984
|
// src/tools/eval-tools.ts
|
|
24914
|
-
var __dirname2 =
|
|
24985
|
+
var __dirname2 = dirname6(fileURLToPath5(import.meta.url));
|
|
24915
24986
|
var PACKAGE_ROOT2 = basename3(__dirname2) === "dist" ? resolve3(__dirname2, "..") : resolve3(__dirname2, "..", "..");
|
|
24916
24987
|
var EVAL_TOOLS = [
|
|
24917
24988
|
{
|
|
@@ -25099,8 +25170,8 @@ function registerEvalTools() {
|
|
|
25099
25170
|
|
|
25100
25171
|
// src/importers/claude-code.ts
|
|
25101
25172
|
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
|
|
25102
|
-
import { join as
|
|
25103
|
-
import { homedir } from "os";
|
|
25173
|
+
import { join as join7 } from "path";
|
|
25174
|
+
import { homedir as homedir2 } from "os";
|
|
25104
25175
|
|
|
25105
25176
|
// src/importers/import-utils.ts
|
|
25106
25177
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -25142,29 +25213,29 @@ var ClaudeCodeImporter = class {
|
|
|
25142
25213
|
name = "claude-code";
|
|
25143
25214
|
basePath;
|
|
25144
25215
|
constructor(basePath) {
|
|
25145
|
-
this.basePath = basePath ??
|
|
25216
|
+
this.basePath = basePath ?? join7(homedir2(), ".claude");
|
|
25146
25217
|
}
|
|
25147
25218
|
detect() {
|
|
25148
|
-
return existsSync5(this.basePath) && existsSync5(
|
|
25219
|
+
return existsSync5(this.basePath) && existsSync5(join7(this.basePath, "projects"));
|
|
25149
25220
|
}
|
|
25150
25221
|
scan() {
|
|
25151
25222
|
let memoryFiles = 0;
|
|
25152
25223
|
let knowledgeFiles = 0;
|
|
25153
25224
|
let sessionFiles = 0;
|
|
25154
|
-
const projectsDir =
|
|
25225
|
+
const projectsDir = join7(this.basePath, "projects");
|
|
25155
25226
|
if (!existsSync5(projectsDir)) {
|
|
25156
25227
|
return { memoryFiles, knowledgeFiles, sessionFiles };
|
|
25157
25228
|
}
|
|
25158
25229
|
for (const projectEntry of readdirSync2(projectsDir, { withFileTypes: true })) {
|
|
25159
25230
|
if (!projectEntry.isDirectory()) continue;
|
|
25160
|
-
const projectDir =
|
|
25161
|
-
const memoryDir =
|
|
25231
|
+
const projectDir = join7(projectsDir, projectEntry.name);
|
|
25232
|
+
const memoryDir = join7(projectDir, "memory");
|
|
25162
25233
|
if (existsSync5(memoryDir)) {
|
|
25163
25234
|
for (const f of readdirSync2(memoryDir)) {
|
|
25164
25235
|
if (f.endsWith(".md") && f !== "MEMORY.md") memoryFiles++;
|
|
25165
25236
|
}
|
|
25166
25237
|
}
|
|
25167
|
-
if (existsSync5(
|
|
25238
|
+
if (existsSync5(join7(projectDir, "CLAUDE.md"))) knowledgeFiles++;
|
|
25168
25239
|
for (const f of readdirSync2(projectDir)) {
|
|
25169
25240
|
if (f.endsWith(".jsonl")) sessionFiles++;
|
|
25170
25241
|
}
|
|
@@ -25173,16 +25244,16 @@ var ClaudeCodeImporter = class {
|
|
|
25173
25244
|
}
|
|
25174
25245
|
async importMemories(db, embed, project) {
|
|
25175
25246
|
const result = { imported: 0, skipped: 0, errors: [] };
|
|
25176
|
-
const projectsDir =
|
|
25247
|
+
const projectsDir = join7(this.basePath, "projects");
|
|
25177
25248
|
if (!existsSync5(projectsDir)) return result;
|
|
25178
25249
|
for (const projectEntry of readdirSync2(projectsDir, { withFileTypes: true })) {
|
|
25179
25250
|
if (!projectEntry.isDirectory()) continue;
|
|
25180
|
-
const projectDir =
|
|
25181
|
-
const memoryDir =
|
|
25251
|
+
const projectDir = join7(projectsDir, projectEntry.name);
|
|
25252
|
+
const memoryDir = join7(projectDir, "memory");
|
|
25182
25253
|
if (!existsSync5(memoryDir)) continue;
|
|
25183
25254
|
for (const filename of readdirSync2(memoryDir)) {
|
|
25184
25255
|
if (!filename.endsWith(".md") || filename === "MEMORY.md") continue;
|
|
25185
|
-
const filePath =
|
|
25256
|
+
const filePath = join7(memoryDir, filename);
|
|
25186
25257
|
try {
|
|
25187
25258
|
const raw = readFileSync6(filePath, "utf8");
|
|
25188
25259
|
const hash2 = contentHash(raw);
|
|
@@ -25217,7 +25288,7 @@ var ClaudeCodeImporter = class {
|
|
|
25217
25288
|
}
|
|
25218
25289
|
async importKnowledge(db, embed) {
|
|
25219
25290
|
const result = { imported: 0, skipped: 0, errors: [] };
|
|
25220
|
-
const claudeMdPath =
|
|
25291
|
+
const claudeMdPath = join7(this.basePath, "CLAUDE.md");
|
|
25221
25292
|
if (!existsSync5(claudeMdPath)) return result;
|
|
25222
25293
|
try {
|
|
25223
25294
|
const raw = readFileSync6(claudeMdPath, "utf8");
|
|
@@ -25247,28 +25318,28 @@ var ClaudeCodeImporter = class {
|
|
|
25247
25318
|
|
|
25248
25319
|
// src/importers/copilot-cli.ts
|
|
25249
25320
|
import { existsSync as existsSync6, readdirSync as readdirSync3, readFileSync as readFileSync7 } from "fs";
|
|
25250
|
-
import { join as
|
|
25251
|
-
import { homedir as
|
|
25321
|
+
import { join as join8 } from "path";
|
|
25322
|
+
import { homedir as homedir3 } from "os";
|
|
25252
25323
|
var CopilotCliImporter = class {
|
|
25253
25324
|
name = "copilot-cli";
|
|
25254
25325
|
basePath;
|
|
25255
25326
|
constructor(basePath) {
|
|
25256
|
-
this.basePath = basePath ??
|
|
25327
|
+
this.basePath = basePath ?? join8(homedir3(), ".copilot");
|
|
25257
25328
|
}
|
|
25258
25329
|
detect() {
|
|
25259
|
-
return existsSync6(this.basePath) && existsSync6(
|
|
25330
|
+
return existsSync6(this.basePath) && existsSync6(join8(this.basePath, "session-state"));
|
|
25260
25331
|
}
|
|
25261
25332
|
scan() {
|
|
25262
25333
|
let knowledgeFiles = 0;
|
|
25263
25334
|
let sessionFiles = 0;
|
|
25264
|
-
const sessionStateDir =
|
|
25335
|
+
const sessionStateDir = join8(this.basePath, "session-state");
|
|
25265
25336
|
if (!existsSync6(sessionStateDir)) {
|
|
25266
25337
|
return { memoryFiles: 0, knowledgeFiles, sessionFiles };
|
|
25267
25338
|
}
|
|
25268
25339
|
for (const entry of readdirSync3(sessionStateDir, { withFileTypes: true })) {
|
|
25269
25340
|
if (!entry.isDirectory()) continue;
|
|
25270
|
-
const sessionDir =
|
|
25271
|
-
if (existsSync6(
|
|
25341
|
+
const sessionDir = join8(sessionStateDir, entry.name);
|
|
25342
|
+
if (existsSync6(join8(sessionDir, "plan.md"))) knowledgeFiles++;
|
|
25272
25343
|
for (const f of readdirSync3(sessionDir)) {
|
|
25273
25344
|
if (f.endsWith(".jsonl")) sessionFiles++;
|
|
25274
25345
|
}
|
|
@@ -25280,11 +25351,11 @@ var CopilotCliImporter = class {
|
|
|
25280
25351
|
}
|
|
25281
25352
|
async importKnowledge(db, embed) {
|
|
25282
25353
|
const result = { imported: 0, skipped: 0, errors: [] };
|
|
25283
|
-
const sessionStateDir =
|
|
25354
|
+
const sessionStateDir = join8(this.basePath, "session-state");
|
|
25284
25355
|
if (!existsSync6(sessionStateDir)) return result;
|
|
25285
25356
|
for (const entry of readdirSync3(sessionStateDir, { withFileTypes: true })) {
|
|
25286
25357
|
if (!entry.isDirectory()) continue;
|
|
25287
|
-
const planPath =
|
|
25358
|
+
const planPath = join8(sessionStateDir, entry.name, "plan.md");
|
|
25288
25359
|
if (!existsSync6(planPath)) continue;
|
|
25289
25360
|
try {
|
|
25290
25361
|
const raw = readFileSync7(planPath, "utf8");
|
|
@@ -25311,36 +25382,44 @@ var CopilotCliImporter = class {
|
|
|
25311
25382
|
|
|
25312
25383
|
// src/importers/cursor.ts
|
|
25313
25384
|
import { existsSync as existsSync7, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "fs";
|
|
25314
|
-
import { join as
|
|
25315
|
-
import { homedir as
|
|
25316
|
-
import {
|
|
25385
|
+
import { join as join9 } from "path";
|
|
25386
|
+
import { homedir as homedir4 } from "os";
|
|
25387
|
+
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
25388
|
+
import { Database as Database3 } from "bun:sqlite";
|
|
25389
|
+
function safeFileURLToPath(url2) {
|
|
25390
|
+
try {
|
|
25391
|
+
return fileURLToPath6(url2);
|
|
25392
|
+
} catch {
|
|
25393
|
+
return null;
|
|
25394
|
+
}
|
|
25395
|
+
}
|
|
25317
25396
|
var CursorImporter = class {
|
|
25318
25397
|
name = "cursor";
|
|
25319
25398
|
configPath;
|
|
25320
25399
|
extensionPath;
|
|
25321
25400
|
constructor(configPath, extensionPath) {
|
|
25322
|
-
this.configPath = configPath ??
|
|
25323
|
-
this.extensionPath = extensionPath ??
|
|
25401
|
+
this.configPath = configPath ?? join9(homedir4(), ".config", "Cursor");
|
|
25402
|
+
this.extensionPath = extensionPath ?? join9(homedir4(), ".cursor");
|
|
25324
25403
|
}
|
|
25325
25404
|
detect() {
|
|
25326
25405
|
return existsSync7(this.configPath) || existsSync7(this.extensionPath);
|
|
25327
25406
|
}
|
|
25328
25407
|
scan() {
|
|
25329
25408
|
let knowledgeFiles = 0;
|
|
25330
|
-
const globalDb =
|
|
25409
|
+
const globalDb = join9(this.configPath, "User", "globalStorage", "state.vscdb");
|
|
25331
25410
|
if (existsSync7(globalDb)) knowledgeFiles++;
|
|
25332
|
-
const workspaceDir =
|
|
25411
|
+
const workspaceDir = join9(this.configPath, "User", "workspaceStorage");
|
|
25333
25412
|
if (existsSync7(workspaceDir)) {
|
|
25334
25413
|
for (const entry of readdirSync4(workspaceDir, { withFileTypes: true })) {
|
|
25335
25414
|
if (!entry.isDirectory()) continue;
|
|
25336
|
-
const wsJson =
|
|
25415
|
+
const wsJson = join9(workspaceDir, entry.name, "workspace.json");
|
|
25337
25416
|
if (!existsSync7(wsJson)) continue;
|
|
25338
25417
|
try {
|
|
25339
25418
|
const ws = JSON.parse(readFileSync8(wsJson, "utf8"));
|
|
25340
|
-
const projectPath = ws.folder ?
|
|
25419
|
+
const projectPath = ws.folder ? safeFileURLToPath(ws.folder) : ws.workspace ? safeFileURLToPath(ws.workspace) : null;
|
|
25341
25420
|
if (!projectPath) continue;
|
|
25342
|
-
if (existsSync7(
|
|
25343
|
-
const rulesDir =
|
|
25421
|
+
if (existsSync7(join9(projectPath, ".cursorrules"))) knowledgeFiles++;
|
|
25422
|
+
const rulesDir = join9(projectPath, ".cursor", "rules");
|
|
25344
25423
|
if (existsSync7(rulesDir)) {
|
|
25345
25424
|
for (const f of readdirSync4(rulesDir)) {
|
|
25346
25425
|
if (f.endsWith(".mdc")) knowledgeFiles++;
|
|
@@ -25362,11 +25441,11 @@ var CursorImporter = class {
|
|
|
25362
25441
|
return result;
|
|
25363
25442
|
}
|
|
25364
25443
|
async importGlobalRules(db, embed, result) {
|
|
25365
|
-
const dbPath =
|
|
25444
|
+
const dbPath = join9(this.configPath, "User", "globalStorage", "state.vscdb");
|
|
25366
25445
|
if (!existsSync7(dbPath)) return;
|
|
25367
25446
|
let cursorDb = null;
|
|
25368
25447
|
try {
|
|
25369
|
-
cursorDb = new
|
|
25448
|
+
cursorDb = new Database3(dbPath, { readonly: true });
|
|
25370
25449
|
const row = cursorDb.query("SELECT value FROM ItemTable WHERE key = 'aicontext.personalContext'").get();
|
|
25371
25450
|
if (!row?.value) return;
|
|
25372
25451
|
const content = row.value;
|
|
@@ -25391,30 +25470,30 @@ var CursorImporter = class {
|
|
|
25391
25470
|
}
|
|
25392
25471
|
}
|
|
25393
25472
|
async importProjectRules(db, embed, result) {
|
|
25394
|
-
const workspaceDir =
|
|
25473
|
+
const workspaceDir = join9(this.configPath, "User", "workspaceStorage");
|
|
25395
25474
|
if (!existsSync7(workspaceDir)) return;
|
|
25396
25475
|
const projectPaths = /* @__PURE__ */ new Set();
|
|
25397
25476
|
for (const entry of readdirSync4(workspaceDir, { withFileTypes: true })) {
|
|
25398
25477
|
if (!entry.isDirectory()) continue;
|
|
25399
|
-
const wsJson =
|
|
25478
|
+
const wsJson = join9(workspaceDir, entry.name, "workspace.json");
|
|
25400
25479
|
if (!existsSync7(wsJson)) continue;
|
|
25401
25480
|
try {
|
|
25402
25481
|
const ws = JSON.parse(readFileSync8(wsJson, "utf8"));
|
|
25403
|
-
const projectPath = ws.folder ?
|
|
25482
|
+
const projectPath = ws.folder ? safeFileURLToPath(ws.folder) : ws.workspace ? safeFileURLToPath(ws.workspace) : null;
|
|
25404
25483
|
if (projectPath) projectPaths.add(projectPath);
|
|
25405
25484
|
} catch {
|
|
25406
25485
|
}
|
|
25407
25486
|
}
|
|
25408
25487
|
for (const projectPath of projectPaths) {
|
|
25409
|
-
const legacyPath =
|
|
25488
|
+
const legacyPath = join9(projectPath, ".cursorrules");
|
|
25410
25489
|
if (existsSync7(legacyPath)) {
|
|
25411
25490
|
await this.importRuleFile(db, embed, result, legacyPath, ["cursorrules", "legacy"]);
|
|
25412
25491
|
}
|
|
25413
|
-
const rulesDir =
|
|
25492
|
+
const rulesDir = join9(projectPath, ".cursor", "rules");
|
|
25414
25493
|
if (existsSync7(rulesDir)) {
|
|
25415
25494
|
for (const filename of readdirSync4(rulesDir)) {
|
|
25416
25495
|
if (!filename.endsWith(".mdc")) continue;
|
|
25417
|
-
await this.importRuleFile(db, embed, result,
|
|
25496
|
+
await this.importRuleFile(db, embed, result, join9(rulesDir, filename), ["cursor-rule"]);
|
|
25418
25497
|
}
|
|
25419
25498
|
}
|
|
25420
25499
|
}
|
|
@@ -25446,24 +25525,24 @@ var CursorImporter = class {
|
|
|
25446
25525
|
|
|
25447
25526
|
// src/importers/cline.ts
|
|
25448
25527
|
import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync9 } from "fs";
|
|
25449
|
-
import { join as
|
|
25450
|
-
import { homedir as
|
|
25528
|
+
import { join as join10 } from "path";
|
|
25529
|
+
import { homedir as homedir5 } from "os";
|
|
25451
25530
|
var ClineImporter = class {
|
|
25452
25531
|
name = "cline";
|
|
25453
25532
|
dataPath;
|
|
25454
25533
|
legacyPath;
|
|
25455
25534
|
globalRulesPath;
|
|
25456
25535
|
constructor(dataPath, legacyPath) {
|
|
25457
|
-
this.dataPath = dataPath ??
|
|
25458
|
-
this.legacyPath = legacyPath ??
|
|
25459
|
-
|
|
25536
|
+
this.dataPath = dataPath ?? join10(homedir5(), ".cline", "data");
|
|
25537
|
+
this.legacyPath = legacyPath ?? join10(
|
|
25538
|
+
homedir5(),
|
|
25460
25539
|
".config",
|
|
25461
25540
|
"Code",
|
|
25462
25541
|
"User",
|
|
25463
25542
|
"globalStorage",
|
|
25464
25543
|
"saoudrizwan.claude-dev"
|
|
25465
25544
|
);
|
|
25466
|
-
this.globalRulesPath =
|
|
25545
|
+
this.globalRulesPath = join10(homedir5(), "Documents", "Cline", "Rules");
|
|
25467
25546
|
}
|
|
25468
25547
|
detect() {
|
|
25469
25548
|
return existsSync8(this.dataPath) || existsSync8(this.legacyPath);
|
|
@@ -25471,13 +25550,13 @@ var ClineImporter = class {
|
|
|
25471
25550
|
scan() {
|
|
25472
25551
|
let knowledgeFiles = 0;
|
|
25473
25552
|
let sessionFiles = 0;
|
|
25474
|
-
const ruleDirs = [this.globalRulesPath,
|
|
25553
|
+
const ruleDirs = [this.globalRulesPath, join10(homedir5(), "Cline", "Rules")];
|
|
25475
25554
|
for (const dir of ruleDirs) {
|
|
25476
25555
|
if (existsSync8(dir)) knowledgeFiles += countFiles(dir, [".md", ".txt"]);
|
|
25477
25556
|
}
|
|
25478
25557
|
const stateDir = this.resolveStateDir();
|
|
25479
25558
|
if (stateDir) {
|
|
25480
|
-
const historyPath =
|
|
25559
|
+
const historyPath = join10(stateDir, "taskHistory.json");
|
|
25481
25560
|
if (existsSync8(historyPath)) {
|
|
25482
25561
|
try {
|
|
25483
25562
|
const items = JSON.parse(readFileSync9(historyPath, "utf8"));
|
|
@@ -25486,7 +25565,7 @@ var ClineImporter = class {
|
|
|
25486
25565
|
}
|
|
25487
25566
|
}
|
|
25488
25567
|
}
|
|
25489
|
-
const mcpSettings =
|
|
25568
|
+
const mcpSettings = join10(this.resolveDataDir() ?? "", "settings", "cline_mcp_settings.json");
|
|
25490
25569
|
if (existsSync8(mcpSettings)) knowledgeFiles++;
|
|
25491
25570
|
return { memoryFiles: 0, knowledgeFiles, sessionFiles };
|
|
25492
25571
|
}
|
|
@@ -25507,20 +25586,20 @@ var ClineImporter = class {
|
|
|
25507
25586
|
resolveStateDir() {
|
|
25508
25587
|
const dataDir = this.resolveDataDir();
|
|
25509
25588
|
if (!dataDir) return null;
|
|
25510
|
-
const newState =
|
|
25589
|
+
const newState = join10(dataDir, "state");
|
|
25511
25590
|
if (existsSync8(newState)) return newState;
|
|
25512
25591
|
return dataDir;
|
|
25513
25592
|
}
|
|
25514
25593
|
async importGlobalRules(db, embed, result) {
|
|
25515
25594
|
const ruleDirs = [
|
|
25516
25595
|
this.globalRulesPath,
|
|
25517
|
-
|
|
25596
|
+
join10(homedir5(), "Cline", "Rules")
|
|
25518
25597
|
];
|
|
25519
25598
|
for (const dir of ruleDirs) {
|
|
25520
25599
|
if (!existsSync8(dir)) continue;
|
|
25521
25600
|
for (const filename of readdirSync5(dir)) {
|
|
25522
25601
|
if (!filename.endsWith(".md") && !filename.endsWith(".txt")) continue;
|
|
25523
|
-
const filePath =
|
|
25602
|
+
const filePath = join10(dir, filename);
|
|
25524
25603
|
try {
|
|
25525
25604
|
const raw = readFileSync9(filePath, "utf8");
|
|
25526
25605
|
const hash2 = contentHash(raw);
|
|
@@ -25546,7 +25625,7 @@ var ClineImporter = class {
|
|
|
25546
25625
|
async importTaskSummaries(db, embed, result) {
|
|
25547
25626
|
const stateDir = this.resolveStateDir();
|
|
25548
25627
|
if (!stateDir) return;
|
|
25549
|
-
const historyPath =
|
|
25628
|
+
const historyPath = join10(stateDir, "taskHistory.json");
|
|
25550
25629
|
if (!existsSync8(historyPath)) return;
|
|
25551
25630
|
let items;
|
|
25552
25631
|
try {
|
|
@@ -25595,20 +25674,20 @@ function countFiles(dir, extensions) {
|
|
|
25595
25674
|
|
|
25596
25675
|
// src/importers/opencode.ts
|
|
25597
25676
|
import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync10 } from "fs";
|
|
25598
|
-
import { join as
|
|
25599
|
-
import { homedir as
|
|
25600
|
-
import { Database as
|
|
25677
|
+
import { join as join11 } from "path";
|
|
25678
|
+
import { homedir as homedir6 } from "os";
|
|
25679
|
+
import { Database as Database4 } from "bun:sqlite";
|
|
25601
25680
|
var OpenCodeImporter = class {
|
|
25602
25681
|
name = "opencode";
|
|
25603
25682
|
dataPath;
|
|
25604
25683
|
configPath;
|
|
25605
25684
|
constructor(dataPath, configPath) {
|
|
25606
|
-
this.dataPath = dataPath ??
|
|
25607
|
-
process.env["XDG_DATA_HOME"] ??
|
|
25685
|
+
this.dataPath = dataPath ?? join11(
|
|
25686
|
+
process.env["XDG_DATA_HOME"] ?? join11(homedir6(), ".local", "share"),
|
|
25608
25687
|
"opencode"
|
|
25609
25688
|
);
|
|
25610
|
-
this.configPath = configPath ??
|
|
25611
|
-
process.env["XDG_CONFIG_HOME"] ??
|
|
25689
|
+
this.configPath = configPath ?? join11(
|
|
25690
|
+
process.env["XDG_CONFIG_HOME"] ?? join11(homedir6(), ".config"),
|
|
25612
25691
|
"opencode"
|
|
25613
25692
|
);
|
|
25614
25693
|
}
|
|
@@ -25618,8 +25697,8 @@ var OpenCodeImporter = class {
|
|
|
25618
25697
|
scan() {
|
|
25619
25698
|
let knowledgeFiles = 0;
|
|
25620
25699
|
let sessionFiles = 0;
|
|
25621
|
-
if (existsSync9(
|
|
25622
|
-
const dbPath =
|
|
25700
|
+
if (existsSync9(join11(this.configPath, "AGENTS.md"))) knowledgeFiles++;
|
|
25701
|
+
const dbPath = join11(this.dataPath, "opencode.db");
|
|
25623
25702
|
if (existsSync9(dbPath)) sessionFiles = 1;
|
|
25624
25703
|
return { memoryFiles: 0, knowledgeFiles, sessionFiles };
|
|
25625
25704
|
}
|
|
@@ -25633,7 +25712,7 @@ var OpenCodeImporter = class {
|
|
|
25633
25712
|
return result;
|
|
25634
25713
|
}
|
|
25635
25714
|
async importAgentsMd(db, embed, result) {
|
|
25636
|
-
const agentsMdPath =
|
|
25715
|
+
const agentsMdPath = join11(this.configPath, "AGENTS.md");
|
|
25637
25716
|
if (!existsSync9(agentsMdPath)) return;
|
|
25638
25717
|
try {
|
|
25639
25718
|
const raw = readFileSync10(agentsMdPath, "utf8");
|
|
@@ -25659,28 +25738,28 @@ var OpenCodeImporter = class {
|
|
|
25659
25738
|
async importProjectContent(db, embed, result) {
|
|
25660
25739
|
const projectPaths = await this.discoverProjects();
|
|
25661
25740
|
for (const projectPath of projectPaths) {
|
|
25662
|
-
const openCodeDir =
|
|
25741
|
+
const openCodeDir = join11(projectPath, ".opencode");
|
|
25663
25742
|
if (!existsSync9(openCodeDir)) continue;
|
|
25664
|
-
const agentDir =
|
|
25743
|
+
const agentDir = join11(openCodeDir, "agent");
|
|
25665
25744
|
if (existsSync9(agentDir)) {
|
|
25666
25745
|
await this.importMdDir(db, embed, result, agentDir, ["opencode-agent"]);
|
|
25667
25746
|
}
|
|
25668
|
-
const commandDir =
|
|
25747
|
+
const commandDir = join11(openCodeDir, "command");
|
|
25669
25748
|
if (existsSync9(commandDir)) {
|
|
25670
25749
|
await this.importMdDir(db, embed, result, commandDir, ["opencode-command"]);
|
|
25671
25750
|
}
|
|
25672
|
-
const projectAgentsMd =
|
|
25751
|
+
const projectAgentsMd = join11(projectPath, "AGENTS.md");
|
|
25673
25752
|
if (existsSync9(projectAgentsMd)) {
|
|
25674
25753
|
await this.importSingleFile(db, embed, result, projectAgentsMd, ["agents-md", "project"]);
|
|
25675
25754
|
}
|
|
25676
25755
|
}
|
|
25677
25756
|
}
|
|
25678
25757
|
async discoverProjects() {
|
|
25679
|
-
const dbPath =
|
|
25758
|
+
const dbPath = join11(this.dataPath, "opencode.db");
|
|
25680
25759
|
if (!existsSync9(dbPath)) return [];
|
|
25681
25760
|
let ocDb = null;
|
|
25682
25761
|
try {
|
|
25683
|
-
ocDb = new
|
|
25762
|
+
ocDb = new Database4(dbPath, { readonly: true });
|
|
25684
25763
|
const rows = ocDb.query("SELECT worktree FROM project").all();
|
|
25685
25764
|
return rows.map((r) => r.worktree).filter((p) => existsSync9(p));
|
|
25686
25765
|
} catch {
|
|
@@ -25692,7 +25771,7 @@ var OpenCodeImporter = class {
|
|
|
25692
25771
|
async importMdDir(db, embed, result, dir, tags) {
|
|
25693
25772
|
for (const filename of readdirSync6(dir)) {
|
|
25694
25773
|
if (!filename.endsWith(".md")) continue;
|
|
25695
|
-
await this.importSingleFile(db, embed, result,
|
|
25774
|
+
await this.importSingleFile(db, embed, result, join11(dir, filename), tags);
|
|
25696
25775
|
}
|
|
25697
25776
|
}
|
|
25698
25777
|
async importSingleFile(db, embed, result, filePath, tags) {
|
|
@@ -25722,36 +25801,36 @@ var OpenCodeImporter = class {
|
|
|
25722
25801
|
|
|
25723
25802
|
// src/importers/hermes.ts
|
|
25724
25803
|
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync11 } from "fs";
|
|
25725
|
-
import { join as
|
|
25726
|
-
import { homedir as
|
|
25804
|
+
import { join as join12 } from "path";
|
|
25805
|
+
import { homedir as homedir7 } from "os";
|
|
25727
25806
|
var HermesImporter = class {
|
|
25728
25807
|
name = "hermes";
|
|
25729
25808
|
basePath;
|
|
25730
25809
|
constructor(basePath) {
|
|
25731
|
-
this.basePath = basePath ?? (process.env["HERMES_HOME"] ||
|
|
25810
|
+
this.basePath = basePath ?? (process.env["HERMES_HOME"] || join12(homedir7(), ".hermes"));
|
|
25732
25811
|
}
|
|
25733
25812
|
detect() {
|
|
25734
|
-
return existsSync10(this.basePath) && (existsSync10(
|
|
25813
|
+
return existsSync10(this.basePath) && (existsSync10(join12(this.basePath, "state.db")) || existsSync10(join12(this.basePath, "memories")) || existsSync10(join12(this.basePath, "config.yaml")));
|
|
25735
25814
|
}
|
|
25736
25815
|
scan() {
|
|
25737
25816
|
let memoryFiles = 0;
|
|
25738
25817
|
let knowledgeFiles = 0;
|
|
25739
25818
|
let sessionFiles = 0;
|
|
25740
|
-
const memoriesDir =
|
|
25819
|
+
const memoriesDir = join12(this.basePath, "memories");
|
|
25741
25820
|
if (existsSync10(memoriesDir)) {
|
|
25742
|
-
if (existsSync10(
|
|
25743
|
-
if (existsSync10(
|
|
25821
|
+
if (existsSync10(join12(memoriesDir, "MEMORY.md"))) memoryFiles++;
|
|
25822
|
+
if (existsSync10(join12(memoriesDir, "USER.md"))) memoryFiles++;
|
|
25744
25823
|
}
|
|
25745
|
-
const skillsDir =
|
|
25824
|
+
const skillsDir = join12(this.basePath, "skills");
|
|
25746
25825
|
if (existsSync10(skillsDir)) {
|
|
25747
25826
|
for (const entry of readdirSync7(skillsDir, { withFileTypes: true })) {
|
|
25748
|
-
if (entry.isDirectory() && existsSync10(
|
|
25827
|
+
if (entry.isDirectory() && existsSync10(join12(skillsDir, entry.name, "SKILL.md"))) {
|
|
25749
25828
|
knowledgeFiles++;
|
|
25750
25829
|
}
|
|
25751
25830
|
}
|
|
25752
25831
|
}
|
|
25753
|
-
if (existsSync10(
|
|
25754
|
-
if (existsSync10(
|
|
25832
|
+
if (existsSync10(join12(this.basePath, "SOUL.md"))) knowledgeFiles++;
|
|
25833
|
+
if (existsSync10(join12(this.basePath, "state.db"))) sessionFiles = 1;
|
|
25755
25834
|
return { memoryFiles, knowledgeFiles, sessionFiles };
|
|
25756
25835
|
}
|
|
25757
25836
|
async importMemories(db, embed, _project) {
|
|
@@ -25760,21 +25839,21 @@ var HermesImporter = class {
|
|
|
25760
25839
|
db,
|
|
25761
25840
|
embed,
|
|
25762
25841
|
result,
|
|
25763
|
-
|
|
25842
|
+
join12(this.basePath, "memories", "MEMORY.md"),
|
|
25764
25843
|
["hermes-memory"]
|
|
25765
25844
|
);
|
|
25766
25845
|
await this.importMemoryFile(
|
|
25767
25846
|
db,
|
|
25768
25847
|
embed,
|
|
25769
25848
|
result,
|
|
25770
|
-
|
|
25849
|
+
join12(this.basePath, "memories", "USER.md"),
|
|
25771
25850
|
["hermes-user", "user-profile"]
|
|
25772
25851
|
);
|
|
25773
25852
|
return result;
|
|
25774
25853
|
}
|
|
25775
25854
|
async importKnowledge(db, embed) {
|
|
25776
25855
|
const result = { imported: 0, skipped: 0, errors: [] };
|
|
25777
|
-
const soulPath =
|
|
25856
|
+
const soulPath = join12(this.basePath, "SOUL.md");
|
|
25778
25857
|
if (existsSync10(soulPath)) {
|
|
25779
25858
|
await this.importSingleFile(db, embed, result, soulPath, "warm", ["hermes-soul"]);
|
|
25780
25859
|
}
|
|
@@ -25808,11 +25887,11 @@ var HermesImporter = class {
|
|
|
25808
25887
|
}
|
|
25809
25888
|
}
|
|
25810
25889
|
async importSkills(db, embed, result) {
|
|
25811
|
-
const skillsDir =
|
|
25890
|
+
const skillsDir = join12(this.basePath, "skills");
|
|
25812
25891
|
if (!existsSync10(skillsDir)) return;
|
|
25813
25892
|
for (const entry of readdirSync7(skillsDir, { withFileTypes: true })) {
|
|
25814
25893
|
if (!entry.isDirectory()) continue;
|
|
25815
|
-
const skillPath =
|
|
25894
|
+
const skillPath = join12(skillsDir, entry.name, "SKILL.md");
|
|
25816
25895
|
if (!existsSync10(skillPath)) continue;
|
|
25817
25896
|
await this.importSingleFile(db, embed, result, skillPath, "cold", ["hermes-skill", entry.name]);
|
|
25818
25897
|
}
|
|
@@ -26040,7 +26119,7 @@ async function sweepWarmTier(db, embed, config2, sessionId) {
|
|
|
26040
26119
|
|
|
26041
26120
|
// src/importers/project-docs.ts
|
|
26042
26121
|
import { existsSync as existsSync11, readFileSync as readFileSync12, readdirSync as readdirSync8, statSync as statSync5 } from "fs";
|
|
26043
|
-
import { join as
|
|
26122
|
+
import { join as join13, basename as basename4 } from "path";
|
|
26044
26123
|
import { createHash as createHash4 } from "crypto";
|
|
26045
26124
|
var DOC_FILES = ["README.md", "CONTRIBUTING.md", "CLAUDE.md", "AGENTS.md"];
|
|
26046
26125
|
var DOC_DIRS = ["docs", "doc"];
|
|
@@ -26065,11 +26144,11 @@ async function ingestProjectDocs(db, embed, cwd) {
|
|
|
26065
26144
|
let collectionId = null;
|
|
26066
26145
|
const filesToIngest = [];
|
|
26067
26146
|
for (const file2 of DOC_FILES) {
|
|
26068
|
-
const path =
|
|
26147
|
+
const path = join13(cwd, file2);
|
|
26069
26148
|
if (existsSync11(path)) filesToIngest.push(path);
|
|
26070
26149
|
}
|
|
26071
26150
|
for (const dir of DOC_DIRS) {
|
|
26072
|
-
const dirPath =
|
|
26151
|
+
const dirPath = join13(cwd, dir);
|
|
26073
26152
|
if (existsSync11(dirPath) && statSync5(dirPath).isDirectory()) {
|
|
26074
26153
|
collectMarkdownFiles(dirPath, filesToIngest);
|
|
26075
26154
|
}
|
|
@@ -26097,7 +26176,7 @@ async function ingestProjectDocs(db, embed, cwd) {
|
|
|
26097
26176
|
}
|
|
26098
26177
|
function collectMarkdownFiles(dirPath, files) {
|
|
26099
26178
|
for (const entry of readdirSync8(dirPath, { withFileTypes: true })) {
|
|
26100
|
-
const full =
|
|
26179
|
+
const full = join13(dirPath, entry.name);
|
|
26101
26180
|
if (entry.isDirectory()) {
|
|
26102
26181
|
collectMarkdownFiles(full, files);
|
|
26103
26182
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -26108,10 +26187,11 @@ function collectMarkdownFiles(dirPath, files) {
|
|
|
26108
26187
|
|
|
26109
26188
|
// src/utils/project-detect.ts
|
|
26110
26189
|
import { execFileSync } from "child_process";
|
|
26111
|
-
import { basename as basename5 } from "path";
|
|
26190
|
+
import { basename as basename5, parse as parsePath } from "path";
|
|
26191
|
+
import { homedir as homedir8 } from "os";
|
|
26112
26192
|
function detectProject(cwd) {
|
|
26113
|
-
|
|
26114
|
-
if (cwd ===
|
|
26193
|
+
if (cwd === homedir8()) return null;
|
|
26194
|
+
if (cwd === parsePath(cwd).root) return null;
|
|
26115
26195
|
try {
|
|
26116
26196
|
const remote = execFileSync("git", ["remote", "get-url", "origin"], {
|
|
26117
26197
|
cwd,
|
|
@@ -26128,10 +26208,10 @@ function detectProject(cwd) {
|
|
|
26128
26208
|
}
|
|
26129
26209
|
|
|
26130
26210
|
// src/eval/smoke-test.ts
|
|
26131
|
-
import { resolve as resolve4, dirname as
|
|
26211
|
+
import { resolve as resolve4, dirname as dirname7, basename as basename6 } from "path";
|
|
26132
26212
|
import { readFileSync as readFileSync13 } from "fs";
|
|
26133
|
-
import { fileURLToPath as
|
|
26134
|
-
var __dirname3 =
|
|
26213
|
+
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
26214
|
+
var __dirname3 = dirname7(fileURLToPath7(import.meta.url));
|
|
26135
26215
|
var PACKAGE_ROOT3 = basename6(__dirname3) === "dist" ? resolve4(__dirname3, "..") : resolve4(__dirname3, "..", "..");
|
|
26136
26216
|
var SMOKE_PASS_THRESHOLD = 0.8;
|
|
26137
26217
|
function getMetaValue(db, key) {
|
|
@@ -26529,7 +26609,7 @@ function registerSessionTools() {
|
|
|
26529
26609
|
|
|
26530
26610
|
// src/tools/extra-tools.ts
|
|
26531
26611
|
import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync3, readFileSync as readFileSync14 } from "fs";
|
|
26532
|
-
import { join as
|
|
26612
|
+
import { join as join14 } from "path";
|
|
26533
26613
|
function registerExtraTools() {
|
|
26534
26614
|
return [
|
|
26535
26615
|
{
|
|
@@ -26762,10 +26842,10 @@ async function handleExtraTool(name, args, ctx) {
|
|
|
26762
26842
|
});
|
|
26763
26843
|
}
|
|
26764
26844
|
}
|
|
26765
|
-
const exportsDir =
|
|
26845
|
+
const exportsDir = join14(getDataDir(), "exports");
|
|
26766
26846
|
mkdirSync5(exportsDir, { recursive: true });
|
|
26767
26847
|
const timestamp = Date.now();
|
|
26768
|
-
const exportPath =
|
|
26848
|
+
const exportPath = join14(exportsDir, `${timestamp}.json`);
|
|
26769
26849
|
const exportData = { version: 1, exported_at: timestamp, entries: allEntries };
|
|
26770
26850
|
const jsonStr = JSON.stringify(exportData, null, 2);
|
|
26771
26851
|
writeFileSync3(exportPath, jsonStr, "utf-8");
|
|
@@ -26954,6 +27034,17 @@ async function startServer(ctx) {
|
|
|
26954
27034
|
|
|
26955
27035
|
// src/index.ts
|
|
26956
27036
|
async function main() {
|
|
27037
|
+
let dbPath;
|
|
27038
|
+
try {
|
|
27039
|
+
dbPath = getDbPath();
|
|
27040
|
+
} catch (e) {
|
|
27041
|
+
if (e instanceof SqliteDbPathError) {
|
|
27042
|
+
process.stderr.write(`total-recall: ${e.message}
|
|
27043
|
+
`);
|
|
27044
|
+
process.exit(1);
|
|
27045
|
+
}
|
|
27046
|
+
throw e;
|
|
27047
|
+
}
|
|
26957
27048
|
const config2 = loadConfig();
|
|
26958
27049
|
const db = getDb();
|
|
26959
27050
|
const embedder = new Embedder({
|
|
@@ -26961,7 +27052,7 @@ async function main() {
|
|
|
26961
27052
|
dimensions: config2.embedding.dimensions
|
|
26962
27053
|
});
|
|
26963
27054
|
const sessionId = randomUUID8();
|
|
26964
|
-
process.stderr.write(`total-recall: MCP server starting (db: ${
|
|
27055
|
+
process.stderr.write(`total-recall: MCP server starting (db: ${dbPath})
|
|
26965
27056
|
`);
|
|
26966
27057
|
await startServer({ db, config: config2, embedder, sessionId, configSnapshotId: "default", sessionInitialized: false, sessionInitResult: null, sessionInitPromise: null });
|
|
26967
27058
|
const cleanup = () => {
|