@wrongstack/tools 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_win32-resolve.d.ts +1 -6
- package/dist/audit.js +5 -5
- package/dist/bash.js +2 -2
- package/dist/builtin.js +30 -30
- package/dist/{chunk-7LQCT3LT.js → chunk-32XPUSY3.js} +3 -3
- package/dist/{chunk-N3K2SFEI.js → chunk-3JVSOBHU.js} +1408 -200
- package/dist/{chunk-7N5U2RAU.js → chunk-3LS3FYEF.js} +2 -2
- package/dist/{chunk-FBUP524S.js → chunk-4YKVHCQC.js} +13 -2
- package/dist/{chunk-KE7A76VC.js → chunk-5U5ULQX2.js} +4 -14
- package/dist/{chunk-NU2IZ72J.js → chunk-6LCKF5KH.js} +8 -6
- package/dist/{chunk-GDDXX27P.js → chunk-6ZLRRC74.js} +2 -2
- package/dist/{chunk-IYH4OHBP.js → chunk-77MBK46T.js} +3 -3
- package/dist/{chunk-DK4J2WMH.js → chunk-AMURQAJX.js} +2 -2
- package/dist/{chunk-ZTCJCYLN.js → chunk-CVNCSMVU.js} +49 -6
- package/dist/{chunk-MJSJWXBF.js → chunk-DX5KZEMK.js} +14 -2
- package/dist/{chunk-CGXTR34H.js → chunk-E2ZD4ERD.js} +2 -2
- package/dist/{chunk-DRRY6SCM.js → chunk-EMA2XENR.js} +2 -2
- package/dist/{chunk-3D5DJWOE.js → chunk-FC3X7GGJ.js} +11 -3
- package/dist/{chunk-T3SMFF5Q.js → chunk-GU7QJ37F.js} +2 -2
- package/dist/{chunk-4WPBS45A.js → chunk-IRUEHGCR.js} +3 -3
- package/dist/{chunk-WEEVSWQB.js → chunk-KIQTABBJ.js} +3 -3
- package/dist/{chunk-6H4ERJP7.js → chunk-KYVOTHG7.js} +2 -2
- package/dist/{chunk-O6BY43ZB.js → chunk-MIV2RU5B.js} +3 -3
- package/dist/{chunk-5KS24LTS.js → chunk-NOCU555K.js} +2 -2
- package/dist/{chunk-6GOZTS6F.js → chunk-OUEH4I4X.js} +3 -3
- package/dist/{chunk-YEISRT4S.js → chunk-PNLDTRC5.js} +1429 -242
- package/dist/{chunk-GKSG5CPH.js → chunk-QU2VRCMM.js} +2 -2
- package/dist/{chunk-VVZPQPTY.js → chunk-REWOZIA4.js} +5 -3
- package/dist/{chunk-MGPR7VG3.js → chunk-T7YVY2BV.js} +2 -2
- package/dist/{chunk-IAYMTTR2.js → chunk-TYRVYBHW.js} +27 -23
- package/dist/{chunk-LQSOU63Z.js → chunk-VKAJMHVG.js} +2 -2
- package/dist/{chunk-E7JE3UEX.js → chunk-VO6M2FVG.js} +2 -2
- package/dist/{chunk-NJX2RXKJ.js → chunk-YDTRKEYY.js} +11 -3
- package/dist/{chunk-MK2JK35J.js → chunk-YECHJJJF.js} +3 -3
- package/dist/{chunk-QA6IASYX.js → chunk-Z34CUZCZ.js} +3 -3
- package/dist/{chunk-UCYQTZ7F.js → chunk-ZKC5UNGD.js} +56 -2
- package/dist/codebase-index/atlas-brief.d.ts +90 -0
- package/dist/codebase-index/atlas-export.d.ts +38 -0
- package/dist/codebase-index/atlas-projection.d.ts +114 -0
- package/dist/codebase-index/atlas-types.d.ts +90 -0
- package/dist/codebase-index/background-indexer.d.ts +15 -4
- package/dist/codebase-index/codebase-context-tool.d.ts +54 -0
- package/dist/codebase-index/concept-enrichment.d.ts +154 -0
- package/dist/codebase-index/context-retrieval.d.ts +91 -0
- package/dist/codebase-index/embedding-pass.d.ts +95 -0
- package/dist/codebase-index/graph-adjacency-cache.d.ts +36 -0
- package/dist/codebase-index/graph-rank-pass.d.ts +46 -0
- package/dist/codebase-index/graph-rank.d.ts +198 -0
- package/dist/codebase-index/index-service.d.ts +15 -1
- package/dist/codebase-index/index.d.ts +34 -19
- package/dist/codebase-index/index.js +128 -11
- package/dist/codebase-index/parser-worker-script.js +4 -4
- package/dist/codebase-index/perf-metrics.d.ts +19 -0
- package/dist/codebase-index/project-server-protocol.d.ts +2 -0
- package/dist/codebase-index/project-server-query-cache.d.ts +4 -0
- package/dist/codebase-index/project-server.js +55 -8
- package/dist/codebase-index/repo-map-fallback.d.ts +18 -0
- package/dist/codebase-index/repo-map-render.d.ts +42 -0
- package/dist/codebase-index/repo-map-types.d.ts +21 -0
- package/dist/codebase-index/repo-map.d.ts +28 -16
- package/dist/codebase-index/schema.d.ts +20 -0
- package/dist/codebase-index/worker-protocol.d.ts +47 -1
- package/dist/codebase-index/worker.js +12 -6
- package/dist/codebase-index/writer-concepts.d.ts +84 -0
- package/dist/codebase-index/writer-graph-decorate.d.ts +30 -0
- package/dist/codebase-index/writer-graph-reader.d.ts +22 -0
- package/dist/codebase-index/writer-rank.d.ts +78 -0
- package/dist/codebase-index/writer-schema.d.ts +51 -0
- package/dist/codebase-index/writer-vectors.d.ts +53 -0
- package/dist/codebase-index/writer.d.ts +59 -0
- package/dist/edit.js +8 -8
- package/dist/exec.js +2 -2
- package/dist/fetch.js +1 -1
- package/dist/format.js +5 -5
- package/dist/{go-parser-D7ELWQ7F.js → go-parser-EMKTAAD3.js} +5 -3
- package/dist/index.d.ts +48 -48
- package/dist/index.js +57 -33
- package/dist/install.js +5 -5
- package/dist/languages/index.js +3 -3
- package/dist/{legacy-bridge-YXANP5QB.js → legacy-bridge-WVQ4BHDI.js} +5 -5
- package/dist/lint.js +5 -5
- package/dist/outdated.js +2 -2
- package/dist/pack.js +31 -31
- package/dist/parser-dispatch-UQAB4E6V.js +14 -0
- package/dist/patch.js +8 -8
- package/dist/plan.js +2 -2
- package/dist/{py-parser-QC6MR4GB.js → py-parser-DDG53RXI.js} +4 -4
- package/dist/read.js +8 -8
- package/dist/replace.js +8 -8
- package/dist/task.js +2 -2
- package/dist/test.js +5 -5
- package/dist/todo.js +1 -1
- package/dist/tool-tier.js +32 -32
- package/dist/typecheck.js +5 -5
- package/dist/win32.js +1 -1
- package/dist/write.js +8 -8
- package/package.json +5 -5
- package/dist/parser-dispatch-BDVCJXTV.js +0 -14
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
projectIndexServerBuildId,
|
|
11
11
|
projectIndexServerEndpoint,
|
|
12
12
|
projectIndexServerMetadataPath
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-6ZLRRC74.js";
|
|
14
14
|
import {
|
|
15
|
+
contextService,
|
|
15
16
|
fileGraphService,
|
|
16
17
|
incomingCallsService,
|
|
17
18
|
indexService,
|
|
@@ -21,17 +22,20 @@ import {
|
|
|
21
22
|
resolveIndexDir,
|
|
22
23
|
searchService,
|
|
23
24
|
statsService,
|
|
24
|
-
symbolGraphService
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import "../chunk-
|
|
25
|
+
symbolGraphService,
|
|
26
|
+
vectorSearchService
|
|
27
|
+
} from "../chunk-3JVSOBHU.js";
|
|
28
|
+
import "../chunk-6LCKF5KH.js";
|
|
29
|
+
import "../chunk-REWOZIA4.js";
|
|
28
30
|
import "../chunk-6IEBD27U.js";
|
|
29
|
-
import
|
|
31
|
+
import {
|
|
32
|
+
recordWriteQueueWait
|
|
33
|
+
} from "../chunk-ZKC5UNGD.js";
|
|
30
34
|
import {
|
|
31
35
|
isIndexablePath
|
|
32
36
|
} from "../chunk-YOHO4DVT.js";
|
|
33
37
|
import "../chunk-2CTZW6JQ.js";
|
|
34
|
-
import "../chunk-
|
|
38
|
+
import "../chunk-5U5ULQX2.js";
|
|
35
39
|
|
|
36
40
|
// src/codebase-index/project-server.ts
|
|
37
41
|
import { randomBytes } from "node:crypto";
|
|
@@ -252,6 +256,9 @@ var ServerQueryCaches = class {
|
|
|
252
256
|
*/
|
|
253
257
|
searchCache = new GenerationLruCache(128);
|
|
254
258
|
statsCache = new GenerationLruCache(1);
|
|
259
|
+
// Retrieval answers are query-shaped like search, so they cache the same way.
|
|
260
|
+
contextCache = new GenerationLruCache(64);
|
|
261
|
+
vectorSearchCache = new GenerationLruCache(64);
|
|
255
262
|
packageGraphCache = new GenerationLruCache(1);
|
|
256
263
|
fileGraphCache = new GenerationLruCache(32);
|
|
257
264
|
symbolGraphCache = new GenerationLruCache(64);
|
|
@@ -260,6 +267,8 @@ var ServerQueryCaches = class {
|
|
|
260
267
|
clear() {
|
|
261
268
|
this.searchCache.clear();
|
|
262
269
|
this.statsCache.clear();
|
|
270
|
+
this.contextCache.clear();
|
|
271
|
+
this.vectorSearchCache.clear();
|
|
263
272
|
this.packageGraphCache.clear();
|
|
264
273
|
this.fileGraphCache.clear();
|
|
265
274
|
this.symbolGraphCache.clear();
|
|
@@ -271,6 +280,8 @@ var ServerQueryCaches = class {
|
|
|
271
280
|
return {
|
|
272
281
|
searchCache: this.searchCache.size,
|
|
273
282
|
statsCache: this.statsCache.size,
|
|
283
|
+
contextCache: this.contextCache.size,
|
|
284
|
+
vectorSearchCache: this.vectorSearchCache.size,
|
|
274
285
|
packageGraphCache: this.packageGraphCache.size,
|
|
275
286
|
fileGraphCache: this.fileGraphCache.size,
|
|
276
287
|
symbolGraphCache: this.symbolGraphCache.size,
|
|
@@ -368,6 +379,24 @@ async function dispatchOperation(ctx, state, message) {
|
|
|
368
379
|
);
|
|
369
380
|
return stale ? { ...value, stale: true } : value;
|
|
370
381
|
}
|
|
382
|
+
case "context": {
|
|
383
|
+
const { value, stale } = staleAwareRead(
|
|
384
|
+
ctx.queryCaches.contextCache,
|
|
385
|
+
JSON.stringify(message.args),
|
|
386
|
+
indexActivity2,
|
|
387
|
+
() => contextService(fixedArgs(ctx, message.args))
|
|
388
|
+
);
|
|
389
|
+
return stale ? { ...value, stale: true } : value;
|
|
390
|
+
}
|
|
391
|
+
case "vectorSearch": {
|
|
392
|
+
const { value, stale } = staleAwareRead(
|
|
393
|
+
ctx.queryCaches.vectorSearchCache,
|
|
394
|
+
JSON.stringify(message.args),
|
|
395
|
+
indexActivity2,
|
|
396
|
+
() => vectorSearchService(fixedArgs(ctx, message.args))
|
|
397
|
+
);
|
|
398
|
+
return stale ? { ...value, stale: true } : value;
|
|
399
|
+
}
|
|
371
400
|
case "stats":
|
|
372
401
|
if (indexActivity2.indexing) {
|
|
373
402
|
throw indexRefreshInProgressError(indexActivity2.currentFile, indexActivity2.totalFiles);
|
|
@@ -660,6 +689,8 @@ var writeChain = Promise.resolve();
|
|
|
660
689
|
var activeRequests = 0;
|
|
661
690
|
var activeWrites = 0;
|
|
662
691
|
var queuedWrites = 0;
|
|
692
|
+
var maxQueuedWrites = 0;
|
|
693
|
+
var writeQueueWaitMs = 0;
|
|
663
694
|
var activeFullIndex = null;
|
|
664
695
|
var queryCaches = new ServerQueryCaches();
|
|
665
696
|
var indexActivity = {
|
|
@@ -708,16 +739,30 @@ function send(state, message) {
|
|
|
708
739
|
}
|
|
709
740
|
function withWriteMutex(job) {
|
|
710
741
|
queuedWrites++;
|
|
742
|
+
maxQueuedWrites = Math.max(maxQueuedWrites, queuedWrites);
|
|
711
743
|
const guarded = async () => {
|
|
712
744
|
queuedWrites--;
|
|
713
745
|
activeWrites++;
|
|
714
746
|
try {
|
|
747
|
+
const holdMs = Number(process.env["WRONGSTACK_INDEX_BENCH_WRITE_HOLD_MS"] ?? 0);
|
|
748
|
+
if (Number.isFinite(holdMs) && holdMs > 0) {
|
|
749
|
+
await new Promise((resolve3) => setTimeout(resolve3, Math.min(holdMs, 5e3)));
|
|
750
|
+
}
|
|
715
751
|
return await job();
|
|
716
752
|
} finally {
|
|
717
753
|
activeWrites--;
|
|
718
754
|
}
|
|
719
755
|
};
|
|
720
|
-
const
|
|
756
|
+
const queuedAt = performance.now();
|
|
757
|
+
const wrapped = async () => {
|
|
758
|
+
const elapsedWaitMs = performance.now() - queuedAt;
|
|
759
|
+
const holdMs = Number(process.env["WRONGSTACK_INDEX_BENCH_WRITE_HOLD_MS"] ?? 0);
|
|
760
|
+
const waitMs = Number.isFinite(holdMs) && holdMs > 0 ? Math.max(elapsedWaitMs, holdMs) : elapsedWaitMs;
|
|
761
|
+
writeQueueWaitMs += waitMs;
|
|
762
|
+
recordWriteQueueWait(waitMs);
|
|
763
|
+
return guarded();
|
|
764
|
+
};
|
|
765
|
+
const run = writeChain.then(wrapped, wrapped);
|
|
721
766
|
writeChain = run.then(
|
|
722
767
|
() => void 0,
|
|
723
768
|
() => void 0
|
|
@@ -766,6 +811,8 @@ function serverHealth() {
|
|
|
766
811
|
activeRequests,
|
|
767
812
|
activeWrites,
|
|
768
813
|
queuedWrites,
|
|
814
|
+
maxQueuedWrites,
|
|
815
|
+
writeQueueWaitMs,
|
|
769
816
|
pendingExternalFiles: watcherManager.pendingFileCount,
|
|
770
817
|
watchingExternal: watcherManager.isWatching,
|
|
771
818
|
watchingClients,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem repo map — the path taken when the index has no ranks yet.
|
|
3
|
+
*
|
|
4
|
+
* This is the original heuristic map: walk the tree, score each file by
|
|
5
|
+
* entry-point name and depth, and pack skeletons until the budget runs out.
|
|
6
|
+
* It knows nothing about who references whom, so it is strictly a stand-in
|
|
7
|
+
* for {@link generateRepoMap}'s graph-ranked output on a fresh clone, during
|
|
8
|
+
* the first index run, or in a directory that was never indexed at all.
|
|
9
|
+
*
|
|
10
|
+
* Two defects of the original are fixed here, because a stand-in that lies is
|
|
11
|
+
* worse than no stand-in: it no longer stops after ~500 files (this repo has
|
|
12
|
+
* 8,412, so the old cap meant the "map" described whichever directories the
|
|
13
|
+
* walk happened to reach first), and it honours `.gitignore` instead of a
|
|
14
|
+
* hardcoded list of four directory names.
|
|
15
|
+
*/
|
|
16
|
+
import type { RepoMapOptions, RepoMapResult } from './repo-map-types.js';
|
|
17
|
+
export declare function generateFallbackRepoMap(opts: RepoMapOptions): Promise<RepoMapResult>;
|
|
18
|
+
//# sourceMappingURL=repo-map-fallback.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rendering half of the repo map: turning a ranked candidate list into
|
|
3
|
+
* budgeted skeleton sections. Shared by the graph-ranked generator and the
|
|
4
|
+
* filesystem fallback so the two produce the same section format.
|
|
5
|
+
*/
|
|
6
|
+
import { type SkeletonOptions } from './skeleton-extractor.js';
|
|
7
|
+
export interface RepoMapCandidate {
|
|
8
|
+
/** Absolute path, for reading. */
|
|
9
|
+
absolute: string;
|
|
10
|
+
/** Project-relative POSIX path, for display. */
|
|
11
|
+
relative: string;
|
|
12
|
+
}
|
|
13
|
+
export interface RenderSectionsOptions {
|
|
14
|
+
skeleton?: SkeletonOptions | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Largest a single file's section may be. Without it one 9k-token type
|
|
17
|
+
* module consumes the entire budget and the "map" describes one file. The
|
|
18
|
+
* point of a map is breadth, so each file gets a slice and the rest of the
|
|
19
|
+
* budget goes to the next-most-central file.
|
|
20
|
+
*/
|
|
21
|
+
maxSectionChars?: number | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Drop comment-only lines so the budget buys declarations, not prose.
|
|
24
|
+
* On for the map body; off for callers that want the skeleton verbatim.
|
|
25
|
+
*/
|
|
26
|
+
signaturesOnly?: boolean | undefined;
|
|
27
|
+
}
|
|
28
|
+
export interface RenderedSections {
|
|
29
|
+
sections: string[];
|
|
30
|
+
/** Relative paths actually included, in order. */
|
|
31
|
+
files: string[];
|
|
32
|
+
/** Characters consumed by `sections`, including the blank-line separators. */
|
|
33
|
+
chars: number;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Extract skeletons for `candidates` in order until `charBudget` is exhausted.
|
|
37
|
+
*
|
|
38
|
+
* Unreadable and empty files are skipped rather than ending the walk, so one
|
|
39
|
+
* deleted-since-index path cannot truncate the whole map.
|
|
40
|
+
*/
|
|
41
|
+
export declare function renderSkeletonSections(candidates: readonly RepoMapCandidate[], charBudget: number, options?: RenderSectionsOptions): Promise<RenderedSections>;
|
|
42
|
+
//# sourceMappingURL=repo-map-render.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared shapes for the repo map. Split out so the graph-ranked generator and
|
|
3
|
+
* the filesystem fallback can import them without importing each other.
|
|
4
|
+
*/
|
|
5
|
+
import type { SkeletonOptions } from './skeleton-extractor.js';
|
|
6
|
+
export interface RepoMapOptions {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
maxTokens?: number | undefined;
|
|
9
|
+
focusFiles?: string[] | undefined;
|
|
10
|
+
options?: SkeletonOptions | undefined;
|
|
11
|
+
/** Index directory override, for callers that do not use the default path. */
|
|
12
|
+
indexDir?: string | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface RepoMapResult {
|
|
15
|
+
map: string;
|
|
16
|
+
filesCount: number;
|
|
17
|
+
totalFilesScanned: number;
|
|
18
|
+
estimatedTokens: number;
|
|
19
|
+
rankedFiles: string[];
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=repo-map-types.d.ts.map
|
|
@@ -1,20 +1,32 @@
|
|
|
1
|
-
import { type SkeletonOptions } from './skeleton-extractor.js';
|
|
2
|
-
export interface RepoMapOptions {
|
|
3
|
-
projectRoot: string;
|
|
4
|
-
maxTokens?: number | undefined;
|
|
5
|
-
focusFiles?: string[] | undefined;
|
|
6
|
-
options?: SkeletonOptions | undefined;
|
|
7
|
-
}
|
|
8
|
-
export interface RepoMapResult {
|
|
9
|
-
map: string;
|
|
10
|
-
filesCount: number;
|
|
11
|
-
totalFilesScanned: number;
|
|
12
|
-
estimatedTokens: number;
|
|
13
|
-
rankedFiles: string[];
|
|
14
|
-
}
|
|
15
1
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
2
|
+
* Repository map — a token-budgeted orientation view of the codebase.
|
|
3
|
+
*
|
|
4
|
+
* The map is built from the index's graph centrality (`file_rank`), not from a
|
|
5
|
+
* filesystem walk. Two things follow from that:
|
|
6
|
+
*
|
|
7
|
+
* - **It ranks by evidence.** The previous implementation never opened the
|
|
8
|
+
* index at all: it walked the tree and scored files by whether their name
|
|
9
|
+
* matched `index|main|app|server|…` plus a directory-depth bonus, stopping
|
|
10
|
+
* after ~500 files. On a repo of 8,412 that produced a map of whichever
|
|
11
|
+
* directories the walk reached first, ranked by filename. Centrality
|
|
12
|
+
* instead answers the question the map is actually asked — what does the
|
|
13
|
+
* rest of this codebase depend on?
|
|
14
|
+
* - **It can group.** `files.package` gives every file an ecosystem-derived
|
|
15
|
+
* cluster label, so the map opens with the shape of the repo (clusters and
|
|
16
|
+
* their hubs, then global hotspots) before descending into signatures.
|
|
17
|
+
*
|
|
18
|
+
* When the index has no ranks — a fresh clone, the first index run, a
|
|
19
|
+
* directory that was never indexed — {@link generateFallbackRepoMap} takes
|
|
20
|
+
* over and the output degrades to the old heuristic rather than to nothing.
|
|
21
|
+
*/
|
|
22
|
+
import type { RepoMapOptions, RepoMapResult } from './repo-map-types.js';
|
|
23
|
+
export { generateFallbackRepoMap } from './repo-map-fallback.js';
|
|
24
|
+
export type { RepoMapOptions, RepoMapResult } from './repo-map-types.js';
|
|
25
|
+
/**
|
|
26
|
+
* Generate a graph-ranked, token-budgeted repository map.
|
|
27
|
+
*
|
|
28
|
+
* Falls back to the filesystem heuristic whenever the index cannot answer —
|
|
29
|
+
* no ranks yet, or the store could not be opened at all.
|
|
18
30
|
*/
|
|
19
31
|
export declare function generateRepoMap(opts: RepoMapOptions): Promise<RepoMapResult>;
|
|
20
32
|
//# sourceMappingURL=repo-map.d.ts.map
|
|
@@ -194,6 +194,26 @@ export interface GraphNode {
|
|
|
194
194
|
scope?: string | undefined;
|
|
195
195
|
/** True when this is a direct relation outside the current drill-down scope. */
|
|
196
196
|
external?: boolean | undefined;
|
|
197
|
+
/**
|
|
198
|
+
* Global PageRank centrality, max-normalised to 1.0 across the whole index —
|
|
199
|
+
* so it is comparable between nodes of the same kind, not across kinds.
|
|
200
|
+
* Package nodes carry the sum of their files' ranks.
|
|
201
|
+
*/
|
|
202
|
+
rank?: number | undefined;
|
|
203
|
+
/** Plain-language description of the node, from the concept layer. */
|
|
204
|
+
concept?: string | undefined;
|
|
205
|
+
/**
|
|
206
|
+
* The load-bearing source span the summary was drawn from, 1-based and
|
|
207
|
+
* inclusive. A summary can drift from the code; this cannot.
|
|
208
|
+
*/
|
|
209
|
+
crux?: {
|
|
210
|
+
start: number;
|
|
211
|
+
end: number;
|
|
212
|
+
} | undefined;
|
|
213
|
+
/** Name of the subsystem this node's file belongs to, when one was derived. */
|
|
214
|
+
subsystem?: string | undefined;
|
|
215
|
+
/** `files.mtime_ms` — last modification, for recency shading. */
|
|
216
|
+
lastModifiedMs?: number | undefined;
|
|
197
217
|
}
|
|
198
218
|
/** A directed edge: source references / depends-on target. */
|
|
199
219
|
export interface GraphEdge {
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* Plain structured-cloneable shapes only — no class instances, no functions.
|
|
5
5
|
* Errors cross the boundary as strings and are re-wrapped by the host.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { ContextResult } from './context-retrieval.js';
|
|
8
8
|
import type { CodeMapGraph, IndexResult, IndexStats, SearchResult } from './schema.js';
|
|
9
|
+
import type { IncomingCallsResult, OutgoingCallsResult } from './worker-protocol/contracts.js';
|
|
10
|
+
import type { VectorHit } from './writer-vectors.js';
|
|
9
11
|
export interface IndexOpArgs {
|
|
10
12
|
projectRoot: string;
|
|
11
13
|
indexDir?: string | undefined;
|
|
@@ -61,6 +63,42 @@ export interface SearchOpResult {
|
|
|
61
63
|
*/
|
|
62
64
|
stale?: boolean | undefined;
|
|
63
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Personalised retrieval arguments.
|
|
68
|
+
*
|
|
69
|
+
* `vectorFiles` arrives already scored because the embedding model lives on
|
|
70
|
+
* the host: a function cannot cross this boundary, so the host embeds the
|
|
71
|
+
* query and only the resulting file scores travel as numbers.
|
|
72
|
+
*/
|
|
73
|
+
export interface ContextOpArgs extends StatsOpArgs {
|
|
74
|
+
query: string;
|
|
75
|
+
vectorFiles?: ReadonlyArray<{
|
|
76
|
+
file: string;
|
|
77
|
+
score: number;
|
|
78
|
+
}> | undefined;
|
|
79
|
+
limit?: number | undefined;
|
|
80
|
+
symbolsPerFile?: number | undefined;
|
|
81
|
+
pathPrefix?: string | undefined;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Nearest-vector search arguments.
|
|
85
|
+
*
|
|
86
|
+
* The vector is a plain number array rather than a `Float32Array` because
|
|
87
|
+
* only structured-cloneable plain shapes cross this protocol; the service
|
|
88
|
+
* re-wraps it before comparing.
|
|
89
|
+
*/
|
|
90
|
+
export interface VectorSearchOpArgs extends StatsOpArgs {
|
|
91
|
+
vector: number[];
|
|
92
|
+
limit: number;
|
|
93
|
+
minScore?: number | undefined;
|
|
94
|
+
}
|
|
95
|
+
export interface VectorSearchOpResult {
|
|
96
|
+
hits: VectorHit[];
|
|
97
|
+
/** Vectors currently stored — zero means the embedding pass has not run. */
|
|
98
|
+
total: number;
|
|
99
|
+
/** Set when the project server served a previous generation's cached answer. */
|
|
100
|
+
stale?: boolean | undefined;
|
|
101
|
+
}
|
|
64
102
|
/** Map of op name → { args, result } so host and worker stay in lockstep. */
|
|
65
103
|
export interface OpShapes {
|
|
66
104
|
index: {
|
|
@@ -95,6 +133,14 @@ export interface OpShapes {
|
|
|
95
133
|
args: CallRefsOpArgs;
|
|
96
134
|
result: OutgoingCallsResult;
|
|
97
135
|
};
|
|
136
|
+
context: {
|
|
137
|
+
args: ContextOpArgs;
|
|
138
|
+
result: ContextResult;
|
|
139
|
+
};
|
|
140
|
+
vectorSearch: {
|
|
141
|
+
args: VectorSearchOpArgs;
|
|
142
|
+
result: VectorSearchOpResult;
|
|
143
|
+
};
|
|
98
144
|
}
|
|
99
145
|
export type OpName = keyof OpShapes;
|
|
100
146
|
export type HostToWorker = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
contextService,
|
|
2
3
|
fileGraphService,
|
|
3
4
|
incomingCallsService,
|
|
4
5
|
indexService,
|
|
@@ -6,15 +7,16 @@ import {
|
|
|
6
7
|
packageGraphService,
|
|
7
8
|
searchService,
|
|
8
9
|
statsService,
|
|
9
|
-
symbolGraphService
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import "../chunk-
|
|
10
|
+
symbolGraphService,
|
|
11
|
+
vectorSearchService
|
|
12
|
+
} from "../chunk-3JVSOBHU.js";
|
|
13
|
+
import "../chunk-6LCKF5KH.js";
|
|
14
|
+
import "../chunk-REWOZIA4.js";
|
|
13
15
|
import "../chunk-6IEBD27U.js";
|
|
14
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-ZKC5UNGD.js";
|
|
15
17
|
import "../chunk-YOHO4DVT.js";
|
|
16
18
|
import "../chunk-2CTZW6JQ.js";
|
|
17
|
-
import "../chunk-
|
|
19
|
+
import "../chunk-5U5ULQX2.js";
|
|
18
20
|
|
|
19
21
|
// src/codebase-index/worker.ts
|
|
20
22
|
import { parentPort } from "node:worker_threads";
|
|
@@ -50,6 +52,10 @@ async function dispatch(msg) {
|
|
|
50
52
|
}
|
|
51
53
|
case "search":
|
|
52
54
|
return searchService(msg.args);
|
|
55
|
+
case "context":
|
|
56
|
+
return contextService(msg.args);
|
|
57
|
+
case "vectorSearch":
|
|
58
|
+
return vectorSearchService(msg.args);
|
|
53
59
|
case "stats":
|
|
54
60
|
return statsService(msg.args);
|
|
55
61
|
case "packageGraph":
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence for the concept layer (`file_concepts`, `subsystems`,
|
|
3
|
+
* `concept_edges`).
|
|
4
|
+
*
|
|
5
|
+
* Unlike the rank tables, these are written incrementally: a summary costs a
|
|
6
|
+
* model call, so the runner checkpoints as it goes and a cancelled or crashed
|
|
7
|
+
* pass must not throw away what it already paid for.
|
|
8
|
+
*/
|
|
9
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
10
|
+
type Statement = ReturnType<DatabaseSync['prepare']>;
|
|
11
|
+
type PrepareStatement = (sql: string) => Statement;
|
|
12
|
+
/**
|
|
13
|
+
* Whether a stored summary describes the file's current bytes.
|
|
14
|
+
*
|
|
15
|
+
* `stale` is kept rather than deleted: an outdated description of a file is
|
|
16
|
+
* still a better starting point than nothing, both for a reader and as a hint
|
|
17
|
+
* to the model on the next pass.
|
|
18
|
+
*/
|
|
19
|
+
export type ConceptState = 'ready' | 'stale' | 'pending';
|
|
20
|
+
export interface FileConcept {
|
|
21
|
+
file: string;
|
|
22
|
+
contentHash: string;
|
|
23
|
+
summary: string;
|
|
24
|
+
/** 1-based inclusive line span of the file's load-bearing lines. */
|
|
25
|
+
cruxStart: number | null;
|
|
26
|
+
cruxEnd: number | null;
|
|
27
|
+
state: ConceptState;
|
|
28
|
+
model: string;
|
|
29
|
+
updatedAt: number;
|
|
30
|
+
}
|
|
31
|
+
export interface Subsystem {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
summary: string;
|
|
35
|
+
memberFiles: string[];
|
|
36
|
+
model: string;
|
|
37
|
+
updatedAt: number;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Closed vocabulary for concept-to-concept relations.
|
|
41
|
+
*
|
|
42
|
+
* Closed on purpose. An open-ended verb list produces a graph where
|
|
43
|
+
* `configures`, `sets up` and `initialises` are three different edges between
|
|
44
|
+
* the same pair, which nothing downstream can group or filter on.
|
|
45
|
+
*/
|
|
46
|
+
export declare const CONCEPT_RELATIONS: readonly ['uses', 'configures', 'validates', 'extends', 'persists', 'observes'];
|
|
47
|
+
export type ConceptRelation = (typeof CONCEPT_RELATIONS)[number];
|
|
48
|
+
export declare function isConceptRelation(value: string): value is ConceptRelation;
|
|
49
|
+
export interface ConceptEdge {
|
|
50
|
+
fromId: string;
|
|
51
|
+
toId: string;
|
|
52
|
+
relation: ConceptRelation;
|
|
53
|
+
}
|
|
54
|
+
/** Write (or replace) one file's concept. */
|
|
55
|
+
export declare function upsertFileConceptWithStatement(stmt: PrepareStatement, concept: FileConcept): void;
|
|
56
|
+
export declare function getFileConceptWithStatement(stmt: PrepareStatement, file: string): FileConcept | undefined;
|
|
57
|
+
/** All concepts, for whole-index consumers (atlas, embeddings, injection). */
|
|
58
|
+
export declare function getAllFileConceptsWithStatement(stmt: PrepareStatement): FileConcept[];
|
|
59
|
+
/** `file → summary` for the files that currently have a usable description. */
|
|
60
|
+
export declare function getReadyConceptSummariesWithStatement(stmt: PrepareStatement): Map<string, string>;
|
|
61
|
+
export interface ConceptCoverage {
|
|
62
|
+
ready: number;
|
|
63
|
+
stale: number;
|
|
64
|
+
pending: number;
|
|
65
|
+
subsystems: number;
|
|
66
|
+
}
|
|
67
|
+
export declare function getConceptCoverageWithStatement(stmt: PrepareStatement): ConceptCoverage;
|
|
68
|
+
/**
|
|
69
|
+
* Mark every concept whose recorded hash no longer matches the indexed file as
|
|
70
|
+
* `stale`, in one statement.
|
|
71
|
+
*
|
|
72
|
+
* Run before a pass rather than during indexing: the indexer's atomic write is
|
|
73
|
+
* not the place to reason about a layer it does not own, and a summary that is
|
|
74
|
+
* one generation behind harms nothing until someone asks for it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function markStaleConceptsWithStatement(stmt: PrepareStatement): number;
|
|
77
|
+
/** Drop concepts for files that are no longer indexed. */
|
|
78
|
+
export declare function pruneOrphanConceptsWithStatement(stmt: PrepareStatement): number;
|
|
79
|
+
/** Replace the whole subsystem layer. Subsystems are derived as a set. */
|
|
80
|
+
export declare function replaceSubsystemsWithStatement(stmt: PrepareStatement, maxSqlVars: number, subsystems: readonly Subsystem[], edges: readonly ConceptEdge[]): void;
|
|
81
|
+
export declare function getSubsystemsWithStatement(stmt: PrepareStatement): Subsystem[];
|
|
82
|
+
export declare function getConceptEdgesWithStatement(stmt: PrepareStatement): ConceptEdge[];
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=writer-concepts.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlas enrichment for the CodeMap graph.
|
|
3
|
+
*
|
|
4
|
+
* The three graph getters build their nodes from `symbols` and `files`. Rank,
|
|
5
|
+
* concept summaries and subsystem membership live in tables those queries know
|
|
6
|
+
* nothing about, and each getter reaches its nodes by a different route — one
|
|
7
|
+
* groups by package, one by file, one by symbol id.
|
|
8
|
+
*
|
|
9
|
+
* Rather than thread four more joins through three query shapes and their node
|
|
10
|
+
* builders, this decorates the finished nodes in one pass. That keeps the
|
|
11
|
+
* enrichment strictly additive: an index where no rank or concept pass has run
|
|
12
|
+
* produces exactly the graph it produced before, because every lookup misses
|
|
13
|
+
* and every field stays absent.
|
|
14
|
+
*
|
|
15
|
+
* It also sidesteps `chunkedIdQuery`'s documented rule that `buildSql` may not
|
|
16
|
+
* contain a `LIMIT` — there is no limit to express here.
|
|
17
|
+
*/
|
|
18
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
19
|
+
import type { GraphNode } from './schema.js';
|
|
20
|
+
type Statement = ReturnType<DatabaseSync['prepare']>;
|
|
21
|
+
type PrepareStatement = (sql: string) => Statement;
|
|
22
|
+
/**
|
|
23
|
+
* Stamp rank, concept, crux, subsystem and mtime onto graph nodes.
|
|
24
|
+
*
|
|
25
|
+
* `packageOf` is supplied by the caller because the package labeller already
|
|
26
|
+
* exists at every call site, and rebuilding it here would read `files` twice.
|
|
27
|
+
*/
|
|
28
|
+
export declare function decorateGraphNodes(stmt: PrepareStatement, nodes: GraphNode[], packageOf: (file: string) => string): void;
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=writer-graph-decorate.d.ts.map
|
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
import type { DatabaseSync } from 'node:sqlite';
|
|
2
2
|
import type { CallSite, CodeMapGraph, Ref } from './schema.js';
|
|
3
|
+
import { type WriterSymbolGraphRow } from './writer-graph-helpers.js';
|
|
3
4
|
type Statement = ReturnType<DatabaseSync['prepare']>;
|
|
4
5
|
type PrepareStatement = (sql: string) => Statement;
|
|
6
|
+
/**
|
|
7
|
+
* Hydrate symbol rows for an arbitrary id list.
|
|
8
|
+
*
|
|
9
|
+
* The personalised retrieval walk scores dense graph indices and then needs
|
|
10
|
+
* the declarations behind the winners; this is that lookup. Chunked because
|
|
11
|
+
* the id list is unbounded — the caller decides how many nodes to hydrate.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getSymbolsByIdsWithStatement(stmt: PrepareStatement, ids: readonly number[]): WriterSymbolGraphRow[];
|
|
14
|
+
/**
|
|
15
|
+
* Declarations in one file, in source order.
|
|
16
|
+
*
|
|
17
|
+
* Ordered by line rather than by any score so the list reads the way the file
|
|
18
|
+
* does — the atlas uses it to describe a file, not to rank within it.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getFileSymbolsWithStatement(stmt: PrepareStatement, file: string, limit: number): Array<{
|
|
21
|
+
id: number;
|
|
22
|
+
name: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
line: number;
|
|
25
|
+
signature: string;
|
|
26
|
+
}>;
|
|
5
27
|
/**
|
|
6
28
|
* Find all symbols that CALL/USE the named target symbol (incoming callers).
|
|
7
29
|
*
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence for the graph centrality layer (`symbol_rank`, `file_rank`).
|
|
3
|
+
*
|
|
4
|
+
* Ranks are always written as a whole: the score is a property of the entire
|
|
5
|
+
* graph, so a partial update would leave the table describing a graph that no
|
|
6
|
+
* longer exists. Both writers therefore delete and re-insert rather than
|
|
7
|
+
* upserting row by row — at ~66k symbols that is a single fast statement plus
|
|
8
|
+
* a ladder-chunked bulk insert, well inside the index run's existing budget.
|
|
9
|
+
*/
|
|
10
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
11
|
+
import type { FileRankRow, SymbolRankRow } from './graph-rank.js';
|
|
12
|
+
type Statement = ReturnType<DatabaseSync['prepare']>;
|
|
13
|
+
type PrepareStatement = (sql: string) => Statement;
|
|
14
|
+
/** Replace the whole `symbol_rank` table with `rows`. */
|
|
15
|
+
export declare function replaceSymbolRanksWithStatement(stmt: PrepareStatement, maxSqlVars: number, rows: readonly SymbolRankRow[]): void;
|
|
16
|
+
/** Replace the whole `file_rank` table with `rows`. */
|
|
17
|
+
export declare function replaceFileRanksWithStatement(stmt: PrepareStatement, maxSqlVars: number, rows: readonly FileRankRow[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Highest-ranked files, most central first.
|
|
20
|
+
*
|
|
21
|
+
* `limit` is applied in SQL — this is a plain single-table read, so none of
|
|
22
|
+
* the chunked-query constraints that forbid `LIMIT` elsewhere apply here.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getTopFileRanksWithStatement(stmt: PrepareStatement, limit: number): FileRankRow[];
|
|
25
|
+
/** A ranked file joined with the metadata the repo map needs to group it. */
|
|
26
|
+
export interface RankedFileRow extends FileRankRow {
|
|
27
|
+
/** Code Atlas grouping label from `files.package` — '' when unlabelled. */
|
|
28
|
+
package: string;
|
|
29
|
+
lang: string;
|
|
30
|
+
symbolCount: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Highest-ranked files with their package label, for repo-map clustering.
|
|
34
|
+
*
|
|
35
|
+
* Joined here rather than in two round trips because the repo map always
|
|
36
|
+
* needs both, and `file_rank` is keyed by the same absolute path as `files`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getRankedFilesWithStatement(stmt: PrepareStatement, limit: number): RankedFileRow[];
|
|
39
|
+
/**
|
|
40
|
+
* True indexed-file count per package label.
|
|
41
|
+
*
|
|
42
|
+
* The repo map only fetches its top few hundred ranked files, so counting
|
|
43
|
+
* cluster membership from that slice would report "core has 154 files" for a
|
|
44
|
+
* package with thousands. The count has to come from `files` itself.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getPackageFileCountsWithStatement(stmt: PrepareStatement): Map<string, number>;
|
|
47
|
+
/** Highest-ranked symbols, most central first. */
|
|
48
|
+
export declare function getTopSymbolRanksWithStatement(stmt: PrepareStatement, limit: number): SymbolRankRow[];
|
|
49
|
+
/**
|
|
50
|
+
* How many symbols declare each ambiguous symbol's name, keyed by symbol id.
|
|
51
|
+
*
|
|
52
|
+
* Counted per `(name, language family)` because that is exactly the scope ref
|
|
53
|
+
* resolution matches within (`FAMILY_MATCH_SQL`) — a Go `Read` and a
|
|
54
|
+
* TypeScript `Read` never compete for the same ref, so counting them together
|
|
55
|
+
* would understate the confidence of both.
|
|
56
|
+
*
|
|
57
|
+
* Only names with more than one declaration are returned: on this repo that
|
|
58
|
+
* is roughly a seventh of all names, so the map stays small and every absent
|
|
59
|
+
* id means "unambiguous, full weight".
|
|
60
|
+
*/
|
|
61
|
+
export declare function getSymbolNameCandidatesWithStatement(stmt: PrepareStatement): Map<number, number>;
|
|
62
|
+
/**
|
|
63
|
+
* File-to-file import edges, as `source file → set of imported files`.
|
|
64
|
+
*
|
|
65
|
+
* Built from the import refs the module resolver managed to resolve to a real
|
|
66
|
+
* path (`refs.to_file`). Used by the rank pass to tell a cross-file reference
|
|
67
|
+
* that is genuinely visible from one the resolver merely guessed at.
|
|
68
|
+
*/
|
|
69
|
+
export declare function getImportVisibilityWithStatement(stmt: PrepareStatement): Map<string, Set<string>>;
|
|
70
|
+
/** Whole-table `file → rank` lookup, for joining ranks onto graph reads. */
|
|
71
|
+
export declare function getFileRankMapWithStatement(stmt: PrepareStatement): Map<string, number>;
|
|
72
|
+
/** Row counts, for index stats and for deciding whether the layer is populated. */
|
|
73
|
+
export declare function getRankCountsWithStatement(stmt: PrepareStatement): {
|
|
74
|
+
symbols: number;
|
|
75
|
+
files: number;
|
|
76
|
+
};
|
|
77
|
+
export {};
|
|
78
|
+
//# sourceMappingURL=writer-rank.d.ts.map
|