@tekmidian/pai 0.66.1 → 0.66.2
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/dist/{aibroker-client-B8c42Lh8.mjs → aibroker-client-CHEEvJZW.mjs} +2 -2
- package/dist/{aibroker-client-C5Fw7DNz.mjs → aibroker-client-Dfv7j1Od.mjs} +3 -3
- package/dist/{aibroker-client-C5Fw7DNz.mjs.map → aibroker-client-Dfv7j1Od.mjs.map} +1 -1
- package/dist/{auto-route-o0BOsXn7.mjs → auto-route-BnizyALK.mjs} +65 -4
- package/dist/auto-route-BnizyALK.mjs.map +1 -0
- package/dist/auto-route-D6fW1Q8z.mjs +3 -0
- package/dist/{chain-CZfKIEq9.mjs → chain-D5876UQX.mjs} +3 -4
- package/dist/{chain-CZfKIEq9.mjs.map → chain-D5876UQX.mjs.map} +1 -1
- package/dist/cli/index.mjs +18 -23
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/program.mjs +17 -22
- package/dist/{config-BbLFD7Uf.mjs → config-C-LiGlop.mjs} +2 -2
- package/dist/{config-BbLFD7Uf.mjs.map → config-C-LiGlop.mjs.map} +1 -1
- package/dist/{config-YinjgXEJ.mjs → config-DKIA7wgF.mjs} +1 -1
- package/dist/{context-handover-cache-pkHzmL3c.mjs → context-handover-cache-9PGvXRIw.mjs} +984 -10
- package/dist/context-handover-cache-9PGvXRIw.mjs.map +1 -0
- package/dist/daemon/index.mjs +17 -19
- package/dist/daemon/index.mjs.map +1 -1
- package/dist/daemon-BUgNvMUh.mjs +5029 -0
- package/dist/daemon-BUgNvMUh.mjs.map +1 -0
- package/dist/daemon-DL0eglMJ.mjs +18 -0
- package/dist/daemon-mcp/index.mjs +12 -9
- package/dist/daemon-mcp/index.mjs.map +1 -1
- package/dist/{embeddings-CcscYWwk.mjs → embeddings-CEBGrzwu.mjs} +1 -1
- package/dist/{embeddings-Bx3q0QOY.mjs → embeddings-DOLZnT1X.mjs} +1 -1
- package/dist/{embeddings-Bx3q0QOY.mjs.map → embeddings-DOLZnT1X.mjs.map} +1 -1
- package/dist/{env-JNEIrQWg.mjs → env-DiolswKQ.mjs} +1 -1
- package/dist/{env-JNEIrQWg.mjs.map → env-DiolswKQ.mjs.map} +1 -1
- package/dist/factory-DrBg24UT.mjs +8 -0
- package/dist/factory-Ypf8r0fK.mjs +2892 -0
- package/dist/factory-Ypf8r0fK.mjs.map +1 -0
- package/dist/{fallback-CIiq2Raw.mjs → fallback-D51R4shY.mjs} +23 -11
- package/dist/fallback-D51R4shY.mjs.map +1 -0
- package/dist/{chunker-BH4i-F2b.mjs → helpers-CZsi_49C.mjs} +221 -2
- package/dist/helpers-CZsi_49C.mjs.map +1 -0
- package/dist/hooks/worker-status-line.mjs.map +2 -2
- package/dist/index.mjs +6 -7
- package/dist/{ipc-client-D16Xw6Uo.mjs → ipc-client-BLYX51nG.mjs} +2 -2
- package/dist/{ipc-client-D16Xw6Uo.mjs.map → ipc-client-BLYX51nG.mjs.map} +1 -1
- package/dist/main-resolver-BYgP86C1.mjs +7 -0
- package/dist/{main-resolver-DPPwHNtn.mjs → main-resolver-kVkMJZUD.mjs} +6 -6
- package/dist/{main-resolver-DPPwHNtn.mjs.map → main-resolver-kVkMJZUD.mjs.map} +1 -1
- package/dist/{migrate-BD7D8EEh.mjs → migrate-Bq0esMOa.mjs} +2 -2
- package/dist/{migrate-BD7D8EEh.mjs.map → migrate-Bq0esMOa.mjs.map} +1 -1
- package/dist/{pai-marker-D1MMswkz.mjs → pai-marker-DXVpFsYz.mjs} +1 -1
- package/dist/{pai-marker-D1MMswkz.mjs.map → pai-marker-DXVpFsYz.mjs.map} +1 -1
- package/dist/{planner-Dm5Acyo1.mjs → planner-D5yt0EfA.mjs} +10 -7
- package/dist/{planner-Dm5Acyo1.mjs.map → planner-D5yt0EfA.mjs.map} +1 -1
- package/dist/postgres-BmLr0MUm.mjs +5 -0
- package/dist/{postgres-Ceqsa64C.mjs → postgres-D3xc2RB4.mjs} +364 -9
- package/dist/postgres-D3xc2RB4.mjs.map +1 -0
- package/dist/{program-JJ0TwSHI.mjs → program-DIXRtAFy.mjs} +77 -70
- package/dist/program-DIXRtAFy.mjs.map +1 -0
- package/dist/{query-feedback-BIaZTTFO.mjs → query-feedback-B7FYE4JR.mjs} +1 -1
- package/dist/{query-feedback-BIaZTTFO.mjs.map → query-feedback-B7FYE4JR.mjs.map} +1 -1
- package/dist/{reranker-DKv80KO5.mjs → reranker-3lnggwgq.mjs} +1 -1
- package/dist/{reranker-DKv80KO5.mjs.map → reranker-3lnggwgq.mjs.map} +1 -1
- package/dist/{reranker-CFiEzHQu.mjs → reranker-CZ2mP4cf.mjs} +1 -1
- package/dist/router-BK-hFeQ6.mjs +3 -0
- package/dist/{router-a5G7q8_3.mjs → router-BaTbc9VX.mjs} +2 -2
- package/dist/{router-a5G7q8_3.mjs.map → router-BaTbc9VX.mjs.map} +1 -1
- package/dist/{run-BCpbxqA5.mjs → run-CLYTOm0x.mjs} +599 -22
- package/dist/run-CLYTOm0x.mjs.map +1 -0
- package/dist/{run-env-DRcp7A8K.mjs → run-env-Bnmf6bRI.mjs} +2 -2
- package/dist/{run-env-DRcp7A8K.mjs.map → run-env-Bnmf6bRI.mjs.map} +1 -1
- package/dist/{runtime-paths-CHTg3ywb.mjs → runtime-paths-D3FKAm69.mjs} +1 -1
- package/dist/{runtime-paths-CHTg3ywb.mjs.map → runtime-paths-D3FKAm69.mjs.map} +1 -1
- package/dist/{search-BOSphCJ1.mjs → search-CNAGTiJP.mjs} +2 -2
- package/dist/{search-BOSphCJ1.mjs.map → search-CNAGTiJP.mjs.map} +1 -1
- package/dist/{sources-CijVso3n.mjs → sources-CM2g-CLT.mjs} +2 -2
- package/dist/{sources-CijVso3n.mjs.map → sources-CM2g-CLT.mjs.map} +1 -1
- package/dist/{stop-words-BdQuaE9K.mjs → stop-words-DtxaTWU_.mjs} +1 -1
- package/dist/{stop-words-BdQuaE9K.mjs.map → stop-words-DtxaTWU_.mjs.map} +1 -1
- package/dist/{utils-C9HsYDpO.mjs → utils-DddRwMsG.mjs} +2 -2
- package/dist/{utils-C9HsYDpO.mjs.map → utils-DddRwMsG.mjs.map} +1 -1
- package/dist/{zettelkasten-CtGHQWPU.mjs → zettelkasten-BhZMvmoK.mjs} +149 -7
- package/dist/zettelkasten-BhZMvmoK.mjs.map +1 -0
- package/dist/zettelkasten-BwV1pluL.mjs +5 -0
- package/docs/commands/worker.md +2 -0
- package/package.json +1 -1
- package/dist/async-C2Bm_Lal.mjs +0 -300
- package/dist/async-C2Bm_Lal.mjs.map +0 -1
- package/dist/auto-route-o0BOsXn7.mjs.map +0 -1
- package/dist/chunker-BH4i-F2b.mjs.map +0 -1
- package/dist/clusters-BCtD3fbe.mjs +0 -169
- package/dist/clusters-BCtD3fbe.mjs.map +0 -1
- package/dist/context-handover-cache-pkHzmL3c.mjs.map +0 -1
- package/dist/daemon-DXlaVCkw.mjs +0 -1741
- package/dist/daemon-DXlaVCkw.mjs.map +0 -1
- package/dist/daemon-DyORmxZu.mjs +0 -19
- package/dist/detector-BEPFsINR.mjs +0 -3
- package/dist/detector-BRTtAWrM.mjs +0 -65
- package/dist/detector-BRTtAWrM.mjs.map +0 -1
- package/dist/factory-CNpPQQ-5.mjs +0 -249
- package/dist/factory-CNpPQQ-5.mjs.map +0 -1
- package/dist/factory-DY7x73mE.mjs +0 -3
- package/dist/fallback-CIiq2Raw.mjs.map +0 -1
- package/dist/federation-db-BTyoufBh.mjs +0 -139
- package/dist/federation-db-BTyoufBh.mjs.map +0 -1
- package/dist/federation-db-HfIFc7FG.mjs +0 -3
- package/dist/helpers-BRCJg0G3.mjs +0 -223
- package/dist/helpers-BRCJg0G3.mjs.map +0 -1
- package/dist/indexer-backend-DFF2FrYx.mjs +0 -5
- package/dist/indexer-backend-isSLg6yE.mjs +0 -1
- package/dist/kg-entity-DCOcsVFD.mjs +0 -29
- package/dist/kg-entity-DCOcsVFD.mjs.map +0 -1
- package/dist/latent-ideas-wwAXquGe.mjs +0 -191
- package/dist/latent-ideas-wwAXquGe.mjs.map +0 -1
- package/dist/link-boost-CnI7UVMJ.mjs +0 -34
- package/dist/link-boost-CnI7UVMJ.mjs.map +0 -1
- package/dist/main-resolver-BKz_OuEh.mjs +0 -7
- package/dist/merge-2gqRPFu2.mjs +0 -3
- package/dist/merge-DgU9OgZy.mjs +0 -6
- package/dist/merge-DgU9OgZy.mjs.map +0 -1
- package/dist/module-paths-DdRzbkUI.mjs +0 -44
- package/dist/module-paths-DdRzbkUI.mjs.map +0 -1
- package/dist/neighborhood-2FsmzoxG.mjs +0 -114
- package/dist/neighborhood-2FsmzoxG.mjs.map +0 -1
- package/dist/note-context-De63k8na.mjs +0 -106
- package/dist/note-context-De63k8na.mjs.map +0 -1
- package/dist/postgres-Ceqsa64C.mjs.map +0 -1
- package/dist/program-JJ0TwSHI.mjs.map +0 -1
- package/dist/query-feedback-B_iigYj-.mjs +0 -3
- package/dist/registry-db-C7voqML9.mjs +0 -213
- package/dist/registry-db-C7voqML9.mjs.map +0 -1
- package/dist/registry-db-JHPhA8vF.mjs +0 -3
- package/dist/registry-postgres-nOfyBSIW.mjs +0 -795
- package/dist/registry-postgres-nOfyBSIW.mjs.map +0 -1
- package/dist/registry-sqlite-DrCW1aRK.mjs +0 -593
- package/dist/registry-sqlite-DrCW1aRK.mjs.map +0 -1
- package/dist/router-CXUGsv85.mjs +0 -3
- package/dist/run-BCpbxqA5.mjs.map +0 -1
- package/dist/search-Bf3Kub3F.mjs +0 -3
- package/dist/server-DgmAHyFK.mjs +0 -403
- package/dist/server-DgmAHyFK.mjs.map +0 -1
- package/dist/session-keepalive-DxjTHGcK.mjs +0 -582
- package/dist/session-keepalive-DxjTHGcK.mjs.map +0 -1
- package/dist/sqlite-CqsTy6xo.mjs +0 -936
- package/dist/sqlite-CqsTy6xo.mjs.map +0 -1
- package/dist/state-DW8zdweW.mjs +0 -3
- package/dist/state-HyjqTihC.mjs +0 -76
- package/dist/state-HyjqTihC.mjs.map +0 -1
- package/dist/themes-CTaOj3e1.mjs +0 -148
- package/dist/themes-CTaOj3e1.mjs.map +0 -1
- package/dist/tools-BcOKPBtg.mjs +0 -1489
- package/dist/tools-BcOKPBtg.mjs.map +0 -1
- package/dist/tools-C-_l0o8Z.mjs +0 -6
- package/dist/trace-CtV0RO6n.mjs +0 -137
- package/dist/trace-CtV0RO6n.mjs.map +0 -1
- package/dist/utils-BrX9FLeK.mjs +0 -3
- package/dist/vault-indexer-BG1sEVyM.mjs +0 -537
- package/dist/vault-indexer-BG1sEVyM.mjs.map +0 -1
- package/dist/wakeup-D8n33hYV.mjs +0 -335
- package/dist/wakeup-D8n33hYV.mjs.map +0 -1
- package/dist/work-queue-worker-4tLa5gpQ.mjs +0 -567
- package/dist/work-queue-worker-4tLa5gpQ.mjs.map +0 -1
- package/dist/work-queue-worker-rFZvTO3p.mjs +0 -11
- package/dist/zettelkasten-CtGHQWPU.mjs.map +0 -1
|
@@ -1,12 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
1
|
+
import { a as parseSessionTitleChunk, c as yieldToEventLoop, f as fileContentHash, h as sha256File, i as isPathTooBroadForContentScan, m as sha256, n as chunkId, o as walkContentFiles, r as detectTier, s as walkMdFiles, t as INDEX_YIELD_EVERY, u as chunkMarkdown } from "./helpers-CZsi_49C.mjs";
|
|
2
|
+
import { t as STOP_WORDS } from "./stop-words-DtxaTWU_.mjs";
|
|
3
|
+
import { a as generateEmbeddings, o as serializeEmbedding } from "./embeddings-DOLZnT1X.mjs";
|
|
4
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
5
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
8
|
import pg from "pg";
|
|
9
9
|
|
|
10
|
+
//#region src/module-paths.ts
|
|
11
|
+
/**
|
|
12
|
+
* module-paths.ts — locate a file relative to the package root from a running module.
|
|
13
|
+
*
|
|
14
|
+
* tsdown bundles shared code into chunks emitted directly under dist/ (e.g.
|
|
15
|
+
* dist/program-*.mjs) rather than always alongside the entry that needs them
|
|
16
|
+
* (dist/cli/index.mjs, dist/daemon/index.mjs, ...). A fixed "../daemon/index.mjs"
|
|
17
|
+
* relative to import.meta.url assumes one specific chunk depth and silently
|
|
18
|
+
* resolves to the wrong file — or a file under the source tree instead of
|
|
19
|
+
* dist — whenever the bundler's chunking changes. Walking up from the running
|
|
20
|
+
* module's own directory until `dir/rel` exists is depth-independent, and works
|
|
21
|
+
* whether `rel` lives under dist/ (built entries) or is a sibling of dist/ at
|
|
22
|
+
* the package root (files excluded from the bundle, like docker/migrate-sqlite.ts).
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Resolve `rel` by walking up from the directory containing `moduleUrl`,
|
|
26
|
+
* returning the first `dir/rel` that exists on disk.
|
|
27
|
+
*
|
|
28
|
+
* Throws rather than returning a guessed path, so a caller writing a service
|
|
29
|
+
* file or spawning a process fails loudly instead of pointing at nothing.
|
|
30
|
+
*/
|
|
31
|
+
function resolveFromModule(moduleUrl, rel, maxLevels = 8) {
|
|
32
|
+
let dir = dirname(fileURLToPath(moduleUrl));
|
|
33
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
34
|
+
const candidate = join(dir, rel);
|
|
35
|
+
if (existsSync(candidate)) return candidate;
|
|
36
|
+
const parent = dirname(dir);
|
|
37
|
+
if (parent === dir) break;
|
|
38
|
+
dir = parent;
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`cannot locate "${rel}" above ${dirname(fileURLToPath(moduleUrl))} — is the project built? (bun run build)`);
|
|
41
|
+
}
|
|
42
|
+
/** Package root (the directory holding package.json) for a running module, at any bundle depth. */
|
|
43
|
+
function packageRoot(moduleUrl) {
|
|
44
|
+
return dirname(resolveFromModule(moduleUrl, "package.json"));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
10
48
|
//#region src/storage/postgres/helpers.ts
|
|
11
49
|
/**
|
|
12
50
|
* Internal helper utilities for the Postgres storage backend.
|
|
@@ -508,6 +546,323 @@ async function searchVaultNameIndex(pool, query, limit = 100) {
|
|
|
508
546
|
return (await pool.query("SELECT DISTINCT vault_path FROM vault_name_index WHERE lower(name) LIKE lower($1) LIMIT $2", [`%${query}%`, limit])).rows.map((row) => row.vault_path);
|
|
509
547
|
}
|
|
510
548
|
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/memory/kg-entity.ts
|
|
551
|
+
/**
|
|
552
|
+
* kg-entity.ts — Entity content-addressing with multi-tenant support.
|
|
553
|
+
*
|
|
554
|
+
* Provides UUID5-style deterministic content hashes for KG entities and edges,
|
|
555
|
+
* ensuring that the same entity name always maps to the same ID within a tenant.
|
|
556
|
+
* This enables idempotent upserts and stable foreign keys for kg_triples.
|
|
557
|
+
*
|
|
558
|
+
* Multi-tenant support: each tenant namespace gets its own entity ID space.
|
|
559
|
+
* The default tenant is "default" for single-user deployments.
|
|
560
|
+
*/
|
|
561
|
+
/**
|
|
562
|
+
* Generate a deterministic entity ID (UUID5-style) for a given name and tenant.
|
|
563
|
+
*
|
|
564
|
+
* The ID is a hex digest derived from "tenant_id:name" so the same entity
|
|
565
|
+
* always receives the same ID within a tenant namespace.
|
|
566
|
+
*
|
|
567
|
+
* @param name Entity name (case-preserved)
|
|
568
|
+
* @param tenantId Tenant namespace (default: "default")
|
|
569
|
+
*/
|
|
570
|
+
function entityContentId(name, tenantId = "default") {
|
|
571
|
+
return createHash("sha256").update(`entity:${tenantId}:${name}`).digest("hex").slice(0, 32);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
//#endregion
|
|
575
|
+
//#region src/memory/indexer/async.ts
|
|
576
|
+
/**
|
|
577
|
+
* Backend-aware async indexer for PAI federation memory.
|
|
578
|
+
*
|
|
579
|
+
* Provides the same functionality as sync.ts but writes through the
|
|
580
|
+
* StorageBackend interface instead of directly to the SQLite driver.
|
|
581
|
+
* Used when the daemon is configured with the Postgres backend.
|
|
582
|
+
*
|
|
583
|
+
* The SQLite path still uses sync.ts directly (which is faster for SQLite
|
|
584
|
+
* due to synchronous transactions).
|
|
585
|
+
*/
|
|
586
|
+
/**
|
|
587
|
+
* Index a single file through the StorageBackend interface.
|
|
588
|
+
* Returns true if the file was re-indexed (changed or new), false if skipped.
|
|
589
|
+
*/
|
|
590
|
+
async function indexFileWithBackend(backend, projectId, rootPath, relativePath, source, tier) {
|
|
591
|
+
const absPath = join(rootPath, relativePath);
|
|
592
|
+
let content;
|
|
593
|
+
let stat;
|
|
594
|
+
try {
|
|
595
|
+
content = readFileSync(absPath, "utf8");
|
|
596
|
+
stat = statSync(absPath);
|
|
597
|
+
} catch {
|
|
598
|
+
return false;
|
|
599
|
+
}
|
|
600
|
+
const hash = fileContentHash(content);
|
|
601
|
+
const mtime = Math.floor(stat.mtimeMs);
|
|
602
|
+
const size = stat.size;
|
|
603
|
+
if (await backend.getFileHash(projectId, relativePath) === hash) return false;
|
|
604
|
+
await backend.deleteChunksForFile(projectId, relativePath);
|
|
605
|
+
const rawChunks = chunkMarkdown(content);
|
|
606
|
+
const updatedAt = Date.now();
|
|
607
|
+
const chunks = rawChunks.map((c, i) => ({
|
|
608
|
+
id: chunkId(projectId, relativePath, i, c.startLine, c.endLine),
|
|
609
|
+
projectId,
|
|
610
|
+
source,
|
|
611
|
+
tier,
|
|
612
|
+
path: relativePath,
|
|
613
|
+
startLine: c.startLine,
|
|
614
|
+
endLine: c.endLine,
|
|
615
|
+
hash: c.hash,
|
|
616
|
+
text: c.text,
|
|
617
|
+
updatedAt,
|
|
618
|
+
embedding: null
|
|
619
|
+
}));
|
|
620
|
+
await backend.insertChunks(chunks);
|
|
621
|
+
await backend.upsertFile({
|
|
622
|
+
projectId,
|
|
623
|
+
path: relativePath,
|
|
624
|
+
source,
|
|
625
|
+
tier,
|
|
626
|
+
hash,
|
|
627
|
+
mtime,
|
|
628
|
+
size
|
|
629
|
+
});
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotesDir) {
|
|
633
|
+
const result = {
|
|
634
|
+
filesProcessed: 0,
|
|
635
|
+
chunksCreated: 0,
|
|
636
|
+
filesSkipped: 0
|
|
637
|
+
};
|
|
638
|
+
const filesToIndex = [];
|
|
639
|
+
const rootMemoryMd = join(rootPath, "MEMORY.md");
|
|
640
|
+
if (existsSync(rootMemoryMd)) filesToIndex.push({
|
|
641
|
+
absPath: rootMemoryMd,
|
|
642
|
+
rootBase: rootPath,
|
|
643
|
+
source: "memory",
|
|
644
|
+
tier: "evergreen"
|
|
645
|
+
});
|
|
646
|
+
const memoryDir = join(rootPath, "memory");
|
|
647
|
+
for (const absPath of walkMdFiles(memoryDir)) {
|
|
648
|
+
const tier = detectTier(relative(rootPath, absPath));
|
|
649
|
+
filesToIndex.push({
|
|
650
|
+
absPath,
|
|
651
|
+
rootBase: rootPath,
|
|
652
|
+
source: "memory",
|
|
653
|
+
tier
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
const notesDir = join(rootPath, "Notes");
|
|
657
|
+
for (const absPath of walkMdFiles(notesDir)) filesToIndex.push({
|
|
658
|
+
absPath,
|
|
659
|
+
rootBase: rootPath,
|
|
660
|
+
source: "notes",
|
|
661
|
+
tier: "session"
|
|
662
|
+
});
|
|
663
|
+
{
|
|
664
|
+
const updatedAt = Date.now();
|
|
665
|
+
for (const absPath of walkMdFiles(notesDir)) {
|
|
666
|
+
const text = parseSessionTitleChunk(basename(absPath));
|
|
667
|
+
if (!text) continue;
|
|
668
|
+
const syntheticPath = `${relative(rootPath, absPath)}::title`;
|
|
669
|
+
const titleChunk = {
|
|
670
|
+
id: chunkId(projectId, syntheticPath, 0, 0, 0),
|
|
671
|
+
projectId,
|
|
672
|
+
source: "notes",
|
|
673
|
+
tier: "session",
|
|
674
|
+
path: syntheticPath,
|
|
675
|
+
startLine: 0,
|
|
676
|
+
endLine: 0,
|
|
677
|
+
hash: sha256File(text),
|
|
678
|
+
text,
|
|
679
|
+
updatedAt,
|
|
680
|
+
embedding: null
|
|
681
|
+
};
|
|
682
|
+
try {
|
|
683
|
+
await backend.insertChunks([titleChunk]);
|
|
684
|
+
} catch {}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
if (!isPathTooBroadForContentScan(rootPath)) for (const absPath of walkContentFiles(rootPath)) filesToIndex.push({
|
|
688
|
+
absPath,
|
|
689
|
+
rootBase: rootPath,
|
|
690
|
+
source: "content",
|
|
691
|
+
tier: "topic"
|
|
692
|
+
});
|
|
693
|
+
if (claudeNotesDir && claudeNotesDir !== notesDir) {
|
|
694
|
+
for (const absPath of walkMdFiles(claudeNotesDir)) filesToIndex.push({
|
|
695
|
+
absPath,
|
|
696
|
+
rootBase: claudeNotesDir,
|
|
697
|
+
source: "notes",
|
|
698
|
+
tier: "session"
|
|
699
|
+
});
|
|
700
|
+
{
|
|
701
|
+
const updatedAt = Date.now();
|
|
702
|
+
for (const absPath of walkMdFiles(claudeNotesDir)) {
|
|
703
|
+
const text = parseSessionTitleChunk(basename(absPath));
|
|
704
|
+
if (!text) continue;
|
|
705
|
+
const syntheticPath = `${relative(claudeNotesDir, absPath)}::title`;
|
|
706
|
+
const titleChunk = {
|
|
707
|
+
id: chunkId(projectId, syntheticPath, 0, 0, 0),
|
|
708
|
+
projectId,
|
|
709
|
+
source: "notes",
|
|
710
|
+
tier: "session",
|
|
711
|
+
path: syntheticPath,
|
|
712
|
+
startLine: 0,
|
|
713
|
+
endLine: 0,
|
|
714
|
+
hash: sha256File(text),
|
|
715
|
+
text,
|
|
716
|
+
updatedAt,
|
|
717
|
+
embedding: null
|
|
718
|
+
};
|
|
719
|
+
try {
|
|
720
|
+
await backend.insertChunks([titleChunk]);
|
|
721
|
+
} catch {}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
if (claudeNotesDir.endsWith("/Notes")) {
|
|
725
|
+
const claudeProjectDir = claudeNotesDir.slice(0, -6);
|
|
726
|
+
const claudeMemoryMd = join(claudeProjectDir, "MEMORY.md");
|
|
727
|
+
if (existsSync(claudeMemoryMd)) filesToIndex.push({
|
|
728
|
+
absPath: claudeMemoryMd,
|
|
729
|
+
rootBase: claudeProjectDir,
|
|
730
|
+
source: "memory",
|
|
731
|
+
tier: "evergreen"
|
|
732
|
+
});
|
|
733
|
+
const claudeMemoryDir = join(claudeProjectDir, "memory");
|
|
734
|
+
for (const absPath of walkMdFiles(claudeMemoryDir)) {
|
|
735
|
+
const tier = detectTier(relative(claudeProjectDir, absPath));
|
|
736
|
+
filesToIndex.push({
|
|
737
|
+
absPath,
|
|
738
|
+
rootBase: claudeProjectDir,
|
|
739
|
+
source: "memory",
|
|
740
|
+
tier
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
await yieldToEventLoop();
|
|
746
|
+
let filesSinceYield = 0;
|
|
747
|
+
for (const { absPath, rootBase, source, tier } of filesToIndex) {
|
|
748
|
+
if (filesSinceYield >= INDEX_YIELD_EVERY) {
|
|
749
|
+
await yieldToEventLoop();
|
|
750
|
+
filesSinceYield = 0;
|
|
751
|
+
}
|
|
752
|
+
filesSinceYield++;
|
|
753
|
+
const relPath = relative(rootBase, absPath);
|
|
754
|
+
try {
|
|
755
|
+
if (await indexFileWithBackend(backend, projectId, rootBase, relPath, source, tier)) {
|
|
756
|
+
const ids = await backend.getChunkIds(projectId, relPath);
|
|
757
|
+
result.filesProcessed++;
|
|
758
|
+
result.chunksCreated += ids.length;
|
|
759
|
+
} else result.filesSkipped++;
|
|
760
|
+
} catch {
|
|
761
|
+
result.filesSkipped++;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const livePaths = /* @__PURE__ */ new Set();
|
|
765
|
+
for (const { absPath, rootBase } of filesToIndex) livePaths.add(relative(rootBase, absPath));
|
|
766
|
+
const dbChunkPaths = await backend.getDistinctChunkPaths(projectId);
|
|
767
|
+
const stalePaths = [];
|
|
768
|
+
for (const p of dbChunkPaths) {
|
|
769
|
+
const basePath = p.endsWith("::title") ? p.slice(0, -7) : p;
|
|
770
|
+
if (!livePaths.has(basePath)) stalePaths.push(p);
|
|
771
|
+
}
|
|
772
|
+
if (stalePaths.length > 0) await backend.deletePaths(projectId, stalePaths);
|
|
773
|
+
return result;
|
|
774
|
+
}
|
|
775
|
+
const EMBED_BATCH_SIZE = 50;
|
|
776
|
+
/** Default ceiling on one pass. See EmbedPassOptions. */
|
|
777
|
+
const DEFAULT_MAX_CHUNKS_PER_PASS = 5e3;
|
|
778
|
+
/** Default wall-clock ceiling on one pass, in milliseconds. */
|
|
779
|
+
const DEFAULT_MAX_MILLIS_PER_PASS = 12e4;
|
|
780
|
+
/**
|
|
781
|
+
* Generate and store embeddings for unembedded chunks via the StorageBackend.
|
|
782
|
+
*
|
|
783
|
+
* The pass is deliberately bounded (see EmbedPassOptions) and resumable: it
|
|
784
|
+
* takes a slice of the backlog, embeds it, and returns so the scheduler can run
|
|
785
|
+
* an index pass before coming back. Draining the whole backlog in one call
|
|
786
|
+
* starves indexing for as long as the call runs.
|
|
787
|
+
*
|
|
788
|
+
* The optional `shouldStop` callback is checked between every batch. When it
|
|
789
|
+
* returns true the embed loop exits early so the caller (e.g. the daemon
|
|
790
|
+
* shutdown handler) can close the pool without racing against active queries.
|
|
791
|
+
*
|
|
792
|
+
* Returns the number of newly embedded chunks.
|
|
793
|
+
*/
|
|
794
|
+
async function embedChunksWithBackend(backend, shouldStop, projectNames, options) {
|
|
795
|
+
const maxChunks = options?.maxChunks ?? DEFAULT_MAX_CHUNKS_PER_PASS;
|
|
796
|
+
const maxMillis = options?.maxMillis ?? DEFAULT_MAX_MILLIS_PER_PASS;
|
|
797
|
+
const deadline = Date.now() + maxMillis;
|
|
798
|
+
const rows = await backend.getUnembeddedChunkIds(void 0, maxChunks);
|
|
799
|
+
if (rows.length === 0) return 0;
|
|
800
|
+
const total = rows.length;
|
|
801
|
+
let embedded = 0;
|
|
802
|
+
const projectChunkCounts = /* @__PURE__ */ new Map();
|
|
803
|
+
for (const row of rows) {
|
|
804
|
+
const entry = projectChunkCounts.get(row.project_id);
|
|
805
|
+
if (entry) entry.count++;
|
|
806
|
+
else projectChunkCounts.set(row.project_id, {
|
|
807
|
+
count: 1,
|
|
808
|
+
samplePath: row.path
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
const pName = (pid) => projectNames?.get(pid) ?? `project ${pid}`;
|
|
812
|
+
const projectSummary = Array.from(projectChunkCounts.entries()).map(([pid, { count, samplePath }]) => ` ${pName(pid)}: ${count} chunks (e.g. ${samplePath})`).join("\n");
|
|
813
|
+
process.stderr.write(`[pai-daemon] Embed pass: ${total} unembedded chunks across ${projectChunkCounts.size} project(s)\n${projectSummary}\n`);
|
|
814
|
+
let currentProjectId = -1;
|
|
815
|
+
let projectEmbedded = 0;
|
|
816
|
+
for (let i = 0; i < rows.length; i += EMBED_BATCH_SIZE) {
|
|
817
|
+
if (shouldStop?.()) {
|
|
818
|
+
process.stderr.write(`[pai-daemon] Embed pass cancelled after ${embedded}/${total} chunks (shutdown requested)\n`);
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
if (Date.now() >= deadline) {
|
|
822
|
+
process.stderr.write(`[pai-daemon] Embed pass yielding after ${embedded}/${total} chunks (${maxMillis}ms budget spent); resuming next pass\n`);
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
const batch = rows.slice(i, i + EMBED_BATCH_SIZE);
|
|
826
|
+
await yieldToEventLoop();
|
|
827
|
+
const vecs = await generateEmbeddings(batch.map((r) => r.text));
|
|
828
|
+
await Promise.all(batch.map((row, j) => backend.updateEmbedding(row.id, serializeEmbedding(vecs[j]))));
|
|
829
|
+
for (const { project_id, path } of batch) {
|
|
830
|
+
if (project_id !== currentProjectId) {
|
|
831
|
+
if (currentProjectId !== -1) process.stderr.write(`[pai-daemon] Finished ${pName(currentProjectId)}: ${projectEmbedded} chunks embedded\n`);
|
|
832
|
+
const info = projectChunkCounts.get(project_id);
|
|
833
|
+
process.stderr.write(`[pai-daemon] Embedding ${pName(project_id)} (${info?.count ?? "?"} chunks, starting at ${path})\n`);
|
|
834
|
+
currentProjectId = project_id;
|
|
835
|
+
projectEmbedded = 0;
|
|
836
|
+
}
|
|
837
|
+
projectEmbedded++;
|
|
838
|
+
}
|
|
839
|
+
embedded += batch.length;
|
|
840
|
+
const lastChunk = batch[batch.length - 1];
|
|
841
|
+
process.stderr.write(`[pai-daemon] Embedded ${embedded}/${total} chunks (${pName(lastChunk.project_id)}: ${lastChunk.path})\n`);
|
|
842
|
+
}
|
|
843
|
+
if (currentProjectId !== -1) process.stderr.write(`[pai-daemon] Finished ${pName(currentProjectId)}: ${projectEmbedded} chunks embedded\n`);
|
|
844
|
+
return embedded;
|
|
845
|
+
}
|
|
846
|
+
async function indexAllWithBackend(backend, registry) {
|
|
847
|
+
const projects = await registry.listProjects({ status: "active" });
|
|
848
|
+
const totals = {
|
|
849
|
+
filesProcessed: 0,
|
|
850
|
+
chunksCreated: 0,
|
|
851
|
+
filesSkipped: 0
|
|
852
|
+
};
|
|
853
|
+
for (const project of projects) {
|
|
854
|
+
await yieldToEventLoop();
|
|
855
|
+
const r = await indexProjectWithBackend(backend, project.id, project.root_path, project.claude_notes_dir);
|
|
856
|
+
totals.filesProcessed += r.filesProcessed;
|
|
857
|
+
totals.chunksCreated += r.chunksCreated;
|
|
858
|
+
totals.filesSkipped += r.filesSkipped;
|
|
859
|
+
}
|
|
860
|
+
return {
|
|
861
|
+
projects: projects.length,
|
|
862
|
+
result: totals
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
|
|
511
866
|
//#endregion
|
|
512
867
|
//#region src/storage/postgres/tunnels.ts
|
|
513
868
|
/**
|
|
@@ -1765,5 +2120,5 @@ function rowToKgEntity(row) {
|
|
|
1765
2120
|
}
|
|
1766
2121
|
|
|
1767
2122
|
//#endregion
|
|
1768
|
-
export { PostgresBackend };
|
|
1769
|
-
//# sourceMappingURL=postgres-
|
|
2123
|
+
export { buildPgTsQuery as a, entityContentId as i, embedChunksWithBackend as n, packageRoot as o, indexProjectWithBackend as r, resolveFromModule as s, PostgresBackend as t };
|
|
2124
|
+
//# sourceMappingURL=postgres-D3xc2RB4.mjs.map
|