@fodx/codelens 1.0.0

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.
Files changed (98) hide show
  1. package/README.md +212 -0
  2. package/adapters/pi/codelens.extension.ts +280 -0
  3. package/adapters/pi/extension.json +10 -0
  4. package/build/src/cli.js +265 -0
  5. package/build/src/cli.js.map +1 -0
  6. package/build/src/context/schema.sql +23 -0
  7. package/build/src/context/store.js +91 -0
  8. package/build/src/context/store.js.map +1 -0
  9. package/build/src/db/db.js +65 -0
  10. package/build/src/db/db.js.map +1 -0
  11. package/build/src/db/migrations.js +88 -0
  12. package/build/src/db/migrations.js.map +1 -0
  13. package/build/src/db/schema.js +11 -0
  14. package/build/src/db/schema.js.map +1 -0
  15. package/build/src/db/schema.sql +111 -0
  16. package/build/src/git/scope.js +68 -0
  17. package/build/src/git/scope.js.map +1 -0
  18. package/build/src/graph/edges.js +76 -0
  19. package/build/src/graph/edges.js.map +1 -0
  20. package/build/src/graph/grammars.js +57 -0
  21. package/build/src/graph/grammars.js.map +1 -0
  22. package/build/src/graph/query.js +52 -0
  23. package/build/src/graph/query.js.map +1 -0
  24. package/build/src/graph/resolve.js +68 -0
  25. package/build/src/graph/resolve.js.map +1 -0
  26. package/build/src/graph/symbols.js +84 -0
  27. package/build/src/graph/symbols.js.map +1 -0
  28. package/build/src/graph/tests.js +73 -0
  29. package/build/src/graph/tests.js.map +1 -0
  30. package/build/src/index/autoprune.js +29 -0
  31. package/build/src/index/autoprune.js.map +1 -0
  32. package/build/src/index/deny.js +40 -0
  33. package/build/src/index/deny.js.map +1 -0
  34. package/build/src/index/freshness.js +60 -0
  35. package/build/src/index/freshness.js.map +1 -0
  36. package/build/src/index/fts.js +125 -0
  37. package/build/src/index/fts.js.map +1 -0
  38. package/build/src/index/identity.js +21 -0
  39. package/build/src/index/identity.js.map +1 -0
  40. package/build/src/index/indexer.js +32 -0
  41. package/build/src/index/indexer.js.map +1 -0
  42. package/build/src/index/manager.js +48 -0
  43. package/build/src/index/manager.js.map +1 -0
  44. package/build/src/index/queue.js +47 -0
  45. package/build/src/index/queue.js.map +1 -0
  46. package/build/src/index/recovery.js +51 -0
  47. package/build/src/index/recovery.js.map +1 -0
  48. package/build/src/index/reindex.js +70 -0
  49. package/build/src/index/reindex.js.map +1 -0
  50. package/build/src/index/scanner.js +147 -0
  51. package/build/src/index/scanner.js.map +1 -0
  52. package/build/src/index/ttl.js +87 -0
  53. package/build/src/index/ttl.js.map +1 -0
  54. package/build/src/index/watcher.js +74 -0
  55. package/build/src/index/watcher.js.map +1 -0
  56. package/build/src/installer/agents.js +440 -0
  57. package/build/src/installer/agents.js.map +1 -0
  58. package/build/src/obs/doctor.js +53 -0
  59. package/build/src/obs/doctor.js.map +1 -0
  60. package/build/src/obs/stats.js +28 -0
  61. package/build/src/obs/stats.js.map +1 -0
  62. package/build/src/obs/usage.js +136 -0
  63. package/build/src/obs/usage.js.map +1 -0
  64. package/build/src/search/rank.js +70 -0
  65. package/build/src/search/rank.js.map +1 -0
  66. package/build/src/search/snippet.js +66 -0
  67. package/build/src/search/snippet.js.map +1 -0
  68. package/build/src/server.js +126 -0
  69. package/build/src/server.js.map +1 -0
  70. package/build/src/tools/current.js +32 -0
  71. package/build/src/tools/current.js.map +1 -0
  72. package/build/src/tools/expand.js +54 -0
  73. package/build/src/tools/expand.js.map +1 -0
  74. package/build/src/tools/prune.js +46 -0
  75. package/build/src/tools/prune.js.map +1 -0
  76. package/build/src/tools/refresh.js +14 -0
  77. package/build/src/tools/refresh.js.map +1 -0
  78. package/build/src/tools/registry.js +176 -0
  79. package/build/src/tools/registry.js.map +1 -0
  80. package/build/src/tools/related.js +28 -0
  81. package/build/src/tools/related.js.map +1 -0
  82. package/build/src/tools/save.js +15 -0
  83. package/build/src/tools/save.js.map +1 -0
  84. package/build/src/tools/search.js +124 -0
  85. package/build/src/tools/search.js.map +1 -0
  86. package/build/src/upgrade.js +74 -0
  87. package/build/src/upgrade.js.map +1 -0
  88. package/build/src/util/hash.js +15 -0
  89. package/build/src/util/hash.js.map +1 -0
  90. package/build/src/util/paths.js +67 -0
  91. package/build/src/util/paths.js.map +1 -0
  92. package/build/src/version.js +27 -0
  93. package/build/src/version.js.map +1 -0
  94. package/docs/agent-guide.md +47 -0
  95. package/docs/codelens-preview.png +0 -0
  96. package/docs/routing.md +59 -0
  97. package/docs/tools.md +53 -0
  98. package/package.json +103 -0
@@ -0,0 +1,176 @@
1
+ import { z } from "zod";
2
+ import { ctxCurrent } from "./current.js";
3
+ import { ctxRefresh } from "./refresh.js";
4
+ import { ctxSearch } from "./search.js";
5
+ import { ctxRelated } from "./related.js";
6
+ import { ctxExpand } from "./expand.js";
7
+ import { ctxSave, ctxLoad } from "./save.js";
8
+ import { ctxPrune, ctxDrop } from "./prune.js";
9
+ import { gatherStats } from "../obs/stats.js";
10
+ import { runDoctor } from "../obs/doctor.js";
11
+ import { UsageTracker, openGlobalUsageDb } from "../obs/usage.js";
12
+ import { detectScope } from "../git/scope.js";
13
+ import { getOrCreateIndex, getActiveIndexId } from "../index/manager.js";
14
+ import { buildIndex } from "../index/indexer.js";
15
+ function withScope(ctx) {
16
+ return detectScope(ctx.repoRoot);
17
+ }
18
+ /** Ensure an active index exists for the current repo scope before query tools. */
19
+ function ensureActive(ctx) {
20
+ const scope = withScope(ctx);
21
+ if (!scope)
22
+ throw new Error("not inside a git repo (or plain dir support not enabled)");
23
+ // build the index if none active for this scope
24
+ if (!getActiveIndexId()) {
25
+ buildIndex(ctx.coreDb, scope);
26
+ }
27
+ else {
28
+ getOrCreateIndex(ctx.coreDb, scope);
29
+ }
30
+ return getActiveIndexId();
31
+ }
32
+ export const TOOLS = [
33
+ {
34
+ name: "cl_current",
35
+ description: "Report current repo/branch/index status with freshness fields. Use first to check if an index is ready.\n\nRETURNS: {repo, branch, headSha, indexId, status, dirtyFiles, lastIndexedAt, inGitRepo}\n\nEXAMPLE: cl_current",
36
+ schema: {},
37
+ handler: (ctx) => ctxCurrent(ctx.coreDb, ctx.repoRoot),
38
+ },
39
+ {
40
+ name: "cl_refresh",
41
+ description: "Create or update the current branch/worktree index. Scans files, indexes FTS, extracts symbols, builds graph.\n\nRETURNS: {indexId, branch, indexedFiles, totalChunks, skipped, status}\n\nEXAMPLE: cl_refresh",
42
+ schema: {},
43
+ handler: (ctx) => {
44
+ const scope = withScope(ctx);
45
+ if (!scope)
46
+ throw new Error("not inside a git repo");
47
+ return ctxRefresh(ctx.coreDb, scope);
48
+ },
49
+ },
50
+ {
51
+ name: "cl_search",
52
+ description: "Hybrid search over the current branch index: FTS5 BM25 + symbol-name match + graph proximity, fused via weighted ranking. Compact ranked handles, cursor pagination. Use BEFORE grep/find/read for code discovery. Pass related:true to also get graph neighbors of the top result in one call.\n\nRETURNS: {indexId, results:[{handle,path,startLine,endLine,score,snippet,why}], nextCursor, freshness, pendingFiles}\n\nWHEN NOT: editing exact files (use cl_expand or read instead).\n\nEXAMPLE: cl_search(query: \"session validation\", limit: 5)",
53
+ schema: {
54
+ query: z.string().describe("Search query (2-4 specific technical terms recommended)."),
55
+ limit: z.coerce.number().optional().default(5).describe("Results per page (default 5)."),
56
+ cursor: z.string().optional().describe("Pagination cursor from a prior result's nextCursor."),
57
+ contentType: z.enum(["code", "prose"]).optional().describe("Filter by chunk type: 'code' (source) or 'prose' (docs/markdown). Omit for all, with a modest code boost."),
58
+ related: z.boolean().optional().describe("If true, also return graph neighbors (imports/importers/tests) of the top result — one-call find+explore."),
59
+ },
60
+ handler: (ctx, args) => {
61
+ ensureActive(ctx);
62
+ return ctxSearch(ctx.coreDb, args.query, {
63
+ limit: args.limit,
64
+ cursor: args.cursor,
65
+ scope: withScope(ctx) ?? undefined,
66
+ contentType: args.contentType,
67
+ related: args.related,
68
+ });
69
+ },
70
+ },
71
+ {
72
+ name: "cl_related",
73
+ description: "Graph expansion: neighbors of a file (imports/imported_by/tests/callers) within the current index, bounded by depth. Compact handles.\n\nRETURNS: {indexId, results:[{handle,path,edgeType,hops,confidence}]}\n\nEXAMPLE: cl_related(path: \"src/auth/auth.ts\", types: [\"imports\"], depth: 2)",
74
+ schema: {
75
+ path: z.string().describe("Repo-relative POSIX path to expand from."),
76
+ types: z.array(z.string()).optional().describe("Edge types: imports|imported_by|tests|calls|references|defines|exports|belongs_to."),
77
+ depth: z.coerce.number().optional().default(2).describe("Max hops (capped at 3)."),
78
+ direction: z.enum(["out", "in", "both"]).optional().describe("Edge direction. Default 'both'."),
79
+ },
80
+ handler: (ctx, args) => {
81
+ ensureActive(ctx);
82
+ return ctxRelated(ctx.coreDb, args.path, {
83
+ types: args.types,
84
+ depth: args.depth,
85
+ direction: args.direction,
86
+ });
87
+ },
88
+ },
89
+ {
90
+ name: "cl_expand",
91
+ description: "Return exact current local file content by path/range. Reads from disk — never stale stored text. Use after cl_search/cl_related to read target snippets before editing.\n\nRETURNS: {path, startLine, endLine, content, truncated, chars}\n\nEXAMPLE: cl_expand(path: \"src/auth/session.ts\", startLine: 12, endLine: 58, budget: 1200)",
92
+ schema: {
93
+ path: z.string().optional().describe("Repo-relative POSIX path to read."),
94
+ handle: z.string().optional().describe("Handle from cl_search/cl_related to resolve to a path+range."),
95
+ startLine: z.coerce.number().optional().describe("1-indexed start line (default: file start)."),
96
+ endLine: z.coerce.number().optional().describe("1-indexed end line (default: file end)."),
97
+ budget: z.coerce.number().optional().describe("Max chars to return (default ~4000)."),
98
+ targets: z.array(z.object({
99
+ path: z.string().optional(), handle: z.string().optional(),
100
+ startLine: z.coerce.number().optional(), endLine: z.coerce.number().optional(), budget: z.coerce.number().optional(),
101
+ })).optional().describe("Batch: read multiple targets in one call (cuts round-trips). Returns {results:[...]}."),
102
+ },
103
+ handler: (ctx, args) => {
104
+ ensureActive(ctx);
105
+ if (args.targets && Array.isArray(args.targets)) {
106
+ return { results: args.targets.map((t) => ctxExpand(ctx.coreDb, ctx.repoRoot, t)) };
107
+ }
108
+ return ctxExpand(ctx.coreDb, ctx.repoRoot, {
109
+ path: args.path,
110
+ handle: args.handle,
111
+ startLine: args.startLine,
112
+ endLine: args.endLine,
113
+ budget: args.budget,
114
+ });
115
+ },
116
+ },
117
+ {
118
+ name: "cl_save",
119
+ description: "Save a named working-context set (handles/paths + notes) in a separate DB that survives core-index rebuilds. Pin to prevent TTL deletion.\n\nRETURNS: {id, name, pinned, itemCount}\n\nEXAMPLE: cl_save(name: \"auth-investigation\", items: [{path: \"src/auth/session.ts\"}], notes: \"wip\", pinned: true)",
120
+ schema: {
121
+ name: z.string().describe("Context name (unique per repo)."),
122
+ items: z.array(z.object({
123
+ handle: z.string().optional(),
124
+ path: z.string().optional(),
125
+ symbol_id: z.string().optional(),
126
+ chunk_id: z.string().optional(),
127
+ })).describe("Handles/paths to remember."),
128
+ notes: z.string().optional().describe("Free-form notes."),
129
+ pinned: z.boolean().optional().describe("Pin to prevent TTL deletion."),
130
+ },
131
+ handler: (ctx, args) => ctxSave(ctx.ctxDb, ctx.repoRoot, args.name, args.items, {
132
+ notes: args.notes,
133
+ pinned: args.pinned,
134
+ }),
135
+ },
136
+ {
137
+ name: "cl_load",
138
+ description: "Load a saved working-context by name. Returns items (path/symbol-based, stable across reindex).\n\nRETURNS: {context, items}\n\nEXAMPLE: cl_load(name: \"auth-investigation\")",
139
+ schema: { name: z.string().describe("Context name to load.") },
140
+ handler: (ctx, args) => ctxLoad(ctx.ctxDb, ctx.repoRoot, args.name),
141
+ },
142
+ {
143
+ name: "cl_stats",
144
+ description: "Index statistics: file/symbol/chunk/edge/index counts, total indexes, last indexed. Scoped to active index.\n\nRETURNS: {active, indexId, branch, counts, lastIndexedAt, totalIndexes}\n\nEXAMPLE: cl_stats",
145
+ schema: {},
146
+ handler: (ctx) => gatherStats(ctx.coreDb),
147
+ },
148
+ {
149
+ name: "cl_doctor",
150
+ description: "Health check: node version, better-sqlite3, git, schema version, integrity (PRAGMA quick_check), WAL mode. No PII.\n\nRETURNS: diagnostic booleans + integrityOk\n\nEXAMPLE: cl_doctor",
151
+ schema: {},
152
+ handler: (ctx) => runDoctor(ctx.coreDb, ctx.repoRoot),
153
+ },
154
+ {
155
+ name: "cl_usage",
156
+ description: "Global usage statistics across all repos: per-tool call counts, bytes served, estimated context bytes saved, and a per-repo breakdown. Use to see how much the index tools are being used.\n\nRETURNS: {perTool:[...], perRepo:[...], totals:{calls,bytes_served,bytes_saved}}\n\nEXAMPLE: cl_usage",
157
+ schema: {},
158
+ handler: () => new UsageTracker(openGlobalUsageDb()).snapshot(),
159
+ },
160
+ {
161
+ name: "cl_prune",
162
+ description: "Run a manual TTL sweep: delete expired inactive indexes. Never deletes active/pinned/locked/grace-window indexes.\n\nRETURNS: {deletedIndexes, skipped}\n\nEXAMPLE: cl_prune",
163
+ schema: {},
164
+ handler: (ctx) => ctxPrune(ctx.coreDb),
165
+ },
166
+ {
167
+ name: "cl_drop",
168
+ description: "Delete a specific branch/index explicitly. Refuses the active or pinned index.\n\nRETURNS: {deleted, indexId, reason?}\n\nEXAMPLE: cl_drop(branch: \"old-feature\")",
169
+ schema: {
170
+ indexId: z.string().optional().describe("Index id to drop."),
171
+ branch: z.string().optional().describe("Branch name to drop (resolves to latest index)."),
172
+ },
173
+ handler: (ctx, args) => ctxDrop(ctx.coreDb, { indexId: args.indexId, branch: args.branch }),
174
+ },
175
+ ];
176
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/tools/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { getActiveIndexId, getIndex } from "../index/manager.js";
2
+ import { neighbors as graphNeighbors, testsFor } from "../graph/query.js";
3
+ export function ctxRelated(db, path, opts) {
4
+ const indexId = getActiveIndexId();
5
+ if (!indexId || !getIndex(db, indexId))
6
+ throw new Error("no active index — call cl_refresh first");
7
+ const ns = graphNeighbors(db, indexId, path, opts ?? {});
8
+ const results = ns.map((n) => ({
9
+ handle: `rel:${n.path}`,
10
+ path: n.path,
11
+ edgeType: n.edgeType,
12
+ hops: n.hops,
13
+ confidence: n.confidence,
14
+ }));
15
+ return { indexId, results };
16
+ }
17
+ /** cl_related variant: tests for a given source path. */
18
+ export function ctxRelatedTests(db, sourcePath) {
19
+ const indexId = getActiveIndexId();
20
+ if (!indexId || !getIndex(db, indexId))
21
+ throw new Error("no active index — call cl_refresh first");
22
+ const ns = testsFor(db, indexId, sourcePath);
23
+ return {
24
+ indexId,
25
+ results: ns.map((n) => ({ handle: `rel:${n.path}`, path: n.path, edgeType: n.edgeType, hops: n.hops, confidence: n.confidence })),
26
+ };
27
+ }
28
+ //# sourceMappingURL=related.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"related.js","sourceRoot":"","sources":["../../../src/tools/related.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,SAAS,IAAI,cAAc,EAAE,QAAQ,EAAsB,MAAM,mBAAmB,CAAC;AAoB9F,MAAM,UAAU,UAAU,CACxB,EAAqB,EACrB,IAAY,EACZ,IAA8E;IAE9E,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACnG,MAAM,EAAE,GAAoB,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAoB,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE;QACvB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,UAAU,EAAE,CAAC,CAAC,UAAU;KACzB,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,eAAe,CAAC,EAAqB,EAAE,UAAkB;IACvE,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IACnG,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC7C,OAAO;QACL,OAAO;QACP,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;KAClI,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { saveContext, loadContext, listContexts, deleteContext } from "../context/store.js";
2
+ export function ctxSave(ctxDb, repoRoot, name, items, opts) {
3
+ const c = saveContext(ctxDb, repoRoot, name, items, opts);
4
+ return { id: c.id, name: c.name, pinned: c.pinned, itemCount: items.length };
5
+ }
6
+ export function ctxLoad(ctxDb, repoRoot, name) {
7
+ return loadContext(ctxDb, repoRoot, name);
8
+ }
9
+ export function ctxListContexts(ctxDb, repoRoot) {
10
+ return listContexts(ctxDb, repoRoot);
11
+ }
12
+ export function ctxDeleteContext(ctxDb, repoRoot, name) {
13
+ return deleteContext(ctxDb, repoRoot, name);
14
+ }
15
+ //# sourceMappingURL=save.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save.js","sourceRoot":"","sources":["../../../src/tools/save.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAA4C,MAAM,qBAAqB,CAAC;AAiBtI,MAAM,UAAU,OAAO,CACrB,KAAwB,EACxB,QAAgB,EAChB,IAAY,EACZ,KAAyB,EACzB,IAA2C;IAE3C,MAAM,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1D,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AAC/E,CAAC;AAOD,MAAM,UAAU,OAAO,CAAC,KAAwB,EAAE,QAAgB,EAAE,IAAY;IAC9E,OAAO,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAwB,EAAE,QAAgB;IACxE,OAAO,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAwB,EAAE,QAAgB,EAAE,IAAY;IACvF,OAAO,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,124 @@
1
+ import { getActiveIndexId, touchIndex, getIndex } from "../index/manager.js";
2
+ import { extractSnippet } from "../search/snippet.js";
3
+ import { rank, normalize } from "../search/rank.js";
4
+ import { neighbors } from "../graph/query.js";
5
+ import { ensureFreshIndex } from "../index/reindex.js";
6
+ const DEFAULT_LIMIT = 5;
7
+ function ftsQuery(query) {
8
+ const terms = query.split(/[^A-Za-z0-9_]+/i).filter((t) => t.length > 0);
9
+ if (terms.length === 0)
10
+ return "";
11
+ return terms.map((t) => `"${t}"`).join(" OR ");
12
+ }
13
+ function gatherFts(db, indexId, fts, limit, contentType) {
14
+ const typeClause = contentType ? " AND c.content_type = ?" : "";
15
+ const params = contentType ? [fts, indexId, contentType, limit] : [fts, indexId, limit];
16
+ return db
17
+ .prepare(`SELECT c.path AS path, c.start_line AS startLine, c.end_line AS endLine,
18
+ c.content AS content, c.id AS chunkId, c.content_type AS contentType,
19
+ bm25(chunks_fts) AS rank
20
+ FROM chunks_fts
21
+ JOIN chunks c ON c.id = chunks_fts.chunk_id
22
+ WHERE chunks_fts MATCH ? AND chunks_fts.index_id = ?${typeClause}
23
+ ORDER BY rank ASC LIMIT ?`)
24
+ .all(...params);
25
+ }
26
+ /** Build hybrid signals (FTS + symbol + graph). */
27
+ function buildSignals(db, indexId, query, ftsRows) {
28
+ const ftsNorm = normalize(ftsRows.map((r) => -r.rank));
29
+ const terms = query.toLowerCase().split(/[^a-z0-9_]+/i).filter((t) => t.length > 1);
30
+ const symbolStmt = db.prepare(`SELECT 1 FROM symbols WHERE index_id = ? AND path = ? AND lower(name) LIKE ? LIMIT 1`);
31
+ const topPaths = new Set(ftsRows.slice(0, 8).map((r) => r.path));
32
+ const graphPaths = new Set();
33
+ for (const p of topPaths) {
34
+ try {
35
+ const ns = neighbors(db, indexId, p, { depth: 1 });
36
+ graphPaths.add(p);
37
+ for (const n of ns)
38
+ graphPaths.add(n.path);
39
+ }
40
+ catch { /* ignore */ }
41
+ }
42
+ return ftsRows.map((r, i) => {
43
+ const symMatch = terms.some((t) => !!symbolStmt.get(indexId, r.path, "%" + t + "%"));
44
+ return {
45
+ path: r.path,
46
+ startLine: r.startLine,
47
+ endLine: r.endLine,
48
+ chunkId: r.chunkId,
49
+ fts: ftsNorm[i],
50
+ symbol: symMatch ? 1 : 0,
51
+ graph: graphPaths.has(r.path) ? 1 : 0,
52
+ code: r.contentType === "code" ? 1 : 0,
53
+ };
54
+ });
55
+ }
56
+ function prelude(db, opts) {
57
+ let freshness = "fresh";
58
+ let pendingFiles;
59
+ if (opts?.scope) {
60
+ const r = ensureFreshIndex(db, opts.scope, { budgetMs: opts?.refreshBudgetMs });
61
+ if (r.pending > 0) {
62
+ freshness = "partial";
63
+ pendingFiles = r.pending;
64
+ }
65
+ }
66
+ return { freshness, pendingFiles };
67
+ }
68
+ export function ctxSearch(db, query, opts) {
69
+ const indexId = getActiveIndexId();
70
+ if (!indexId || !getIndex(db, indexId))
71
+ throw new Error("no active index — call cl_refresh first");
72
+ touchIndex(db, indexId);
73
+ const { freshness, pendingFiles } = prelude(db, opts);
74
+ const limit = opts?.limit ?? DEFAULT_LIMIT;
75
+ const offset = decodeCursor(opts?.cursor);
76
+ const fts = ftsQuery(query);
77
+ if (fts.length === 0)
78
+ return { indexId, results: [], nextCursor: null, freshness: "fresh" };
79
+ const ftsRows = gatherFts(db, indexId, fts, limit * 4, opts?.contentType);
80
+ const signals = buildSignals(db, indexId, query, ftsRows);
81
+ const ranked = rank(signals);
82
+ const page = ranked.slice(offset, offset + limit);
83
+ const hasMore = offset + limit < ranked.length;
84
+ const byChunk = new Map(ftsRows.map((r) => [r.chunkId, r]));
85
+ const results = page.map((r, i) => {
86
+ const src = r.chunkId ? byChunk.get(r.chunkId) : undefined;
87
+ const rankOffset = offset + i;
88
+ return {
89
+ handle: r.chunkId ?? "",
90
+ path: r.path,
91
+ startLine: r.startLine,
92
+ endLine: r.endLine,
93
+ score: r.score,
94
+ snippet: src ? extractSnippet(src.content, query) : r.path,
95
+ cursor: encodeCursor(rankOffset, r.chunkId ?? `${rankOffset}`),
96
+ why: r.why,
97
+ };
98
+ });
99
+ const nextCursor = hasMore && results.length > 0 ? encodeCursor(offset + results.length, results[results.length - 1].handle || `${offset}`) : null;
100
+ const out = { indexId, results, nextCursor, freshness, pendingFiles };
101
+ if (opts?.related && results[0]) {
102
+ try {
103
+ out.related = neighbors(db, indexId, results[0].path, { types: ["imports", "imported_by", "tests"], depth: 1 });
104
+ }
105
+ catch { /* graph best-effort */ }
106
+ }
107
+ return out;
108
+ }
109
+ function encodeCursor(rank, tiebreaker) {
110
+ return Buffer.from(`${rank}|${tiebreaker}`, "utf-8").toString("base64url");
111
+ }
112
+ function decodeCursor(cursor) {
113
+ if (!cursor)
114
+ return 0;
115
+ try {
116
+ const dec = Buffer.from(cursor, "base64url").toString("utf-8");
117
+ const rank = parseInt(dec.split("|")[0] ?? "0", 10);
118
+ return Number.isFinite(rank) ? rank : 0;
119
+ }
120
+ catch {
121
+ return 0;
122
+ }
123
+ }
124
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/tools/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { join, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { VERSION } from "./version.js";
6
+ /**
7
+ * Upgrade check + perform (mirrors codegraph's `upgrade --check` / `upgrade`).
8
+ *
9
+ * Detects the app install dir (the repo root that contains package.json and
10
+ * is a git checkout), then:
11
+ * - `checkUpgrade()`: git fetch + compare HEAD vs origin/main (or the tag of
12
+ * the latest release) and report whether an update is available.
13
+ * - `performUpgrade()`: git pull + npm install + npm run build.
14
+ *
15
+ * If not installed from a git checkout (e.g. a future npm-global install), it
16
+ * reports accordingly and suggests `npm i -g codelens`.
17
+ */
18
+ function appRoot() {
19
+ try {
20
+ const here = dirname(fileURLToPath(import.meta.url));
21
+ // build/src/upgrade.js → repo root (../../package.json); src/upgrade.ts → ../package.json
22
+ const candidates = [
23
+ join(here, "..", "..", "package.json"),
24
+ join(here, "..", "package.json"),
25
+ join(process.cwd(), "package.json"),
26
+ ];
27
+ for (const cand of candidates) {
28
+ if (existsSync(cand))
29
+ return dirname(cand);
30
+ }
31
+ }
32
+ catch { /* ignore */ }
33
+ return null;
34
+ }
35
+ function git(root, args) {
36
+ const r = spawnSync("git", args, { cwd: root, encoding: "utf-8" });
37
+ return { ok: r.status === 0, stdout: (r.stdout ?? "").trim(), stderr: (r.stderr ?? "").trim() };
38
+ }
39
+ export async function checkUpgrade() {
40
+ const root = appRoot();
41
+ if (!root)
42
+ return { upToDate: true, message: `codelens ${VERSION} (not a git checkout; use \`npm i -g codelens\` to upgrade if installed via npm)` };
43
+ if (!existsSync(join(root, ".git")))
44
+ return { upToDate: true, message: `codelens ${VERSION} (installed without git; re-run your installer to update)` };
45
+ const branch = git(root, ["rev-parse", "--abbrev-ref", "HEAD"]).stdout || "main";
46
+ const fetch = git(root, ["fetch", "--quiet", "origin", branch]);
47
+ if (!fetch.ok)
48
+ return { upToDate: true, message: `codelens ${VERSION} (could not fetch upstream: ${fetch.stderr || "unknown"})` };
49
+ const local = git(root, ["rev-parse", "HEAD"]).stdout.slice(0, 12);
50
+ const remote = git(root, ["rev-parse", `origin/${branch}`]).stdout.slice(0, 12);
51
+ if (local === remote)
52
+ return { upToDate: true, message: `codelens ${VERSION} is up to date (${local}).` };
53
+ const behind = git(root, ["rev-list", "--count", `HEAD..origin/${branch}`]).stdout;
54
+ return { upToDate: false, message: `codelens ${VERSION}: update available (${behind} commit(s) behind origin/${branch}). Run \`codelens upgrade\` to update.`, local, remote };
55
+ }
56
+ export async function performUpgrade(_version) {
57
+ const root = appRoot();
58
+ if (!root)
59
+ return { ok: false, message: "could not locate the install dir; re-run the installer script." };
60
+ if (!existsSync(join(root, ".git")))
61
+ return { ok: false, message: "not a git checkout; re-run the installer script to update." };
62
+ const branch = git(root, ["rev-parse", "--abbrev-ref", "HEAD"]).stdout || "main";
63
+ const pull = git(root, ["pull", "--ff-only", "origin", branch]);
64
+ if (!pull.ok)
65
+ return { ok: false, message: `git pull failed: ${pull.stderr || pull.stdout}` };
66
+ const inst = spawnSync("npm", ["install", "--legacy-peer-deps"], { cwd: root, encoding: "utf-8" });
67
+ if (inst.status !== 0)
68
+ return { ok: false, message: `npm install failed: ${(inst.stderr ?? inst.stdout ?? "").slice(-500)}` };
69
+ const build = spawnSync("npm", ["run", "build"], { cwd: root, encoding: "utf-8" });
70
+ if (build.status !== 0)
71
+ return { ok: false, message: `npm run build failed: ${(build.stderr ?? build.stdout ?? "").slice(-500)}` };
72
+ return { ok: true, message: `upgraded to ${VERSION} (pulled origin/${branch}, rebuilt). Restart your agent(s) to pick up changes.` };
73
+ }
74
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { createHash } from "node:crypto";
2
+ /**
3
+ * Content hash for files/chunks (Design Decision: freshness).
4
+ *
5
+ * Uses SHA-256 from node:crypto — synchronous, no extra native dep. Non-crypto
6
+ * would be faster (xxhash) but requires async WASM init; SHA-256 is fast enough
7
+ * at 5MB cap and only hashes changed/suspicious files.
8
+ */
9
+ export function contentHash(text) {
10
+ return createHash("sha256").update(text, "utf-8").digest("hex");
11
+ }
12
+ export function contentHashBuffer(buf) {
13
+ return createHash("sha256").update(buf).digest("hex");
14
+ }
15
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../../src/util/hash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;GAMG;AAEH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { relative, isAbsolute, posix } from "node:path";
2
+ import { realpathSync, existsSync } from "node:fs";
3
+ /**
4
+ * Path normalization (Design Decision #11):
5
+ * - Store paths as POSIX internally (forward slashes).
6
+ * - Resolve symlinks to real paths at index time.
7
+ * - Case-preserving (no lowercasing).
8
+ * - Repo-relative for storage; reject traversal outside repo root.
9
+ */
10
+ /** Convert any OS path to POSIX forward-slash form (always replaces backslashes, even on POSIX hosts). */
11
+ export function toPosix(p) {
12
+ return p.split("\\").join("/");
13
+ }
14
+ /** Resolve symlinks to the real path; returns POSIX. Falls back to input if unreachable. */
15
+ export function resolveReal(p) {
16
+ try {
17
+ return toPosix(realpathSync(p));
18
+ }
19
+ catch {
20
+ // Symlink target missing or not a symlink — normalize the literal path.
21
+ return toPosix(isAbsolute(p) ? p : resolveReal(".") + "/" + toPosix(p));
22
+ }
23
+ }
24
+ /**
25
+ * Return the POSIX repo-relative path for `absOrRel` under `root`.
26
+ * Throws PathOutsideRepo if the resolved path escapes root.
27
+ */
28
+ export function repoRelative(root, absOrRel) {
29
+ const rootReal = resolveReal(root);
30
+ const abs = isAbsolute(absOrRel) ? absOrRel : posix.join(rootReal, absOrRel);
31
+ const targetReal = resolveReal(abs);
32
+ if (!targetReal.startsWith(rootReal + "/") && targetReal !== rootReal) {
33
+ throw new PathOutsideRepo(targetReal, rootReal);
34
+ }
35
+ const rel = relative(rootReal, targetReal);
36
+ return toPosix(rel);
37
+ }
38
+ /** True if `absOrRel` resolves inside `root`. */
39
+ export function isInsideRepo(root, absOrRel) {
40
+ try {
41
+ repoRelative(root, absOrRel);
42
+ return true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ /** Assert a path is inside the repo; throw PathOutsideRepo otherwise. */
49
+ export function assertInsideRepo(root, absOrRel) {
50
+ repoRelative(root, absOrRel); // throws on escape
51
+ }
52
+ export class PathOutsideRepo extends Error {
53
+ path;
54
+ root;
55
+ constructor(path, root) {
56
+ super(`path "${path}" escapes repo root "${root}"`);
57
+ this.path = path;
58
+ this.root = root;
59
+ this.name = "PathOutsideRepo";
60
+ }
61
+ }
62
+ /** True if a repo-relative path exists on disk under root. */
63
+ export function existsRelative(root, rel) {
64
+ const full = posix.join(resolveReal(root), rel);
65
+ return existsSync(full);
66
+ }
67
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/util/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAEnD;;;;;;GAMG;AAEH,0GAA0G;AAC1G,MAAM,UAAU,OAAO,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjC,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,WAAW,CAAC,CAAS;IACnC,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,QAAgB;IACzD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC7E,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,QAAQ,GAAG,GAAG,CAAC,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;QACtE,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC;AACtB,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,QAAgB;IACzD,IAAI,CAAC;QACH,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,QAAgB;IAC7D,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,mBAAmB;AACnD,CAAC;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACrB;IAAqB;IAAxC,YAAmB,IAAY,EAAS,IAAY;QAClD,KAAK,CAAC,SAAS,IAAI,wBAAwB,IAAI,GAAG,CAAC,CAAC;QADnC,SAAI,GAAJ,IAAI,CAAQ;QAAS,SAAI,GAAJ,IAAI,CAAQ;QAElD,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,GAAW;IACtD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import { dirname, join } from "node:path";
4
+ /**
5
+ * Version constant. Read from package.json at module load. Resolves the repo
6
+ * root from this module's location (build/src/ or src/ → ../../package.json),
7
+ * falling back to cwd.
8
+ */
9
+ function readVersion() {
10
+ const here = dirname(fileURLToPath(import.meta.url));
11
+ const candidates = [
12
+ join(here, "..", "..", "package.json"), // build/src/ or src/ → repo root
13
+ join(here, "..", "package.json"),
14
+ join(process.cwd(), "package.json"),
15
+ ];
16
+ for (const p of candidates) {
17
+ try {
18
+ const pkg = JSON.parse(readFileSync(p, "utf-8"));
19
+ if (pkg.version)
20
+ return pkg.version;
21
+ }
22
+ catch { /* try next */ }
23
+ }
24
+ return "0.0.0-unknown";
25
+ }
26
+ export const VERSION = readVersion();
27
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C;;;;GAIG;AAEH,SAAS,WAAW;IAClB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG;QACjB,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,iCAAiC;QACzE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC;KACpC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAyB,CAAC;YACzE,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAW,WAAW,EAAE,CAAC"}
@@ -0,0 +1,47 @@
1
+ # Agent Guide — CodeLens
2
+
3
+ End-to-end workflow for a coding agent using codelens.
4
+
5
+ ## Typical session
6
+
7
+ ```
8
+ 1. cl_current
9
+ → { status: "missing" } # first run on this branch
10
+
11
+ 2. cl_refresh
12
+ → { indexedFiles: 812, totalChunks: 2400, status: "ready" }
13
+
14
+ 3. cl_search(query: "session validation")
15
+ → results: [
16
+ { handle: "chk_…", path: "src/auth/session.ts", symbol: "validateSession",
17
+ startLine: 12, endLine: 58, score: 0.92, why: ["fts","symbol","graph"] }
18
+ ]
19
+
20
+ 4. cl_related(path: "src/auth/session.ts", types: ["tests","imported_by"])
21
+ → results: [
22
+ { handle: "rel:src/auth/session.test.ts", path: "…", edgeType: "tests", hops: 1 },
23
+ { handle: "rel:src/routes/login.ts", path: "…", edgeType: "imported_by", hops: 1 }
24
+ ]
25
+
26
+ 5. cl_expand(path: "src/auth/session.ts", startLine: 12, endLine: 58, budget: 1200)
27
+ → { content: "export function validateSession(...) { … }", truncated: false }
28
+
29
+ 6. # edit the file with your normal edit tool now that you know the target
30
+
31
+ 7. cl_save(name: "auth-investigation", items: [{path: "src/auth/session.ts"}], pinned: true)
32
+ 8. cl_load(name: "auth-investigation") # after compaction
33
+ ```
34
+
35
+ ## Branch switch
36
+
37
+ ```
38
+ git checkout feature-b
39
+ cl_current → detects new branch, may say "missing"
40
+ cl_refresh → builds feature-b index; main's results no longer leak in
41
+ ```
42
+
43
+
44
+ ## Saving context across compaction
45
+
46
+ `cl_save` / `cl_load` persist named handle sets in a **separate** DB that
47
+ survives core-index rebuilds. Pin important contexts to prevent TTL deletion.