ctxloom-pro 1.0.7 → 1.0.9

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.
@@ -8044,10 +8044,10 @@ var Schema15 = external_exports.object({
8044
8044
  });
8045
8045
 
8046
8046
  // ../../packages/core/src/tools/git-diff-review.ts
8047
- import { exec as exec2 } from "child_process";
8047
+ import { execFile } from "child_process";
8048
8048
  import { promisify as promisify2 } from "util";
8049
8049
  init_logger();
8050
- var execAsync2 = promisify2(exec2);
8050
+ var execFileAsync = promisify2(execFile);
8051
8051
  var Schema16 = external_exports.object({
8052
8052
  changed_files: external_exports.array(external_exports.string()).optional().describe(
8053
8053
  "Changed file paths (relative to project root). Omit to auto-detect from git diff HEAD~1."
@@ -8116,10 +8116,10 @@ var Schema20 = external_exports.object({
8116
8116
  });
8117
8117
 
8118
8118
  // ../../packages/core/src/tools/detect-changes.ts
8119
- import { exec as exec3 } from "child_process";
8119
+ import { exec as exec2 } from "child_process";
8120
8120
  import { promisify as promisify3 } from "util";
8121
8121
  init_logger();
8122
- var execAsync3 = promisify3(exec3);
8122
+ var execAsync2 = promisify3(exec2);
8123
8123
  var Schema21 = external_exports.object({
8124
8124
  changed_files: external_exports.array(external_exports.string()).optional(),
8125
8125
  use_git: external_exports.boolean().optional().default(true),
@@ -8142,9 +8142,9 @@ var Schema22 = external_exports.object({
8142
8142
 
8143
8143
  // ../../packages/core/src/tools/suggested-questions.ts
8144
8144
  init_logger();
8145
- import { exec as exec4 } from "child_process";
8145
+ import { exec as exec3 } from "child_process";
8146
8146
  import { promisify as promisify4 } from "util";
8147
- var execAsync4 = promisify4(exec4);
8147
+ var execAsync3 = promisify4(exec3);
8148
8148
  var Schema23 = external_exports.object({
8149
8149
  changed_files: external_exports.array(external_exports.string()).optional(),
8150
8150
  use_git: external_exports.boolean().optional().default(true)
@@ -10806,9 +10806,9 @@ var RulesConfigSchema = external_exports.object({
10806
10806
 
10807
10807
  // ../../packages/core/src/tools/get-affected-flows.ts
10808
10808
  init_logger();
10809
- import { exec as exec5 } from "child_process";
10809
+ import { exec as exec4 } from "child_process";
10810
10810
  import { promisify as promisify5 } from "util";
10811
- var execAsync5 = promisify5(exec5);
10811
+ var execAsync4 = promisify5(exec4);
10812
10812
  var Schema27 = external_exports.object({
10813
10813
  changed_files: external_exports.array(external_exports.string()).optional().describe(
10814
10814
  "Changed file paths (relative). Defaults to auto-detection from git diff HEAD~1."
@@ -10886,8 +10886,9 @@ import { readFileSync as readFileSync2 } from "fs";
10886
10886
  import os3 from "os";
10887
10887
 
10888
10888
  // ../../packages/core/src/license/telemetry.ts
10889
- var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? "phc_xAusXPkHxhjhzRguxcyylLO6s5Hn1ZNNeThATGP4Dlf";
10890
- var SENTRY_DSN = process.env["SENTRY_DSN"] ?? "https://e52f4c5fdc82eca82dadb4261e474069@o4508531702497280.ingest.de.sentry.io/4511256875368528";
10889
+ var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
10890
+ var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (typeof __TELEMETRY_POSTHOG_KEY__ === "string" ? __TELEMETRY_POSTHOG_KEY__ : "");
10891
+ var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (typeof __TELEMETRY_SENTRY_DSN__ === "string" ? __TELEMETRY_SENTRY_DSN__ : "");
10891
10892
 
10892
10893
  // server/loader.ts
10893
10894
  async function loadContext(root) {
@@ -11144,7 +11145,10 @@ function buildFileRouter(ctx) {
11144
11145
  const rel = req.query.path;
11145
11146
  if (!rel) return res.status(400).json({ error: "missing path" });
11146
11147
  const abs = path32.resolve(ctx.root, rel);
11147
- if (!abs.startsWith(ctx.root)) return res.status(403).json({ error: "forbidden" });
11148
+ const rootBoundary = ctx.root.endsWith(path32.sep) ? ctx.root : ctx.root + path32.sep;
11149
+ if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
11150
+ return res.status(403).json({ error: "forbidden" });
11151
+ }
11148
11152
  try {
11149
11153
  const content = await fs27.readFile(abs, "utf-8");
11150
11154
  const ext = path32.extname(abs).slice(1);
@@ -11158,22 +11162,24 @@ function buildFileRouter(ctx) {
11158
11162
 
11159
11163
  // server/routes/open.ts
11160
11164
  import { Router as Router8 } from "express";
11161
- import { exec as exec6 } from "child_process";
11165
+ import { execFile as execFile2 } from "child_process";
11162
11166
  import path33 from "path";
11163
- function tryOpen(cmd) {
11167
+ function tryOpen(bin, abs) {
11164
11168
  return new Promise((resolve) => {
11165
- exec6(cmd, (err) => resolve(!err));
11169
+ execFile2(bin, [abs], { timeout: 5e3 }, (err) => resolve(!err));
11166
11170
  });
11167
11171
  }
11168
11172
  function buildOpenRouter(ctx) {
11169
11173
  const router = Router8();
11170
11174
  router.post("/", async (req, res) => {
11171
11175
  const rel = req.body?.path;
11172
- if (!rel) return res.status(400).json({ error: "missing path" });
11176
+ if (!rel || typeof rel !== "string") return res.status(400).json({ error: "missing path" });
11173
11177
  const abs = path33.resolve(ctx.root, rel);
11174
- if (!abs.startsWith(ctx.root)) return res.status(403).json({ error: "forbidden" });
11175
- const escaped = JSON.stringify(abs);
11176
- const opened = await tryOpen(`code ${escaped}`) || await tryOpen(`cursor ${escaped}`) || await tryOpen(`open ${escaped}`);
11178
+ const rootBoundary = ctx.root.endsWith(path33.sep) ? ctx.root : ctx.root + path33.sep;
11179
+ if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
11180
+ return res.status(403).json({ error: "forbidden" });
11181
+ }
11182
+ const opened = await tryOpen("code", abs) || await tryOpen("cursor", abs) || await tryOpen("open", abs);
11177
11183
  res.json({ ok: opened });
11178
11184
  });
11179
11185
  return router;
@@ -11259,7 +11265,17 @@ async function startDashboard(options) {
11259
11265
  const ctx = await loadContext(root);
11260
11266
  console.log(` ${ctx.graph.allFiles().length} files, ${ctx.graph.edgeCount()} edges, git=${ctx.gitEnabled}`);
11261
11267
  const app = express();
11262
- app.use(cors());
11268
+ const allowedOrigins = /* @__PURE__ */ new Set([
11269
+ `http://localhost:${port}`,
11270
+ `http://127.0.0.1:${port}`
11271
+ ]);
11272
+ app.use(cors({
11273
+ origin: (origin, cb) => {
11274
+ if (!origin) return cb(null, true);
11275
+ cb(null, allowedOrigins.has(origin));
11276
+ },
11277
+ credentials: false
11278
+ }));
11263
11279
  app.use(express.json());
11264
11280
  app.use("/api/overview", buildOverviewRouter(ctx));
11265
11281
  app.use("/api/graph", buildGraphRouter(ctx));
@@ -11271,7 +11287,7 @@ async function startDashboard(options) {
11271
11287
  app.use("/api/open", buildOpenRouter(ctx));
11272
11288
  app.use("/api/tokens", buildTokensRouter(ctx));
11273
11289
  app.use("/api/trends", buildTrendsRouter(ctx));
11274
- app.get("/api/health", (_req, res) => res.json({ ok: true, root, gitEnabled: ctx.gitEnabled }));
11290
+ app.get("/api/health", (_req, res) => res.json({ ok: true, gitEnabled: ctx.gitEnabled }));
11275
11291
  app.get("/api/status", (_req, res) => res.json({
11276
11292
  lastIndexed: ctx.lastIndexed.toISOString(),
11277
11293
  fileCount: ctx.graph.allFiles().length,
@@ -5442,9 +5442,9 @@ function registerGraphExportTool(registry, ctx) {
5442
5442
 
5443
5443
  // packages/core/src/tools/git-diff-review.ts
5444
5444
  import { z as z16 } from "zod";
5445
- import { exec as exec2 } from "child_process";
5445
+ import { execFile } from "child_process";
5446
5446
  import { promisify as promisify2 } from "util";
5447
- var execAsync2 = promisify2(exec2);
5447
+ var execFileAsync = promisify2(execFile);
5448
5448
  var Schema16 = z16.object({
5449
5449
  changed_files: z16.array(z16.string()).optional().describe(
5450
5450
  "Changed file paths (relative to project root). Omit to auto-detect from git diff HEAD~1."
@@ -5462,8 +5462,13 @@ function escapeXML16(text) {
5462
5462
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5463
5463
  }
5464
5464
  async function getFileDiff(projectRoot, file) {
5465
+ if (file.includes("\0") || file.startsWith("-")) return "";
5465
5466
  try {
5466
- const { stdout } = await execAsync2(`git diff HEAD~1 -- "${file}"`, { cwd: projectRoot });
5467
+ const { stdout } = await execFileAsync(
5468
+ "git",
5469
+ ["diff", "HEAD~1", "--", file],
5470
+ { cwd: projectRoot, maxBuffer: 10 * 1024 * 1024 }
5471
+ );
5467
5472
  return stdout.trim();
5468
5473
  } catch {
5469
5474
  return "";
@@ -5504,10 +5509,15 @@ function registerGitDiffReviewTool(registry, ctx) {
5504
5509
  },
5505
5510
  async (args) => {
5506
5511
  const { changed_files, depth, use_git, include_skeletons, max_diff_lines } = Schema16.parse(args);
5507
- let files = changed_files ?? [];
5512
+ const validator = ctx.getPathValidator();
5513
+ let files = (changed_files ?? []).filter((f) => validator.isWithinRoot(f));
5508
5514
  if (files.length === 0 && use_git) {
5509
5515
  try {
5510
- const { stdout } = await execAsync2("git diff HEAD~1 --name-only", { cwd: ctx.projectRoot });
5516
+ const { stdout } = await execFileAsync(
5517
+ "git",
5518
+ ["diff", "HEAD~1", "--name-only"],
5519
+ { cwd: ctx.projectRoot, maxBuffer: 10 * 1024 * 1024 }
5520
+ );
5511
5521
  files = stdout.trim().split("\n").filter(Boolean);
5512
5522
  } catch {
5513
5523
  logger.warn("git diff failed \u2014 no changed files detected");
@@ -6083,9 +6093,9 @@ function registerApplyRefactorTool(registry, ctx) {
6083
6093
 
6084
6094
  // packages/core/src/tools/detect-changes.ts
6085
6095
  import { z as z21 } from "zod";
6086
- import { exec as exec3 } from "child_process";
6096
+ import { exec as exec2 } from "child_process";
6087
6097
  import { promisify as promisify3 } from "util";
6088
- var execAsync3 = promisify3(exec3);
6098
+ var execAsync2 = promisify3(exec2);
6089
6099
  var Schema21 = z21.object({
6090
6100
  changed_files: z21.array(z21.string()).optional(),
6091
6101
  use_git: z21.boolean().optional().default(true),
@@ -6099,7 +6109,7 @@ function escapeXML21(text) {
6099
6109
  }
6100
6110
  async function detectChangedFiles2(projectRoot) {
6101
6111
  try {
6102
- const { stdout } = await execAsync3("git diff HEAD~1 --name-only", { cwd: projectRoot });
6112
+ const { stdout } = await execAsync2("git diff HEAD~1 --name-only", { cwd: projectRoot });
6103
6113
  return stdout.trim().split("\n").filter(Boolean);
6104
6114
  } catch {
6105
6115
  logger.warn("git diff failed for detect_changes");
@@ -6334,9 +6344,9 @@ function registerFullTextSearchTool(registry, ctx) {
6334
6344
 
6335
6345
  // packages/core/src/tools/suggested-questions.ts
6336
6346
  import { z as z23 } from "zod";
6337
- import { exec as exec4 } from "child_process";
6347
+ import { exec as exec3 } from "child_process";
6338
6348
  import { promisify as promisify4 } from "util";
6339
- var execAsync4 = promisify4(exec4);
6349
+ var execAsync3 = promisify4(exec3);
6340
6350
  var Schema23 = z23.object({
6341
6351
  changed_files: z23.array(z23.string()).optional(),
6342
6352
  use_git: z23.boolean().optional().default(true)
@@ -6347,7 +6357,7 @@ function escapeXML23(text) {
6347
6357
  }
6348
6358
  async function detectChangedFiles3(projectRoot) {
6349
6359
  try {
6350
- const { stdout } = await execAsync4("git diff HEAD~1 --name-only", { cwd: projectRoot });
6360
+ const { stdout } = await execAsync3("git diff HEAD~1 --name-only", { cwd: projectRoot });
6351
6361
  return stdout.trim().split("\n").filter(Boolean);
6352
6362
  } catch {
6353
6363
  logger.warn("git diff failed for suggested_questions");
@@ -7154,9 +7164,9 @@ function registerRulesCheckTool(registry, ctx) {
7154
7164
 
7155
7165
  // packages/core/src/tools/get-affected-flows.ts
7156
7166
  import { z as z31 } from "zod";
7157
- import { exec as exec5 } from "child_process";
7167
+ import { exec as exec4 } from "child_process";
7158
7168
  import { promisify as promisify5 } from "util";
7159
- var execAsync5 = promisify5(exec5);
7169
+ var execAsync4 = promisify5(exec4);
7160
7170
  var Schema27 = z31.object({
7161
7171
  changed_files: z31.array(z31.string()).optional().describe(
7162
7172
  "Changed file paths (relative). Defaults to auto-detection from git diff HEAD~1."
@@ -7211,7 +7221,7 @@ function buildFlow(entrySymbol, entryFile, maxDepth, maxSteps, graph, callIdx) {
7211
7221
  }
7212
7222
  async function detectChangedFiles4(projectRoot) {
7213
7223
  try {
7214
- const { stdout } = await execAsync5("git diff HEAD~1 --name-only", { cwd: projectRoot });
7224
+ const { stdout } = await execAsync4("git diff HEAD~1 --name-only", { cwd: projectRoot });
7215
7225
  return stdout.trim().split("\n").filter(Boolean);
7216
7226
  } catch {
7217
7227
  logger.warn("git diff failed for get_affected_flows \u2014 no changed files detected");
@@ -8021,7 +8031,7 @@ var LicenseStore = class {
8021
8031
  } catch (err) {
8022
8032
  if (process.env["CTXLOOM_DEBUG"]) {
8023
8033
  const detail = err instanceof Error ? err.message : String(err);
8024
- process.stderr.write(`[ctxloom] LicenseStore.read failed at ${this.filePath}: ${detail}
8034
+ process.stderr.write(`[ctxloom] LicenseStore.read failed: ${detail}
8025
8035
  `);
8026
8036
  }
8027
8037
  return null;
@@ -8029,7 +8039,10 @@ var LicenseStore = class {
8029
8039
  }
8030
8040
  async write(license) {
8031
8041
  mkdirSync(path28.dirname(this.filePath), { recursive: true });
8032
- writeFileSync(this.filePath, JSON.stringify(license, null, 2), "utf8");
8042
+ writeFileSync(this.filePath, JSON.stringify(license, null, 2), {
8043
+ encoding: "utf8",
8044
+ mode: 384
8045
+ });
8033
8046
  if (process.platform !== "win32") {
8034
8047
  chmodSync(this.filePath, 384);
8035
8048
  }
@@ -8253,15 +8266,16 @@ async function startTrial(email, opts = {}) {
8253
8266
  }
8254
8267
 
8255
8268
  // packages/core/src/license/telemetry.ts
8269
+ var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
8256
8270
  var POSTHOG_HOST = "https://eu.i.posthog.com";
8257
- var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? "phc_xAusXPkHxhjhzRguxcyylLO6s5Hn1ZNNeThATGP4Dlf";
8258
- var SENTRY_DSN = process.env["SENTRY_DSN"] ?? "https://e52f4c5fdc82eca82dadb4261e474069@o4508531702497280.ingest.de.sentry.io/4511256875368528";
8271
+ var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
8272
+ var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
8259
8273
  function track(event, distinctId, props = {}) {
8260
- if (!POSTHOG_KEY) return;
8274
+ if (TELEMETRY_DISABLED || !POSTHOG_KEY) return;
8261
8275
  void sendPostHog(event, distinctId, props);
8262
8276
  }
8263
8277
  function captureError(err, context = {}) {
8264
- if (!SENTRY_DSN) return;
8278
+ if (TELEMETRY_DISABLED || !SENTRY_DSN) return;
8265
8279
  void sendSentry(err, context);
8266
8280
  }
8267
8281
  async function sendPostHog(event, distinctId, props) {
@@ -8406,4 +8420,4 @@ export {
8406
8420
  track,
8407
8421
  captureError
8408
8422
  };
8409
- //# sourceMappingURL=chunk-UIP6NEKV.js.map
8423
+ //# sourceMappingURL=chunk-UMFIYUGI.js.map
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  startTrial,
35
35
  track,
36
36
  writeCODEOWNERS
37
- } from "./chunk-UIP6NEKV.js";
37
+ } from "./chunk-UMFIYUGI.js";
38
38
  import {
39
39
  VectorStore
40
40
  } from "./chunk-NEHYSE2Y.js";
@@ -574,14 +574,12 @@ function buildActivityFromOverlay(store) {
574
574
  lastCommitTimestamp
575
575
  }));
576
576
  }
577
- var LICENSE_BYPASS = process.env["CTXLOOM_LICENSE_BYPASS"] === "1";
578
577
  var LICENSE_GATE_BYPASS_COMMANDS = /* @__PURE__ */ new Set(["trial", "activate", "deactivate", "status", "--help"]);
579
578
  async function checkLicense() {
580
- if (LICENSE_BYPASS) return;
581
579
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
582
580
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
583
581
  if (ciKey) {
584
- const { ApiClient } = await import("./src-X2BT3ERD.js");
582
+ const { ApiClient } = await import("./src-D3CS3BFE.js");
585
583
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
586
584
  try {
587
585
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1102,7 +1100,7 @@ Suggested reviewers for ${files.length} file(s):`);
1102
1100
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1103
1101
  process.exit(2);
1104
1102
  }
1105
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-X2BT3ERD.js");
1103
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-D3CS3BFE.js");
1106
1104
  let config;
1107
1105
  try {
1108
1106
  config = await loadRulesConfig(root);
@@ -1126,7 +1124,7 @@ Suggested reviewers for ${files.length} file(s):`);
1126
1124
  }
1127
1125
  let graph;
1128
1126
  if (useSnapshot) {
1129
- const { DependencyGraph: DG } = await import("./src-X2BT3ERD.js");
1127
+ const { DependencyGraph: DG } = await import("./src-D3CS3BFE.js");
1130
1128
  graph = new DG();
1131
1129
  const loaded = await graph.loadSnapshotOnly(root);
1132
1130
  if (!loaded) {
@@ -1135,7 +1133,7 @@ Suggested reviewers for ${files.length} file(s):`);
1135
1133
  }
1136
1134
  } else {
1137
1135
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1138
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-X2BT3ERD.js");
1136
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-D3CS3BFE.js");
1139
1137
  let parser;
1140
1138
  try {
1141
1139
  parser = new ASTParser2();
@@ -69,7 +69,7 @@ import {
69
69
  startTrial,
70
70
  track,
71
71
  writeCODEOWNERS
72
- } from "./chunk-UIP6NEKV.js";
72
+ } from "./chunk-UMFIYUGI.js";
73
73
  import {
74
74
  VectorStore
75
75
  } from "./chunk-NEHYSE2Y.js";
@@ -160,4 +160,4 @@ export {
160
160
  track,
161
161
  writeCODEOWNERS
162
162
  };
163
- //# sourceMappingURL=src-X2BT3ERD.js.map
163
+ //# sourceMappingURL=src-D3CS3BFE.js.map
@@ -9,8 +9,23 @@ import "../chunk-TYDMSHV7.js";
9
9
  // packages/core/src/workers/indexerWorker.ts
10
10
  import { parentPort, workerData } from "worker_threads";
11
11
  import path from "path";
12
+ import { z } from "zod";
13
+ var WorkerDataSchema = z.object({
14
+ filePath: z.string().min(1),
15
+ content: z.string(),
16
+ root: z.string().min(1),
17
+ dbPath: z.string().min(1)
18
+ });
12
19
  async function run() {
13
- const { filePath, content, root, dbPath } = workerData;
20
+ const parsed = WorkerDataSchema.safeParse(workerData);
21
+ if (!parsed.success) {
22
+ parentPort?.postMessage({
23
+ status: "error",
24
+ error: `invalid workerData: ${parsed.error.message}`
25
+ });
26
+ return;
27
+ }
28
+ const { filePath, content, root, dbPath } = parsed.data;
14
29
  let store = null;
15
30
  try {
16
31
  const relPath = path.relative(root, filePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxloom-pro",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "ctxloom — The Universal Code Context Engine. A local-first MCP server providing intelligent code context via hybrid Vector + AST + Graph search with Skeletonization (92% token reduction).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -74,7 +74,6 @@
74
74
  },
75
75
  "author": "Codzign",
76
76
  "dependencies": {
77
- "@ctxloom/core": "*",
78
77
  "@huggingface/transformers": "^3.0.0",
79
78
  "@lancedb/lancedb": "^0.27.0",
80
79
  "@modelcontextprotocol/sdk": "^1.12.0",
@@ -90,6 +89,7 @@
90
89
  "zod": "^3.23.0"
91
90
  },
92
91
  "devDependencies": {
92
+ "@ctxloom/core": "*",
93
93
  "@types/js-yaml": "^4.0.9",
94
94
  "@types/node": "^22.0.0",
95
95
  "@types/picomatch": "^4.0.3",