ctxloom-pro 1.1.0 → 1.1.1
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.
|
@@ -169,12 +169,12 @@ var init_VectorStore = __esm({
|
|
|
169
169
|
// server/index.ts
|
|
170
170
|
import express from "express";
|
|
171
171
|
import cors from "cors";
|
|
172
|
-
import
|
|
172
|
+
import path41 from "path";
|
|
173
173
|
import fs32 from "fs";
|
|
174
174
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
175
175
|
|
|
176
176
|
// server/loader.ts
|
|
177
|
-
import
|
|
177
|
+
import path35 from "path";
|
|
178
178
|
|
|
179
179
|
// ../../packages/core/src/graph/DependencyGraph.ts
|
|
180
180
|
import fs7 from "fs";
|
|
@@ -3133,8 +3133,8 @@ var CoChangeIndex = class _CoChangeIndex {
|
|
|
3133
3133
|
if (event.isBulk || event.isMerge) return;
|
|
3134
3134
|
const paths = event.files.map((f) => f.path);
|
|
3135
3135
|
if (paths.length === 0) return;
|
|
3136
|
-
for (const
|
|
3137
|
-
this.nodeCounts.set(
|
|
3136
|
+
for (const path42 of paths) {
|
|
3137
|
+
this.nodeCounts.set(path42, (this.nodeCounts.get(path42) ?? 0) + 1);
|
|
3138
3138
|
}
|
|
3139
3139
|
for (let i = 0; i < paths.length; i++) {
|
|
3140
3140
|
for (let j = i + 1; j < paths.length; j++) {
|
|
@@ -3281,8 +3281,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3281
3281
|
*/
|
|
3282
3282
|
snapshot() {
|
|
3283
3283
|
const nodes = {};
|
|
3284
|
-
for (const [
|
|
3285
|
-
nodes[
|
|
3284
|
+
for (const [path42, raw] of this.nodes) {
|
|
3285
|
+
nodes[path42] = {
|
|
3286
3286
|
commits: raw.commits,
|
|
3287
3287
|
churnLines: raw.churnLines,
|
|
3288
3288
|
bugCommits: raw.bugCommits,
|
|
@@ -3297,8 +3297,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3297
3297
|
*/
|
|
3298
3298
|
static load(s) {
|
|
3299
3299
|
const idx = new _ChurnIndex();
|
|
3300
|
-
for (const [
|
|
3301
|
-
idx.nodes.set(
|
|
3300
|
+
for (const [path42, raw] of Object.entries(s.nodes)) {
|
|
3301
|
+
idx.nodes.set(path42, {
|
|
3302
3302
|
commits: raw.commits,
|
|
3303
3303
|
churnLines: raw.churnLines,
|
|
3304
3304
|
bugCommits: raw.bugCommits,
|
|
@@ -3311,8 +3311,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3311
3311
|
// -------------------------------------------------------------------------
|
|
3312
3312
|
// Private helpers
|
|
3313
3313
|
// -------------------------------------------------------------------------
|
|
3314
|
-
getOrCreate(
|
|
3315
|
-
const existing = this.nodes.get(
|
|
3314
|
+
getOrCreate(path42) {
|
|
3315
|
+
const existing = this.nodes.get(path42);
|
|
3316
3316
|
if (existing !== void 0) return existing;
|
|
3317
3317
|
const fresh = {
|
|
3318
3318
|
commits: 0,
|
|
@@ -3321,7 +3321,7 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3321
3321
|
authorCounts: {},
|
|
3322
3322
|
lastTouch: 0
|
|
3323
3323
|
};
|
|
3324
|
-
this.nodes.set(
|
|
3324
|
+
this.nodes.set(path42, fresh);
|
|
3325
3325
|
return fresh;
|
|
3326
3326
|
}
|
|
3327
3327
|
};
|
|
@@ -3402,12 +3402,12 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
3402
3402
|
*/
|
|
3403
3403
|
snapshot() {
|
|
3404
3404
|
const nodes = {};
|
|
3405
|
-
for (const [
|
|
3405
|
+
for (const [path42, raw] of this.nodes) {
|
|
3406
3406
|
const authorWeights = {};
|
|
3407
3407
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
3408
3408
|
authorWeights[email] = { ...entry };
|
|
3409
3409
|
}
|
|
3410
|
-
nodes[
|
|
3410
|
+
nodes[path42] = { authorWeights, lastTouch: raw.lastTouch };
|
|
3411
3411
|
}
|
|
3412
3412
|
return { version: 1, nodes };
|
|
3413
3413
|
}
|
|
@@ -3416,23 +3416,23 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
3416
3416
|
*/
|
|
3417
3417
|
static load(s) {
|
|
3418
3418
|
const idx = new _OwnershipIndex();
|
|
3419
|
-
for (const [
|
|
3419
|
+
for (const [path42, raw] of Object.entries(s.nodes)) {
|
|
3420
3420
|
const authorWeights = {};
|
|
3421
3421
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
3422
3422
|
authorWeights[email] = { ...entry };
|
|
3423
3423
|
}
|
|
3424
|
-
idx.nodes.set(
|
|
3424
|
+
idx.nodes.set(path42, { authorWeights, lastTouch: raw.lastTouch });
|
|
3425
3425
|
}
|
|
3426
3426
|
return idx;
|
|
3427
3427
|
}
|
|
3428
3428
|
// -------------------------------------------------------------------------
|
|
3429
3429
|
// Private helpers
|
|
3430
3430
|
// -------------------------------------------------------------------------
|
|
3431
|
-
getOrCreate(
|
|
3432
|
-
const existing = this.nodes.get(
|
|
3431
|
+
getOrCreate(path42) {
|
|
3432
|
+
const existing = this.nodes.get(path42);
|
|
3433
3433
|
if (existing !== void 0) return existing;
|
|
3434
3434
|
const fresh = { authorWeights: {}, lastTouch: 0 };
|
|
3435
|
-
this.nodes.set(
|
|
3435
|
+
this.nodes.set(path42, fresh);
|
|
3436
3436
|
return fresh;
|
|
3437
3437
|
}
|
|
3438
3438
|
};
|
|
@@ -4670,8 +4670,8 @@ function getErrorMap() {
|
|
|
4670
4670
|
|
|
4671
4671
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
4672
4672
|
var makeIssue = (params) => {
|
|
4673
|
-
const { data, path:
|
|
4674
|
-
const fullPath = [...
|
|
4673
|
+
const { data, path: path42, errorMaps, issueData } = params;
|
|
4674
|
+
const fullPath = [...path42, ...issueData.path || []];
|
|
4675
4675
|
const fullIssue = {
|
|
4676
4676
|
...issueData,
|
|
4677
4677
|
path: fullPath
|
|
@@ -4787,11 +4787,11 @@ var errorUtil;
|
|
|
4787
4787
|
|
|
4788
4788
|
// ../../node_modules/zod/v3/types.js
|
|
4789
4789
|
var ParseInputLazyPath = class {
|
|
4790
|
-
constructor(parent, value,
|
|
4790
|
+
constructor(parent, value, path42, key) {
|
|
4791
4791
|
this._cachedPath = [];
|
|
4792
4792
|
this.parent = parent;
|
|
4793
4793
|
this.data = value;
|
|
4794
|
-
this._path =
|
|
4794
|
+
this._path = path42;
|
|
4795
4795
|
this._key = key;
|
|
4796
4796
|
}
|
|
4797
4797
|
get path() {
|
|
@@ -11270,22 +11270,28 @@ import os3 from "os";
|
|
|
11270
11270
|
|
|
11271
11271
|
// ../../packages/core/src/license/telemetry.ts
|
|
11272
11272
|
var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
|
|
11273
|
+
var CTXLOOM_VERSION = typeof __CTXLOOM_VERSION__ === "string" && __CTXLOOM_VERSION__.length > 0 ? __CTXLOOM_VERSION__ : "dev";
|
|
11273
11274
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (typeof __TELEMETRY_POSTHOG_KEY__ === "string" ? __TELEMETRY_POSTHOG_KEY__ : "");
|
|
11274
11275
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (typeof __TELEMETRY_SENTRY_DSN__ === "string" ? __TELEMETRY_SENTRY_DSN__ : "");
|
|
11275
11276
|
|
|
11276
11277
|
// ../../packages/core/src/server/ProjectState.ts
|
|
11278
|
+
import path33 from "path";
|
|
11279
|
+
|
|
11280
|
+
// ../../packages/core/src/server/projectId.ts
|
|
11281
|
+
import crypto5 from "crypto";
|
|
11277
11282
|
import path32 from "path";
|
|
11278
11283
|
|
|
11279
11284
|
// ../../packages/core/src/server/ProjectStateManager.ts
|
|
11280
11285
|
init_logger();
|
|
11286
|
+
import os4 from "os";
|
|
11281
11287
|
|
|
11282
11288
|
// ../../packages/core/src/server/resolveProjectRoot.ts
|
|
11283
11289
|
import fs29 from "fs";
|
|
11284
|
-
import
|
|
11290
|
+
import path34 from "path";
|
|
11285
11291
|
|
|
11286
11292
|
// server/loader.ts
|
|
11287
11293
|
async function loadContext(root) {
|
|
11288
|
-
const absRoot =
|
|
11294
|
+
const absRoot = path35.resolve(root);
|
|
11289
11295
|
const overlay = new GitOverlayStore(absRoot);
|
|
11290
11296
|
const gitEnabled = await overlay.loadSnapshot();
|
|
11291
11297
|
const graph = new DependencyGraph();
|
|
@@ -11539,20 +11545,20 @@ function buildOwnershipRouter(ctx) {
|
|
|
11539
11545
|
// server/routes/file.ts
|
|
11540
11546
|
import { Router as Router7 } from "express";
|
|
11541
11547
|
import fs30 from "fs/promises";
|
|
11542
|
-
import
|
|
11548
|
+
import path36 from "path";
|
|
11543
11549
|
function buildFileRouter(ctx) {
|
|
11544
11550
|
const router = Router7();
|
|
11545
11551
|
router.get("/", async (req, res) => {
|
|
11546
11552
|
const rel = req.query.path;
|
|
11547
11553
|
if (!rel) return res.status(400).json({ error: "missing path" });
|
|
11548
|
-
const abs =
|
|
11549
|
-
const rootBoundary = ctx.root.endsWith(
|
|
11554
|
+
const abs = path36.resolve(ctx.root, rel);
|
|
11555
|
+
const rootBoundary = ctx.root.endsWith(path36.sep) ? ctx.root : ctx.root + path36.sep;
|
|
11550
11556
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
11551
11557
|
return res.status(403).json({ error: "forbidden" });
|
|
11552
11558
|
}
|
|
11553
11559
|
try {
|
|
11554
11560
|
const content = await fs30.readFile(abs, "utf-8");
|
|
11555
|
-
const ext =
|
|
11561
|
+
const ext = path36.extname(abs).slice(1);
|
|
11556
11562
|
res.json({ content, lines: content.split("\n").length, ext });
|
|
11557
11563
|
} catch {
|
|
11558
11564
|
res.status(404).json({ error: "not found" });
|
|
@@ -11564,7 +11570,7 @@ function buildFileRouter(ctx) {
|
|
|
11564
11570
|
// server/routes/open.ts
|
|
11565
11571
|
import { Router as Router8 } from "express";
|
|
11566
11572
|
import { execFile as execFile2 } from "child_process";
|
|
11567
|
-
import
|
|
11573
|
+
import path37 from "path";
|
|
11568
11574
|
function tryOpen(bin, abs) {
|
|
11569
11575
|
return new Promise((resolve) => {
|
|
11570
11576
|
execFile2(bin, [abs], { timeout: 5e3 }, (err) => resolve(!err));
|
|
@@ -11575,8 +11581,8 @@ function buildOpenRouter(ctx) {
|
|
|
11575
11581
|
router.post("/", async (req, res) => {
|
|
11576
11582
|
const rel = req.body?.path;
|
|
11577
11583
|
if (!rel || typeof rel !== "string") return res.status(400).json({ error: "missing path" });
|
|
11578
|
-
const abs =
|
|
11579
|
-
const rootBoundary = ctx.root.endsWith(
|
|
11584
|
+
const abs = path37.resolve(ctx.root, rel);
|
|
11585
|
+
const rootBoundary = ctx.root.endsWith(path37.sep) ? ctx.root : ctx.root + path37.sep;
|
|
11580
11586
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
11581
11587
|
return res.status(403).json({ error: "forbidden" });
|
|
11582
11588
|
}
|
|
@@ -11588,7 +11594,7 @@ function buildOpenRouter(ctx) {
|
|
|
11588
11594
|
|
|
11589
11595
|
// server/routes/tokens.ts
|
|
11590
11596
|
import { Router as Router9 } from "express";
|
|
11591
|
-
import
|
|
11597
|
+
import path38 from "path";
|
|
11592
11598
|
import fs31 from "fs";
|
|
11593
11599
|
var CHARS_PER_TOKEN = 4;
|
|
11594
11600
|
var cache = null;
|
|
@@ -11604,7 +11610,7 @@ function buildTokensRouter(ctx) {
|
|
|
11604
11610
|
let fullChars = 0;
|
|
11605
11611
|
let skeletonChars = 0;
|
|
11606
11612
|
for (const file of files) {
|
|
11607
|
-
const absPath =
|
|
11613
|
+
const absPath = path38.join(ctx.root, file);
|
|
11608
11614
|
try {
|
|
11609
11615
|
const content = fs31.readFileSync(absPath, "utf-8");
|
|
11610
11616
|
fullChars += content.length;
|
|
@@ -11707,18 +11713,18 @@ function buildFileTrendsRouter(ctx) {
|
|
|
11707
11713
|
|
|
11708
11714
|
// server/routes/projects.ts
|
|
11709
11715
|
import { Router as Router12 } from "express";
|
|
11710
|
-
import
|
|
11716
|
+
import path40 from "path";
|
|
11711
11717
|
|
|
11712
11718
|
// server/projects.ts
|
|
11713
11719
|
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
11714
|
-
import
|
|
11715
|
-
import
|
|
11716
|
-
import
|
|
11717
|
-
var HOME =
|
|
11718
|
-
var REGISTRY_PATH =
|
|
11720
|
+
import os5 from "os";
|
|
11721
|
+
import path39 from "path";
|
|
11722
|
+
import crypto6 from "crypto";
|
|
11723
|
+
var HOME = os5.homedir();
|
|
11724
|
+
var REGISTRY_PATH = path39.join(HOME, ".ctxloom", "repos.json");
|
|
11719
11725
|
function slugFor(root) {
|
|
11720
|
-
const abs =
|
|
11721
|
-
return
|
|
11726
|
+
const abs = path39.resolve(root);
|
|
11727
|
+
return crypto6.createHash("sha1").update(abs).digest("hex").slice(0, 12);
|
|
11722
11728
|
}
|
|
11723
11729
|
function readRegistry() {
|
|
11724
11730
|
if (!existsSync2(REGISTRY_PATH)) return [];
|
|
@@ -11732,27 +11738,27 @@ function readRegistry() {
|
|
|
11732
11738
|
}
|
|
11733
11739
|
}
|
|
11734
11740
|
function listProjects(defaultRoot) {
|
|
11735
|
-
const absDefault =
|
|
11741
|
+
const absDefault = path39.resolve(defaultRoot);
|
|
11736
11742
|
const out = [
|
|
11737
11743
|
{
|
|
11738
11744
|
slug: slugFor(absDefault),
|
|
11739
|
-
name:
|
|
11745
|
+
name: path39.basename(absDefault) || absDefault,
|
|
11740
11746
|
root: absDefault,
|
|
11741
11747
|
isDefault: true,
|
|
11742
|
-
hasSnapshot: existsSync2(
|
|
11748
|
+
hasSnapshot: existsSync2(path39.join(absDefault, ".ctxloom"))
|
|
11743
11749
|
}
|
|
11744
11750
|
];
|
|
11745
11751
|
const seen = /* @__PURE__ */ new Set([absDefault]);
|
|
11746
11752
|
for (const entry of readRegistry()) {
|
|
11747
|
-
const abs =
|
|
11753
|
+
const abs = path39.resolve(entry.root);
|
|
11748
11754
|
if (seen.has(abs)) continue;
|
|
11749
11755
|
seen.add(abs);
|
|
11750
11756
|
const item = {
|
|
11751
11757
|
slug: slugFor(abs),
|
|
11752
|
-
name: entry.name ?? (
|
|
11758
|
+
name: entry.name ?? (path39.basename(abs) || abs),
|
|
11753
11759
|
root: abs,
|
|
11754
11760
|
isDefault: false,
|
|
11755
|
-
hasSnapshot: existsSync2(
|
|
11761
|
+
hasSnapshot: existsSync2(path39.join(abs, ".ctxloom"))
|
|
11756
11762
|
};
|
|
11757
11763
|
if (entry.alias !== void 0) item.alias = entry.alias;
|
|
11758
11764
|
out.push(item);
|
|
@@ -11805,7 +11811,7 @@ function buildProjectsRouter(deps) {
|
|
|
11805
11811
|
} catch (err) {
|
|
11806
11812
|
const detail = err instanceof Error ? err.message : String(err);
|
|
11807
11813
|
res.status(500).json({
|
|
11808
|
-
error: `failed to switch to ${
|
|
11814
|
+
error: `failed to switch to ${path40.basename(target.root)}: ${detail}`
|
|
11809
11815
|
});
|
|
11810
11816
|
}
|
|
11811
11817
|
});
|
|
@@ -11813,7 +11819,7 @@ function buildProjectsRouter(deps) {
|
|
|
11813
11819
|
}
|
|
11814
11820
|
|
|
11815
11821
|
// server/index.ts
|
|
11816
|
-
var __dirname2 =
|
|
11822
|
+
var __dirname2 = path41.dirname(fileURLToPath2(import.meta.url));
|
|
11817
11823
|
async function startDashboard(options) {
|
|
11818
11824
|
const { root, port, open } = options;
|
|
11819
11825
|
console.log(`ctxloom dashboard \u2014 loading context from ${root}...`);
|
|
@@ -11872,7 +11878,7 @@ async function startDashboard(options) {
|
|
|
11872
11878
|
}
|
|
11873
11879
|
activeWatcher = null;
|
|
11874
11880
|
}
|
|
11875
|
-
const snapshotDir =
|
|
11881
|
+
const snapshotDir = path41.join(targetRoot, ".ctxloom");
|
|
11876
11882
|
try {
|
|
11877
11883
|
activeWatcher = fs32.watch(snapshotDir, (_event, filename) => {
|
|
11878
11884
|
if (!filename || !filename.includes("snapshot")) return;
|
|
@@ -11902,12 +11908,12 @@ async function startDashboard(options) {
|
|
|
11902
11908
|
attachSnapshotWatcher(newRoot);
|
|
11903
11909
|
}
|
|
11904
11910
|
}));
|
|
11905
|
-
const clientDist =
|
|
11906
|
-
const clientDistExists = fs32.existsSync(
|
|
11911
|
+
const clientDist = path41.join(__dirname2, "../dashboard/client");
|
|
11912
|
+
const clientDistExists = fs32.existsSync(path41.join(clientDist, "index.html"));
|
|
11907
11913
|
if (clientDistExists) {
|
|
11908
11914
|
app.use(express.static(clientDist, { dotfiles: "allow" }));
|
|
11909
11915
|
app.get(/.*/, (_req, res) => {
|
|
11910
|
-
res.sendFile(
|
|
11916
|
+
res.sendFile(path41.join(clientDist, "index.html"), { dotfiles: "allow" });
|
|
11911
11917
|
});
|
|
11912
11918
|
} else {
|
|
11913
11919
|
app.get(/^\/(?!api\/).*/, (_req, res) => {
|
|
@@ -3406,8 +3406,8 @@ var CoChangeIndex = class _CoChangeIndex {
|
|
|
3406
3406
|
if (event.isBulk || event.isMerge) return;
|
|
3407
3407
|
const paths = event.files.map((f) => f.path);
|
|
3408
3408
|
if (paths.length === 0) return;
|
|
3409
|
-
for (const
|
|
3410
|
-
this.nodeCounts.set(
|
|
3409
|
+
for (const path33 of paths) {
|
|
3410
|
+
this.nodeCounts.set(path33, (this.nodeCounts.get(path33) ?? 0) + 1);
|
|
3411
3411
|
}
|
|
3412
3412
|
for (let i = 0; i < paths.length; i++) {
|
|
3413
3413
|
for (let j = i + 1; j < paths.length; j++) {
|
|
@@ -3554,8 +3554,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3554
3554
|
*/
|
|
3555
3555
|
snapshot() {
|
|
3556
3556
|
const nodes = {};
|
|
3557
|
-
for (const [
|
|
3558
|
-
nodes[
|
|
3557
|
+
for (const [path33, raw] of this.nodes) {
|
|
3558
|
+
nodes[path33] = {
|
|
3559
3559
|
commits: raw.commits,
|
|
3560
3560
|
churnLines: raw.churnLines,
|
|
3561
3561
|
bugCommits: raw.bugCommits,
|
|
@@ -3570,8 +3570,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3570
3570
|
*/
|
|
3571
3571
|
static load(s) {
|
|
3572
3572
|
const idx = new _ChurnIndex();
|
|
3573
|
-
for (const [
|
|
3574
|
-
idx.nodes.set(
|
|
3573
|
+
for (const [path33, raw] of Object.entries(s.nodes)) {
|
|
3574
|
+
idx.nodes.set(path33, {
|
|
3575
3575
|
commits: raw.commits,
|
|
3576
3576
|
churnLines: raw.churnLines,
|
|
3577
3577
|
bugCommits: raw.bugCommits,
|
|
@@ -3584,8 +3584,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3584
3584
|
// -------------------------------------------------------------------------
|
|
3585
3585
|
// Private helpers
|
|
3586
3586
|
// -------------------------------------------------------------------------
|
|
3587
|
-
getOrCreate(
|
|
3588
|
-
const existing = this.nodes.get(
|
|
3587
|
+
getOrCreate(path33) {
|
|
3588
|
+
const existing = this.nodes.get(path33);
|
|
3589
3589
|
if (existing !== void 0) return existing;
|
|
3590
3590
|
const fresh = {
|
|
3591
3591
|
commits: 0,
|
|
@@ -3594,7 +3594,7 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
3594
3594
|
authorCounts: {},
|
|
3595
3595
|
lastTouch: 0
|
|
3596
3596
|
};
|
|
3597
|
-
this.nodes.set(
|
|
3597
|
+
this.nodes.set(path33, fresh);
|
|
3598
3598
|
return fresh;
|
|
3599
3599
|
}
|
|
3600
3600
|
};
|
|
@@ -3675,12 +3675,12 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
3675
3675
|
*/
|
|
3676
3676
|
snapshot() {
|
|
3677
3677
|
const nodes = {};
|
|
3678
|
-
for (const [
|
|
3678
|
+
for (const [path33, raw] of this.nodes) {
|
|
3679
3679
|
const authorWeights = {};
|
|
3680
3680
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
3681
3681
|
authorWeights[email] = { ...entry };
|
|
3682
3682
|
}
|
|
3683
|
-
nodes[
|
|
3683
|
+
nodes[path33] = { authorWeights, lastTouch: raw.lastTouch };
|
|
3684
3684
|
}
|
|
3685
3685
|
return { version: 1, nodes };
|
|
3686
3686
|
}
|
|
@@ -3689,23 +3689,23 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
3689
3689
|
*/
|
|
3690
3690
|
static load(s) {
|
|
3691
3691
|
const idx = new _OwnershipIndex();
|
|
3692
|
-
for (const [
|
|
3692
|
+
for (const [path33, raw] of Object.entries(s.nodes)) {
|
|
3693
3693
|
const authorWeights = {};
|
|
3694
3694
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
3695
3695
|
authorWeights[email] = { ...entry };
|
|
3696
3696
|
}
|
|
3697
|
-
idx.nodes.set(
|
|
3697
|
+
idx.nodes.set(path33, { authorWeights, lastTouch: raw.lastTouch });
|
|
3698
3698
|
}
|
|
3699
3699
|
return idx;
|
|
3700
3700
|
}
|
|
3701
3701
|
// -------------------------------------------------------------------------
|
|
3702
3702
|
// Private helpers
|
|
3703
3703
|
// -------------------------------------------------------------------------
|
|
3704
|
-
getOrCreate(
|
|
3705
|
-
const existing = this.nodes.get(
|
|
3704
|
+
getOrCreate(path33) {
|
|
3705
|
+
const existing = this.nodes.get(path33);
|
|
3706
3706
|
if (existing !== void 0) return existing;
|
|
3707
3707
|
const fresh = { authorWeights: {}, lastTouch: 0 };
|
|
3708
|
-
this.nodes.set(
|
|
3708
|
+
this.nodes.set(path33, fresh);
|
|
3709
3709
|
return fresh;
|
|
3710
3710
|
}
|
|
3711
3711
|
};
|
|
@@ -8796,6 +8796,7 @@ async function startTrial(email, opts = {}) {
|
|
|
8796
8796
|
|
|
8797
8797
|
// packages/core/src/license/telemetry.ts
|
|
8798
8798
|
var TELEMETRY_DISABLED = process.env["CTXLOOM_NO_TELEMETRY"] === "1" || process.env["DO_NOT_TRACK"] === "1";
|
|
8799
|
+
var CTXLOOM_VERSION = "1.1.1".length > 0 ? "1.1.1" : "dev";
|
|
8799
8800
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
8800
8801
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
8801
8802
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -8818,6 +8819,7 @@ async function sendPostHog(event, distinctId, props) {
|
|
|
8818
8819
|
event,
|
|
8819
8820
|
properties: {
|
|
8820
8821
|
$lib: "ctxloom-cli",
|
|
8822
|
+
release: CTXLOOM_VERSION,
|
|
8821
8823
|
...props
|
|
8822
8824
|
}
|
|
8823
8825
|
}),
|
|
@@ -8853,7 +8855,7 @@ async function sendSentry(err, context) {
|
|
|
8853
8855
|
]
|
|
8854
8856
|
},
|
|
8855
8857
|
extra: context,
|
|
8856
|
-
tags: { runtime: "node", component: "cli-license" }
|
|
8858
|
+
tags: { runtime: "node", component: "cli-license", release: CTXLOOM_VERSION }
|
|
8857
8859
|
}),
|
|
8858
8860
|
signal: AbortSignal.timeout(4e3)
|
|
8859
8861
|
});
|
|
@@ -8869,20 +8871,33 @@ function parseDsn(dsn) {
|
|
|
8869
8871
|
return null;
|
|
8870
8872
|
}
|
|
8871
8873
|
}
|
|
8874
|
+
function scrubPath(filename) {
|
|
8875
|
+
return filename.replace(/^\/Users\/[^/]+\//, "/Users/~/").replace(/^\/home\/[^/]+\//, "/home/~/").replace(/^([A-Z]:\\\\Users\\\\)[^\\]+\\\\/, "$1~\\\\").replace(/^([A-Z]:\\Users\\)[^\\]+\\/, "$1~\\");
|
|
8876
|
+
}
|
|
8872
8877
|
function parseStack(stack) {
|
|
8873
8878
|
return stack.split("\n").slice(1).map((line) => {
|
|
8874
8879
|
const m = line.trim().match(/at (.+?) \((.+?):(\d+):\d+\)/);
|
|
8875
8880
|
if (!m) return null;
|
|
8876
|
-
return { function: m[1] ?? "", filename: m[2] ?? "", lineno: Number(m[3]) };
|
|
8881
|
+
return { function: m[1] ?? "", filename: scrubPath(m[2] ?? ""), lineno: Number(m[3]) };
|
|
8877
8882
|
}).filter((f) => f !== null).slice(0, 20);
|
|
8878
8883
|
}
|
|
8879
8884
|
|
|
8880
8885
|
// packages/core/src/server/ProjectState.ts
|
|
8886
|
+
import path31 from "path";
|
|
8887
|
+
|
|
8888
|
+
// packages/core/src/server/projectId.ts
|
|
8889
|
+
import crypto5 from "crypto";
|
|
8881
8890
|
import path30 from "path";
|
|
8891
|
+
function hashProjectRoot(absPath) {
|
|
8892
|
+
const canonical = path30.resolve(absPath);
|
|
8893
|
+
return crypto5.createHash("sha256").update(canonical).digest("hex").slice(0, 16);
|
|
8894
|
+
}
|
|
8895
|
+
|
|
8896
|
+
// packages/core/src/server/ProjectState.ts
|
|
8882
8897
|
function createProjectState(projectRoot, opts = {}) {
|
|
8883
8898
|
return {
|
|
8884
8899
|
projectRoot,
|
|
8885
|
-
dbPath:
|
|
8900
|
+
dbPath: path31.join(projectRoot, ".ctxloom", "vectors.lancedb"),
|
|
8886
8901
|
pinned: opts.pinned ?? false,
|
|
8887
8902
|
lastTouchedAt: Date.now(),
|
|
8888
8903
|
vectorsInitialized: false,
|
|
@@ -8900,8 +8915,16 @@ function createProjectState(projectRoot, opts = {}) {
|
|
|
8900
8915
|
async function ensureVectorsInitialized(state) {
|
|
8901
8916
|
if (state.vectorsInitialized) return;
|
|
8902
8917
|
if (!state.storePromise) return;
|
|
8903
|
-
|
|
8904
|
-
|
|
8918
|
+
try {
|
|
8919
|
+
await state.storePromise;
|
|
8920
|
+
state.vectorsInitialized = true;
|
|
8921
|
+
} catch (err) {
|
|
8922
|
+
captureError(err, {
|
|
8923
|
+
project_id: hashProjectRoot(state.projectRoot),
|
|
8924
|
+
phase: "vector_init"
|
|
8925
|
+
});
|
|
8926
|
+
throw err;
|
|
8927
|
+
}
|
|
8905
8928
|
}
|
|
8906
8929
|
async function disposeProjectState(state) {
|
|
8907
8930
|
try {
|
|
@@ -8926,6 +8949,7 @@ async function disposeProjectState(state) {
|
|
|
8926
8949
|
}
|
|
8927
8950
|
|
|
8928
8951
|
// packages/core/src/server/ProjectStateManager.ts
|
|
8952
|
+
import os4 from "os";
|
|
8929
8953
|
var DEFAULT_MAX_PROJECTS = 5;
|
|
8930
8954
|
var ProjectStateManager = class {
|
|
8931
8955
|
map = /* @__PURE__ */ new Map();
|
|
@@ -8995,12 +9019,23 @@ var ProjectStateManager = class {
|
|
|
8995
9019
|
);
|
|
8996
9020
|
}
|
|
8997
9021
|
this.map.delete(victim.projectRoot);
|
|
9022
|
+
const pinnedCount = Array.from(this.map.values()).filter((s) => s.pinned).length;
|
|
9023
|
+
track("project_evicted", os4.hostname(), {
|
|
9024
|
+
project_id: hashProjectRoot(victim.projectRoot),
|
|
9025
|
+
pinned_count: pinnedCount,
|
|
9026
|
+
cap: this.maxProjects
|
|
9027
|
+
});
|
|
8998
9028
|
void this.onDispose(victim).then(() => {
|
|
8999
9029
|
logger.info("project.evicted", {
|
|
9000
9030
|
root: victim.projectRoot,
|
|
9001
9031
|
reason: "lru_cap_reached",
|
|
9002
9032
|
ttl_seconds: Math.round((Date.now() - victim.lastTouchedAt) / 1e3)
|
|
9003
9033
|
});
|
|
9034
|
+
}).catch((err) => {
|
|
9035
|
+
captureError(err, {
|
|
9036
|
+
project_id: hashProjectRoot(victim.projectRoot),
|
|
9037
|
+
phase: "dispose"
|
|
9038
|
+
});
|
|
9004
9039
|
});
|
|
9005
9040
|
}
|
|
9006
9041
|
/**
|
|
@@ -9016,7 +9051,7 @@ var ProjectStateManager = class {
|
|
|
9016
9051
|
|
|
9017
9052
|
// packages/core/src/server/resolveProjectRoot.ts
|
|
9018
9053
|
import fs27 from "fs";
|
|
9019
|
-
import
|
|
9054
|
+
import path32 from "path";
|
|
9020
9055
|
var PATH_SEPARATOR_PATTERN = /[/\\~]|^[A-Za-z]:/;
|
|
9021
9056
|
function looksLikePath(value) {
|
|
9022
9057
|
return PATH_SEPARATOR_PATTERN.test(value);
|
|
@@ -9041,9 +9076,9 @@ function resolvePathSafely(p, cwd) {
|
|
|
9041
9076
|
let expanded = p;
|
|
9042
9077
|
if (p === "~" || p.startsWith("~/")) {
|
|
9043
9078
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
|
|
9044
|
-
expanded = p === "~" ? home :
|
|
9079
|
+
expanded = p === "~" ? home : path32.join(home, p.slice(2));
|
|
9045
9080
|
}
|
|
9046
|
-
return
|
|
9081
|
+
return path32.isAbsolute(expanded) ? path32.resolve(expanded) : path32.resolve(cwd, expanded);
|
|
9047
9082
|
}
|
|
9048
9083
|
function realpathOrSame(p) {
|
|
9049
9084
|
try {
|
|
@@ -9115,7 +9150,7 @@ function validateDefaultRoot(candidate) {
|
|
|
9115
9150
|
} catch {
|
|
9116
9151
|
return false;
|
|
9117
9152
|
}
|
|
9118
|
-
return PROJECT_MARKERS.some((m) => fs27.existsSync(
|
|
9153
|
+
return PROJECT_MARKERS.some((m) => fs27.existsSync(path32.join(candidate, m)));
|
|
9119
9154
|
}
|
|
9120
9155
|
|
|
9121
9156
|
// packages/core/src/server/structuredErrors.ts
|
|
@@ -9171,6 +9206,21 @@ var FirstTouchTracker = class {
|
|
|
9171
9206
|
}
|
|
9172
9207
|
};
|
|
9173
9208
|
|
|
9209
|
+
// packages/core/src/server/EmittedOnceTracker.ts
|
|
9210
|
+
var EmittedOnceTracker = class {
|
|
9211
|
+
seen = /* @__PURE__ */ new Set();
|
|
9212
|
+
/** Returns true the first time `key` is seen, false thereafter. */
|
|
9213
|
+
markAndCheck(key) {
|
|
9214
|
+
if (this.seen.has(key)) return false;
|
|
9215
|
+
this.seen.add(key);
|
|
9216
|
+
return true;
|
|
9217
|
+
}
|
|
9218
|
+
/** Clear all keys. Used by tests. */
|
|
9219
|
+
reset() {
|
|
9220
|
+
this.seen.clear();
|
|
9221
|
+
}
|
|
9222
|
+
};
|
|
9223
|
+
|
|
9174
9224
|
export {
|
|
9175
9225
|
GRAMMAR_MANIFEST,
|
|
9176
9226
|
findGrammar,
|
|
@@ -9255,6 +9305,7 @@ export {
|
|
|
9255
9305
|
startTrial,
|
|
9256
9306
|
track,
|
|
9257
9307
|
captureError,
|
|
9308
|
+
hashProjectRoot,
|
|
9258
9309
|
createProjectState,
|
|
9259
9310
|
ensureVectorsInitialized,
|
|
9260
9311
|
disposeProjectState,
|
|
@@ -9267,6 +9318,7 @@ export {
|
|
|
9267
9318
|
aliasNotFoundError,
|
|
9268
9319
|
noParseableSourcesWarning,
|
|
9269
9320
|
wrapWithIndexingEnvelope,
|
|
9270
|
-
FirstTouchTracker
|
|
9321
|
+
FirstTouchTracker,
|
|
9322
|
+
EmittedOnceTracker
|
|
9271
9323
|
};
|
|
9272
|
-
//# sourceMappingURL=chunk-
|
|
9324
|
+
//# sourceMappingURL=chunk-CXKKREER.js.map
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
AuthorResolver,
|
|
9
9
|
DependencyGraph,
|
|
10
10
|
EmailAlreadyUsedError,
|
|
11
|
+
EmittedOnceTracker,
|
|
11
12
|
FileWatcher,
|
|
12
13
|
FingerprintAlreadyUsedError,
|
|
13
14
|
FirstTouchTracker,
|
|
@@ -30,6 +31,7 @@ import {
|
|
|
30
31
|
ensureVectorsInitialized,
|
|
31
32
|
generateCODEOWNERS,
|
|
32
33
|
getLicenseInfo,
|
|
34
|
+
hashProjectRoot,
|
|
33
35
|
isActive,
|
|
34
36
|
loadReviewConfig,
|
|
35
37
|
noDefaultProjectError,
|
|
@@ -43,7 +45,7 @@ import {
|
|
|
43
45
|
validateDefaultRoot,
|
|
44
46
|
wrapWithIndexingEnvelope,
|
|
45
47
|
writeCODEOWNERS
|
|
46
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-CXKKREER.js";
|
|
47
49
|
import {
|
|
48
50
|
VectorStore
|
|
49
51
|
} from "./chunk-NEHYSE2Y.js";
|
|
@@ -61,6 +63,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
61
63
|
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
62
64
|
import path from "path";
|
|
63
65
|
import fs from "fs";
|
|
66
|
+
import os from "os";
|
|
64
67
|
var PROJECT_ROOT = (() => {
|
|
65
68
|
if (process.env.CTXLOOM_ROOT) return process.env.CTXLOOM_ROOT;
|
|
66
69
|
const cwd = process.cwd();
|
|
@@ -87,6 +90,7 @@ var stateManager = new ProjectStateManager({
|
|
|
87
90
|
maxProjects: DISABLE_MULTIPROJECT ? 1 : MAX_PROJECTS
|
|
88
91
|
});
|
|
89
92
|
var firstTouchTracker = new FirstTouchTracker();
|
|
93
|
+
var emittedOnceTracker = new EmittedOnceTracker();
|
|
90
94
|
async function initStore(state) {
|
|
91
95
|
if (!state.storePromise) {
|
|
92
96
|
state.storePromise = (async () => {
|
|
@@ -110,12 +114,20 @@ async function initParser(state) {
|
|
|
110
114
|
async function initGraph(state) {
|
|
111
115
|
if (!state.graphPromise) {
|
|
112
116
|
state.graphPromise = (async () => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
try {
|
|
118
|
+
const parser = await initParser(state);
|
|
119
|
+
const graph = new DependencyGraph();
|
|
120
|
+
graph.setParser(parser);
|
|
121
|
+
await graph.buildFromDirectory(state.projectRoot);
|
|
122
|
+
state.graphInitialized = true;
|
|
123
|
+
return graph;
|
|
124
|
+
} catch (err) {
|
|
125
|
+
captureError(err, {
|
|
126
|
+
project_id: hashProjectRoot(state.projectRoot),
|
|
127
|
+
phase: "graph_init"
|
|
128
|
+
});
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
119
131
|
})();
|
|
120
132
|
}
|
|
121
133
|
return state.graphPromise;
|
|
@@ -130,31 +142,60 @@ async function initSkeletonizer(state) {
|
|
|
130
142
|
}
|
|
131
143
|
return state.skeletonizerPromise;
|
|
132
144
|
}
|
|
145
|
+
function classifyResolutionSource(arg, env) {
|
|
146
|
+
if (arg !== void 0) {
|
|
147
|
+
return /[/\\~]|^[A-Za-z]:/.test(arg) ? "arg-path" : "alias";
|
|
148
|
+
}
|
|
149
|
+
return env ? "env" : "cwd";
|
|
150
|
+
}
|
|
133
151
|
function buildContext(defaultRoot, noDefaultMode) {
|
|
134
152
|
const repoRegistry = new RepoRegistry(repoRegistryPath);
|
|
135
153
|
function resolveOrDefault(arg) {
|
|
154
|
+
let state;
|
|
155
|
+
let source;
|
|
136
156
|
if (DISABLE_MULTIPROJECT) {
|
|
137
157
|
if (!defaultRoot) {
|
|
138
158
|
throw new Error("CTXLOOM_DISABLE_MULTIPROJECT=1 but server has no default root.");
|
|
139
159
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (arg === void 0) {
|
|
160
|
+
state = stateManager.get(defaultRoot);
|
|
161
|
+
source = "env";
|
|
162
|
+
} else if (arg === void 0) {
|
|
143
163
|
if (!defaultRoot) {
|
|
144
164
|
throw new Error("no_default_project");
|
|
145
165
|
}
|
|
146
|
-
|
|
166
|
+
state = stateManager.get(defaultRoot);
|
|
167
|
+
source = classifyResolutionSource(void 0, process.env.CTXLOOM_ROOT);
|
|
168
|
+
} else {
|
|
169
|
+
const outcome = resolveProjectRoot({
|
|
170
|
+
arg,
|
|
171
|
+
env: process.env.CTXLOOM_ROOT,
|
|
172
|
+
cwd: process.cwd(),
|
|
173
|
+
registry: repoRegistry
|
|
174
|
+
});
|
|
175
|
+
if (outcome.kind !== "ok") {
|
|
176
|
+
throw new Error(JSON.stringify(outcome));
|
|
177
|
+
}
|
|
178
|
+
state = stateManager.get(outcome.root);
|
|
179
|
+
source = classifyResolutionSource(arg, process.env.CTXLOOM_ROOT);
|
|
147
180
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
181
|
+
try {
|
|
182
|
+
const projectId = hashProjectRoot(state.projectRoot);
|
|
183
|
+
if (emittedOnceTracker.markAndCheck(`project_resolved:${projectId}`)) {
|
|
184
|
+
track("project_resolved", os.hostname(), {
|
|
185
|
+
project_id: projectId,
|
|
186
|
+
source,
|
|
187
|
+
via_alias: source === "alias"
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (stateManager.size() >= 2 && emittedOnceTracker.markAndCheck("multi_project_active")) {
|
|
191
|
+
track("multi_project_active", os.hostname(), {
|
|
192
|
+
active_count: stateManager.size(),
|
|
193
|
+
cap: stateManager.max
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
156
197
|
}
|
|
157
|
-
return
|
|
198
|
+
return state;
|
|
158
199
|
}
|
|
159
200
|
const ctx = {
|
|
160
201
|
projectRoot: defaultRoot ?? "",
|
|
@@ -231,6 +272,17 @@ function createServer() {
|
|
|
231
272
|
const root = state.projectRoot;
|
|
232
273
|
const graphFirstTouch = firstTouchTracker.markAndCheck(root, "graph");
|
|
233
274
|
if (graphFirstTouch) {
|
|
275
|
+
try {
|
|
276
|
+
const graphInst = state.graphPromise ? await state.graphPromise : null;
|
|
277
|
+
track("project_first_touch", os.hostname(), {
|
|
278
|
+
project_id: hashProjectRoot(root),
|
|
279
|
+
tier: "graph",
|
|
280
|
+
duration_ms: durationMs,
|
|
281
|
+
nodes: graphInst?.allFiles().length ?? null,
|
|
282
|
+
edges: graphInst?.edgeCount() ?? null
|
|
283
|
+
});
|
|
284
|
+
} catch {
|
|
285
|
+
}
|
|
234
286
|
const wrapped = wrapWithIndexingEnvelope(
|
|
235
287
|
{ firstTouch: true, projectRoot: root, tier: "graph", durationMs },
|
|
236
288
|
text
|
|
@@ -240,6 +292,14 @@ function createServer() {
|
|
|
240
292
|
if (state.vectorsInitialized) {
|
|
241
293
|
const vectorsFirstTouch = firstTouchTracker.markAndCheck(root, "vectors");
|
|
242
294
|
if (vectorsFirstTouch) {
|
|
295
|
+
try {
|
|
296
|
+
track("project_first_touch", os.hostname(), {
|
|
297
|
+
project_id: hashProjectRoot(root),
|
|
298
|
+
tier: "vectors",
|
|
299
|
+
duration_ms: durationMs
|
|
300
|
+
});
|
|
301
|
+
} catch {
|
|
302
|
+
}
|
|
243
303
|
const wrapped = wrapWithIndexingEnvelope(
|
|
244
304
|
{ firstTouch: true, projectRoot: root, tier: "vectors", durationMs },
|
|
245
305
|
text
|
|
@@ -250,9 +310,31 @@ function createServer() {
|
|
|
250
310
|
} catch {
|
|
251
311
|
}
|
|
252
312
|
}
|
|
313
|
+
if (Math.random() < 0.25) {
|
|
314
|
+
try {
|
|
315
|
+
const projectRootArg2 = args2?.project_root;
|
|
316
|
+
if (!ctx.noDefaultMode || projectRootArg2 !== void 0) {
|
|
317
|
+
const sampleState = resolveOrDefault(projectRootArg2);
|
|
318
|
+
track("tool_dispatched", os.hostname(), {
|
|
319
|
+
project_id: hashProjectRoot(sampleState.projectRoot),
|
|
320
|
+
tool: name,
|
|
321
|
+
duration_ms: durationMs
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
} catch {
|
|
325
|
+
}
|
|
326
|
+
}
|
|
253
327
|
return { content: [{ type: "text", text }] };
|
|
254
328
|
} catch (err) {
|
|
255
329
|
if (err instanceof Error && err.message === "no_default_project") {
|
|
330
|
+
const hadArg10 = args2?.project_root !== void 0;
|
|
331
|
+
try {
|
|
332
|
+
track("project_resolution_failed", os.hostname(), {
|
|
333
|
+
error_code: "no_default_project",
|
|
334
|
+
had_arg: hadArg10
|
|
335
|
+
});
|
|
336
|
+
} catch {
|
|
337
|
+
}
|
|
256
338
|
const xml = noDefaultProjectError({
|
|
257
339
|
attemptedRoot: PROJECT_ROOT,
|
|
258
340
|
resolutionChain: "CTXLOOM_ROOT env var\u2192unset, fallback_cwd\u2192" + PROJECT_ROOT,
|
|
@@ -264,6 +346,13 @@ function createServer() {
|
|
|
264
346
|
try {
|
|
265
347
|
const parsed2 = JSON.parse(err.message);
|
|
266
348
|
if (parsed2.kind === "alias_not_found") {
|
|
349
|
+
try {
|
|
350
|
+
track("project_resolution_failed", os.hostname(), {
|
|
351
|
+
error_code: "alias_not_found",
|
|
352
|
+
had_arg: true
|
|
353
|
+
});
|
|
354
|
+
} catch {
|
|
355
|
+
}
|
|
267
356
|
const xml = aliasNotFoundError({
|
|
268
357
|
alias: String(parsed2.alias ?? ""),
|
|
269
358
|
didYouMean: Array.isArray(parsed2.didYouMean) ? parsed2.didYouMean : []
|
|
@@ -271,6 +360,13 @@ function createServer() {
|
|
|
271
360
|
return { content: [{ type: "text", text: xml }], isError: true };
|
|
272
361
|
}
|
|
273
362
|
if (parsed2.kind === "project_root_not_found") {
|
|
363
|
+
try {
|
|
364
|
+
track("project_resolution_failed", os.hostname(), {
|
|
365
|
+
error_code: "project_root_not_found",
|
|
366
|
+
had_arg: true
|
|
367
|
+
});
|
|
368
|
+
} catch {
|
|
369
|
+
}
|
|
274
370
|
const xml = projectRootNotFoundError({
|
|
275
371
|
path: String(parsed2.attemptedPath ?? ""),
|
|
276
372
|
resolutionChain: String(parsed2.resolutionChain ?? "")
|
|
@@ -280,6 +376,20 @@ function createServer() {
|
|
|
280
376
|
} catch {
|
|
281
377
|
}
|
|
282
378
|
}
|
|
379
|
+
try {
|
|
380
|
+
const projectRootArg13 = args2?.project_root;
|
|
381
|
+
let projectIdForCtx;
|
|
382
|
+
try {
|
|
383
|
+
const fallbackState = resolveOrDefault(projectRootArg13);
|
|
384
|
+
projectIdForCtx = hashProjectRoot(fallbackState.projectRoot);
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
captureError(err, {
|
|
388
|
+
tool: name,
|
|
389
|
+
...projectIdForCtx ? { project_id: projectIdForCtx } : {}
|
|
390
|
+
});
|
|
391
|
+
} catch {
|
|
392
|
+
}
|
|
283
393
|
return {
|
|
284
394
|
content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
285
395
|
isError: true
|
|
@@ -300,6 +410,7 @@ async function startServer(opts = {}) {
|
|
|
300
410
|
logger.warn(
|
|
301
411
|
"[DEPRECATED] CTXLOOM_DISABLE_MULTIPROJECT=1 is set \u2014 multi-project support is disabled. maxProjects is capped at 1 and project_root arguments are ignored. This kill switch will be removed in a future release."
|
|
302
412
|
);
|
|
413
|
+
track("kill_switch_active", os.hostname(), { cap: 1 });
|
|
303
414
|
}
|
|
304
415
|
try {
|
|
305
416
|
const { execSync: execSync2 } = await import("child_process");
|
|
@@ -770,7 +881,7 @@ ${body}
|
|
|
770
881
|
// src/index.ts
|
|
771
882
|
import { execSync } from "child_process";
|
|
772
883
|
import * as readline from "readline";
|
|
773
|
-
import
|
|
884
|
+
import os2 from "os";
|
|
774
885
|
import path3 from "path";
|
|
775
886
|
try {
|
|
776
887
|
const proc = process;
|
|
@@ -782,7 +893,7 @@ try {
|
|
|
782
893
|
} catch {
|
|
783
894
|
}
|
|
784
895
|
var args = process.argv.slice(2);
|
|
785
|
-
var ctxloomVersion = "1.1.
|
|
896
|
+
var ctxloomVersion = "1.1.1".length > 0 ? "1.1.1" : "dev";
|
|
786
897
|
if (args.includes("--version") || args.includes("-v")) {
|
|
787
898
|
process.stdout.write(`ctxloom ${ctxloomVersion}
|
|
788
899
|
`);
|
|
@@ -855,7 +966,7 @@ async function checkLicense() {
|
|
|
855
966
|
if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
|
|
856
967
|
const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
|
|
857
968
|
if (ciKey) {
|
|
858
|
-
const { ApiClient } = await import("./src-
|
|
969
|
+
const { ApiClient } = await import("./src-JI5LH2V7.js");
|
|
859
970
|
const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
|
|
860
971
|
try {
|
|
861
972
|
const result = await client.validate(ciKey, "ci-ephemeral");
|
|
@@ -876,7 +987,7 @@ ctxloom license is ${result.status}.
|
|
|
876
987
|
}
|
|
877
988
|
const active = await isActive();
|
|
878
989
|
if (!active) {
|
|
879
|
-
track("license_gate_hit",
|
|
990
|
+
track("license_gate_hit", os2.hostname());
|
|
880
991
|
process.stderr.write(errorBlock("ctxloom requires an active license.", [
|
|
881
992
|
`${style.bold("ctxloom trial")} ${style.dim("\u2014 start a 7-day free trial")}`,
|
|
882
993
|
`${style.bold("ctxloom activate <KEY>")} ${style.dim("\u2014 activate a purchased key")}`,
|
|
@@ -925,7 +1036,7 @@ async function runTrial() {
|
|
|
925
1036
|
process.stdout.write(` ${style.dim(`Your license key will arrive at ${email} after checkout.`)}
|
|
926
1037
|
`);
|
|
927
1038
|
process.stdout.write(nextStep("Activate on this machine", "ctxloom activate <KEY>"));
|
|
928
|
-
track("trial_started",
|
|
1039
|
+
track("trial_started", os2.hostname(), { email });
|
|
929
1040
|
} catch (err) {
|
|
930
1041
|
if (err instanceof FingerprintAlreadyUsedError) {
|
|
931
1042
|
process.stdout.write(errorBlock("A trial has already been used on this machine.", [
|
|
@@ -967,10 +1078,10 @@ async function runActivate(key) {
|
|
|
967
1078
|
process.stdout.write(kvTable([
|
|
968
1079
|
["Tier", tier],
|
|
969
1080
|
["Expires", expires],
|
|
970
|
-
["Machine", `${
|
|
1081
|
+
["Machine", `${os2.hostname()} (${os2.platform()}-${os2.arch()})`]
|
|
971
1082
|
]));
|
|
972
1083
|
process.stdout.write(nextStep("Configure your AI tools", "ctxloom setup"));
|
|
973
|
-
track("license_activated",
|
|
1084
|
+
track("license_activated", os2.hostname(), { tier: license.tier });
|
|
974
1085
|
} catch (err) {
|
|
975
1086
|
if (err instanceof SeatLimitError) {
|
|
976
1087
|
process.stdout.write(errorBlock("Seat limit reached.", [
|
|
@@ -1007,7 +1118,7 @@ async function runDeactivate() {
|
|
|
1007
1118
|
process.stdout.write(` ${success("Deactivated")}
|
|
1008
1119
|
`);
|
|
1009
1120
|
process.stdout.write(nextStep("Activate on another machine", "ctxloom activate <KEY>"));
|
|
1010
|
-
track("license_deactivated",
|
|
1121
|
+
track("license_deactivated", os2.hostname());
|
|
1011
1122
|
} catch (err) {
|
|
1012
1123
|
if (err instanceof NetworkError) {
|
|
1013
1124
|
process.stderr.write(errorBlock("Deactivation failed \u2014 network error.", [
|
|
@@ -1054,7 +1165,7 @@ async function runStatus() {
|
|
|
1054
1165
|
["Tier", style.bold(tier)],
|
|
1055
1166
|
["Status", statusColored],
|
|
1056
1167
|
["Expires", expiresLabel],
|
|
1057
|
-
["Machine", `${
|
|
1168
|
+
["Machine", `${os2.hostname()} ${style.dim(`(${os2.platform()}-${os2.arch()})`)}`],
|
|
1058
1169
|
["Last sync", style.dim(lastCheck)]
|
|
1059
1170
|
]));
|
|
1060
1171
|
process.stdout.write("\n");
|
|
@@ -1208,7 +1319,7 @@ async function main() {
|
|
|
1208
1319
|
process.exit(1);
|
|
1209
1320
|
}
|
|
1210
1321
|
if (alias !== void 0) {
|
|
1211
|
-
const { validateAlias } = await import("./src-
|
|
1322
|
+
const { validateAlias } = await import("./src-JI5LH2V7.js");
|
|
1212
1323
|
const v = validateAlias(alias);
|
|
1213
1324
|
if (!v.ok) {
|
|
1214
1325
|
console.error(`[ctxloom] Invalid alias: ${v.reason}`);
|
|
@@ -1216,7 +1327,7 @@ async function main() {
|
|
|
1216
1327
|
}
|
|
1217
1328
|
}
|
|
1218
1329
|
const dbPath = path3.join(absPath, ".ctxloom", "vectors.lancedb");
|
|
1219
|
-
const registryPath = path3.join(
|
|
1330
|
+
const registryPath = path3.join(os2.homedir(), ".ctxloom", "repos.json");
|
|
1220
1331
|
const reg = new RepoRegistry(registryPath);
|
|
1221
1332
|
try {
|
|
1222
1333
|
reg.register(absPath, dbPath, alias !== void 0 ? { alias } : {});
|
|
@@ -1224,13 +1335,19 @@ async function main() {
|
|
|
1224
1335
|
console.error(`[ctxloom] ${err instanceof Error ? err.message : String(err)}`);
|
|
1225
1336
|
process.exit(1);
|
|
1226
1337
|
}
|
|
1338
|
+
if (alias !== void 0) {
|
|
1339
|
+
track("alias_registered", os2.hostname(), {
|
|
1340
|
+
alias_length: alias.length,
|
|
1341
|
+
was_collision: false
|
|
1342
|
+
});
|
|
1343
|
+
}
|
|
1227
1344
|
console.log(`[ctxloom] Registered repo: ${absPath}${alias ? ` (alias: ${alias})` : ""}`);
|
|
1228
1345
|
console.log(`[ctxloom] LanceDB path: ${dbPath}`);
|
|
1229
1346
|
console.log(`[ctxloom] Registry: ${registryPath}`);
|
|
1230
1347
|
break;
|
|
1231
1348
|
}
|
|
1232
1349
|
case "repos": {
|
|
1233
|
-
const registryPath = path3.join(
|
|
1350
|
+
const registryPath = path3.join(os2.homedir(), ".ctxloom", "repos.json");
|
|
1234
1351
|
const reg = new RepoRegistry(registryPath);
|
|
1235
1352
|
const repos = reg.list();
|
|
1236
1353
|
if (repos.length === 0) {
|
|
@@ -1446,7 +1563,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
1446
1563
|
process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
|
|
1447
1564
|
process.exit(2);
|
|
1448
1565
|
}
|
|
1449
|
-
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-
|
|
1566
|
+
const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-JI5LH2V7.js");
|
|
1450
1567
|
let config;
|
|
1451
1568
|
try {
|
|
1452
1569
|
config = await loadRulesConfig(root);
|
|
@@ -1470,7 +1587,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
1470
1587
|
}
|
|
1471
1588
|
let graph;
|
|
1472
1589
|
if (useSnapshot) {
|
|
1473
|
-
const { DependencyGraph: DG } = await import("./src-
|
|
1590
|
+
const { DependencyGraph: DG } = await import("./src-JI5LH2V7.js");
|
|
1474
1591
|
graph = new DG();
|
|
1475
1592
|
const loaded = await graph.loadSnapshotOnly(root);
|
|
1476
1593
|
if (!loaded) {
|
|
@@ -1479,7 +1596,7 @@ Suggested reviewers for ${files.length} file(s):`);
|
|
|
1479
1596
|
}
|
|
1480
1597
|
} else {
|
|
1481
1598
|
process.stderr.write("[ctxloom] Building dependency graph...\n");
|
|
1482
|
-
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-
|
|
1599
|
+
const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-JI5LH2V7.js");
|
|
1483
1600
|
let parser;
|
|
1484
1601
|
try {
|
|
1485
1602
|
parser = new ASTParser2();
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DEFAULT_REVIEW_CONFIG,
|
|
11
11
|
DependencyGraph,
|
|
12
12
|
EmailAlreadyUsedError,
|
|
13
|
+
EmittedOnceTracker,
|
|
13
14
|
FileWatcher,
|
|
14
15
|
Fingerprint,
|
|
15
16
|
FingerprintAlreadyUsedError,
|
|
@@ -66,6 +67,7 @@ import {
|
|
|
66
67
|
generateCODEOWNERS,
|
|
67
68
|
getImpactRadius,
|
|
68
69
|
getLicenseInfo,
|
|
70
|
+
hashProjectRoot,
|
|
69
71
|
isActive,
|
|
70
72
|
isSiloed,
|
|
71
73
|
listNamedSnapshots,
|
|
@@ -95,7 +97,7 @@ import {
|
|
|
95
97
|
validateDefaultRoot,
|
|
96
98
|
wrapWithIndexingEnvelope,
|
|
97
99
|
writeCODEOWNERS
|
|
98
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-CXKKREER.js";
|
|
99
101
|
import {
|
|
100
102
|
VectorStore
|
|
101
103
|
} from "./chunk-NEHYSE2Y.js";
|
|
@@ -121,6 +123,7 @@ export {
|
|
|
121
123
|
DependencyGraph,
|
|
122
124
|
EMBEDDING_DIMENSION,
|
|
123
125
|
EmailAlreadyUsedError,
|
|
126
|
+
EmittedOnceTracker,
|
|
124
127
|
FileWatcher,
|
|
125
128
|
Fingerprint,
|
|
126
129
|
FingerprintAlreadyUsedError,
|
|
@@ -180,6 +183,7 @@ export {
|
|
|
180
183
|
generateEmbedding,
|
|
181
184
|
getImpactRadius,
|
|
182
185
|
getLicenseInfo,
|
|
186
|
+
hashProjectRoot,
|
|
183
187
|
indexDirectory,
|
|
184
188
|
isActive,
|
|
185
189
|
isSiloed,
|
|
@@ -212,4 +216,4 @@ export {
|
|
|
212
216
|
wrapWithIndexingEnvelope,
|
|
213
217
|
writeCODEOWNERS
|
|
214
218
|
};
|
|
215
|
-
//# sourceMappingURL=src-
|
|
219
|
+
//# sourceMappingURL=src-JI5LH2V7.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctxloom-pro",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
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",
|