ctxloom-pro 1.7.9 → 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
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() {
|
|
@@ -9569,6 +9569,10 @@ var schema3 = external_exports.object({
|
|
|
9569
9569
|
response_format: external_exports.enum(["full", "skeleton", "auto"]).optional().describe("'full'/'auto' default; 'skeleton' produces the same output (response is already compact).")
|
|
9570
9570
|
});
|
|
9571
9571
|
|
|
9572
|
+
// ../../packages/core/src/tools/overlayNote.ts
|
|
9573
|
+
import fs25 from "fs";
|
|
9574
|
+
import path27 from "path";
|
|
9575
|
+
|
|
9572
9576
|
// ../../packages/core/src/tools/git-coupling.ts
|
|
9573
9577
|
var Schema26 = external_exports.object({
|
|
9574
9578
|
file: external_exports.string().describe("File path to look up co-changed siblings for"),
|
|
@@ -9585,8 +9589,8 @@ var Schema27 = external_exports.object({
|
|
|
9585
9589
|
});
|
|
9586
9590
|
|
|
9587
9591
|
// ../../packages/core/src/rules/loadConfig.ts
|
|
9588
|
-
import
|
|
9589
|
-
import
|
|
9592
|
+
import fs26 from "fs/promises";
|
|
9593
|
+
import path28 from "path";
|
|
9590
9594
|
|
|
9591
9595
|
// ../../node_modules/js-yaml/dist/js-yaml.mjs
|
|
9592
9596
|
function isNothing(subject) {
|
|
@@ -12227,24 +12231,24 @@ var Schema30 = external_exports.object({
|
|
|
12227
12231
|
});
|
|
12228
12232
|
|
|
12229
12233
|
// ../../packages/core/src/tools/ruleManager.ts
|
|
12230
|
-
import
|
|
12231
|
-
import path28 from "path";
|
|
12232
|
-
|
|
12233
|
-
// ../../packages/core/src/review/AuthorResolver.ts
|
|
12234
|
-
import fs27 from "fs/promises";
|
|
12234
|
+
import fs27 from "fs";
|
|
12235
12235
|
import path29 from "path";
|
|
12236
12236
|
|
|
12237
|
-
// ../../packages/core/src/review/
|
|
12237
|
+
// ../../packages/core/src/review/AuthorResolver.ts
|
|
12238
12238
|
import fs28 from "fs/promises";
|
|
12239
12239
|
import path30 from "path";
|
|
12240
12240
|
|
|
12241
|
-
// ../../packages/core/src/review/
|
|
12241
|
+
// ../../packages/core/src/review/CodeownersWriter.ts
|
|
12242
12242
|
import fs29 from "fs/promises";
|
|
12243
12243
|
import path31 from "path";
|
|
12244
12244
|
|
|
12245
|
-
// ../../packages/core/src/
|
|
12245
|
+
// ../../packages/core/src/review/loadConfig.ts
|
|
12246
|
+
import fs30 from "fs/promises";
|
|
12246
12247
|
import path32 from "path";
|
|
12247
|
-
|
|
12248
|
+
|
|
12249
|
+
// ../../packages/core/src/security/PathValidator.ts
|
|
12250
|
+
import path33 from "path";
|
|
12251
|
+
import fs31 from "fs";
|
|
12248
12252
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
12249
12253
|
|
|
12250
12254
|
// ../../packages/core/src/index.ts
|
|
@@ -12256,7 +12260,7 @@ init_logger();
|
|
|
12256
12260
|
|
|
12257
12261
|
// ../../packages/core/src/license/LicenseStore.ts
|
|
12258
12262
|
import { readFileSync, writeFileSync, unlinkSync, mkdirSync, chmodSync, existsSync } from "fs";
|
|
12259
|
-
import
|
|
12263
|
+
import path34 from "path";
|
|
12260
12264
|
|
|
12261
12265
|
// ../../packages/core/src/license/types.ts
|
|
12262
12266
|
var FINGERPRINT_RE = /^sha256:[0-9a-f]{64}$/;
|
|
@@ -12287,11 +12291,11 @@ import os6 from "os";
|
|
|
12287
12291
|
|
|
12288
12292
|
// ../../packages/core/src/license/DistinctIdStore.ts
|
|
12289
12293
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2 } from "fs";
|
|
12290
|
-
import
|
|
12294
|
+
import path35 from "path";
|
|
12291
12295
|
import os4 from "os";
|
|
12292
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;
|
|
12293
12297
|
function distinctIdPath(home) {
|
|
12294
|
-
return
|
|
12298
|
+
return path35.join(home ?? os4.homedir(), ".ctxloom", "distinct_id");
|
|
12295
12299
|
}
|
|
12296
12300
|
function isValidV4(id) {
|
|
12297
12301
|
return typeof id === "string" && UUID_V4_REGEX.test(id);
|
|
@@ -12312,7 +12316,7 @@ function getOrCreateDistinctId(home) {
|
|
|
12312
12316
|
id: crypto.randomUUID(),
|
|
12313
12317
|
alias_pending: os4.hostname()
|
|
12314
12318
|
};
|
|
12315
|
-
mkdirSync2(
|
|
12319
|
+
mkdirSync2(path35.dirname(filePath), { recursive: true });
|
|
12316
12320
|
writeFileSync2(filePath, JSON.stringify(record), { mode: 384 });
|
|
12317
12321
|
return record;
|
|
12318
12322
|
}
|
|
@@ -12338,7 +12342,7 @@ function resolveTelemetryLevel() {
|
|
|
12338
12342
|
}
|
|
12339
12343
|
var TELEMETRY_LEVEL = resolveTelemetryLevel();
|
|
12340
12344
|
var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
|
|
12341
|
-
var CTXLOOM_VERSION2 = "1.7.
|
|
12345
|
+
var CTXLOOM_VERSION2 = "1.7.10".length > 0 ? "1.7.10" : "dev";
|
|
12342
12346
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
12343
12347
|
var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
|
|
12344
12348
|
var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
|
|
@@ -12471,32 +12475,32 @@ function parseStack(stack) {
|
|
|
12471
12475
|
|
|
12472
12476
|
// ../../packages/core/src/license/FunnelMilestones.ts
|
|
12473
12477
|
import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
12474
|
-
import
|
|
12478
|
+
import path36 from "path";
|
|
12475
12479
|
import os5 from "os";
|
|
12476
12480
|
|
|
12477
12481
|
// ../../packages/core/src/license/TelemetryNotice.ts
|
|
12478
12482
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
12479
|
-
import
|
|
12483
|
+
import path37 from "path";
|
|
12480
12484
|
import os7 from "os";
|
|
12481
12485
|
|
|
12482
12486
|
// ../../packages/core/src/server/ProjectState.ts
|
|
12483
|
-
import
|
|
12487
|
+
import path39 from "path";
|
|
12484
12488
|
|
|
12485
12489
|
// ../../packages/core/src/server/projectId.ts
|
|
12486
12490
|
import crypto5 from "crypto";
|
|
12487
|
-
import
|
|
12491
|
+
import path38 from "path";
|
|
12488
12492
|
|
|
12489
12493
|
// ../../packages/core/src/server/ProjectStateManager.ts
|
|
12490
12494
|
init_logger();
|
|
12491
12495
|
|
|
12492
12496
|
// ../../packages/core/src/server/resolveProjectRoot.ts
|
|
12493
|
-
import fs31 from "fs";
|
|
12494
|
-
import path39 from "path";
|
|
12495
|
-
|
|
12496
|
-
// ../../packages/core/src/install/installer.ts
|
|
12497
12497
|
import fs32 from "fs";
|
|
12498
12498
|
import path40 from "path";
|
|
12499
12499
|
|
|
12500
|
+
// ../../packages/core/src/install/installer.ts
|
|
12501
|
+
import fs33 from "fs";
|
|
12502
|
+
import path41 from "path";
|
|
12503
|
+
|
|
12500
12504
|
// ../../packages/core/src/install/templates.ts
|
|
12501
12505
|
var RULES_BLOCK_CONTENT = `## MCP Tools: ctxloom
|
|
12502
12506
|
|
|
@@ -12761,7 +12765,7 @@ function summarize(events, windowStart, windowEnd) {
|
|
|
12761
12765
|
|
|
12762
12766
|
// server/loader.ts
|
|
12763
12767
|
async function loadContext(root) {
|
|
12764
|
-
const absRoot =
|
|
12768
|
+
const absRoot = path42.resolve(root);
|
|
12765
12769
|
const overlay = new GitOverlayStore(absRoot);
|
|
12766
12770
|
const gitEnabled = await overlay.loadSnapshot();
|
|
12767
12771
|
const graph = new DependencyGraph();
|
|
@@ -13014,21 +13018,21 @@ function buildOwnershipRouter(ctx) {
|
|
|
13014
13018
|
|
|
13015
13019
|
// server/routes/file.ts
|
|
13016
13020
|
import { Router as Router7 } from "express";
|
|
13017
|
-
import
|
|
13018
|
-
import
|
|
13021
|
+
import fs34 from "fs/promises";
|
|
13022
|
+
import path43 from "path";
|
|
13019
13023
|
function buildFileRouter(ctx) {
|
|
13020
13024
|
const router = Router7();
|
|
13021
13025
|
router.get("/", async (req, res) => {
|
|
13022
13026
|
const rel = req.query.path;
|
|
13023
13027
|
if (!rel) return res.status(400).json({ error: "missing path" });
|
|
13024
|
-
const abs =
|
|
13025
|
-
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;
|
|
13026
13030
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
13027
13031
|
return res.status(403).json({ error: "forbidden" });
|
|
13028
13032
|
}
|
|
13029
13033
|
try {
|
|
13030
|
-
const content = await
|
|
13031
|
-
const ext =
|
|
13034
|
+
const content = await fs34.readFile(abs, "utf-8");
|
|
13035
|
+
const ext = path43.extname(abs).slice(1);
|
|
13032
13036
|
res.json({ content, lines: content.split("\n").length, ext });
|
|
13033
13037
|
} catch {
|
|
13034
13038
|
res.status(404).json({ error: "not found" });
|
|
@@ -13040,7 +13044,7 @@ function buildFileRouter(ctx) {
|
|
|
13040
13044
|
// server/routes/open.ts
|
|
13041
13045
|
import { Router as Router8 } from "express";
|
|
13042
13046
|
import { execFile as execFile2 } from "child_process";
|
|
13043
|
-
import
|
|
13047
|
+
import path44 from "path";
|
|
13044
13048
|
function tryOpen(bin, abs) {
|
|
13045
13049
|
return new Promise((resolve) => {
|
|
13046
13050
|
execFile2(bin, [abs], { timeout: 5e3 }, (err) => resolve(!err));
|
|
@@ -13051,8 +13055,8 @@ function buildOpenRouter(ctx) {
|
|
|
13051
13055
|
router.post("/", async (req, res) => {
|
|
13052
13056
|
const rel = req.body?.path;
|
|
13053
13057
|
if (!rel || typeof rel !== "string") return res.status(400).json({ error: "missing path" });
|
|
13054
|
-
const abs =
|
|
13055
|
-
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;
|
|
13056
13060
|
if (abs !== ctx.root && !abs.startsWith(rootBoundary)) {
|
|
13057
13061
|
return res.status(403).json({ error: "forbidden" });
|
|
13058
13062
|
}
|
|
@@ -13064,8 +13068,8 @@ function buildOpenRouter(ctx) {
|
|
|
13064
13068
|
|
|
13065
13069
|
// server/routes/tokens.ts
|
|
13066
13070
|
import { Router as Router9 } from "express";
|
|
13067
|
-
import
|
|
13068
|
-
import
|
|
13071
|
+
import path45 from "path";
|
|
13072
|
+
import fs35 from "fs";
|
|
13069
13073
|
var CHARS_PER_TOKEN = 4;
|
|
13070
13074
|
var cache = null;
|
|
13071
13075
|
function buildTokensRouter(ctx) {
|
|
@@ -13080,9 +13084,9 @@ function buildTokensRouter(ctx) {
|
|
|
13080
13084
|
let fullChars = 0;
|
|
13081
13085
|
let skeletonChars = 0;
|
|
13082
13086
|
for (const file of files) {
|
|
13083
|
-
const absPath =
|
|
13087
|
+
const absPath = path45.join(ctx.root, file);
|
|
13084
13088
|
try {
|
|
13085
|
-
const content =
|
|
13089
|
+
const content = fs35.readFileSync(absPath, "utf-8");
|
|
13086
13090
|
fullChars += content.length;
|
|
13087
13091
|
const skeleton = await skeletonizer.skeletonize(absPath);
|
|
13088
13092
|
skeletonChars += skeleton.length;
|
|
@@ -13183,17 +13187,17 @@ function buildFileTrendsRouter(ctx) {
|
|
|
13183
13187
|
|
|
13184
13188
|
// server/routes/projects.ts
|
|
13185
13189
|
import { Router as Router12 } from "express";
|
|
13186
|
-
import
|
|
13190
|
+
import path47 from "path";
|
|
13187
13191
|
|
|
13188
13192
|
// server/projects.ts
|
|
13189
13193
|
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
13190
13194
|
import os8 from "os";
|
|
13191
|
-
import
|
|
13195
|
+
import path46 from "path";
|
|
13192
13196
|
import crypto7 from "crypto";
|
|
13193
13197
|
var HOME = os8.homedir();
|
|
13194
|
-
var REGISTRY_PATH =
|
|
13198
|
+
var REGISTRY_PATH = path46.join(HOME, ".ctxloom", "repos.json");
|
|
13195
13199
|
function slugFor(root) {
|
|
13196
|
-
const abs =
|
|
13200
|
+
const abs = path46.resolve(root);
|
|
13197
13201
|
return crypto7.createHash("sha1").update(abs).digest("hex").slice(0, 12);
|
|
13198
13202
|
}
|
|
13199
13203
|
function readRegistry() {
|
|
@@ -13208,27 +13212,27 @@ function readRegistry() {
|
|
|
13208
13212
|
}
|
|
13209
13213
|
}
|
|
13210
13214
|
function listProjects(defaultRoot) {
|
|
13211
|
-
const absDefault =
|
|
13215
|
+
const absDefault = path46.resolve(defaultRoot);
|
|
13212
13216
|
const out = [
|
|
13213
13217
|
{
|
|
13214
13218
|
slug: slugFor(absDefault),
|
|
13215
|
-
name:
|
|
13219
|
+
name: path46.basename(absDefault) || absDefault,
|
|
13216
13220
|
root: absDefault,
|
|
13217
13221
|
isDefault: true,
|
|
13218
|
-
hasSnapshot: existsSync5(
|
|
13222
|
+
hasSnapshot: existsSync5(path46.join(absDefault, ".ctxloom"))
|
|
13219
13223
|
}
|
|
13220
13224
|
];
|
|
13221
13225
|
const seen = /* @__PURE__ */ new Set([absDefault]);
|
|
13222
13226
|
for (const entry of readRegistry()) {
|
|
13223
|
-
const abs =
|
|
13227
|
+
const abs = path46.resolve(entry.root);
|
|
13224
13228
|
if (seen.has(abs)) continue;
|
|
13225
13229
|
seen.add(abs);
|
|
13226
13230
|
const item = {
|
|
13227
13231
|
slug: slugFor(abs),
|
|
13228
|
-
name: entry.name ?? (
|
|
13232
|
+
name: entry.name ?? (path46.basename(abs) || abs),
|
|
13229
13233
|
root: abs,
|
|
13230
13234
|
isDefault: false,
|
|
13231
|
-
hasSnapshot: existsSync5(
|
|
13235
|
+
hasSnapshot: existsSync5(path46.join(abs, ".ctxloom"))
|
|
13232
13236
|
};
|
|
13233
13237
|
if (entry.alias !== void 0) item.alias = entry.alias;
|
|
13234
13238
|
out.push(item);
|
|
@@ -13281,7 +13285,7 @@ function buildProjectsRouter(deps) {
|
|
|
13281
13285
|
} catch (err) {
|
|
13282
13286
|
const detail = err instanceof Error ? err.message : String(err);
|
|
13283
13287
|
res.status(500).json({
|
|
13284
|
-
error: `failed to switch to ${
|
|
13288
|
+
error: `failed to switch to ${path47.basename(target.root)}: ${detail}`
|
|
13285
13289
|
});
|
|
13286
13290
|
}
|
|
13287
13291
|
});
|
|
@@ -13391,7 +13395,7 @@ function buildBudgetEventsRouter() {
|
|
|
13391
13395
|
}
|
|
13392
13396
|
|
|
13393
13397
|
// server/index.ts
|
|
13394
|
-
var __dirname2 =
|
|
13398
|
+
var __dirname2 = path48.dirname(fileURLToPath2(import.meta.url));
|
|
13395
13399
|
async function startDashboard(options) {
|
|
13396
13400
|
const { root, port, open } = options;
|
|
13397
13401
|
console.log(`ctxloom dashboard \u2014 loading context from ${root}...`);
|
|
@@ -13451,9 +13455,9 @@ async function startDashboard(options) {
|
|
|
13451
13455
|
}
|
|
13452
13456
|
activeWatcher = null;
|
|
13453
13457
|
}
|
|
13454
|
-
const snapshotDir =
|
|
13458
|
+
const snapshotDir = path48.join(targetRoot, ".ctxloom");
|
|
13455
13459
|
try {
|
|
13456
|
-
activeWatcher =
|
|
13460
|
+
activeWatcher = fs36.watch(snapshotDir, (_event, filename) => {
|
|
13457
13461
|
if (!filename || !filename.includes("snapshot")) return;
|
|
13458
13462
|
if (debounce) clearTimeout(debounce);
|
|
13459
13463
|
debounce = setTimeout(async () => {
|
|
@@ -13482,12 +13486,12 @@ async function startDashboard(options) {
|
|
|
13482
13486
|
attachSnapshotWatcher(newRoot);
|
|
13483
13487
|
}
|
|
13484
13488
|
}));
|
|
13485
|
-
const clientDist =
|
|
13486
|
-
const clientDistExists =
|
|
13489
|
+
const clientDist = path48.join(__dirname2, "../dashboard/client");
|
|
13490
|
+
const clientDistExists = fs36.existsSync(path48.join(clientDist, "index.html"));
|
|
13487
13491
|
if (clientDistExists) {
|
|
13488
13492
|
app.use(express.static(clientDist, { dotfiles: "allow" }));
|
|
13489
13493
|
app.get(/.*/, (_req, res) => {
|
|
13490
|
-
res.sendFile(
|
|
13494
|
+
res.sendFile(path48.join(clientDist, "index.html"), { dotfiles: "allow" });
|
|
13491
13495
|
});
|
|
13492
13496
|
} else {
|
|
13493
13497
|
app.get(/^\/(?!api\/).*/, (_req, res) => {
|