ctxloom-pro 1.1.2 → 1.1.3

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.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>ctxloom dashboard</title>
7
- <script type="module" crossorigin src="/assets/index-Bfa2_GyA.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-DNFP0Mer.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/assets/index-MBoNDzdn.css">
9
9
  </head>
10
10
  <body>
@@ -4458,8 +4458,8 @@ var ZodIssueCode = util.arrayToEnum([
4458
4458
  "not_finite"
4459
4459
  ]);
4460
4460
  var quotelessJson = (obj) => {
4461
- const json2 = JSON.stringify(obj, null, 2);
4462
- return json2.replace(/"([^"]+)":/g, "$1:");
4461
+ const json3 = JSON.stringify(obj, null, 2);
4462
+ return json3.replace(/"([^"]+)":/g, "$1:");
4463
4463
  };
4464
4464
  var ZodError = class _ZodError extends Error {
4465
4465
  get errors() {
@@ -11272,12 +11272,176 @@ import os3 from "os";
11272
11272
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
11273
11273
  import path32 from "path";
11274
11274
  import os4 from "os";
11275
+ var UUID_V4_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
11276
+ function distinctIdPath(home) {
11277
+ return path32.join(home ?? os4.homedir(), ".ctxloom", "distinct_id");
11278
+ }
11279
+ function isValidV4(id) {
11280
+ return typeof id === "string" && UUID_V4_REGEX.test(id);
11281
+ }
11282
+ function getOrCreateDistinctId(home) {
11283
+ const filePath = distinctIdPath(home);
11284
+ if (existsSync2(filePath)) {
11285
+ try {
11286
+ const raw = readFileSync3(filePath, "utf8");
11287
+ const parsed = JSON.parse(raw);
11288
+ if (parsed !== null && typeof parsed === "object" && isValidV4(parsed["id"])) {
11289
+ return parsed;
11290
+ }
11291
+ } catch {
11292
+ }
11293
+ }
11294
+ const record = {
11295
+ id: crypto.randomUUID(),
11296
+ alias_pending: os4.hostname()
11297
+ };
11298
+ mkdirSync2(path32.dirname(filePath), { recursive: true });
11299
+ writeFileSync2(filePath, JSON.stringify(record), { mode: 384 });
11300
+ return record;
11301
+ }
11302
+ function markAliasSent(home) {
11303
+ const filePath = distinctIdPath(home);
11304
+ try {
11305
+ const raw = readFileSync3(filePath, "utf8");
11306
+ const parsed = JSON.parse(raw);
11307
+ const { alias_pending: _dropped, ...rest } = parsed;
11308
+ writeFileSync2(filePath, JSON.stringify(rest), { mode: 384 });
11309
+ } catch {
11310
+ }
11311
+ }
11275
11312
 
11276
11313
  // ../../packages/core/src/license/telemetry.ts
11277
11314
  var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
11278
11315
  var CTXLOOM_VERSION = typeof __CTXLOOM_VERSION__ === "string" && __CTXLOOM_VERSION__.length > 0 ? __CTXLOOM_VERSION__ : "dev";
11316
+ var POSTHOG_HOST = "https://eu.i.posthog.com";
11279
11317
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (typeof __TELEMETRY_POSTHOG_KEY__ === "string" ? __TELEMETRY_POSTHOG_KEY__ : "");
11280
11318
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (typeof __TELEMETRY_SENTRY_DSN__ === "string" ? __TELEMETRY_SENTRY_DSN__ : "");
11319
+ var cachedDistinctId = null;
11320
+ function resolveDistinctId() {
11321
+ if (cachedDistinctId) return cachedDistinctId;
11322
+ try {
11323
+ cachedDistinctId = getOrCreateDistinctId();
11324
+ return cachedDistinctId;
11325
+ } catch {
11326
+ return null;
11327
+ }
11328
+ }
11329
+ function track(event, props = {}) {
11330
+ if (TELEMETRY_DISABLED || !POSTHOG_KEY) return;
11331
+ const record = resolveDistinctId();
11332
+ if (!record) return;
11333
+ void sendPostHog(event, record.id, props);
11334
+ if (record.alias_pending) {
11335
+ const oldAlias = record.alias_pending;
11336
+ void sendAlias(record.id, oldAlias);
11337
+ }
11338
+ }
11339
+ function captureError(err, context = {}) {
11340
+ if (TELEMETRY_DISABLED || !SENTRY_DSN) return;
11341
+ const record = resolveDistinctId();
11342
+ const augmented = record ? { ...context, distinct_id: record.id } : context;
11343
+ void sendSentry(err, augmented);
11344
+ }
11345
+ async function sendPostHog(event, distinctId, props) {
11346
+ try {
11347
+ await fetch(`${POSTHOG_HOST}/capture/`, {
11348
+ method: "POST",
11349
+ headers: { "Content-Type": "application/json" },
11350
+ body: JSON.stringify({
11351
+ api_key: POSTHOG_KEY,
11352
+ distinct_id: distinctId,
11353
+ event,
11354
+ properties: {
11355
+ $lib: "ctxloom-cli",
11356
+ release: CTXLOOM_VERSION,
11357
+ ...props
11358
+ }
11359
+ }),
11360
+ signal: AbortSignal.timeout(4e3)
11361
+ });
11362
+ } catch {
11363
+ }
11364
+ }
11365
+ async function sendAlias(newId, oldAlias) {
11366
+ try {
11367
+ const res = await fetch(`${POSTHOG_HOST}/capture/`, {
11368
+ method: "POST",
11369
+ headers: { "Content-Type": "application/json" },
11370
+ body: JSON.stringify({
11371
+ api_key: POSTHOG_KEY,
11372
+ distinct_id: newId,
11373
+ event: "$create_alias",
11374
+ properties: {
11375
+ $lib: "ctxloom-cli",
11376
+ release: CTXLOOM_VERSION,
11377
+ alias: oldAlias
11378
+ }
11379
+ }),
11380
+ signal: AbortSignal.timeout(4e3)
11381
+ });
11382
+ if (res.ok) {
11383
+ try {
11384
+ markAliasSent();
11385
+ } catch {
11386
+ }
11387
+ if (cachedDistinctId) cachedDistinctId = { id: cachedDistinctId.id };
11388
+ }
11389
+ } catch {
11390
+ }
11391
+ }
11392
+ async function sendSentry(err, context) {
11393
+ try {
11394
+ const dsn = parseDsn(SENTRY_DSN);
11395
+ if (!dsn) return;
11396
+ const message = err instanceof Error ? err.message : String(err);
11397
+ const stack = err instanceof Error ? err.stack : void 0;
11398
+ await fetch(`https://${dsn.host}/api/${dsn.projectId}/store/`, {
11399
+ method: "POST",
11400
+ headers: {
11401
+ "Content-Type": "application/json",
11402
+ "X-Sentry-Auth": `Sentry sentry_version=7, sentry_key=${dsn.key}`
11403
+ },
11404
+ body: JSON.stringify({
11405
+ event_id: crypto.randomUUID().replace(/-/g, ""),
11406
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11407
+ platform: "node",
11408
+ level: "error",
11409
+ exception: {
11410
+ values: [
11411
+ {
11412
+ type: err instanceof Error ? err.constructor.name : "Error",
11413
+ value: message,
11414
+ stacktrace: stack ? { frames: parseStack(stack) } : void 0
11415
+ }
11416
+ ]
11417
+ },
11418
+ extra: context,
11419
+ tags: { runtime: "node", component: "cli-license", release: CTXLOOM_VERSION }
11420
+ }),
11421
+ signal: AbortSignal.timeout(4e3)
11422
+ });
11423
+ } catch {
11424
+ }
11425
+ }
11426
+ function parseDsn(dsn) {
11427
+ try {
11428
+ const url = new URL(dsn);
11429
+ const projectId = url.pathname.replace(/^\//, "");
11430
+ return { host: url.hostname, key: url.username, projectId };
11431
+ } catch {
11432
+ return null;
11433
+ }
11434
+ }
11435
+ function scrubPath(filename) {
11436
+ return filename.replace(/^\/Users\/[^/]+\//, "/Users/~/").replace(/^\/home\/[^/]+\//, "/home/~/").replace(/^([A-Z]:\\\\Users\\\\)[^\\]+\\\\/, "$1~\\\\").replace(/^([A-Z]:\\Users\\)[^\\]+\\/, "$1~\\");
11437
+ }
11438
+ function parseStack(stack) {
11439
+ return stack.split("\n").slice(1).map((line) => {
11440
+ const m = line.trim().match(/at (.+?) \((.+?):(\d+):\d+\)/);
11441
+ if (!m) return null;
11442
+ return { function: m[1] ?? "", filename: scrubPath(m[2] ?? ""), lineno: Number(m[3]) };
11443
+ }).filter((f) => f !== null).slice(0, 20);
11444
+ }
11281
11445
 
11282
11446
  // ../../packages/core/src/server/ProjectState.ts
11283
11447
  import path34 from "path";
@@ -11822,6 +11986,55 @@ function buildProjectsRouter(deps) {
11822
11986
  return router;
11823
11987
  }
11824
11988
 
11989
+ // server/routes/telemetry.ts
11990
+ import { Router as Router13, json as json2 } from "express";
11991
+ var DASHBOARD_EVENT_ALLOWLIST = /* @__PURE__ */ new Set([
11992
+ "dashboard_loaded",
11993
+ "dashboard_page_viewed"
11994
+ ]);
11995
+ var MAX_MESSAGE_LENGTH = 2e3;
11996
+ var MAX_STACK_LENGTH = 1e4;
11997
+ function buildTelemetryRouter() {
11998
+ const router = Router13();
11999
+ router.get("/identity", (_req, res) => {
12000
+ const disabled = process.env.CTXLOOM_NO_TELEMETRY === "1" || process.env.DO_NOT_TRACK === "1";
12001
+ res.json({ enabled: !disabled });
12002
+ });
12003
+ router.post("/event", json2(), (req, res) => {
12004
+ const body = req.body;
12005
+ const event = body?.event;
12006
+ if (typeof event !== "string" || !DASHBOARD_EVENT_ALLOWLIST.has(event)) {
12007
+ res.status(400).json({ error: "invalid event" });
12008
+ return;
12009
+ }
12010
+ const rawProps = body?.props;
12011
+ const sanitizedProps = rawProps && typeof rawProps === "object" && !Array.isArray(rawProps) ? rawProps : {};
12012
+ track(event, {
12013
+ ...sanitizedProps,
12014
+ surface: "dashboard"
12015
+ });
12016
+ res.status(204).end();
12017
+ });
12018
+ router.post("/error", json2(), (req, res) => {
12019
+ const body = req.body;
12020
+ const message = body?.message;
12021
+ if (typeof message !== "string" || message.length === 0 || message.length > MAX_MESSAGE_LENGTH) {
12022
+ res.status(400).json({ error: "invalid message" });
12023
+ return;
12024
+ }
12025
+ const stack = body?.stack;
12026
+ const err = new Error(message);
12027
+ if (typeof stack === "string" && stack.length > 0 && stack.length <= MAX_STACK_LENGTH) {
12028
+ err.stack = stack;
12029
+ }
12030
+ const rawContext = body?.context;
12031
+ const sanitizedContext = rawContext && typeof rawContext === "object" && !Array.isArray(rawContext) ? rawContext : {};
12032
+ captureError(err, { ...sanitizedContext, surface: "dashboard" });
12033
+ res.status(204).end();
12034
+ });
12035
+ return router;
12036
+ }
12037
+
11825
12038
  // server/index.ts
11826
12039
  var __dirname2 = path42.dirname(fileURLToPath2(import.meta.url));
11827
12040
  async function startDashboard(options) {
@@ -11903,6 +12116,7 @@ async function startDashboard(options) {
11903
12116
  }
11904
12117
  }
11905
12118
  attachSnapshotWatcher(ctx.root);
12119
+ app.use("/api/telemetry", buildTelemetryRouter());
11906
12120
  app.use("/api/projects", buildProjectsRouter({
11907
12121
  ctx,
11908
12122
  defaultRoot: root,
@@ -8838,7 +8838,7 @@ function markAliasSent(home) {
8838
8838
 
8839
8839
  // packages/core/src/license/telemetry.ts
8840
8840
  var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
8841
- var CTXLOOM_VERSION = "1.1.2".length > 0 ? "1.1.2" : "dev";
8841
+ var CTXLOOM_VERSION = "1.1.3".length > 0 ? "1.1.3" : "dev";
8842
8842
  var POSTHOG_HOST = "https://eu.i.posthog.com";
8843
8843
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
8844
8844
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -9409,4 +9409,4 @@ export {
9409
9409
  FirstTouchTracker,
9410
9410
  EmittedOnceTracker
9411
9411
  };
9412
- //# sourceMappingURL=chunk-RGO3M3IR.js.map
9412
+ //# sourceMappingURL=chunk-POGILISN.js.map
package/dist/index.js CHANGED
@@ -45,7 +45,7 @@ import {
45
45
  validateDefaultRoot,
46
46
  wrapWithIndexingEnvelope,
47
47
  writeCODEOWNERS
48
- } from "./chunk-RGO3M3IR.js";
48
+ } from "./chunk-POGILISN.js";
49
49
  import {
50
50
  VectorStore
51
51
  } from "./chunk-NEHYSE2Y.js";
@@ -892,7 +892,7 @@ try {
892
892
  } catch {
893
893
  }
894
894
  var args = process.argv.slice(2);
895
- var ctxloomVersion = "1.1.2".length > 0 ? "1.1.2" : "dev";
895
+ var ctxloomVersion = "1.1.3".length > 0 ? "1.1.3" : "dev";
896
896
  if (args.includes("--version") || args.includes("-v")) {
897
897
  process.stdout.write(`ctxloom ${ctxloomVersion}
898
898
  `);
@@ -965,7 +965,7 @@ async function checkLicense() {
965
965
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
966
966
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
967
967
  if (ciKey) {
968
- const { ApiClient } = await import("./src-5MVUPLMZ.js");
968
+ const { ApiClient } = await import("./src-2I4ZNYVG.js");
969
969
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
970
970
  try {
971
971
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1318,7 +1318,7 @@ async function main() {
1318
1318
  process.exit(1);
1319
1319
  }
1320
1320
  if (alias !== void 0) {
1321
- const { validateAlias } = await import("./src-5MVUPLMZ.js");
1321
+ const { validateAlias } = await import("./src-2I4ZNYVG.js");
1322
1322
  const v = validateAlias(alias);
1323
1323
  if (!v.ok) {
1324
1324
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1562,7 +1562,7 @@ Suggested reviewers for ${files.length} file(s):`);
1562
1562
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1563
1563
  process.exit(2);
1564
1564
  }
1565
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-5MVUPLMZ.js");
1565
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-2I4ZNYVG.js");
1566
1566
  let config;
1567
1567
  try {
1568
1568
  config = await loadRulesConfig(root);
@@ -1586,7 +1586,7 @@ Suggested reviewers for ${files.length} file(s):`);
1586
1586
  }
1587
1587
  let graph;
1588
1588
  if (useSnapshot) {
1589
- const { DependencyGraph: DG } = await import("./src-5MVUPLMZ.js");
1589
+ const { DependencyGraph: DG } = await import("./src-2I4ZNYVG.js");
1590
1590
  graph = new DG();
1591
1591
  const loaded = await graph.loadSnapshotOnly(root);
1592
1592
  if (!loaded) {
@@ -1595,7 +1595,7 @@ Suggested reviewers for ${files.length} file(s):`);
1595
1595
  }
1596
1596
  } else {
1597
1597
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1598
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-5MVUPLMZ.js");
1598
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-2I4ZNYVG.js");
1599
1599
  let parser;
1600
1600
  try {
1601
1601
  parser = new ASTParser2();
@@ -99,7 +99,7 @@ import {
99
99
  validateDefaultRoot,
100
100
  wrapWithIndexingEnvelope,
101
101
  writeCODEOWNERS
102
- } from "./chunk-RGO3M3IR.js";
102
+ } from "./chunk-POGILISN.js";
103
103
  import {
104
104
  VectorStore
105
105
  } from "./chunk-NEHYSE2Y.js";
@@ -220,4 +220,4 @@ export {
220
220
  wrapWithIndexingEnvelope,
221
221
  writeCODEOWNERS
222
222
  };
223
- //# sourceMappingURL=src-5MVUPLMZ.js.map
223
+ //# sourceMappingURL=src-2I4ZNYVG.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxloom-pro",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
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",