ctxloom-pro 1.0.5 → 1.0.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.
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@ctxloom/dashboard",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev:server": "tsx server/index.ts",
8
+ "dev:client": "vite",
9
+ "build:server": "tsup --config tsup.server.config.ts",
10
+ "build:client": "vite build",
11
+ "build": "npm run build:server && npm run build:client",
12
+ "test": "vitest run",
13
+ "preview": "vite preview"
14
+ },
15
+ "dependencies": {
16
+ "@ctxloom/core": "*",
17
+ "cors": "^2.8.5",
18
+ "express": "^4.18.0",
19
+ "open": "^10.1.0"
20
+ },
21
+ "devDependencies": {
22
+ "@testing-library/jest-dom": "^6.4.0",
23
+ "@testing-library/react": "^16.0.0",
24
+ "@testing-library/user-event": "^14.6.1",
25
+ "@types/cors": "^2.8.17",
26
+ "@types/d3": "^7.4.0",
27
+ "@types/express": "^4.17.21",
28
+ "@types/node": "^22.0.0",
29
+ "@types/react": "^18.3.0",
30
+ "@types/react-dom": "^18.3.0",
31
+ "@types/supertest": "^6.0.0",
32
+ "@vitejs/plugin-react": "^4.3.0",
33
+ "autoprefixer": "^10.4.0",
34
+ "d3": "^7.9.0",
35
+ "jsdom": "^24.0.0",
36
+ "postcss": "^8.4.0",
37
+ "react": "^18.3.0",
38
+ "react-dom": "^18.3.0",
39
+ "react-router-dom": "^6.23.0",
40
+ "recharts": "^2.12.0",
41
+ "supertest": "^7.0.0",
42
+ "tailwindcss": "^3.4.0",
43
+ "tsx": "^4.0.0",
44
+ "typescript": "^5.7.0",
45
+ "vite": "^5.3.0",
46
+ "vitest": "^3.0.0"
47
+ }
48
+ }
@@ -0,0 +1,8 @@
1
+ import {
2
+ VectorStore
3
+ } from "./chunk-NEHYSE2Y.js";
4
+ import "./chunk-TYDMSHV7.js";
5
+ export {
6
+ VectorStore
7
+ };
8
+ //# sourceMappingURL=VectorStore-HOSUSLV7.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-IHXVD5SO.js";
3
+ } from "./chunk-TYDMSHV7.js";
4
4
 
5
- // src/db/VectorStore.js
5
+ // packages/core/src/db/VectorStore.ts
6
6
  import lancedb from "@lancedb/lancedb";
7
7
  import { makeArrowTable } from "@lancedb/lancedb";
8
8
  import path from "path";
@@ -19,8 +19,7 @@ var VectorStore = class {
19
19
  this.dbPath = dbPath ?? path.join(process.cwd(), ".ctxloom", "vectors.lancedb");
20
20
  }
21
21
  async init() {
22
- if (this.initialized)
23
- return;
22
+ if (this.initialized) return;
24
23
  const dir = path.dirname(this.dbPath);
25
24
  if (!fs.existsSync(dir)) {
26
25
  fs.mkdirSync(dir, { recursive: true });
@@ -43,12 +42,35 @@ var VectorStore = class {
43
42
  }
44
43
  this.initialized = true;
45
44
  }
45
+ /**
46
+ * Release LanceDB resources (file descriptors held by the underlying
47
+ * connection / table handles). Must be called at the end of long-lived
48
+ * indexing runs — without this, every SSTable opened during 600+ upserts
49
+ * stays open until process exit, which can exhaust the per-process FD
50
+ * limit (256 on macOS by default for processes spawned by Claude /
51
+ * VS Code) and cause downstream loaders (tree-sitter WASM, ONNX models)
52
+ * to fail with ENFILE.
53
+ *
54
+ * Safe to call multiple times.
55
+ */
56
+ async close() {
57
+ if (!this.initialized) return;
58
+ try {
59
+ const conn = this.db;
60
+ if (typeof conn.close === "function") {
61
+ await conn.close();
62
+ }
63
+ } catch {
64
+ }
65
+ this.db = null;
66
+ this.table = null;
67
+ this.initialized = false;
68
+ }
46
69
  /**
47
70
  * Insert or update a code record.
48
71
  */
49
72
  async upsert(filePath, embedding, content) {
50
- if (!this.table)
51
- throw new Error("VectorStore not initialized. Call init() first.");
73
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
52
74
  const safe = sanitizeFilterPath(filePath);
53
75
  try {
54
76
  await this.table.delete(`filePath = '${safe}'`);
@@ -67,8 +89,7 @@ var VectorStore = class {
67
89
  * Search for the top-K most similar code records using vector search.
68
90
  */
69
91
  async search(queryEmbedding, limit = 10) {
70
- if (!this.table)
71
- throw new Error("VectorStore not initialized. Call init() first.");
92
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
72
93
  try {
73
94
  const results = await this.table.vectorSearch(queryEmbedding).limit(limit).toArray();
74
95
  return results.filter((r) => r.id !== "__seed__").map((r) => ({
@@ -95,8 +116,7 @@ var VectorStore = class {
95
116
  * Remove a file's embedding from the store.
96
117
  */
97
118
  async remove(filePath) {
98
- if (!this.table)
99
- throw new Error("VectorStore not initialized. Call init() first.");
119
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
100
120
  const safe = sanitizeFilterPath(filePath);
101
121
  try {
102
122
  await this.table.delete(`filePath = '${safe}'`);
@@ -108,8 +128,7 @@ var VectorStore = class {
108
128
  * Get the total number of records.
109
129
  */
110
130
  async count() {
111
- if (!this.table)
112
- return 0;
131
+ if (!this.table) return 0;
113
132
  try {
114
133
  return await this.table.countRows();
115
134
  } catch (err) {
@@ -122,4 +141,4 @@ var VectorStore = class {
122
141
  export {
123
142
  VectorStore
124
143
  };
125
- //# sourceMappingURL=chunk-XNKTZGDX.js.map
144
+ //# sourceMappingURL=chunk-NEHYSE2Y.js.map
@@ -0,0 +1,62 @@
1
+ // packages/core/src/utils/logger.ts
2
+ var LEVELS = {
3
+ debug: 0,
4
+ info: 1,
5
+ warn: 2,
6
+ error: 3
7
+ };
8
+ var ANSI = {
9
+ reset: "\x1B[0m",
10
+ dim: "\x1B[2m",
11
+ yellow: "\x1B[33m",
12
+ red: "\x1B[31m"
13
+ };
14
+ function getConfiguredLevel() {
15
+ const raw = (process.env["LOG_LEVEL"] ?? "info").toLowerCase();
16
+ return raw in LEVELS ? raw : "info";
17
+ }
18
+ function getMode() {
19
+ if (process.env["CTXLOOM_LOG_MODE"] === "cli") return "cli";
20
+ if (process.env["CTXLOOM_LOG_MODE"] === "json") return "json";
21
+ return process.argv.length > 2 ? "cli" : "json";
22
+ }
23
+ function isTTY() {
24
+ return process.stderr.isTTY === true;
25
+ }
26
+ function writeJson(level, msg, extra) {
27
+ const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level, msg };
28
+ if (extra) Object.assign(entry, extra);
29
+ process.stderr.write(JSON.stringify(entry) + "\n");
30
+ }
31
+ function writeCli(level, msg, extra) {
32
+ if (level === "debug" || level === "info") return;
33
+ const color = level === "error" ? ANSI.red : ANSI.yellow;
34
+ const icon = level === "error" ? isTTY() ? "\u2717" : "X" : isTTY() ? "\u26A0" : "!";
35
+ const prefix = isTTY() ? `${color}${icon}${ANSI.reset}` : icon;
36
+ let line = ` ${prefix} ${msg}`;
37
+ if (extra && Object.keys(extra).length > 0) {
38
+ const pairs = Object.entries(extra).map(([k, v]) => `${k}=${typeof v === "string" ? v : JSON.stringify(v)}`).join(" ");
39
+ const dim = isTTY() ? `${ANSI.dim}${pairs}${ANSI.reset}` : pairs;
40
+ line += ` ${dim}`;
41
+ }
42
+ process.stderr.write(line + "\n");
43
+ }
44
+ function write(level, msg, extra) {
45
+ if (LEVELS[level] < LEVELS[getConfiguredLevel()]) return;
46
+ if (getMode() === "cli") {
47
+ writeCli(level, msg, extra);
48
+ } else {
49
+ writeJson(level, msg, extra);
50
+ }
51
+ }
52
+ var logger = {
53
+ debug: (msg, extra) => write("debug", msg, extra),
54
+ info: (msg, extra) => write("info", msg, extra),
55
+ warn: (msg, extra) => write("warn", msg, extra),
56
+ error: (msg, extra) => write("error", msg, extra)
57
+ };
58
+
59
+ export {
60
+ logger
61
+ };
62
+ //# sourceMappingURL=chunk-TYDMSHV7.js.map
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-IHXVD5SO.js";
3
+ } from "./chunk-TYDMSHV7.js";
4
4
 
5
- // src/indexer/embedder.js
5
+ // packages/core/src/indexer/embedder.ts
6
6
  import { pipeline } from "@huggingface/transformers";
7
7
  import fs from "fs";
8
8
  import path from "path";
@@ -89,7 +89,7 @@ function collectFiles(dir, results = []) {
89
89
  return results;
90
90
  }
91
91
  async function indexDirectory(rootDir, onProgress) {
92
- const { VectorStore } = await import("./VectorStore-UQNBYPBV.js");
92
+ const { VectorStore } = await import("./VectorStore-HOSUSLV7.js");
93
93
  const store = new VectorStore(path.join(rootDir, ".ctxloom", "vectors.lancedb"));
94
94
  await store.init();
95
95
  const files = collectFiles(rootDir);
@@ -98,35 +98,40 @@ async function indexDirectory(rootDir, onProgress) {
98
98
  let errors = 0;
99
99
  let processed = 0;
100
100
  const CONCURRENCY = 4;
101
- for (let i = 0; i < files.length; i += CONCURRENCY) {
102
- const batch = files.slice(i, i + CONCURRENCY);
103
- const results = await Promise.allSettled(batch.map(async (filePath) => {
104
- const MAX_INDEX_SIZE = 5 * 1024 * 1024;
105
- const stat = fs.statSync(filePath);
106
- if (stat.size > MAX_INDEX_SIZE) {
107
- logger.warn("Skipping oversized file", { file: filePath, size: stat.size });
108
- return null;
109
- }
110
- const content = fs.readFileSync(filePath, "utf-8");
111
- if (!content.trim())
112
- return null;
113
- const relPath = path.relative(rootDir, filePath);
114
- const embedding = await generateEmbedding(content);
115
- await store.upsert(relPath, embedding, content);
116
- return relPath;
117
- }));
118
- for (const result of results) {
119
- processed++;
120
- if (result.status === "fulfilled") {
121
- if (result.value !== null) {
122
- indexed++;
123
- onProgress?.(result.value, processed, total);
101
+ try {
102
+ for (let i = 0; i < files.length; i += CONCURRENCY) {
103
+ const batch = files.slice(i, i + CONCURRENCY);
104
+ const results = await Promise.allSettled(
105
+ batch.map(async (filePath) => {
106
+ const MAX_INDEX_SIZE = 5 * 1024 * 1024;
107
+ const stat = fs.statSync(filePath);
108
+ if (stat.size > MAX_INDEX_SIZE) {
109
+ logger.warn("Skipping oversized file", { file: filePath, size: stat.size });
110
+ return null;
111
+ }
112
+ const content = fs.readFileSync(filePath, "utf-8");
113
+ if (!content.trim()) return null;
114
+ const relPath = path.relative(rootDir, filePath);
115
+ const embedding = await generateEmbedding(content);
116
+ await store.upsert(relPath, embedding, content);
117
+ return relPath;
118
+ })
119
+ );
120
+ for (const result of results) {
121
+ processed++;
122
+ if (result.status === "fulfilled") {
123
+ if (result.value !== null) {
124
+ indexed++;
125
+ onProgress?.(result.value, processed, total);
126
+ }
127
+ } else {
128
+ errors++;
129
+ logger.error("Failed to index file", { detail: result.reason instanceof Error ? result.reason.message : String(result.reason) });
124
130
  }
125
- } else {
126
- errors++;
127
- logger.error("Failed to index file", { detail: result.reason instanceof Error ? result.reason.message : String(result.reason) });
128
131
  }
129
132
  }
133
+ } finally {
134
+ await store.close();
130
135
  }
131
136
  return { indexed, errors };
132
137
  }
@@ -137,4 +142,4 @@ export {
137
142
  collectFiles,
138
143
  indexDirectory
139
144
  };
140
- //# sourceMappingURL=chunk-ZYDVY7VZ.js.map
145
+ //# sourceMappingURL=chunk-U3AVIYSJ.js.map