ctxloom-pro 1.7.8 → 1.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/apps/dashboard/dist/server/index.js +86 -79
- package/dist/VectorStore-ZA4EEL6C.js +11 -0
- package/dist/{chunk-7WLMI4AD.js → chunk-J3NVYR6J.js} +185 -140
- package/dist/{chunk-Z3NQHCWG.js → chunk-UWQKNIZO.js} +37 -5
- package/dist/{chunk-R32CUQAL.js → chunk-XJJHX227.js} +2 -2
- package/dist/{embedder-E2GDBGOH.js → embedder-WQMRK5T7.js} +2 -2
- package/dist/index.js +43 -14
- package/dist/{src-C5NS2JAW.js → src-7ETGK3MB.js} +7 -5
- package/dist/workers/indexerWorker.js +2 -2
- package/package.json +1 -1
- package/dist/VectorStore-IHNQ3NOD.js +0 -9
package/README.md
CHANGED
|
@@ -69,7 +69,7 @@ The full first-run flow is **one install + one trial + one init per project.** E
|
|
|
69
69
|
npm install -g ctxloom-pro
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
> **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.
|
|
72
|
+
> **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.10`) so future CLI releases don't silently desync your agent-spec coverage — see the workflow example below.
|
|
73
73
|
|
|
74
74
|
### 2 — Start your free trial (once per email)
|
|
75
75
|
|
|
@@ -383,7 +383,7 @@ jobs:
|
|
|
383
383
|
# Exact pin (not `@^1`) so future CLI releases that add/remove MCP
|
|
384
384
|
# tools don't silently desync your reviewer-agent specs. Bump on
|
|
385
385
|
# every release; see CHANGELOG.md for the live version table.
|
|
386
|
-
- run: npm install -g ctxloom-pro@1.7.
|
|
386
|
+
- run: npm install -g ctxloom-pro@1.7.10
|
|
387
387
|
- run: ctxloom index
|
|
388
388
|
- run: ctxloom rules check --json
|
|
389
389
|
```
|
|
@@ -233,12 +233,12 @@ var init_VectorStore = __esm({
|
|
|
233
233
|
// server/index.ts
|
|
234
234
|
import express from "express";
|
|
235
235
|
import cors from "cors";
|
|
236
|
-
import
|
|
237
|
-
import
|
|
236
|
+
import path48 from "path";
|
|
237
|
+
import fs36 from "fs";
|
|
238
238
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
239
239
|
|
|
240
240
|
// server/loader.ts
|
|
241
|
-
import
|
|
241
|
+
import path42 from "path";
|
|
242
242
|
|
|
243
243
|
// ../../packages/core/src/graph/DependencyGraph.ts
|
|
244
244
|
import fs7 from "fs";
|
|
@@ -2929,7 +2929,7 @@ var CallGraphIndex = class _CallGraphIndex {
|
|
|
2929
2929
|
var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
|
|
2930
2930
|
var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
|
|
2931
2931
|
var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
|
|
2932
|
-
var CTXLOOM_VERSION = "1.7.
|
|
2932
|
+
var CTXLOOM_VERSION = "1.7.10".length > 0 ? "1.7.10" : "dev";
|
|
2933
2933
|
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
2934
2934
|
function compareCtxloomVersions(snapshotVer, currentVer) {
|
|
2935
2935
|
if (snapshotVer === currentVer) return "same";
|
|
@@ -4004,8 +4004,8 @@ var CoChangeIndex = class _CoChangeIndex {
|
|
|
4004
4004
|
if (event.isBulk || event.isMerge) return;
|
|
4005
4005
|
const paths = event.files.map((f) => f.path);
|
|
4006
4006
|
if (paths.length === 0) return;
|
|
4007
|
-
for (const
|
|
4008
|
-
this.nodeCounts.set(
|
|
4007
|
+
for (const path49 of paths) {
|
|
4008
|
+
this.nodeCounts.set(path49, (this.nodeCounts.get(path49) ?? 0) + 1);
|
|
4009
4009
|
}
|
|
4010
4010
|
for (let i = 0; i < paths.length; i++) {
|
|
4011
4011
|
for (let j = i + 1; j < paths.length; j++) {
|
|
@@ -4152,8 +4152,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
4152
4152
|
*/
|
|
4153
4153
|
snapshot() {
|
|
4154
4154
|
const nodes = {};
|
|
4155
|
-
for (const [
|
|
4156
|
-
nodes[
|
|
4155
|
+
for (const [path49, raw] of this.nodes) {
|
|
4156
|
+
nodes[path49] = {
|
|
4157
4157
|
commits: raw.commits,
|
|
4158
4158
|
churnLines: raw.churnLines,
|
|
4159
4159
|
bugCommits: raw.bugCommits,
|
|
@@ -4168,8 +4168,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
4168
4168
|
*/
|
|
4169
4169
|
static load(s) {
|
|
4170
4170
|
const idx = new _ChurnIndex();
|
|
4171
|
-
for (const [
|
|
4172
|
-
idx.nodes.set(
|
|
4171
|
+
for (const [path49, raw] of Object.entries(s.nodes)) {
|
|
4172
|
+
idx.nodes.set(path49, {
|
|
4173
4173
|
commits: raw.commits,
|
|
4174
4174
|
churnLines: raw.churnLines,
|
|
4175
4175
|
bugCommits: raw.bugCommits,
|
|
@@ -4182,8 +4182,8 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
4182
4182
|
// -------------------------------------------------------------------------
|
|
4183
4183
|
// Private helpers
|
|
4184
4184
|
// -------------------------------------------------------------------------
|
|
4185
|
-
getOrCreate(
|
|
4186
|
-
const existing = this.nodes.get(
|
|
4185
|
+
getOrCreate(path49) {
|
|
4186
|
+
const existing = this.nodes.get(path49);
|
|
4187
4187
|
if (existing !== void 0) return existing;
|
|
4188
4188
|
const fresh = {
|
|
4189
4189
|
commits: 0,
|
|
@@ -4192,7 +4192,7 @@ var ChurnIndex = class _ChurnIndex {
|
|
|
4192
4192
|
authorCounts: {},
|
|
4193
4193
|
lastTouch: 0
|
|
4194
4194
|
};
|
|
4195
|
-
this.nodes.set(
|
|
4195
|
+
this.nodes.set(path49, fresh);
|
|
4196
4196
|
return fresh;
|
|
4197
4197
|
}
|
|
4198
4198
|
};
|
|
@@ -4273,12 +4273,12 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
4273
4273
|
*/
|
|
4274
4274
|
snapshot() {
|
|
4275
4275
|
const nodes = {};
|
|
4276
|
-
for (const [
|
|
4276
|
+
for (const [path49, raw] of this.nodes) {
|
|
4277
4277
|
const authorWeights = {};
|
|
4278
4278
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
4279
4279
|
authorWeights[email] = { ...entry };
|
|
4280
4280
|
}
|
|
4281
|
-
nodes[
|
|
4281
|
+
nodes[path49] = { authorWeights, lastTouch: raw.lastTouch };
|
|
4282
4282
|
}
|
|
4283
4283
|
return { version: 1, nodes };
|
|
4284
4284
|
}
|
|
@@ -4287,23 +4287,23 @@ var OwnershipIndex = class _OwnershipIndex {
|
|
|
4287
4287
|
*/
|
|
4288
4288
|
static load(s) {
|
|
4289
4289
|
const idx = new _OwnershipIndex();
|
|
4290
|
-
for (const [
|
|
4290
|
+
for (const [path49, raw] of Object.entries(s.nodes)) {
|
|
4291
4291
|
const authorWeights = {};
|
|
4292
4292
|
for (const [email, entry] of Object.entries(raw.authorWeights)) {
|
|
4293
4293
|
authorWeights[email] = { ...entry };
|
|
4294
4294
|
}
|
|
4295
|
-
idx.nodes.set(
|
|
4295
|
+
idx.nodes.set(path49, { authorWeights, lastTouch: raw.lastTouch });
|
|
4296
4296
|
}
|
|
4297
4297
|
return idx;
|
|
4298
4298
|
}
|
|
4299
4299
|
// -------------------------------------------------------------------------
|
|
4300
4300
|
// Private helpers
|
|
4301
4301
|
// -------------------------------------------------------------------------
|
|
4302
|
-
getOrCreate(
|
|
4303
|
-
const existing = this.nodes.get(
|
|
4302
|
+
getOrCreate(path49) {
|
|
4303
|
+
const existing = this.nodes.get(path49);
|
|
4304
4304
|
if (existing !== void 0) return existing;
|
|
4305
4305
|
const fresh = { authorWeights: {}, lastTouch: 0 };
|
|
4306
|
-
this.nodes.set(
|
|
4306
|
+
this.nodes.set(path49, fresh);
|
|
4307
4307
|
return fresh;
|
|
4308
4308
|
}
|
|
4309
4309
|
};
|
|
@@ -5546,8 +5546,8 @@ function getErrorMap() {
|
|
|
5546
5546
|
|
|
5547
5547
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
5548
5548
|
var makeIssue = (params) => {
|
|
5549
|
-
const { data, path:
|
|
5550
|
-
const fullPath = [...
|
|
5549
|
+
const { data, path: path49, errorMaps, issueData } = params;
|
|
5550
|
+
const fullPath = [...path49, ...issueData.path || []];
|
|
5551
5551
|
const fullIssue = {
|
|
5552
5552
|
...issueData,
|
|
5553
5553
|
path: fullPath
|
|
@@ -5663,11 +5663,11 @@ var errorUtil;
|
|
|
5663
5663
|
|
|
5664
5664
|
// ../../node_modules/zod/v3/types.js
|
|
5665
5665
|
var ParseInputLazyPath = class {
|
|
5666
|
-
constructor(parent, value,
|
|
5666
|
+
constructor(parent, value, path49, key) {
|
|
5667
5667
|
this._cachedPath = [];
|
|
5668
5668
|
this.parent = parent;
|
|
5669
5669
|
this.data = value;
|
|
5670
|
-
this._path =
|
|
5670
|
+
this._path = path49;
|
|
5671
5671
|
this._key = key;
|
|
5672
5672
|
}
|
|
5673
5673
|
get path() {
|
|
@@ -9113,6 +9113,9 @@ var NEVER = INVALID;
|
|
|
9113
9113
|
var PROJECT_ROOT_DESCRIPTION = "Absolute path or registered alias of the project to operate on. Falls back to CTXLOOM_ROOT env, then server cwd. Register aliases with `ctxloom register <path> --alias <name>`.";
|
|
9114
9114
|
var ProjectRootField = external_exports.string().optional().describe(PROJECT_ROOT_DESCRIPTION);
|
|
9115
9115
|
|
|
9116
|
+
// ../../packages/core/src/tools/status.ts
|
|
9117
|
+
init_VectorStore();
|
|
9118
|
+
|
|
9116
9119
|
// ../../packages/core/src/tools/registry.ts
|
|
9117
9120
|
init_logger();
|
|
9118
9121
|
|
|
@@ -9566,6 +9569,10 @@ var schema3 = external_exports.object({
|
|
|
9566
9569
|
response_format: external_exports.enum(["full", "skeleton", "auto"]).optional().describe("'full'/'auto' default; 'skeleton' produces the same output (response is already compact).")
|
|
9567
9570
|
});
|
|
9568
9571
|
|
|
9572
|
+
// ../../packages/core/src/tools/overlayNote.ts
|
|
9573
|
+
import fs25 from "fs";
|
|
9574
|
+
import path27 from "path";
|
|
9575
|
+
|
|
9569
9576
|
// ../../packages/core/src/tools/git-coupling.ts
|
|
9570
9577
|
var Schema26 = external_exports.object({
|
|
9571
9578
|
file: external_exports.string().describe("File path to look up co-changed siblings for"),
|
|
@@ -9582,8 +9589,8 @@ var Schema27 = external_exports.object({
|
|
|
9582
9589
|
});
|
|
9583
9590
|
|
|
9584
9591
|
// ../../packages/core/src/rules/loadConfig.ts
|
|
9585
|
-
import
|
|
9586
|
-
import
|
|
9592
|
+
import fs26 from "fs/promises";
|
|
9593
|
+
import path28 from "path";
|
|
9587
9594
|
|
|
9588
9595
|
// ../../node_modules/js-yaml/dist/js-yaml.mjs
|
|
9589
9596
|
function isNothing(subject) {
|
|
@@ -12224,24 +12231,24 @@ var Schema30 = external_exports.object({
|
|
|
12224
12231
|
});
|
|
12225
12232
|
|
|
12226
12233
|
// ../../packages/core/src/tools/ruleManager.ts
|
|
12227
|
-
import
|
|
12228
|
-
import path28 from "path";
|
|
12229
|
-
|
|
12230
|
-
// ../../packages/core/src/review/AuthorResolver.ts
|
|
12231
|
-
import fs27 from "fs/promises";
|
|
12234
|
+
import fs27 from "fs";
|
|
12232
12235
|
import path29 from "path";
|
|
12233
12236
|
|
|
12234
|
-
// ../../packages/core/src/review/
|
|
12237
|
+
// ../../packages/core/src/review/AuthorResolver.ts
|
|
12235
12238
|
import fs28 from "fs/promises";
|
|
12236
12239
|
import path30 from "path";
|
|
12237
12240
|
|
|
12238
|
-
// ../../packages/core/src/review/
|
|
12241
|
+
// ../../packages/core/src/review/CodeownersWriter.ts
|
|
12239
12242
|
import fs29 from "fs/promises";
|
|
12240
12243
|
import path31 from "path";
|
|
12241
12244
|
|
|
12242
|
-
// ../../packages/core/src/
|
|
12245
|
+
// ../../packages/core/src/review/loadConfig.ts
|
|
12246
|
+
import fs30 from "fs/promises";
|
|
12243
12247
|
import path32 from "path";
|
|
12244
|
-
|
|
12248
|
+
|
|
12249
|
+
// ../../packages/core/src/security/PathValidator.ts
|
|
12250
|
+
import path33 from "path";
|
|
12251
|
+
import fs31 from "fs";
|
|
12245
12252
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
12246
12253
|
|
|
12247
12254
|
// ../../packages/core/src/index.ts
|
|
@@ -12253,7 +12260,7 @@ init_logger();
|
|
|
12253
12260
|
|
|
12254
12261
|
// ../../packages/core/src/license/LicenseStore.ts
|
|
12255
12262
|
import { readFileSync, writeFileSync, unlinkSync, mkdirSync, chmodSync, existsSync } from "fs";
|
|
12256
|
-
import
|
|
12263
|
+
import path34 from "path";
|
|
12257
12264
|
|
|
12258
12265
|
// ../../packages/core/src/license/types.ts
|
|
12259
12266
|
var FINGERPRINT_RE = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -12284,11 +12291,11 @@ import os6 from "os";
|
|
|
12284
12291
|
|
|
12285
12292
|
// ../../packages/core/src/license/DistinctIdStore.ts
|
|
12286
12293
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
12287
|
-
import
|
|
12294
|
+
import path35 from "path";
|
|
12288
12295
|
import os4 from "os";
|
|
12289
12296
|
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;
|
|
12290
12297
|
function distinctIdPath(home) {
|
|
12291
|
-
return
|
|
12298
|
+
return path35.join(home ?? os4.homedir(), ".ctxloom", "distinct_id");
|
|
12292
12299
|
}
|
|
12293
12300
|
function isValidV4(id) {
|
|
12294
12301
|
return typeof id === "string" && UUID_V4_REGEX.test(id);
|
|
@@ -12309,7 +12316,7 @@ function getOrCreateDistinctId(home) {
|
|
|
12309
12316
|
id: crypto.randomUUID(),
|
|
12310
12317
|
alias_pending: os4.hostname()
|
|
12311
12318
|
};
|
|
12312
|
-
mkdirSync2(
|
|
12319
|
+
mkdirSync2(path35.dirname(filePath), { recursive: true });
|
|
12313
12320
|
writeFileSync2(filePath, JSON.stringify(record), { mode: 384 });
|
|
12314
12321
|
return record;
|
|
12315
12322
|
}
|
|
@@ -12335,7 +12342,7 @@ function resolveTelemetryLevel() {
|
|
|
12335
12342
|
}
|
|
12336
12343
|
var TELEMETRY_LEVEL = resolveTelemetryLevel();
|
|
12337
12344
|
var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
12338
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
12345
|
+
var CTXLOOM_VERSION2 = "1.7.10".length > 0 ? "1.7.10" : "dev";
|
|
12339
12346
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
12340
12347
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
12341
12348
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -12468,32 +12475,32 @@ function parseStack(stack) {
|
|
|
12468
12475
|
|
|
12469
12476
|
// ../../packages/core/src/license/FunnelMilestones.ts
|
|
12470
12477
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
12471
|
-
import
|
|
12478
|
+
import path36 from "path";
|
|
12472
12479
|
import os5 from "os";
|
|
12473
12480
|
|
|
12474
12481
|
// ../../packages/core/src/license/TelemetryNotice.ts
|
|
12475
12482
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
12476
|
-
import
|
|
12483
|
+
import path37 from "path";
|
|
12477
12484
|
import os7 from "os";
|
|
12478
12485
|
|
|
12479
12486
|
// ../../packages/core/src/server/ProjectState.ts
|
|
12480
|
-
import
|
|
12487
|
+
import path39 from "path";
|
|
12481
12488
|
|
|
12482
12489
|
// ../../packages/core/src/server/projectId.ts
|
|
12483
12490
|
import crypto5 from "crypto";
|
|
12484
|
-
import
|
|
12491
|
+
import path38 from "path";
|
|
12485
12492
|
|
|
12486
12493
|
// ../../packages/core/src/server/ProjectStateManager.ts
|
|
12487
12494
|
init_logger();
|
|
12488
12495
|
|
|
12489
12496
|
// ../../packages/core/src/server/resolveProjectRoot.ts
|
|
12490
|
-
import fs31 from "fs";
|
|
12491
|
-
import path39 from "path";
|
|
12492
|
-
|
|
12493
|
-
// ../../packages/core/src/install/installer.ts
|
|
12494
12497
|
import fs32 from "fs";
|
|
12495
12498
|
import path40 from "path";
|
|
12496
12499
|
|
|
12500
|
+
// ../../packages/core/src/install/installer.ts
|
|
12501
|
+
import fs33 from "fs";
|
|
12502
|
+
import path41 from "path";
|
|
12503
|
+
|
|
12497
12504
|
// ../../packages/core/src/install/templates.ts
|
|
12498
12505
|
var RULES_BLOCK_CONTENT = `## MCP Tools: ctxloom
|
|
12499
12506
|
|
|
@@ -12758,7 +12765,7 @@ function summarize(events, windowStart, windowEnd) {
|
|
|
12758
12765
|
|
|
12759
12766
|
// server/loader.ts
|
|
12760
12767
|
async function loadContext(root) {
|
|
12761
|
-
const absRoot =
|
|
12768
|
+
const absRoot = path42.resolve(root);
|
|
12762
12769
|
const overlay = new GitOverlayStore(absRoot);
|
|
12763
12770
|
const gitEnabled = await overlay.loadSnapshot();
|
|
12764
12771
|
const graph = new DependencyGraph();
|
|
@@ -13011,21 +13018,21 @@ function buildOwnershipRouter(ctx) {
|
|
|
13011
13018
|
|
|
13012
13019
|
// server/routes/file.ts
|
|
13013
13020
|
import { Router as Router7 } from "express";
|
|
13014
|
-
import
|
|
13015
|
-
import
|
|
13021
|
+
import fs34 from "fs/promises";
|
|
13022
|
+
import path43 from "path";
|
|
13016
13023
|
function buildFileRouter(ctx) {
|
|
13017
13024
|
const router = Router7();
|
|
13018
13025
|
router.get("/", async (req, res) => {
|
|
13019
13026
|
const rel = req.query.path;
|
|
13020
13027
|
if (!rel) return res.status(400).json({ error: "missing path" });
|
|
13021
|
-
const abs =
|
|
13022
|
-
const rootBoundary = ctx.root.endsWith(
|
|
13028
|
+
const abs = path43.resolve(ctx.root, rel);
|
|
13029
|
+
const rootBoundary = ctx.root.endsWith(path43.sep) ? ctx.root : ctx.root + path43.sep;
|
|
13023
13030
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
13024
13031
|
return res.status(403).json({ error: "forbidden" });
|
|
13025
13032
|
}
|
|
13026
13033
|
try {
|
|
13027
|
-
const content = await
|
|
13028
|
-
const ext =
|
|
13034
|
+
const content = await fs34.readFile(abs, "utf-8");
|
|
13035
|
+
const ext = path43.extname(abs).slice(1);
|
|
13029
13036
|
res.json({ content, lines: content.split("\n").length, ext });
|
|
13030
13037
|
} catch {
|
|
13031
13038
|
res.status(404).json({ error: "not found" });
|
|
@@ -13037,7 +13044,7 @@ function buildFileRouter(ctx) {
|
|
|
13037
13044
|
// server/routes/open.ts
|
|
13038
13045
|
import { Router as Router8 } from "express";
|
|
13039
13046
|
import { execFile as execFile2 } from "child_process";
|
|
13040
|
-
import
|
|
13047
|
+
import path44 from "path";
|
|
13041
13048
|
function tryOpen(bin, abs) {
|
|
13042
13049
|
return new Promise((resolve) => {
|
|
13043
13050
|
execFile2(bin, [abs], { timeout: 5e3 }, (err) => resolve(!err));
|
|
@@ -13048,8 +13055,8 @@ function buildOpenRouter(ctx) {
|
|
|
13048
13055
|
router.post("/", async (req, res) => {
|
|
13049
13056
|
const rel = req.body?.path;
|
|
13050
13057
|
if (!rel || typeof rel !== "string") return res.status(400).json({ error: "missing path" });
|
|
13051
|
-
const abs =
|
|
13052
|
-
const rootBoundary = ctx.root.endsWith(
|
|
13058
|
+
const abs = path44.resolve(ctx.root, rel);
|
|
13059
|
+
const rootBoundary = ctx.root.endsWith(path44.sep) ? ctx.root : ctx.root + path44.sep;
|
|
13053
13060
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
13054
13061
|
return res.status(403).json({ error: "forbidden" });
|
|
13055
13062
|
}
|
|
@@ -13061,8 +13068,8 @@ function buildOpenRouter(ctx) {
|
|
|
13061
13068
|
|
|
13062
13069
|
// server/routes/tokens.ts
|
|
13063
13070
|
import { Router as Router9 } from "express";
|
|
13064
|
-
import
|
|
13065
|
-
import
|
|
13071
|
+
import path45 from "path";
|
|
13072
|
+
import fs35 from "fs";
|
|
13066
13073
|
var CHARS_PER_TOKEN = 4;
|
|
13067
13074
|
var cache = null;
|
|
13068
13075
|
function buildTokensRouter(ctx) {
|
|
@@ -13077,9 +13084,9 @@ function buildTokensRouter(ctx) {
|
|
|
13077
13084
|
let fullChars = 0;
|
|
13078
13085
|
let skeletonChars = 0;
|
|
13079
13086
|
for (const file of files) {
|
|
13080
|
-
const absPath =
|
|
13087
|
+
const absPath = path45.join(ctx.root, file);
|
|
13081
13088
|
try {
|
|
13082
|
-
const content =
|
|
13089
|
+
const content = fs35.readFileSync(absPath, "utf-8");
|
|
13083
13090
|
fullChars += content.length;
|
|
13084
13091
|
const skeleton = await skeletonizer.skeletonize(absPath);
|
|
13085
13092
|
skeletonChars += skeleton.length;
|
|
@@ -13180,17 +13187,17 @@ function buildFileTrendsRouter(ctx) {
|
|
|
13180
13187
|
|
|
13181
13188
|
// server/routes/projects.ts
|
|
13182
13189
|
import { Router as Router12 } from "express";
|
|
13183
|
-
import
|
|
13190
|
+
import path47 from "path";
|
|
13184
13191
|
|
|
13185
13192
|
// server/projects.ts
|
|
13186
13193
|
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
13187
13194
|
import os8 from "os";
|
|
13188
|
-
import
|
|
13195
|
+
import path46 from "path";
|
|
13189
13196
|
import crypto7 from "crypto";
|
|
13190
13197
|
var HOME = os8.homedir();
|
|
13191
|
-
var REGISTRY_PATH =
|
|
13198
|
+
var REGISTRY_PATH = path46.join(HOME, ".ctxloom", "repos.json");
|
|
13192
13199
|
function slugFor(root) {
|
|
13193
|
-
const abs =
|
|
13200
|
+
const abs = path46.resolve(root);
|
|
13194
13201
|
return crypto7.createHash("sha1").update(abs).digest("hex").slice(0, 12);
|
|
13195
13202
|
}
|
|
13196
13203
|
function readRegistry() {
|
|
@@ -13205,27 +13212,27 @@ function readRegistry() {
|
|
|
13205
13212
|
}
|
|
13206
13213
|
}
|
|
13207
13214
|
function listProjects(defaultRoot) {
|
|
13208
|
-
const absDefault =
|
|
13215
|
+
const absDefault = path46.resolve(defaultRoot);
|
|
13209
13216
|
const out = [
|
|
13210
13217
|
{
|
|
13211
13218
|
slug: slugFor(absDefault),
|
|
13212
|
-
name:
|
|
13219
|
+
name: path46.basename(absDefault) || absDefault,
|
|
13213
13220
|
root: absDefault,
|
|
13214
13221
|
isDefault: true,
|
|
13215
|
-
hasSnapshot: existsSync5(
|
|
13222
|
+
hasSnapshot: existsSync5(path46.join(absDefault, ".ctxloom"))
|
|
13216
13223
|
}
|
|
13217
13224
|
];
|
|
13218
13225
|
const seen = /* @__PURE__ */ new Set([absDefault]);
|
|
13219
13226
|
for (const entry of readRegistry()) {
|
|
13220
|
-
const abs =
|
|
13227
|
+
const abs = path46.resolve(entry.root);
|
|
13221
13228
|
if (seen.has(abs)) continue;
|
|
13222
13229
|
seen.add(abs);
|
|
13223
13230
|
const item = {
|
|
13224
13231
|
slug: slugFor(abs),
|
|
13225
|
-
name: entry.name ?? (
|
|
13232
|
+
name: entry.name ?? (path46.basename(abs) || abs),
|
|
13226
13233
|
root: abs,
|
|
13227
13234
|
isDefault: false,
|
|
13228
|
-
hasSnapshot: existsSync5(
|
|
13235
|
+
hasSnapshot: existsSync5(path46.join(abs, ".ctxloom"))
|
|
13229
13236
|
};
|
|
13230
13237
|
if (entry.alias !== void 0) item.alias = entry.alias;
|
|
13231
13238
|
out.push(item);
|
|
@@ -13278,7 +13285,7 @@ function buildProjectsRouter(deps) {
|
|
|
13278
13285
|
} catch (err) {
|
|
13279
13286
|
const detail = err instanceof Error ? err.message : String(err);
|
|
13280
13287
|
res.status(500).json({
|
|
13281
|
-
error: `failed to switch to ${
|
|
13288
|
+
error: `failed to switch to ${path47.basename(target.root)}: ${detail}`
|
|
13282
13289
|
});
|
|
13283
13290
|
}
|
|
13284
13291
|
});
|
|
@@ -13388,7 +13395,7 @@ function buildBudgetEventsRouter() {
|
|
|
13388
13395
|
}
|
|
13389
13396
|
|
|
13390
13397
|
// server/index.ts
|
|
13391
|
-
var __dirname2 =
|
|
13398
|
+
var __dirname2 = path48.dirname(fileURLToPath2(import.meta.url));
|
|
13392
13399
|
async function startDashboard(options) {
|
|
13393
13400
|
const { root, port, open } = options;
|
|
13394
13401
|
console.log(`ctxloom dashboard \u2014 loading context from ${root}...`);
|
|
@@ -13448,9 +13455,9 @@ async function startDashboard(options) {
|
|
|
13448
13455
|
}
|
|
13449
13456
|
activeWatcher = null;
|
|
13450
13457
|
}
|
|
13451
|
-
const snapshotDir =
|
|
13458
|
+
const snapshotDir = path48.join(targetRoot, ".ctxloom");
|
|
13452
13459
|
try {
|
|
13453
|
-
activeWatcher =
|
|
13460
|
+
activeWatcher = fs36.watch(snapshotDir, (_event, filename) => {
|
|
13454
13461
|
if (!filename || !filename.includes("snapshot")) return;
|
|
13455
13462
|
if (debounce) clearTimeout(debounce);
|
|
13456
13463
|
debounce = setTimeout(async () => {
|
|
@@ -13479,12 +13486,12 @@ async function startDashboard(options) {
|
|
|
13479
13486
|
attachSnapshotWatcher(newRoot);
|
|
13480
13487
|
}
|
|
13481
13488
|
}));
|
|
13482
|
-
const clientDist =
|
|
13483
|
-
const clientDistExists =
|
|
13489
|
+
const clientDist = path48.join(__dirname2, "../dashboard/client");
|
|
13490
|
+
const clientDistExists = fs36.existsSync(path48.join(clientDist, "index.html"));
|
|
13484
13491
|
if (clientDistExists) {
|
|
13485
13492
|
app.use(express.static(clientDist, { dotfiles: "allow" }));
|
|
13486
13493
|
app.get(/.*/, (_req, res) => {
|
|
13487
|
-
res.sendFile(
|
|
13494
|
+
res.sendFile(path48.join(clientDist, "index.html"), { dotfiles: "allow" });
|
|
13488
13495
|
});
|
|
13489
13496
|
} else {
|
|
13490
13497
|
app.get(/^\/(?!api\/).*/, (_req, res) => {
|