crispy-recall 0.2.1 → 0.3.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/README.md +230 -192
- package/THIRD-PARTY-LICENSES +43 -145
- package/dist/SKILL.md.template +7 -0
- package/dist/embed-pending.js +642 -189
- package/dist/recall.js +4935 -3049
- package/dist/statusline.js +180 -0
- package/dist/stop-hook.js +607 -143
- package/package.json +2 -1
package/dist/embed-pending.js
CHANGED
|
@@ -158,21 +158,21 @@ var require_file_uri_to_path = __commonJS({
|
|
|
158
158
|
var rest = decodeURI(uri.substring(7));
|
|
159
159
|
var firstSlash = rest.indexOf("/");
|
|
160
160
|
var host = rest.substring(0, firstSlash);
|
|
161
|
-
var
|
|
161
|
+
var path2 = rest.substring(firstSlash + 1);
|
|
162
162
|
if ("localhost" == host)
|
|
163
163
|
host = "";
|
|
164
164
|
if (host) {
|
|
165
165
|
host = sep2 + sep2 + host;
|
|
166
166
|
}
|
|
167
|
-
|
|
167
|
+
path2 = path2.replace(/^(.+)\|/, "$1:");
|
|
168
168
|
if (sep2 == "\\") {
|
|
169
|
-
|
|
169
|
+
path2 = path2.replace(/\//g, "\\");
|
|
170
170
|
}
|
|
171
|
-
if (/^.+\:/.test(
|
|
171
|
+
if (/^.+\:/.test(path2)) {
|
|
172
172
|
} else {
|
|
173
|
-
|
|
173
|
+
path2 = sep2 + path2;
|
|
174
174
|
}
|
|
175
|
-
return host +
|
|
175
|
+
return host + path2;
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
});
|
|
@@ -181,18 +181,18 @@ var require_file_uri_to_path = __commonJS({
|
|
|
181
181
|
var require_bindings = __commonJS({
|
|
182
182
|
"node_modules/bindings/bindings.js"(exports2, module2) {
|
|
183
183
|
var fs3 = require("fs");
|
|
184
|
-
var
|
|
184
|
+
var path2 = require("path");
|
|
185
185
|
var fileURLToPath3 = require_file_uri_to_path();
|
|
186
|
-
var
|
|
187
|
-
var dirname3 =
|
|
188
|
-
var exists = fs3.accessSync && function(
|
|
186
|
+
var join7 = path2.join;
|
|
187
|
+
var dirname3 = path2.dirname;
|
|
188
|
+
var exists = fs3.accessSync && function(path3) {
|
|
189
189
|
try {
|
|
190
|
-
fs3.accessSync(
|
|
190
|
+
fs3.accessSync(path3);
|
|
191
191
|
} catch (e) {
|
|
192
192
|
return false;
|
|
193
193
|
}
|
|
194
194
|
return true;
|
|
195
|
-
} || fs3.existsSync ||
|
|
195
|
+
} || fs3.existsSync || path2.existsSync;
|
|
196
196
|
var defaults2 = {
|
|
197
197
|
arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
|
|
198
198
|
compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
|
|
@@ -238,13 +238,13 @@ var require_bindings = __commonJS({
|
|
|
238
238
|
if (!opts.module_root) {
|
|
239
239
|
opts.module_root = exports2.getRoot(exports2.getFileName());
|
|
240
240
|
}
|
|
241
|
-
if (
|
|
241
|
+
if (path2.extname(opts.bindings) != ".node") {
|
|
242
242
|
opts.bindings += ".node";
|
|
243
243
|
}
|
|
244
244
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
245
245
|
var tries = [], i = 0, l = opts.try.length, n, b, err;
|
|
246
246
|
for (; i < l; i++) {
|
|
247
|
-
n =
|
|
247
|
+
n = join7.apply(
|
|
248
248
|
null,
|
|
249
249
|
opts.try[i].map(function(p) {
|
|
250
250
|
return opts[p] || p;
|
|
@@ -305,7 +305,7 @@ var require_bindings = __commonJS({
|
|
|
305
305
|
if (dir === ".") {
|
|
306
306
|
dir = process.cwd();
|
|
307
307
|
}
|
|
308
|
-
if (exists(
|
|
308
|
+
if (exists(join7(dir, "package.json")) || exists(join7(dir, "node_modules"))) {
|
|
309
309
|
return dir;
|
|
310
310
|
}
|
|
311
311
|
if (prev === dir) {
|
|
@@ -314,7 +314,7 @@ var require_bindings = __commonJS({
|
|
|
314
314
|
);
|
|
315
315
|
}
|
|
316
316
|
prev = dir;
|
|
317
|
-
dir =
|
|
317
|
+
dir = join7(dir, "..");
|
|
318
318
|
}
|
|
319
319
|
};
|
|
320
320
|
}
|
|
@@ -482,7 +482,7 @@ var require_backup = __commonJS({
|
|
|
482
482
|
"node_modules/better-sqlite3/lib/methods/backup.js"(exports2, module2) {
|
|
483
483
|
"use strict";
|
|
484
484
|
var fs3 = require("fs");
|
|
485
|
-
var
|
|
485
|
+
var path2 = require("path");
|
|
486
486
|
var { promisify: promisify2 } = require("util");
|
|
487
487
|
var { cppdb } = require_util();
|
|
488
488
|
var fsAccess = promisify2(fs3.access);
|
|
@@ -506,7 +506,7 @@ var require_backup = __commonJS({
|
|
|
506
506
|
throw new TypeError('The "attached" option cannot be an empty string');
|
|
507
507
|
if (handler != null && typeof handler !== "function")
|
|
508
508
|
throw new TypeError('Expected the "progress" option to be a function');
|
|
509
|
-
await fsAccess(
|
|
509
|
+
await fsAccess(path2.dirname(filename)).catch(() => {
|
|
510
510
|
throw new TypeError("Cannot save backup because the directory does not exist");
|
|
511
511
|
});
|
|
512
512
|
const isNewFile = await fsAccess(filename).then(() => false, () => true);
|
|
@@ -837,7 +837,7 @@ var require_database = __commonJS({
|
|
|
837
837
|
"node_modules/better-sqlite3/lib/database.js"(exports2, module2) {
|
|
838
838
|
"use strict";
|
|
839
839
|
var fs3 = require("fs");
|
|
840
|
-
var
|
|
840
|
+
var path2 = require("path");
|
|
841
841
|
var util = require_util();
|
|
842
842
|
var SqliteError = require_sqlite_error();
|
|
843
843
|
var DEFAULT_ADDON;
|
|
@@ -884,7 +884,7 @@ var require_database = __commonJS({
|
|
|
884
884
|
addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
|
|
885
885
|
} else if (typeof nativeBinding === "string") {
|
|
886
886
|
const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : require;
|
|
887
|
-
addon = requireFunc(
|
|
887
|
+
addon = requireFunc(path2.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
|
|
888
888
|
} else {
|
|
889
889
|
addon = nativeBinding;
|
|
890
890
|
}
|
|
@@ -892,7 +892,7 @@ var require_database = __commonJS({
|
|
|
892
892
|
addon.setErrorConstructor(SqliteError);
|
|
893
893
|
addon.isInitialized = true;
|
|
894
894
|
}
|
|
895
|
-
if (!anonymous && !filename.startsWith("file:") && !fs3.existsSync(
|
|
895
|
+
if (!anonymous && !filename.startsWith("file:") && !fs3.existsSync(path2.dirname(filename))) {
|
|
896
896
|
throw new TypeError("Cannot open database because the directory does not exist");
|
|
897
897
|
}
|
|
898
898
|
Object.defineProperties(this, {
|
|
@@ -2648,7 +2648,7 @@ var require_yauzl = __commonJS({
|
|
|
2648
2648
|
exports2.ZipFile = ZipFile;
|
|
2649
2649
|
exports2.Entry = Entry;
|
|
2650
2650
|
exports2.RandomAccessReader = RandomAccessReader;
|
|
2651
|
-
function open(
|
|
2651
|
+
function open(path2, options, callback) {
|
|
2652
2652
|
if (typeof options === "function") {
|
|
2653
2653
|
callback = options;
|
|
2654
2654
|
options = null;
|
|
@@ -2667,7 +2667,7 @@ var require_yauzl = __commonJS({
|
|
|
2667
2667
|
options.strictFileNames = false;
|
|
2668
2668
|
if (callback == null)
|
|
2669
2669
|
callback = defaultCallback;
|
|
2670
|
-
fs3.open(
|
|
2670
|
+
fs3.open(path2, "r", function(err, fd) {
|
|
2671
2671
|
if (err)
|
|
2672
2672
|
return callback(err);
|
|
2673
2673
|
fromFd(fd, options, function(err2, zipfile) {
|
|
@@ -3334,7 +3334,7 @@ var require_extract_zip = __commonJS({
|
|
|
3334
3334
|
var debug = require_src()("extract-zip");
|
|
3335
3335
|
var { createWriteStream: createWriteStream2, promises: fs3 } = require("fs");
|
|
3336
3336
|
var getStream = require_get_stream();
|
|
3337
|
-
var
|
|
3337
|
+
var path2 = require("path");
|
|
3338
3338
|
var { promisify: promisify2 } = require("util");
|
|
3339
3339
|
var stream2 = require("stream");
|
|
3340
3340
|
var yauzl = require_yauzl();
|
|
@@ -3371,12 +3371,12 @@ var require_extract_zip = __commonJS({
|
|
|
3371
3371
|
this.zipfile.readEntry();
|
|
3372
3372
|
return;
|
|
3373
3373
|
}
|
|
3374
|
-
const destDir =
|
|
3374
|
+
const destDir = path2.dirname(path2.join(this.opts.dir, entry.fileName));
|
|
3375
3375
|
try {
|
|
3376
3376
|
await fs3.mkdir(destDir, { recursive: true });
|
|
3377
3377
|
const canonicalDestDir = await fs3.realpath(destDir);
|
|
3378
|
-
const relativeDestDir =
|
|
3379
|
-
if (relativeDestDir.split(
|
|
3378
|
+
const relativeDestDir = path2.relative(this.opts.dir, canonicalDestDir);
|
|
3379
|
+
if (relativeDestDir.split(path2.sep).includes("..")) {
|
|
3380
3380
|
throw new Error(`Out of bound path "${canonicalDestDir}" found while processing file ${entry.fileName}`);
|
|
3381
3381
|
}
|
|
3382
3382
|
await this.extractEntry(entry);
|
|
@@ -3398,7 +3398,7 @@ var require_extract_zip = __commonJS({
|
|
|
3398
3398
|
if (this.opts.onEntry) {
|
|
3399
3399
|
this.opts.onEntry(entry, this.zipfile);
|
|
3400
3400
|
}
|
|
3401
|
-
const dest =
|
|
3401
|
+
const dest = path2.join(this.opts.dir, entry.fileName);
|
|
3402
3402
|
const mode = entry.externalFileAttributes >> 16 & 65535;
|
|
3403
3403
|
const IFMT2 = 61440;
|
|
3404
3404
|
const IFDIR2 = 16384;
|
|
@@ -3413,7 +3413,7 @@ var require_extract_zip = __commonJS({
|
|
|
3413
3413
|
isDir = madeBy === 0 && entry.externalFileAttributes === 16;
|
|
3414
3414
|
debug("extracting entry", { filename: entry.fileName, isDir, isSymlink: symlink });
|
|
3415
3415
|
const procMode = this.getExtractedMode(mode, isDir) & 511;
|
|
3416
|
-
const destDir = isDir ? dest :
|
|
3416
|
+
const destDir = isDir ? dest : path2.dirname(dest);
|
|
3417
3417
|
const mkdirOptions = { recursive: true };
|
|
3418
3418
|
if (isDir) {
|
|
3419
3419
|
mkdirOptions.mode = procMode;
|
|
@@ -3456,7 +3456,7 @@ var require_extract_zip = __commonJS({
|
|
|
3456
3456
|
};
|
|
3457
3457
|
module2.exports = async function(zipPath, opts) {
|
|
3458
3458
|
debug("creating target directory", opts.dir);
|
|
3459
|
-
if (!
|
|
3459
|
+
if (!path2.isAbsolute(opts.dir)) {
|
|
3460
3460
|
throw new Error("Target directory is expected to be absolute");
|
|
3461
3461
|
}
|
|
3462
3462
|
await fs3.mkdir(opts.dir, { recursive: true });
|
|
@@ -3478,6 +3478,8 @@ var init_settings_merge = __esm({
|
|
|
3478
3478
|
"src/installer/settings-merge.ts"() {
|
|
3479
3479
|
"use strict";
|
|
3480
3480
|
init_stable_node();
|
|
3481
|
+
init_config();
|
|
3482
|
+
init_paths();
|
|
3481
3483
|
}
|
|
3482
3484
|
});
|
|
3483
3485
|
|
|
@@ -3527,6 +3529,7 @@ __export(embedder_exports, {
|
|
|
3527
3529
|
disposeEmbedder: () => disposeEmbedder,
|
|
3528
3530
|
embed: () => embed,
|
|
3529
3531
|
embedBatch: () => embedBatch,
|
|
3532
|
+
embedBatchOneShot: () => embedBatchOneShot,
|
|
3530
3533
|
ensureBinary: () => ensureBinary,
|
|
3531
3534
|
ensureModel: () => ensureModel,
|
|
3532
3535
|
extractArchive: () => extractArchive,
|
|
@@ -4227,13 +4230,13 @@ async function retryServer() {
|
|
|
4227
4230
|
serverRetryPromise = null;
|
|
4228
4231
|
}
|
|
4229
4232
|
}
|
|
4230
|
-
function httpPost(socketPath,
|
|
4233
|
+
function httpPost(socketPath, path2, body, timeoutMs) {
|
|
4231
4234
|
return new Promise((resolve, reject) => {
|
|
4232
4235
|
const data = JSON.stringify(body);
|
|
4233
4236
|
const req = (0, import_node_http.request)(
|
|
4234
4237
|
{
|
|
4235
4238
|
socketPath,
|
|
4236
|
-
path:
|
|
4239
|
+
path: path2,
|
|
4237
4240
|
method: "POST",
|
|
4238
4241
|
headers: {
|
|
4239
4242
|
"Content-Type": "application/json",
|
|
@@ -4286,7 +4289,7 @@ async function embedViaHttp(socketPath, texts) {
|
|
|
4286
4289
|
return new Float32Array(item.embedding);
|
|
4287
4290
|
});
|
|
4288
4291
|
}
|
|
4289
|
-
async function embedViaProcess(texts, modelPath) {
|
|
4292
|
+
async function embedViaProcess(texts, modelPath, opts) {
|
|
4290
4293
|
if (!binaryPath)
|
|
4291
4294
|
throw new Error("llama-embedding binary not available");
|
|
4292
4295
|
const sanitized = texts.map((t) => t.replaceAll(BATCH_SEPARATOR, " "));
|
|
@@ -4335,7 +4338,8 @@ async function embedViaProcess(texts, modelPath) {
|
|
|
4335
4338
|
}
|
|
4336
4339
|
const { stdout, stderr } = await execFileAsync(binaryPath, args, {
|
|
4337
4340
|
maxBuffer: 2 * 1024 * 1024,
|
|
4338
|
-
env
|
|
4341
|
+
env,
|
|
4342
|
+
...opts?.timeoutMs ? { timeout: opts.timeoutMs, killSignal: "SIGKILL" } : {}
|
|
4339
4343
|
});
|
|
4340
4344
|
if (stderr) {
|
|
4341
4345
|
log({
|
|
@@ -4377,6 +4381,19 @@ async function embedBatch(texts) {
|
|
|
4377
4381
|
return [];
|
|
4378
4382
|
return withEmbedMutex(() => embedBatchInner(texts));
|
|
4379
4383
|
}
|
|
4384
|
+
async function embedBatchOneShot(texts, opts) {
|
|
4385
|
+
if (texts.length === 0)
|
|
4386
|
+
return [];
|
|
4387
|
+
return withEmbedMutex(async () => {
|
|
4388
|
+
if (!binaryPath) {
|
|
4389
|
+
await ensureBinary();
|
|
4390
|
+
}
|
|
4391
|
+
if (!binaryPath)
|
|
4392
|
+
throw new Error("llama-embedding binary not available");
|
|
4393
|
+
const modelPath = await ensureModel();
|
|
4394
|
+
return embedViaProcess(texts, modelPath, opts);
|
|
4395
|
+
});
|
|
4396
|
+
}
|
|
4380
4397
|
async function embedBatchInner(texts) {
|
|
4381
4398
|
if (!binaryPath) {
|
|
4382
4399
|
await ensureBinary();
|
|
@@ -4773,6 +4790,15 @@ Run \`recall doctor\` for details.`
|
|
|
4773
4790
|
this.name = "BindingLoadError";
|
|
4774
4791
|
}
|
|
4775
4792
|
};
|
|
4793
|
+
var MigrationPendingError = class extends Error {
|
|
4794
|
+
constructor(dbPath2) {
|
|
4795
|
+
super(
|
|
4796
|
+
"recall: this database needs a one-time schema migration \u2014 run `recall install` to finish it. (Normal commands refuse to rewrite the index unattended.)"
|
|
4797
|
+
);
|
|
4798
|
+
this.dbPath = dbPath2;
|
|
4799
|
+
this.name = "MigrationPendingError";
|
|
4800
|
+
}
|
|
4801
|
+
};
|
|
4776
4802
|
function isBindingLoadError(e) {
|
|
4777
4803
|
if (!e || typeof e !== "object")
|
|
4778
4804
|
return false;
|
|
@@ -4787,7 +4813,7 @@ function isBindingLoadError(e) {
|
|
|
4787
4813
|
}
|
|
4788
4814
|
var db = null;
|
|
4789
4815
|
var currentDbPath = null;
|
|
4790
|
-
function getDb(dbPath2) {
|
|
4816
|
+
function getDb(dbPath2, opts) {
|
|
4791
4817
|
if (db && currentDbPath === dbPath2)
|
|
4792
4818
|
return db;
|
|
4793
4819
|
if (db) {
|
|
@@ -4802,12 +4828,45 @@ function getDb(dbPath2) {
|
|
|
4802
4828
|
raw.close();
|
|
4803
4829
|
throw e;
|
|
4804
4830
|
}
|
|
4805
|
-
|
|
4831
|
+
const adapter = createAdapter(raw);
|
|
4832
|
+
if (isRetrievalMigrationPending(adapter)) {
|
|
4833
|
+
if (!opts?.allowPendingMigration) {
|
|
4834
|
+
raw.close();
|
|
4835
|
+
throw new MigrationPendingError(dbPath2);
|
|
4836
|
+
}
|
|
4837
|
+
db = adapter;
|
|
4838
|
+
currentDbPath = dbPath2;
|
|
4839
|
+
log({ source: "db", level: "info", summary: `DB: opened pending-migration DB at ${dbPath2} (installer mode)` });
|
|
4840
|
+
return db;
|
|
4841
|
+
}
|
|
4842
|
+
db = adapter;
|
|
4806
4843
|
currentDbPath = dbPath2;
|
|
4807
4844
|
ensureSchema(db);
|
|
4808
4845
|
log({ source: "db", level: "info", summary: `DB: initialized at ${dbPath2}` });
|
|
4809
4846
|
return db;
|
|
4810
4847
|
}
|
|
4848
|
+
var RETRIEVAL_MIGRATION_KEY = "retrieval_class_migration";
|
|
4849
|
+
function isRetrievalMigrationPending(d) {
|
|
4850
|
+
try {
|
|
4851
|
+
const hasMessages = d.get(
|
|
4852
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'messages'`
|
|
4853
|
+
);
|
|
4854
|
+
if (!hasMessages)
|
|
4855
|
+
return false;
|
|
4856
|
+
const hasMeta = d.get(
|
|
4857
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_meta'`
|
|
4858
|
+
);
|
|
4859
|
+
if (!hasMeta)
|
|
4860
|
+
return true;
|
|
4861
|
+
const row = d.get(
|
|
4862
|
+
`SELECT value FROM schema_meta WHERE key = ?`,
|
|
4863
|
+
[RETRIEVAL_MIGRATION_KEY]
|
|
4864
|
+
);
|
|
4865
|
+
return row?.value !== "complete";
|
|
4866
|
+
} catch {
|
|
4867
|
+
return true;
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4811
4870
|
function closeDb() {
|
|
4812
4871
|
if (db) {
|
|
4813
4872
|
db.close();
|
|
@@ -4918,16 +4977,18 @@ function cleanupWasmArtifacts(dbPath2) {
|
|
|
4918
4977
|
} catch {
|
|
4919
4978
|
}
|
|
4920
4979
|
}
|
|
4921
|
-
|
|
4922
|
-
|
|
4980
|
+
var RETRIEVAL_SCHEMA_DDL = {
|
|
4981
|
+
/** messages + provenance tables + indexes (no FTS objects). */
|
|
4982
|
+
tables: `
|
|
4923
4983
|
CREATE TABLE IF NOT EXISTS messages (
|
|
4924
|
-
message_id
|
|
4925
|
-
session_id
|
|
4926
|
-
message_seq
|
|
4927
|
-
message_text
|
|
4928
|
-
project_id
|
|
4929
|
-
created_at
|
|
4930
|
-
message_role
|
|
4984
|
+
message_id TEXT PRIMARY KEY,
|
|
4985
|
+
session_id TEXT NOT NULL,
|
|
4986
|
+
message_seq INTEGER NOT NULL,
|
|
4987
|
+
message_text TEXT NOT NULL,
|
|
4988
|
+
project_id TEXT,
|
|
4989
|
+
created_at INTEGER NOT NULL,
|
|
4990
|
+
message_role TEXT,
|
|
4991
|
+
retrieval_class TEXT NOT NULL DEFAULT 'hot',
|
|
4931
4992
|
UNIQUE(session_id, message_id)
|
|
4932
4993
|
);
|
|
4933
4994
|
|
|
@@ -4939,68 +5000,134 @@ function ensureSchema(db3) {
|
|
|
4939
5000
|
-- embed drain and every Stop-hook catch-up. This index serves the ORDER BY so
|
|
4940
5001
|
-- the planner walks it and early-terminates at LIMIT instead.
|
|
4941
5002
|
CREATE INDEX IF NOT EXISTS idx_messages_created_at ON messages(created_at);
|
|
4942
|
-
|
|
4943
|
-
|
|
5003
|
+
|
|
5004
|
+
-- session_provenance \u2014 durable per-session classification evidence:
|
|
5005
|
+
-- canonical id, vendor, root-vs-agent kind, parent thread, hook/agent
|
|
5006
|
+
-- metadata, and the transcript path \u2192 canonical id mapping that lets
|
|
5007
|
+
-- later T1/mtime scans resolve a child to ONE identity.
|
|
5008
|
+
CREATE TABLE IF NOT EXISTS session_provenance (
|
|
5009
|
+
session_id TEXT PRIMARY KEY,
|
|
5010
|
+
vendor TEXT NOT NULL,
|
|
5011
|
+
kind TEXT NOT NULL,
|
|
5012
|
+
parent_session_id TEXT,
|
|
5013
|
+
agent_depth INTEGER,
|
|
5014
|
+
agent_meta TEXT,
|
|
5015
|
+
transcript_path TEXT,
|
|
5016
|
+
updated_at INTEGER NOT NULL
|
|
5017
|
+
);
|
|
5018
|
+
CREATE INDEX IF NOT EXISTS idx_provenance_path ON session_provenance(transcript_path);
|
|
5019
|
+
|
|
5020
|
+
-- session_aliases \u2014 alternate identifiers (e.g. a hook agent_id that
|
|
5021
|
+
-- differs from the child rollout's session-meta UUID) \u2192 canonical id.
|
|
5022
|
+
CREATE TABLE IF NOT EXISTS session_aliases (
|
|
5023
|
+
alias_id TEXT PRIMARY KEY,
|
|
5024
|
+
session_id TEXT NOT NULL,
|
|
5025
|
+
source TEXT,
|
|
5026
|
+
created_at INTEGER NOT NULL
|
|
5027
|
+
);
|
|
5028
|
+
|
|
5029
|
+
CREATE TABLE IF NOT EXISTS schema_meta (
|
|
5030
|
+
key TEXT PRIMARY KEY,
|
|
5031
|
+
value TEXT NOT NULL
|
|
5032
|
+
);
|
|
5033
|
+
`,
|
|
5034
|
+
/** Filtered external-content view + FTS + four-state triggers + vocab. */
|
|
5035
|
+
fts: `
|
|
5036
|
+
-- Filtered external-content source: FTS5 rebuild/integrity-check read
|
|
5037
|
+
-- THIS view, so 'rebuild' repopulates only hot rows and the (rank-1)
|
|
5038
|
+
-- integrity check compares against the filtered corpus.
|
|
5039
|
+
CREATE VIEW IF NOT EXISTS searchable_messages AS
|
|
5040
|
+
SELECT rowid, message_text FROM messages WHERE retrieval_class = 'hot';
|
|
5041
|
+
|
|
4944
5042
|
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
|
|
4945
5043
|
message_text,
|
|
4946
|
-
content=
|
|
5044
|
+
content=searchable_messages,
|
|
4947
5045
|
content_rowid=rowid,
|
|
4948
5046
|
tokenize='porter unicode61'
|
|
4949
5047
|
);
|
|
4950
5048
|
|
|
4951
|
-
|
|
5049
|
+
-- Four-state trigger behavior:
|
|
5050
|
+
-- insert hot \u2192 add | insert agent \u2192 no-op
|
|
5051
|
+
-- delete hot \u2192 delete | delete agent \u2192 no-op
|
|
5052
|
+
-- update hot\u2192hot \u2192 delete old + add new
|
|
5053
|
+
-- update hot\u2192agent \u2192 delete old only
|
|
5054
|
+
-- update agent\u2192hot \u2192 add new only
|
|
5055
|
+
-- update agent\u2192agent \u2192 no-op
|
|
5056
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ai AFTER INSERT ON messages
|
|
5057
|
+
WHEN new.retrieval_class = 'hot'
|
|
5058
|
+
BEGIN
|
|
4952
5059
|
INSERT INTO messages_fts(rowid, message_text) VALUES (new.rowid, new.message_text);
|
|
4953
5060
|
END;
|
|
4954
5061
|
|
|
4955
|
-
CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages
|
|
5062
|
+
CREATE TRIGGER IF NOT EXISTS messages_fts_ad AFTER DELETE ON messages
|
|
5063
|
+
WHEN old.retrieval_class = 'hot'
|
|
5064
|
+
BEGIN
|
|
4956
5065
|
INSERT INTO messages_fts(messages_fts, rowid, message_text)
|
|
4957
5066
|
VALUES ('delete', old.rowid, old.message_text);
|
|
4958
5067
|
END;
|
|
4959
5068
|
|
|
4960
5069
|
CREATE TRIGGER IF NOT EXISTS messages_fts_au AFTER UPDATE ON messages BEGIN
|
|
4961
5070
|
INSERT INTO messages_fts(messages_fts, rowid, message_text)
|
|
4962
|
-
|
|
4963
|
-
INSERT INTO messages_fts(rowid, message_text)
|
|
5071
|
+
SELECT 'delete', old.rowid, old.message_text WHERE old.retrieval_class = 'hot';
|
|
5072
|
+
INSERT INTO messages_fts(rowid, message_text)
|
|
5073
|
+
SELECT new.rowid, new.message_text WHERE new.retrieval_class = 'hot';
|
|
4964
5074
|
END;
|
|
4965
|
-
|
|
4966
|
-
db3.exec(`
|
|
5075
|
+
|
|
4967
5076
|
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts_vocab
|
|
4968
5077
|
USING fts5vocab(messages_fts, 'row');
|
|
4969
|
-
`
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
5078
|
+
`
|
|
5079
|
+
};
|
|
5080
|
+
function ensureSchema(db3) {
|
|
5081
|
+
db3.exec("BEGIN IMMEDIATE");
|
|
5082
|
+
try {
|
|
5083
|
+
db3.exec(RETRIEVAL_SCHEMA_DDL.tables);
|
|
5084
|
+
db3.exec(RETRIEVAL_SCHEMA_DDL.fts);
|
|
5085
|
+
db3.exec(`
|
|
5086
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS _stem USING fts5(
|
|
5087
|
+
t, tokenize='porter unicode61'
|
|
5088
|
+
);
|
|
5089
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS _stem_vocab
|
|
5090
|
+
USING fts5vocab(_stem, 'row');
|
|
5091
|
+
`);
|
|
5092
|
+
db3.exec(`
|
|
5093
|
+
CREATE TABLE IF NOT EXISTS message_vectors (
|
|
5094
|
+
message_id TEXT PRIMARY KEY REFERENCES messages(message_id) ON DELETE CASCADE,
|
|
5095
|
+
embedding_q8 BLOB NOT NULL,
|
|
5096
|
+
norm REAL NOT NULL,
|
|
5097
|
+
quant_scale REAL NOT NULL,
|
|
5098
|
+
embed_version INTEGER NOT NULL DEFAULT 1
|
|
5099
|
+
);
|
|
5100
|
+
`);
|
|
5101
|
+
const hasEmbedVersion = () => db3.all(`PRAGMA table_info(message_vectors)`).some((c) => c.name === "embed_version");
|
|
5102
|
+
if (!hasEmbedVersion()) {
|
|
5103
|
+
try {
|
|
5104
|
+
db3.exec(`ALTER TABLE message_vectors ADD COLUMN embed_version INTEGER NOT NULL DEFAULT 1`);
|
|
5105
|
+
} catch (e) {
|
|
5106
|
+
if (!hasEmbedVersion())
|
|
5107
|
+
throw e;
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
db3.exec(`
|
|
5111
|
+
CREATE TABLE IF NOT EXISTS ingest_watermark (
|
|
5112
|
+
transcript_path TEXT PRIMARY KEY,
|
|
5113
|
+
last_mtime INTEGER NOT NULL,
|
|
5114
|
+
last_size INTEGER NOT NULL,
|
|
5115
|
+
vendor TEXT NOT NULL
|
|
5116
|
+
);
|
|
5117
|
+
CREATE INDEX IF NOT EXISTS idx_watermark_vendor ON ingest_watermark(vendor);
|
|
5118
|
+
`);
|
|
5119
|
+
db3.exec(`
|
|
5120
|
+
INSERT OR IGNORE INTO schema_meta(key, value)
|
|
5121
|
+
VALUES ('${RETRIEVAL_MIGRATION_KEY}', 'complete');
|
|
5122
|
+
`);
|
|
5123
|
+
db3.exec("COMMIT");
|
|
5124
|
+
} catch (e) {
|
|
4988
5125
|
try {
|
|
4989
|
-
db3.exec(
|
|
4990
|
-
} catch
|
|
4991
|
-
if (!hasEmbedVersion())
|
|
4992
|
-
throw e;
|
|
5126
|
+
db3.exec("ROLLBACK");
|
|
5127
|
+
} catch {
|
|
4993
5128
|
}
|
|
5129
|
+
throw e;
|
|
4994
5130
|
}
|
|
4995
|
-
db3.exec(`
|
|
4996
|
-
CREATE TABLE IF NOT EXISTS ingest_watermark (
|
|
4997
|
-
transcript_path TEXT PRIMARY KEY,
|
|
4998
|
-
last_mtime INTEGER NOT NULL,
|
|
4999
|
-
last_size INTEGER NOT NULL,
|
|
5000
|
-
vendor TEXT NOT NULL
|
|
5001
|
-
);
|
|
5002
|
-
CREATE INDEX IF NOT EXISTS idx_watermark_vendor ON ingest_watermark(vendor);
|
|
5003
|
-
`);
|
|
5004
5131
|
}
|
|
5005
5132
|
|
|
5006
5133
|
// src/recall/message-store.ts
|
|
@@ -5037,7 +5164,7 @@ function ensureDir2() {
|
|
|
5037
5164
|
}
|
|
5038
5165
|
}
|
|
5039
5166
|
function insertMessages(messages, opts) {
|
|
5040
|
-
if (messages.length === 0 && !opts?.replaceSessionId)
|
|
5167
|
+
if (messages.length === 0 && !opts?.replaceSessionId && !opts?.provenance)
|
|
5041
5168
|
return;
|
|
5042
5169
|
ensureDir2();
|
|
5043
5170
|
const d = db2();
|
|
@@ -5053,8 +5180,8 @@ function insertMessages(messages, opts) {
|
|
|
5053
5180
|
}
|
|
5054
5181
|
const stmt = d.prepare(
|
|
5055
5182
|
`INSERT OR IGNORE INTO messages
|
|
5056
|
-
(message_id, session_id, message_seq, message_text, project_id, created_at, message_role)
|
|
5057
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
5183
|
+
(message_id, session_id, message_seq, message_text, project_id, created_at, message_role, retrieval_class)
|
|
5184
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
|
|
5058
5185
|
);
|
|
5059
5186
|
for (const m of messages) {
|
|
5060
5187
|
stmt.run([
|
|
@@ -5064,9 +5191,55 @@ function insertMessages(messages, opts) {
|
|
|
5064
5191
|
m.message_text,
|
|
5065
5192
|
m.project_id,
|
|
5066
5193
|
m.created_at,
|
|
5067
|
-
m.message_role
|
|
5194
|
+
m.message_role,
|
|
5195
|
+
m.retrieval_class ?? "hot"
|
|
5068
5196
|
]);
|
|
5069
5197
|
}
|
|
5198
|
+
if (opts?.provenance) {
|
|
5199
|
+
const p = opts.provenance;
|
|
5200
|
+
d.run(
|
|
5201
|
+
`INSERT INTO session_provenance
|
|
5202
|
+
(session_id, vendor, kind, parent_session_id, agent_depth, agent_meta, transcript_path, updated_at)
|
|
5203
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
5204
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
5205
|
+
vendor = excluded.vendor,
|
|
5206
|
+
kind = excluded.kind,
|
|
5207
|
+
parent_session_id = COALESCE(excluded.parent_session_id, session_provenance.parent_session_id),
|
|
5208
|
+
agent_depth = COALESCE(excluded.agent_depth, session_provenance.agent_depth),
|
|
5209
|
+
agent_meta = COALESCE(excluded.agent_meta, session_provenance.agent_meta),
|
|
5210
|
+
transcript_path = COALESCE(excluded.transcript_path, session_provenance.transcript_path),
|
|
5211
|
+
updated_at = excluded.updated_at`,
|
|
5212
|
+
[
|
|
5213
|
+
p.sessionId,
|
|
5214
|
+
p.vendor,
|
|
5215
|
+
p.kind,
|
|
5216
|
+
p.parentSessionId,
|
|
5217
|
+
p.agentDepth,
|
|
5218
|
+
p.agentMeta ? JSON.stringify(p.agentMeta) : null,
|
|
5219
|
+
p.transcriptPath,
|
|
5220
|
+
Date.now()
|
|
5221
|
+
]
|
|
5222
|
+
);
|
|
5223
|
+
if (p.kind === "agent") {
|
|
5224
|
+
d.run(
|
|
5225
|
+
`UPDATE messages SET retrieval_class = 'agent'
|
|
5226
|
+
WHERE session_id = ? AND retrieval_class != 'agent'`,
|
|
5227
|
+
[p.sessionId]
|
|
5228
|
+
);
|
|
5229
|
+
d.run(
|
|
5230
|
+
`DELETE FROM message_vectors WHERE message_id IN
|
|
5231
|
+
(SELECT message_id FROM messages WHERE session_id = ?)`,
|
|
5232
|
+
[p.sessionId]
|
|
5233
|
+
);
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
for (const a of opts?.aliases ?? []) {
|
|
5237
|
+
d.run(
|
|
5238
|
+
`INSERT OR REPLACE INTO session_aliases (alias_id, session_id, source, created_at)
|
|
5239
|
+
VALUES (?, ?, ?, ?)`,
|
|
5240
|
+
[a.aliasId, a.sessionId, a.source, Date.now()]
|
|
5241
|
+
);
|
|
5242
|
+
}
|
|
5070
5243
|
d.exec("COMMIT");
|
|
5071
5244
|
} catch (e) {
|
|
5072
5245
|
d.exec("ROLLBACK");
|
|
@@ -5083,15 +5256,17 @@ function insertMessageVectors(records) {
|
|
|
5083
5256
|
const stmt = d.prepare(
|
|
5084
5257
|
`INSERT OR REPLACE INTO message_vectors
|
|
5085
5258
|
(message_id, embedding_q8, norm, quant_scale, embed_version)
|
|
5086
|
-
|
|
5259
|
+
SELECT m.message_id, ?, ?, ?, ?
|
|
5260
|
+
FROM messages m
|
|
5261
|
+
WHERE m.message_id = ? AND m.retrieval_class = 'hot'`
|
|
5087
5262
|
);
|
|
5088
5263
|
for (const r of records) {
|
|
5089
5264
|
stmt.run([
|
|
5090
|
-
r.messageId,
|
|
5091
5265
|
Buffer.from(r.embeddingQ8.buffer, r.embeddingQ8.byteOffset, r.embeddingQ8.byteLength),
|
|
5092
5266
|
r.norm,
|
|
5093
5267
|
r.quantScale,
|
|
5094
|
-
EMBED_VERSION
|
|
5268
|
+
EMBED_VERSION,
|
|
5269
|
+
r.messageId
|
|
5095
5270
|
]);
|
|
5096
5271
|
}
|
|
5097
5272
|
d.exec("COMMIT");
|
|
@@ -5106,12 +5281,13 @@ function getUnembeddedMessages(limit) {
|
|
|
5106
5281
|
const rows = db2().all(
|
|
5107
5282
|
`SELECT m.message_id, m.session_id, m.message_text,
|
|
5108
5283
|
(SELECT p.message_text FROM messages p
|
|
5109
|
-
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq
|
|
5284
|
+
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq AND p.retrieval_class = 'hot'
|
|
5110
5285
|
ORDER BY p.message_seq DESC LIMIT 1) AS prev_text
|
|
5111
5286
|
FROM messages m
|
|
5112
5287
|
WHERE m.message_text != ''
|
|
5288
|
+
AND m.retrieval_class = 'hot'
|
|
5113
5289
|
AND (LENGTH(m.message_text) >= ${MIN_EMBED_CHARS}
|
|
5114
|
-
OR EXISTS (SELECT 1 FROM messages p2 WHERE p2.session_id = m.session_id AND p2.message_seq < m.message_seq))
|
|
5290
|
+
OR EXISTS (SELECT 1 FROM messages p2 WHERE p2.session_id = m.session_id AND p2.message_seq < m.message_seq AND p2.retrieval_class = 'hot'))
|
|
5115
5291
|
AND NOT EXISTS (SELECT 1 FROM message_vectors mv WHERE mv.message_id = m.message_id AND mv.embed_version = ?)
|
|
5116
5292
|
ORDER BY m.created_at DESC
|
|
5117
5293
|
LIMIT ?`,
|
|
@@ -5132,6 +5308,260 @@ function getUnembeddedMessages(limit) {
|
|
|
5132
5308
|
}
|
|
5133
5309
|
}
|
|
5134
5310
|
|
|
5311
|
+
// src/recall/session-classifier.ts
|
|
5312
|
+
init_paths();
|
|
5313
|
+
init_log();
|
|
5314
|
+
|
|
5315
|
+
// src/adapters/codex/codex-jsonl-reader.ts
|
|
5316
|
+
var fs = __toESM(require("fs"));
|
|
5317
|
+
init_log();
|
|
5318
|
+
function parseCodexJsonlFile(filepath) {
|
|
5319
|
+
try {
|
|
5320
|
+
const content = fs.readFileSync(filepath, "utf-8");
|
|
5321
|
+
const lines = content.split("\n");
|
|
5322
|
+
const records = [];
|
|
5323
|
+
for (const line of lines) {
|
|
5324
|
+
const trimmed = line.trim();
|
|
5325
|
+
if (!trimmed)
|
|
5326
|
+
continue;
|
|
5327
|
+
try {
|
|
5328
|
+
const record = JSON.parse(trimmed);
|
|
5329
|
+
records.push(record);
|
|
5330
|
+
} catch (err) {
|
|
5331
|
+
log({ level: "warn", source: "codex-jsonl-reader", summary: `Skipping unparseable line: ${err.message}` });
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
return records;
|
|
5335
|
+
} catch (error) {
|
|
5336
|
+
log({ level: "error", source: "codex-jsonl-reader", summary: `Failed to read ${filepath}: ${error instanceof Error ? error.message : String(error)}`, data: { filepath, error: String(error) } });
|
|
5337
|
+
return [];
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
function extractCodexSessionMeta(filepath) {
|
|
5341
|
+
let fd = null;
|
|
5342
|
+
try {
|
|
5343
|
+
fd = fs.openSync(filepath, "r");
|
|
5344
|
+
const buffer = Buffer.alloc(8192);
|
|
5345
|
+
const bytesRead = fs.readSync(fd, buffer, 0, 8192, 0);
|
|
5346
|
+
if (bytesRead === 0)
|
|
5347
|
+
return null;
|
|
5348
|
+
const content = buffer.toString("utf-8", 0, bytesRead);
|
|
5349
|
+
const newlineIdx = content.indexOf("\n");
|
|
5350
|
+
const firstLine = newlineIdx >= 0 ? content.slice(0, newlineIdx) : content;
|
|
5351
|
+
const record = JSON.parse(firstLine.trim());
|
|
5352
|
+
if (record.type !== "session_meta")
|
|
5353
|
+
return null;
|
|
5354
|
+
const payload = record.payload;
|
|
5355
|
+
return {
|
|
5356
|
+
id: payload.id,
|
|
5357
|
+
cwd: payload.cwd,
|
|
5358
|
+
cli_version: payload.cli_version,
|
|
5359
|
+
git: payload.git,
|
|
5360
|
+
...payload.source && typeof payload.source === "object" ? { source: payload.source } : {}
|
|
5361
|
+
};
|
|
5362
|
+
} catch {
|
|
5363
|
+
return null;
|
|
5364
|
+
} finally {
|
|
5365
|
+
if (fd !== null) {
|
|
5366
|
+
try {
|
|
5367
|
+
fs.closeSync(fd);
|
|
5368
|
+
} catch {
|
|
5369
|
+
}
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5372
|
+
}
|
|
5373
|
+
var READ_BUFFER_SIZE = 64 * 1024;
|
|
5374
|
+
var TURN_CONTENT_CAP = 8 * 1024;
|
|
5375
|
+
|
|
5376
|
+
// src/recall/session-classifier.ts
|
|
5377
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5378
|
+
var ROLLOUT_UUID_RE = /rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
|
|
5379
|
+
function normalize(p) {
|
|
5380
|
+
return p.replace(/\\/g, "/");
|
|
5381
|
+
}
|
|
5382
|
+
function basenameNoExt(p) {
|
|
5383
|
+
return normalize(p).split("/").pop().replace(/\.jsonl$/i, "");
|
|
5384
|
+
}
|
|
5385
|
+
function lookupStoredProvenance(transcriptPath) {
|
|
5386
|
+
try {
|
|
5387
|
+
const row = getDb(dbPath()).get(
|
|
5388
|
+
`SELECT session_id, kind, parent_session_id FROM session_provenance
|
|
5389
|
+
WHERE transcript_path = ? LIMIT 1`,
|
|
5390
|
+
[normalize(transcriptPath)]
|
|
5391
|
+
);
|
|
5392
|
+
return row ?? null;
|
|
5393
|
+
} catch {
|
|
5394
|
+
return null;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
function claudeSubagentParent(normPath) {
|
|
5398
|
+
const segments = normPath.split("/");
|
|
5399
|
+
const idx = segments.lastIndexOf("subagents");
|
|
5400
|
+
if (idx <= 0)
|
|
5401
|
+
return null;
|
|
5402
|
+
const parent = segments[idx - 1];
|
|
5403
|
+
return parent || null;
|
|
5404
|
+
}
|
|
5405
|
+
function classifySession(args) {
|
|
5406
|
+
const { sessionId, transcriptPath, vendor, hook } = args;
|
|
5407
|
+
const normPath = normalize(transcriptPath);
|
|
5408
|
+
const base = basenameNoExt(transcriptPath);
|
|
5409
|
+
const stored = lookupStoredProvenance(transcriptPath);
|
|
5410
|
+
if (stored && !(stored.kind !== "agent" && hook?.isSubagent)) {
|
|
5411
|
+
return {
|
|
5412
|
+
kind: stored.kind === "agent" ? "agent" : "root",
|
|
5413
|
+
canonicalSessionId: stored.session_id,
|
|
5414
|
+
parentSessionId: stored.parent_session_id,
|
|
5415
|
+
agentDepth: null,
|
|
5416
|
+
agentMeta: null,
|
|
5417
|
+
aliases: aliasCandidates(stored.session_id, sessionId, hook),
|
|
5418
|
+
evidence: "stored"
|
|
5419
|
+
};
|
|
5420
|
+
}
|
|
5421
|
+
if (vendor === "claude")
|
|
5422
|
+
return classifyClaude(sessionId, normPath, base, hook);
|
|
5423
|
+
return classifyCodex(sessionId, transcriptPath, base, hook);
|
|
5424
|
+
}
|
|
5425
|
+
function aliasCandidates(canonical, proposed, hook) {
|
|
5426
|
+
const out = /* @__PURE__ */ new Set();
|
|
5427
|
+
if (hook?.agentId && hook.agentId !== canonical)
|
|
5428
|
+
out.add(hook.agentId);
|
|
5429
|
+
if (proposed && proposed !== canonical)
|
|
5430
|
+
out.add(proposed);
|
|
5431
|
+
return [...out];
|
|
5432
|
+
}
|
|
5433
|
+
function classifyClaude(sessionId, normPath, base, hook) {
|
|
5434
|
+
if (normPath.includes("/subagents/") && base.startsWith("agent-")) {
|
|
5435
|
+
return {
|
|
5436
|
+
kind: "agent",
|
|
5437
|
+
canonicalSessionId: base,
|
|
5438
|
+
parentSessionId: claudeSubagentParent(normPath) ?? hook?.payloadSessionId ?? null,
|
|
5439
|
+
agentDepth: null,
|
|
5440
|
+
agentMeta: hook?.agentId ? { hookAgentId: hook.agentId } : null,
|
|
5441
|
+
aliases: aliasCandidates(base, sessionId, hook),
|
|
5442
|
+
evidence: "claude-path"
|
|
5443
|
+
};
|
|
5444
|
+
}
|
|
5445
|
+
if (base.startsWith("agent-") || sessionId.startsWith("agent-")) {
|
|
5446
|
+
const canonical = base.startsWith("agent-") ? base : sessionId;
|
|
5447
|
+
return {
|
|
5448
|
+
kind: "agent",
|
|
5449
|
+
canonicalSessionId: canonical,
|
|
5450
|
+
parentSessionId: hook?.payloadSessionId ?? null,
|
|
5451
|
+
agentDepth: null,
|
|
5452
|
+
agentMeta: hook?.agentId ? { hookAgentId: hook.agentId } : null,
|
|
5453
|
+
aliases: aliasCandidates(canonical, sessionId, hook),
|
|
5454
|
+
evidence: "claude-name"
|
|
5455
|
+
};
|
|
5456
|
+
}
|
|
5457
|
+
if (hook?.isSubagent) {
|
|
5458
|
+
return {
|
|
5459
|
+
kind: "agent",
|
|
5460
|
+
canonicalSessionId: base || sessionId,
|
|
5461
|
+
parentSessionId: hook.payloadSessionId ?? null,
|
|
5462
|
+
agentDepth: null,
|
|
5463
|
+
agentMeta: hook.agentId ? { hookAgentId: hook.agentId } : null,
|
|
5464
|
+
aliases: aliasCandidates(base || sessionId, sessionId, hook),
|
|
5465
|
+
evidence: "hook"
|
|
5466
|
+
};
|
|
5467
|
+
}
|
|
5468
|
+
return {
|
|
5469
|
+
kind: "root",
|
|
5470
|
+
canonicalSessionId: sessionId,
|
|
5471
|
+
parentSessionId: null,
|
|
5472
|
+
agentDepth: null,
|
|
5473
|
+
agentMeta: null,
|
|
5474
|
+
aliases: [],
|
|
5475
|
+
evidence: "default-root"
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
function classifyCodex(sessionId, transcriptPath, base, hook) {
|
|
5479
|
+
const meta = extractCodexSessionMeta(transcriptPath);
|
|
5480
|
+
const filenameUuid = ROLLOUT_UUID_RE.exec(normalize(transcriptPath))?.[1] ?? null;
|
|
5481
|
+
const canonical = meta?.id && typeof meta.id === "string" && meta.id.length > 0 ? meta.id : filenameUuid ?? (UUID_RE.test(sessionId) ? sessionId : null);
|
|
5482
|
+
const sub = parseSubagentSource(meta?.source, transcriptPath);
|
|
5483
|
+
if (sub.malformed) {
|
|
5484
|
+
log({
|
|
5485
|
+
source: "recall:classify",
|
|
5486
|
+
level: "warn",
|
|
5487
|
+
summary: `codex session_meta.source looks subagent-like but is malformed \u2014 leaving session hot (conservative): ${transcriptPath}`
|
|
5488
|
+
});
|
|
5489
|
+
}
|
|
5490
|
+
if (sub.isSubagent || hook?.isSubagent) {
|
|
5491
|
+
if (!canonical) {
|
|
5492
|
+
log({
|
|
5493
|
+
source: "recall:classify",
|
|
5494
|
+
level: "warn",
|
|
5495
|
+
summary: `codex subagent transcript has no derivable canonical id \u2014 skipping ingest (conservative): ${transcriptPath}`
|
|
5496
|
+
});
|
|
5497
|
+
return {
|
|
5498
|
+
kind: "agent",
|
|
5499
|
+
canonicalSessionId: base || sessionId,
|
|
5500
|
+
parentSessionId: sub.parentThreadId ?? hook?.payloadSessionId ?? null,
|
|
5501
|
+
agentDepth: sub.depth,
|
|
5502
|
+
agentMeta: sub.meta,
|
|
5503
|
+
aliases: [],
|
|
5504
|
+
evidence: sub.isSubagent ? "codex-meta" : "hook",
|
|
5505
|
+
unresolvable: true
|
|
5506
|
+
};
|
|
5507
|
+
}
|
|
5508
|
+
return {
|
|
5509
|
+
kind: "agent",
|
|
5510
|
+
canonicalSessionId: canonical,
|
|
5511
|
+
parentSessionId: sub.parentThreadId ?? hook?.payloadSessionId ?? null,
|
|
5512
|
+
agentDepth: sub.depth,
|
|
5513
|
+
agentMeta: mergeMeta(sub.meta, hook?.agentId),
|
|
5514
|
+
aliases: aliasCandidates(canonical, sessionId, hook),
|
|
5515
|
+
evidence: sub.isSubagent ? "codex-meta" : "hook"
|
|
5516
|
+
};
|
|
5517
|
+
}
|
|
5518
|
+
return {
|
|
5519
|
+
kind: "root",
|
|
5520
|
+
canonicalSessionId: canonical ?? sessionId,
|
|
5521
|
+
parentSessionId: null,
|
|
5522
|
+
agentDepth: null,
|
|
5523
|
+
agentMeta: null,
|
|
5524
|
+
aliases: canonical && canonical !== sessionId ? [sessionId] : [],
|
|
5525
|
+
evidence: "default-root"
|
|
5526
|
+
};
|
|
5527
|
+
}
|
|
5528
|
+
function mergeMeta(meta, hookAgentId) {
|
|
5529
|
+
if (!hookAgentId)
|
|
5530
|
+
return meta;
|
|
5531
|
+
return { ...meta ?? {}, hookAgentId };
|
|
5532
|
+
}
|
|
5533
|
+
function parseSubagentSource(source, _transcriptPath) {
|
|
5534
|
+
const none = { isSubagent: false, malformed: false, parentThreadId: null, depth: null, meta: null };
|
|
5535
|
+
if (!source || typeof source !== "object")
|
|
5536
|
+
return none;
|
|
5537
|
+
const subRaw = source.subagent;
|
|
5538
|
+
const typeTag = source.type;
|
|
5539
|
+
const looksSubagent = subRaw !== void 0 || typeTag === "subagent";
|
|
5540
|
+
if (!looksSubagent)
|
|
5541
|
+
return none;
|
|
5542
|
+
if (subRaw !== void 0 && (typeof subRaw !== "object" || subRaw === null)) {
|
|
5543
|
+
return { ...none, malformed: true };
|
|
5544
|
+
}
|
|
5545
|
+
const sub = subRaw ?? {};
|
|
5546
|
+
const spawnRaw = sub.thread_spawn ?? source.thread_spawn;
|
|
5547
|
+
const spawn2 = spawnRaw && typeof spawnRaw === "object" ? spawnRaw : {};
|
|
5548
|
+
const parentThreadId = typeof spawn2.parent_thread_id === "string" && spawn2.parent_thread_id ? spawn2.parent_thread_id : null;
|
|
5549
|
+
const depth = typeof spawn2.depth === "number" && Number.isFinite(spawn2.depth) ? spawn2.depth : null;
|
|
5550
|
+
const meta = {};
|
|
5551
|
+
for (const k of ["agent_path", "agent_type", "agent_name", "path", "type", "name"]) {
|
|
5552
|
+
const v = spawn2[k] ?? sub[k];
|
|
5553
|
+
if (typeof v === "string" || typeof v === "number")
|
|
5554
|
+
meta[k] = v;
|
|
5555
|
+
}
|
|
5556
|
+
return {
|
|
5557
|
+
isSubagent: true,
|
|
5558
|
+
malformed: false,
|
|
5559
|
+
parentThreadId,
|
|
5560
|
+
depth,
|
|
5561
|
+
meta: Object.keys(meta).length > 0 ? meta : null
|
|
5562
|
+
};
|
|
5563
|
+
}
|
|
5564
|
+
|
|
5135
5565
|
// src/recall/message-ingest.ts
|
|
5136
5566
|
init_paths();
|
|
5137
5567
|
|
|
@@ -5150,13 +5580,13 @@ function normalizePath(p) {
|
|
|
5150
5580
|
init_log();
|
|
5151
5581
|
|
|
5152
5582
|
// src/adapters/claude/jsonl-reader.ts
|
|
5153
|
-
var
|
|
5583
|
+
var fs2 = __toESM(require("fs"));
|
|
5154
5584
|
init_log();
|
|
5155
|
-
var
|
|
5156
|
-
var
|
|
5585
|
+
var READ_BUFFER_SIZE2 = 64 * 1024;
|
|
5586
|
+
var TURN_CONTENT_CAP2 = 8 * 1024;
|
|
5157
5587
|
function parseJsonlFile(filepath) {
|
|
5158
5588
|
try {
|
|
5159
|
-
const content =
|
|
5589
|
+
const content = fs2.readFileSync(filepath, "utf-8");
|
|
5160
5590
|
const lines = content.split("\n");
|
|
5161
5591
|
const entries = [];
|
|
5162
5592
|
for (const line of lines) {
|
|
@@ -5345,37 +5775,6 @@ function adaptClaudeEntries(rawEntries) {
|
|
|
5345
5775
|
return rawEntries.map(adaptClaudeEntry).filter((entry) => entry !== null);
|
|
5346
5776
|
}
|
|
5347
5777
|
|
|
5348
|
-
// src/adapters/codex/codex-jsonl-reader.ts
|
|
5349
|
-
var fs2 = __toESM(require("fs"));
|
|
5350
|
-
init_log();
|
|
5351
|
-
var path = __toESM(require("path"));
|
|
5352
|
-
var os = __toESM(require("os"));
|
|
5353
|
-
var CODEX_SESSIONS_DIR = path.join(os.homedir(), ".codex", "sessions");
|
|
5354
|
-
function parseCodexJsonlFile(filepath) {
|
|
5355
|
-
try {
|
|
5356
|
-
const content = fs2.readFileSync(filepath, "utf-8");
|
|
5357
|
-
const lines = content.split("\n");
|
|
5358
|
-
const records = [];
|
|
5359
|
-
for (const line of lines) {
|
|
5360
|
-
const trimmed = line.trim();
|
|
5361
|
-
if (!trimmed)
|
|
5362
|
-
continue;
|
|
5363
|
-
try {
|
|
5364
|
-
const record = JSON.parse(trimmed);
|
|
5365
|
-
records.push(record);
|
|
5366
|
-
} catch (err) {
|
|
5367
|
-
log({ level: "warn", source: "codex-jsonl-reader", summary: `Skipping unparseable line: ${err.message}` });
|
|
5368
|
-
}
|
|
5369
|
-
}
|
|
5370
|
-
return records;
|
|
5371
|
-
} catch (error) {
|
|
5372
|
-
log({ level: "error", source: "codex-jsonl-reader", summary: `Failed to read ${filepath}: ${error instanceof Error ? error.message : String(error)}`, data: { filepath, error: String(error) } });
|
|
5373
|
-
return [];
|
|
5374
|
-
}
|
|
5375
|
-
}
|
|
5376
|
-
var READ_BUFFER_SIZE2 = 64 * 1024;
|
|
5377
|
-
var TURN_CONTENT_CAP2 = 8 * 1024;
|
|
5378
|
-
|
|
5379
5778
|
// src/adapters/codex/codex-jsonl-adapter.ts
|
|
5380
5779
|
function adaptCodexJsonlRecords(records, sessionId) {
|
|
5381
5780
|
const outputIndex = /* @__PURE__ */ new Map();
|
|
@@ -6010,6 +6409,36 @@ function entriesCwd(entries) {
|
|
|
6010
6409
|
return void 0;
|
|
6011
6410
|
}
|
|
6012
6411
|
async function ingestSessionMessages(sessionId, transcriptPath, vendor, options) {
|
|
6412
|
+
const classification = classifySession({
|
|
6413
|
+
sessionId,
|
|
6414
|
+
transcriptPath,
|
|
6415
|
+
vendor,
|
|
6416
|
+
...options?.hook ? { hook: options.hook } : {}
|
|
6417
|
+
});
|
|
6418
|
+
if (classification.unresolvable) {
|
|
6419
|
+
return {
|
|
6420
|
+
sessionId,
|
|
6421
|
+
chunksCreated: 0,
|
|
6422
|
+
skipped: true,
|
|
6423
|
+
error: "subagent transcript has no derivable canonical identity \u2014 skipped (conservative)"
|
|
6424
|
+
};
|
|
6425
|
+
}
|
|
6426
|
+
const canonicalId = classification.canonicalSessionId;
|
|
6427
|
+
const retrievalClass = classification.kind === "agent" ? "agent" : "hot";
|
|
6428
|
+
const provenance = {
|
|
6429
|
+
sessionId: canonicalId,
|
|
6430
|
+
vendor,
|
|
6431
|
+
kind: classification.kind,
|
|
6432
|
+
parentSessionId: classification.parentSessionId,
|
|
6433
|
+
agentDepth: classification.agentDepth,
|
|
6434
|
+
agentMeta: classification.agentMeta,
|
|
6435
|
+
transcriptPath: transcriptPath.replace(/\\/g, "/")
|
|
6436
|
+
};
|
|
6437
|
+
const aliases = classification.aliases.map((aliasId) => ({
|
|
6438
|
+
aliasId,
|
|
6439
|
+
sessionId: canonicalId,
|
|
6440
|
+
source: options?.hook?.agentId === aliasId ? "hook-agent-id" : "ingest-request-id"
|
|
6441
|
+
}));
|
|
6013
6442
|
let rawEntries;
|
|
6014
6443
|
try {
|
|
6015
6444
|
if (vendor === "claude") {
|
|
@@ -6017,18 +6446,25 @@ async function ingestSessionMessages(sessionId, transcriptPath, vendor, options)
|
|
|
6017
6446
|
rawEntries = adaptClaudeEntries(raw);
|
|
6018
6447
|
} else {
|
|
6019
6448
|
const envelopes = parseCodexJsonlFile(transcriptPath);
|
|
6020
|
-
rawEntries = adaptCodexJsonlRecords(envelopes,
|
|
6449
|
+
rawEntries = adaptCodexJsonlRecords(envelopes, canonicalId);
|
|
6021
6450
|
}
|
|
6022
6451
|
} catch (err) {
|
|
6023
6452
|
return {
|
|
6024
|
-
sessionId,
|
|
6453
|
+
sessionId: canonicalId,
|
|
6025
6454
|
chunksCreated: 0,
|
|
6026
6455
|
skipped: false,
|
|
6027
|
-
error: `Failed to load session: ${err instanceof Error ? err.message : String(err)}
|
|
6456
|
+
error: `Failed to load session: ${err instanceof Error ? err.message : String(err)}`,
|
|
6457
|
+
retrievalClass
|
|
6028
6458
|
};
|
|
6029
6459
|
}
|
|
6030
6460
|
if (rawEntries.length === 0) {
|
|
6031
|
-
|
|
6461
|
+
if (options?.force) {
|
|
6462
|
+
try {
|
|
6463
|
+
insertMessages([], { replaceSessionId: canonicalId, provenance, aliases });
|
|
6464
|
+
} catch {
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
return { sessionId: canonicalId, chunksCreated: 0, skipped: true, retrievalClass };
|
|
6032
6468
|
}
|
|
6033
6469
|
const rawProjectId = options?.projectId ?? entriesCwd(rawEntries);
|
|
6034
6470
|
const projectId = rawProjectId ? normalizePath(rawProjectId) : null;
|
|
@@ -6045,31 +6481,44 @@ async function ingestSessionMessages(sessionId, transcriptPath, vendor, options)
|
|
|
6045
6481
|
const createdAt = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();
|
|
6046
6482
|
records.push({
|
|
6047
6483
|
message_id: entry.uuid,
|
|
6048
|
-
session_id:
|
|
6484
|
+
session_id: canonicalId,
|
|
6049
6485
|
message_seq: i,
|
|
6050
6486
|
message_text: text,
|
|
6051
6487
|
project_id: projectId,
|
|
6052
6488
|
created_at: createdAt,
|
|
6053
|
-
message_role: entry.message?.role ?? entry.type ?? null
|
|
6489
|
+
message_role: entry.message?.role ?? entry.type ?? null,
|
|
6490
|
+
retrieval_class: retrievalClass
|
|
6054
6491
|
});
|
|
6055
6492
|
}
|
|
6056
6493
|
if (records.length === 0) {
|
|
6057
|
-
|
|
6494
|
+
if (options?.force) {
|
|
6495
|
+
try {
|
|
6496
|
+
insertMessages([], { replaceSessionId: canonicalId, provenance, aliases });
|
|
6497
|
+
} catch {
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
return { sessionId: canonicalId, chunksCreated: 0, skipped: true, retrievalClass };
|
|
6058
6501
|
}
|
|
6059
6502
|
try {
|
|
6060
|
-
insertMessages(records,
|
|
6503
|
+
insertMessages(records, {
|
|
6504
|
+
...options?.force ? { replaceSessionId: canonicalId } : {},
|
|
6505
|
+
provenance,
|
|
6506
|
+
aliases
|
|
6507
|
+
});
|
|
6061
6508
|
} catch (err) {
|
|
6062
6509
|
return {
|
|
6063
|
-
sessionId,
|
|
6510
|
+
sessionId: canonicalId,
|
|
6064
6511
|
chunksCreated: 0,
|
|
6065
6512
|
skipped: false,
|
|
6066
|
-
error: `DB insert failed: ${err instanceof Error ? err.message : String(err)}
|
|
6513
|
+
error: `DB insert failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
6514
|
+
retrievalClass
|
|
6067
6515
|
};
|
|
6068
6516
|
}
|
|
6069
6517
|
return {
|
|
6070
|
-
sessionId,
|
|
6518
|
+
sessionId: canonicalId,
|
|
6071
6519
|
chunksCreated: records.length,
|
|
6072
|
-
skipped: false
|
|
6520
|
+
skipped: false,
|
|
6521
|
+
retrievalClass
|
|
6073
6522
|
};
|
|
6074
6523
|
}
|
|
6075
6524
|
var MAX_EMBED_CHARS = 14e3;
|
|
@@ -6113,14 +6562,14 @@ async function embedSessionMessages(sessionId, force) {
|
|
|
6113
6562
|
const rows = d.all(
|
|
6114
6563
|
force ? `SELECT m.message_id, m.message_text,
|
|
6115
6564
|
(SELECT p.message_text FROM messages p
|
|
6116
|
-
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq
|
|
6565
|
+
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq AND p.retrieval_class = 'hot'
|
|
6117
6566
|
ORDER BY p.message_seq DESC LIMIT 1) AS prev_text
|
|
6118
|
-
FROM messages m WHERE m.session_id = ? ORDER BY m.message_seq ASC` : `SELECT m.message_id, m.message_text,
|
|
6567
|
+
FROM messages m WHERE m.session_id = ? AND m.retrieval_class = 'hot' ORDER BY m.message_seq ASC` : `SELECT m.message_id, m.message_text,
|
|
6119
6568
|
(SELECT p.message_text FROM messages p
|
|
6120
|
-
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq
|
|
6569
|
+
WHERE p.session_id = m.session_id AND p.message_seq < m.message_seq AND p.retrieval_class = 'hot'
|
|
6121
6570
|
ORDER BY p.message_seq DESC LIMIT 1) AS prev_text
|
|
6122
6571
|
FROM messages m
|
|
6123
|
-
WHERE m.session_id = ?
|
|
6572
|
+
WHERE m.session_id = ? AND m.retrieval_class = 'hot'
|
|
6124
6573
|
AND NOT EXISTS (SELECT 1 FROM message_vectors mv WHERE mv.message_id = m.message_id AND mv.embed_version = ?)
|
|
6125
6574
|
ORDER BY m.message_seq ASC`,
|
|
6126
6575
|
force ? [sessionId] : [sessionId, EMBED_VERSION]
|
|
@@ -6173,7 +6622,9 @@ init_embedder();
|
|
|
6173
6622
|
var import_node_fs5 = require("node:fs");
|
|
6174
6623
|
var import_node_path5 = require("node:path");
|
|
6175
6624
|
init_paths();
|
|
6176
|
-
|
|
6625
|
+
function embedLockPath() {
|
|
6626
|
+
return (0, import_node_path5.join)(runDir(), "embed.lock");
|
|
6627
|
+
}
|
|
6177
6628
|
var STALE_MS = 30 * 60 * 1e3;
|
|
6178
6629
|
function isAlive(pid) {
|
|
6179
6630
|
try {
|
|
@@ -6186,21 +6637,21 @@ function isAlive(pid) {
|
|
|
6186
6637
|
function tryAcquireEmbedLock() {
|
|
6187
6638
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
6188
6639
|
try {
|
|
6189
|
-
(0, import_node_fs5.writeFileSync)(
|
|
6640
|
+
(0, import_node_fs5.writeFileSync)(embedLockPath(), String(process.pid), { flag: "wx" });
|
|
6190
6641
|
return true;
|
|
6191
6642
|
} catch {
|
|
6192
6643
|
let heldPid;
|
|
6193
6644
|
let ageMs;
|
|
6194
6645
|
try {
|
|
6195
|
-
heldPid = parseInt((0, import_node_fs5.readFileSync)(
|
|
6196
|
-
ageMs = Date.now() - (0, import_node_fs5.statSync)(
|
|
6646
|
+
heldPid = parseInt((0, import_node_fs5.readFileSync)(embedLockPath(), "utf8"), 10);
|
|
6647
|
+
ageMs = Date.now() - (0, import_node_fs5.statSync)(embedLockPath()).mtimeMs;
|
|
6197
6648
|
} catch {
|
|
6198
6649
|
continue;
|
|
6199
6650
|
}
|
|
6200
6651
|
if (isAlive(heldPid) && ageMs < STALE_MS)
|
|
6201
6652
|
return false;
|
|
6202
6653
|
try {
|
|
6203
|
-
(0, import_node_fs5.unlinkSync)(
|
|
6654
|
+
(0, import_node_fs5.unlinkSync)(embedLockPath());
|
|
6204
6655
|
} catch {
|
|
6205
6656
|
}
|
|
6206
6657
|
}
|
|
@@ -6209,9 +6660,9 @@ function tryAcquireEmbedLock() {
|
|
|
6209
6660
|
}
|
|
6210
6661
|
function releaseEmbedLock() {
|
|
6211
6662
|
try {
|
|
6212
|
-
const held = parseInt((0, import_node_fs5.readFileSync)(
|
|
6663
|
+
const held = parseInt((0, import_node_fs5.readFileSync)(embedLockPath(), "utf8"), 10);
|
|
6213
6664
|
if (held === process.pid)
|
|
6214
|
-
(0, import_node_fs5.unlinkSync)(
|
|
6665
|
+
(0, import_node_fs5.unlinkSync)(embedLockPath());
|
|
6215
6666
|
} catch {
|
|
6216
6667
|
}
|
|
6217
6668
|
}
|
|
@@ -7021,11 +7472,11 @@ var qmarksTestNoExtDot = ([$0]) => {
|
|
|
7021
7472
|
return (f) => f.length === len && f !== "." && f !== "..";
|
|
7022
7473
|
};
|
|
7023
7474
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
7024
|
-
var
|
|
7475
|
+
var path = {
|
|
7025
7476
|
win32: { sep: "\\" },
|
|
7026
7477
|
posix: { sep: "/" }
|
|
7027
7478
|
};
|
|
7028
|
-
var sep = defaultPlatform === "win32" ?
|
|
7479
|
+
var sep = defaultPlatform === "win32" ? path.win32.sep : path.posix.sep;
|
|
7029
7480
|
minimatch.sep = sep;
|
|
7030
7481
|
var GLOBSTAR = Symbol("globstar **");
|
|
7031
7482
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
@@ -10057,7 +10508,7 @@ var ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
|
|
|
10057
10508
|
var TYPEMASK = 1023;
|
|
10058
10509
|
var entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
|
|
10059
10510
|
var normalizeCache = /* @__PURE__ */ new Map();
|
|
10060
|
-
var
|
|
10511
|
+
var normalize2 = (s) => {
|
|
10061
10512
|
const c = normalizeCache.get(s);
|
|
10062
10513
|
if (c)
|
|
10063
10514
|
return c;
|
|
@@ -10070,7 +10521,7 @@ var normalizeNocase = (s) => {
|
|
|
10070
10521
|
const c = normalizeNocaseCache.get(s);
|
|
10071
10522
|
if (c)
|
|
10072
10523
|
return c;
|
|
10073
|
-
const n =
|
|
10524
|
+
const n = normalize2(s.toLowerCase());
|
|
10074
10525
|
normalizeNocaseCache.set(s, n);
|
|
10075
10526
|
return n;
|
|
10076
10527
|
};
|
|
@@ -10237,7 +10688,7 @@ var PathBase = class {
|
|
|
10237
10688
|
*/
|
|
10238
10689
|
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
|
10239
10690
|
this.name = name;
|
|
10240
|
-
this.#matchName = nocase ? normalizeNocase(name) :
|
|
10691
|
+
this.#matchName = nocase ? normalizeNocase(name) : normalize2(name);
|
|
10241
10692
|
this.#type = type & TYPEMASK;
|
|
10242
10693
|
this.nocase = nocase;
|
|
10243
10694
|
this.roots = roots;
|
|
@@ -10274,12 +10725,12 @@ var PathBase = class {
|
|
|
10274
10725
|
/**
|
|
10275
10726
|
* Get the Path object referenced by the string path, resolved from this Path
|
|
10276
10727
|
*/
|
|
10277
|
-
resolve(
|
|
10278
|
-
if (!
|
|
10728
|
+
resolve(path2) {
|
|
10729
|
+
if (!path2) {
|
|
10279
10730
|
return this;
|
|
10280
10731
|
}
|
|
10281
|
-
const rootPath = this.getRootString(
|
|
10282
|
-
const dir =
|
|
10732
|
+
const rootPath = this.getRootString(path2);
|
|
10733
|
+
const dir = path2.substring(rootPath.length);
|
|
10283
10734
|
const dirParts = dir.split(this.splitSep);
|
|
10284
10735
|
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
|
|
10285
10736
|
return result;
|
|
@@ -10330,7 +10781,7 @@ var PathBase = class {
|
|
|
10330
10781
|
return this.parent || this;
|
|
10331
10782
|
}
|
|
10332
10783
|
const children = this.children();
|
|
10333
|
-
const name = this.nocase ? normalizeNocase(pathPart) :
|
|
10784
|
+
const name = this.nocase ? normalizeNocase(pathPart) : normalize2(pathPart);
|
|
10334
10785
|
for (const p of children) {
|
|
10335
10786
|
if (p.#matchName === name) {
|
|
10336
10787
|
return p;
|
|
@@ -10575,7 +11026,7 @@ var PathBase = class {
|
|
|
10575
11026
|
* directly.
|
|
10576
11027
|
*/
|
|
10577
11028
|
isNamed(n) {
|
|
10578
|
-
return !this.nocase ? this.#matchName ===
|
|
11029
|
+
return !this.nocase ? this.#matchName === normalize2(n) : this.#matchName === normalizeNocase(n);
|
|
10579
11030
|
}
|
|
10580
11031
|
/**
|
|
10581
11032
|
* Return the Path object corresponding to the target of a symbolic link.
|
|
@@ -10714,7 +11165,7 @@ var PathBase = class {
|
|
|
10714
11165
|
#readdirMaybePromoteChild(e, c) {
|
|
10715
11166
|
for (let p = c.provisional; p < c.length; p++) {
|
|
10716
11167
|
const pchild = c[p];
|
|
10717
|
-
const name = this.nocase ? normalizeNocase(e.name) :
|
|
11168
|
+
const name = this.nocase ? normalizeNocase(e.name) : normalize2(e.name);
|
|
10718
11169
|
if (name !== pchild.#matchName) {
|
|
10719
11170
|
continue;
|
|
10720
11171
|
}
|
|
@@ -11031,8 +11482,8 @@ var PathWin32 = class _PathWin32 extends PathBase {
|
|
|
11031
11482
|
/**
|
|
11032
11483
|
* @internal
|
|
11033
11484
|
*/
|
|
11034
|
-
getRootString(
|
|
11035
|
-
return import_node_path6.win32.parse(
|
|
11485
|
+
getRootString(path2) {
|
|
11486
|
+
return import_node_path6.win32.parse(path2).root;
|
|
11036
11487
|
}
|
|
11037
11488
|
/**
|
|
11038
11489
|
* @internal
|
|
@@ -11078,8 +11529,8 @@ var PathPosix = class _PathPosix extends PathBase {
|
|
|
11078
11529
|
/**
|
|
11079
11530
|
* @internal
|
|
11080
11531
|
*/
|
|
11081
|
-
getRootString(
|
|
11082
|
-
return
|
|
11532
|
+
getRootString(path2) {
|
|
11533
|
+
return path2.startsWith("/") ? "/" : "";
|
|
11083
11534
|
}
|
|
11084
11535
|
/**
|
|
11085
11536
|
* @internal
|
|
@@ -11168,11 +11619,11 @@ var PathScurryBase = class {
|
|
|
11168
11619
|
/**
|
|
11169
11620
|
* Get the depth of a provided path, string, or the cwd
|
|
11170
11621
|
*/
|
|
11171
|
-
depth(
|
|
11172
|
-
if (typeof
|
|
11173
|
-
|
|
11622
|
+
depth(path2 = this.cwd) {
|
|
11623
|
+
if (typeof path2 === "string") {
|
|
11624
|
+
path2 = this.cwd.resolve(path2);
|
|
11174
11625
|
}
|
|
11175
|
-
return
|
|
11626
|
+
return path2.depth();
|
|
11176
11627
|
}
|
|
11177
11628
|
/**
|
|
11178
11629
|
* Return the cache of child entries. Exposed so subclasses can create
|
|
@@ -11659,9 +12110,9 @@ var PathScurryBase = class {
|
|
|
11659
12110
|
process2();
|
|
11660
12111
|
return results;
|
|
11661
12112
|
}
|
|
11662
|
-
chdir(
|
|
12113
|
+
chdir(path2 = this.cwd) {
|
|
11663
12114
|
const oldCwd = this.cwd;
|
|
11664
|
-
this.cwd = typeof
|
|
12115
|
+
this.cwd = typeof path2 === "string" ? this.cwd.resolve(path2) : path2;
|
|
11665
12116
|
this.cwd[setAsCwd](oldCwd);
|
|
11666
12117
|
}
|
|
11667
12118
|
};
|
|
@@ -12017,8 +12468,8 @@ var MatchRecord = class {
|
|
|
12017
12468
|
}
|
|
12018
12469
|
// match, absolute, ifdir
|
|
12019
12470
|
entries() {
|
|
12020
|
-
return [...this.store.entries()].map(([
|
|
12021
|
-
|
|
12471
|
+
return [...this.store.entries()].map(([path2, n]) => [
|
|
12472
|
+
path2,
|
|
12022
12473
|
!!(n & 2),
|
|
12023
12474
|
!!(n & 1)
|
|
12024
12475
|
]);
|
|
@@ -12223,9 +12674,9 @@ var GlobUtil = class {
|
|
|
12223
12674
|
signal;
|
|
12224
12675
|
maxDepth;
|
|
12225
12676
|
includeChildMatches;
|
|
12226
|
-
constructor(patterns,
|
|
12677
|
+
constructor(patterns, path2, opts) {
|
|
12227
12678
|
this.patterns = patterns;
|
|
12228
|
-
this.path =
|
|
12679
|
+
this.path = path2;
|
|
12229
12680
|
this.opts = opts;
|
|
12230
12681
|
this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
|
|
12231
12682
|
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
@@ -12244,11 +12695,11 @@ var GlobUtil = class {
|
|
|
12244
12695
|
});
|
|
12245
12696
|
}
|
|
12246
12697
|
}
|
|
12247
|
-
#ignored(
|
|
12248
|
-
return this.seen.has(
|
|
12698
|
+
#ignored(path2) {
|
|
12699
|
+
return this.seen.has(path2) || !!this.#ignore?.ignored?.(path2);
|
|
12249
12700
|
}
|
|
12250
|
-
#childrenIgnored(
|
|
12251
|
-
return !!this.#ignore?.childrenIgnored?.(
|
|
12701
|
+
#childrenIgnored(path2) {
|
|
12702
|
+
return !!this.#ignore?.childrenIgnored?.(path2);
|
|
12252
12703
|
}
|
|
12253
12704
|
// backpressure mechanism
|
|
12254
12705
|
pause() {
|
|
@@ -12463,8 +12914,8 @@ var GlobUtil = class {
|
|
|
12463
12914
|
};
|
|
12464
12915
|
var GlobWalker = class extends GlobUtil {
|
|
12465
12916
|
matches = /* @__PURE__ */ new Set();
|
|
12466
|
-
constructor(patterns,
|
|
12467
|
-
super(patterns,
|
|
12917
|
+
constructor(patterns, path2, opts) {
|
|
12918
|
+
super(patterns, path2, opts);
|
|
12468
12919
|
}
|
|
12469
12920
|
matchEmit(e) {
|
|
12470
12921
|
this.matches.add(e);
|
|
@@ -12501,8 +12952,8 @@ var GlobWalker = class extends GlobUtil {
|
|
|
12501
12952
|
};
|
|
12502
12953
|
var GlobStream = class extends GlobUtil {
|
|
12503
12954
|
results;
|
|
12504
|
-
constructor(patterns,
|
|
12505
|
-
super(patterns,
|
|
12955
|
+
constructor(patterns, path2, opts) {
|
|
12956
|
+
super(patterns, path2, opts);
|
|
12506
12957
|
this.results = new Minipass({
|
|
12507
12958
|
signal: this.signal,
|
|
12508
12959
|
objectMode: true
|
|
@@ -12890,7 +13341,7 @@ var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
|
12890
13341
|
process.on("SIGTERM", onSignal);
|
|
12891
13342
|
const heartbeat = setInterval(() => {
|
|
12892
13343
|
try {
|
|
12893
|
-
(0, import_node_fs7.utimesSync)(
|
|
13344
|
+
(0, import_node_fs7.utimesSync)(embedLockPath(), /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date());
|
|
12894
13345
|
} catch {
|
|
12895
13346
|
}
|
|
12896
13347
|
}, HEARTBEAT_INTERVAL_MS);
|
|
@@ -12937,4 +13388,6 @@ var HEARTBEAT_INTERVAL_MS = 5 * 60 * 1e3;
|
|
|
12937
13388
|
}
|
|
12938
13389
|
releaseEmbedLock();
|
|
12939
13390
|
}
|
|
12940
|
-
})()
|
|
13391
|
+
})().catch(() => {
|
|
13392
|
+
process.exit(0);
|
|
13393
|
+
});
|