@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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes the Codebase Atlas projection emits.
|
|
3
|
+
*
|
|
4
|
+
* They live apart from the code that builds them so that a renderer can name
|
|
5
|
+
* what it renders without importing the builder: `atlas-projection` produces
|
|
6
|
+
* these and calls `atlas-export` to render them, and `atlas-export` needs the
|
|
7
|
+
* types but must never reach back for the builder. Declaring them here is what
|
|
8
|
+
* keeps that a one-way edge instead of a module cycle.
|
|
9
|
+
*
|
|
10
|
+
* Everything here is plain data — no imports, no behaviour. `atlas-projection`
|
|
11
|
+
* re-exports the whole set, so consumers keep importing from there.
|
|
12
|
+
*/
|
|
13
|
+
export interface AtlasSymbol {
|
|
14
|
+
name: string;
|
|
15
|
+
kind: string;
|
|
16
|
+
line: number;
|
|
17
|
+
}
|
|
18
|
+
export interface AtlasFile {
|
|
19
|
+
path: string;
|
|
20
|
+
rank: number;
|
|
21
|
+
inDeg: number;
|
|
22
|
+
outDeg: number;
|
|
23
|
+
package: string;
|
|
24
|
+
symbols: AtlasSymbol[];
|
|
25
|
+
/** Concept-layer summary. Omitted entirely when the layer has not run. */
|
|
26
|
+
concept?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface AtlasPackage {
|
|
29
|
+
name: string;
|
|
30
|
+
files: number;
|
|
31
|
+
/** Highest-ranked file in the package. */
|
|
32
|
+
hub: string;
|
|
33
|
+
rank: number;
|
|
34
|
+
/** Subsystem summary for this package, when the concept layer derived one. */
|
|
35
|
+
summary?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A package-level dependency, aggregated from the reference graph.
|
|
39
|
+
*
|
|
40
|
+
* Only the package level is projected. File-level edges would be tens of
|
|
41
|
+
* thousands of rows — a diff nobody can read and a file nobody can render,
|
|
42
|
+
* for a level of detail the index itself answers better on demand.
|
|
43
|
+
*/
|
|
44
|
+
export interface AtlasEdge {
|
|
45
|
+
from: string;
|
|
46
|
+
to: string;
|
|
47
|
+
weight: number;
|
|
48
|
+
refType: string;
|
|
49
|
+
}
|
|
50
|
+
export interface AtlasDocument {
|
|
51
|
+
schema: number;
|
|
52
|
+
counts: {
|
|
53
|
+
files: number;
|
|
54
|
+
symbols: number;
|
|
55
|
+
packages: number;
|
|
56
|
+
};
|
|
57
|
+
packages: AtlasPackage[];
|
|
58
|
+
edges: AtlasEdge[];
|
|
59
|
+
files: AtlasFile[];
|
|
60
|
+
}
|
|
61
|
+
export interface AtlasManifest {
|
|
62
|
+
schema: number;
|
|
63
|
+
/**
|
|
64
|
+
* `files`/`symbols` are the index's own totals, for display.
|
|
65
|
+
*
|
|
66
|
+
* `tracked` is the size of the file set the digest was computed over — the
|
|
67
|
+
* only number a freshness check may compare its own file set against. The
|
|
68
|
+
* two can differ (a file with no symbols is tracked but may not count
|
|
69
|
+
* towards `files`), and comparing across them reported phantom additions.
|
|
70
|
+
*/
|
|
71
|
+
counts: {
|
|
72
|
+
files: number;
|
|
73
|
+
symbols: number;
|
|
74
|
+
tracked: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* sha-256 over every indexed file's `path\0contentHash`, sorted. Catches a
|
|
78
|
+
* change anywhere in the repository, including files the atlas does not
|
|
79
|
+
* itself carry.
|
|
80
|
+
*/
|
|
81
|
+
digest: string;
|
|
82
|
+
/** Per-file content hashes, for the files the atlas describes. */
|
|
83
|
+
files: Record<string, string>;
|
|
84
|
+
}
|
|
85
|
+
export interface AtlasProjection {
|
|
86
|
+
document: AtlasDocument;
|
|
87
|
+
manifest: AtlasManifest;
|
|
88
|
+
markdown: string;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=atlas-types.d.ts.map
|
|
@@ -26,10 +26,11 @@
|
|
|
26
26
|
* for the TUI status chip and the search/stats tools' gating.
|
|
27
27
|
*/
|
|
28
28
|
import { type CircuitSnapshot } from './circuit-breaker.js';
|
|
29
|
+
import type { ContextResult } from './context-retrieval.js';
|
|
29
30
|
import { type IncomingCallsResult, type OutgoingCallsResult } from './index-service.js';
|
|
30
31
|
import { type ProjectIndexServerClientHealth, type ProjectIndexServerConnectionState, type ProjectIndexServerShutdownResult } from './project-server-client.js';
|
|
31
32
|
import type { CodeMapGraph, IndexResult, IndexStats } from './schema.js';
|
|
32
|
-
import type { CallRefsOpArgs, FileGraphOpArgs, SearchOpArgs, SearchOpResult, StatsOpArgs, SymbolGraphOpArgs } from './worker-protocol.js';
|
|
33
|
+
import type { CallRefsOpArgs, ContextOpArgs, FileGraphOpArgs, SearchOpArgs, SearchOpResult, StatsOpArgs, SymbolGraphOpArgs, VectorSearchOpArgs, VectorSearchOpResult } from './worker-protocol.js';
|
|
33
34
|
/** True once the first full-project index has completed (success or failure). */
|
|
34
35
|
export declare function isIndexReady(): boolean;
|
|
35
36
|
/**
|
|
@@ -89,14 +90,13 @@ export declare function enqueueReindex(opts: {
|
|
|
89
90
|
* Per-project trailing coalescing window. After a file's debounce timer
|
|
90
91
|
* fires, the ready batch stays open for this long before flushing. Any file
|
|
91
92
|
* whose timer fires within the window joins the same batch and resets the
|
|
92
|
-
* timer (sliding). Default: 50ms
|
|
93
|
-
* debounce timer fires (legacy behavior — staggered bursts don't coalesce).
|
|
93
|
+
* timer (sliding). Default: 50ms; set to 0 for immediate flush.
|
|
94
94
|
*/
|
|
95
95
|
coalesceWindowMs?: number | undefined;
|
|
96
96
|
/** Watchdog timeout per file. Default: 30s. */
|
|
97
97
|
timeoutMs?: number | undefined;
|
|
98
98
|
onError?: ((err: unknown) => void) | undefined;
|
|
99
|
-
}): void
|
|
99
|
+
}): Promise<void>;
|
|
100
100
|
/** Cancel all pending debounced reindexes. For teardown / tests. */
|
|
101
101
|
export declare function cancelPendingReindexes(): void;
|
|
102
102
|
/**
|
|
@@ -115,6 +115,17 @@ export declare function codebaseIndexStats(args: StatsOpArgs, opts?: {
|
|
|
115
115
|
timeoutMs?: number | undefined;
|
|
116
116
|
signal?: AbortSignal | undefined;
|
|
117
117
|
}): Promise<IndexStats>;
|
|
118
|
+
/**
|
|
119
|
+
* Personalised retrieval — the single call that answers "which files does this
|
|
120
|
+
* task touch?", served by the same per-project index process so the wiring
|
|
121
|
+
* graph is built once per generation rather than once per query.
|
|
122
|
+
*/
|
|
123
|
+
export declare function codebaseContext(args: ContextOpArgs): Promise<ContextResult>;
|
|
124
|
+
/**
|
|
125
|
+
* Nearest files to an already-embedded query vector. The model stays in the
|
|
126
|
+
* caller's process; only numbers cross IPC.
|
|
127
|
+
*/
|
|
128
|
+
export declare function codebaseVectorSearch(args: VectorSearchOpArgs): Promise<VectorSearchOpResult>;
|
|
118
129
|
/** Package dependency graph, served by the same per-project index process. */
|
|
119
130
|
export declare function packageGraphService(args: StatsOpArgs): Promise<CodeMapGraph>;
|
|
120
131
|
/** File dependency graph, served by the same per-project index process. */
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `codebase-context` tool — one call that answers "which files does this task
|
|
3
|
+
* touch, and what is in them?".
|
|
4
|
+
*
|
|
5
|
+
* The index already exposed the ingredients: `codebase-search` finds symbols
|
|
6
|
+
* by name, `codebase-skeleton` shows a file's shape, `codebase-incoming-calls`
|
|
7
|
+
* finds callers. Composing them was left to the model, which meant re-deriving
|
|
8
|
+
* the same chain on every task and spending several round trips on plumbing.
|
|
9
|
+
* This tool runs the composition server-side: lexical search seeds a
|
|
10
|
+
* personalised PageRank walk over the reference graph, and what comes back is
|
|
11
|
+
* the ranked file set with the declarations that matter in each.
|
|
12
|
+
*
|
|
13
|
+
* It deliberately returns signatures and line numbers rather than source. The
|
|
14
|
+
* point is to make the subsequent `read` land in the right place, not to
|
|
15
|
+
* replace it — inlining bodies here would spend the caller's context on code
|
|
16
|
+
* they may not need.
|
|
17
|
+
*/
|
|
18
|
+
import type { Tool } from '@wrongstack/core/types';
|
|
19
|
+
import type { ContextEntry } from './context-retrieval.js';
|
|
20
|
+
import type { EmbeddingPort } from './embedding-pass.js';
|
|
21
|
+
export interface CodebaseContextInput {
|
|
22
|
+
/** What you are trying to do or understand, in plain words. */
|
|
23
|
+
query: string;
|
|
24
|
+
/** Files to return. Defaults to 12, capped at 50. */
|
|
25
|
+
limit?: number | undefined;
|
|
26
|
+
/** Declarations shown per file. Defaults to 4, capped at 20. */
|
|
27
|
+
symbolsPerFile?: number | undefined;
|
|
28
|
+
/** Restrict results to a project-relative path prefix. */
|
|
29
|
+
pathPrefix?: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
export interface CodebaseContextOutput {
|
|
32
|
+
query: string;
|
|
33
|
+
entries: ContextEntry[];
|
|
34
|
+
/** Lexical hits that seeded the walk. */
|
|
35
|
+
seedCount: number;
|
|
36
|
+
/** Semantic hits that also seeded it. Zero without an embedding model. */
|
|
37
|
+
semanticSeedCount: number;
|
|
38
|
+
/** Files the walk reached before truncation to `limit`. */
|
|
39
|
+
totalCandidates: number;
|
|
40
|
+
/**
|
|
41
|
+
* `ok` — a ranked answer. `no-index` — nothing indexed yet.
|
|
42
|
+
* `no-matches` — the index exists but the query matched nothing.
|
|
43
|
+
* `unranked` — symbols exist but no reference graph, so results are lexical
|
|
44
|
+
* only. `error` — the lookup itself failed; see `error`.
|
|
45
|
+
*/
|
|
46
|
+
indexStatus: 'ok' | 'no-index' | 'no-matches' | 'unranked' | 'error';
|
|
47
|
+
/** True when a cached answer from a previous generation was served. */
|
|
48
|
+
stale?: boolean | undefined;
|
|
49
|
+
error?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
/** Install (or clear) the query-time embedding model. */
|
|
52
|
+
export declare function setContextQueryEmbedder(port: EmbeddingPort | undefined): void;
|
|
53
|
+
export declare const codebaseContextTool: Tool<CodebaseContextInput, CodebaseContextOutput>;
|
|
54
|
+
//# sourceMappingURL=codebase-context-tool.d.ts.map
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The concept-layer enrichment pass.
|
|
3
|
+
*
|
|
4
|
+
* Walks the index's files most-central-first and asks a model, once per file,
|
|
5
|
+
* what the file is for. The answer is a short plain-English summary plus a
|
|
6
|
+
* **crux**: the line span that actually carries the file's meaning. A summary
|
|
7
|
+
* can drift from the truth; a pointer into the source cannot, so the two are
|
|
8
|
+
* always stored together.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this is a separate pass
|
|
11
|
+
*
|
|
12
|
+
* Model calls take seconds. `runIndexerAtomic` is a SQLite write transaction —
|
|
13
|
+
* holding one open across thousands of network round trips would block every
|
|
14
|
+
* other writer for the duration and roll the whole thing back on the first
|
|
15
|
+
* failure. So enrichment runs on its own, outside the indexer, writing each
|
|
16
|
+
* result as it arrives.
|
|
17
|
+
*
|
|
18
|
+
* ## Why it is affordable
|
|
19
|
+
*
|
|
20
|
+
* `files.content_hash` already exists and is exactly the right cache key: a
|
|
21
|
+
* file whose bytes have not changed is never re-sent. A first pass over this
|
|
22
|
+
* repository is thousands of calls; every pass after it is only the files that
|
|
23
|
+
* actually changed. That is the difference between a one-off cost and a
|
|
24
|
+
* recurring one.
|
|
25
|
+
*
|
|
26
|
+
* ## Why it never takes the caller down
|
|
27
|
+
*
|
|
28
|
+
* Enrichment is an optional layer over a working index. A model that refuses,
|
|
29
|
+
* times out, or returns something unparseable degrades one file's summary — it
|
|
30
|
+
* is recorded in `errors` and the walk continues. Cancellation is honoured
|
|
31
|
+
* between files, and everything already written stays written.
|
|
32
|
+
*/
|
|
33
|
+
import { type IndexStore } from './writer.js';
|
|
34
|
+
/** What the summariser is given about one file. */
|
|
35
|
+
export interface SummarizeFileInput {
|
|
36
|
+
/** Project-relative path, for the model's benefit. */
|
|
37
|
+
file: string;
|
|
38
|
+
/** Absolute path, if the summariser wants to read more itself. */
|
|
39
|
+
absolutePath: string;
|
|
40
|
+
language: string;
|
|
41
|
+
/** File source, already truncated to {@link MAX_SOURCE_CHARS}. */
|
|
42
|
+
source: string;
|
|
43
|
+
/** Whether `source` was cut short. */
|
|
44
|
+
truncated: boolean;
|
|
45
|
+
/** Declarations the index recorded, as orientation. */
|
|
46
|
+
declarations: ReadonlyArray<{
|
|
47
|
+
name: string;
|
|
48
|
+
kind: string;
|
|
49
|
+
line: number;
|
|
50
|
+
}>;
|
|
51
|
+
/** A previous, now-outdated summary, when one exists. */
|
|
52
|
+
staleSummary?: string | undefined;
|
|
53
|
+
signal?: AbortSignal | undefined;
|
|
54
|
+
}
|
|
55
|
+
export interface SummarizeFileResult {
|
|
56
|
+
/** One or two sentences on what the file is for. */
|
|
57
|
+
summary: string;
|
|
58
|
+
/** 1-based inclusive line span of the load-bearing lines. */
|
|
59
|
+
cruxStart?: number | undefined;
|
|
60
|
+
cruxEnd?: number | undefined;
|
|
61
|
+
/** Model identifier, recorded so a later pass can tell what produced this. */
|
|
62
|
+
model?: string | undefined;
|
|
63
|
+
}
|
|
64
|
+
export interface SummarizeSubsystemInput {
|
|
65
|
+
/** Package or directory label. */
|
|
66
|
+
name: string;
|
|
67
|
+
files: ReadonlyArray<{
|
|
68
|
+
file: string;
|
|
69
|
+
summary: string;
|
|
70
|
+
rank: number;
|
|
71
|
+
}>;
|
|
72
|
+
signal?: AbortSignal | undefined;
|
|
73
|
+
}
|
|
74
|
+
export interface SummarizeSubsystemResult {
|
|
75
|
+
summary: string;
|
|
76
|
+
/**
|
|
77
|
+
* Other subsystem names this one relates to, with a relation from the closed
|
|
78
|
+
* vocabulary. Unknown relations and unknown targets are dropped by the caller.
|
|
79
|
+
*/
|
|
80
|
+
relations?: ReadonlyArray<{
|
|
81
|
+
to: string;
|
|
82
|
+
relation: string;
|
|
83
|
+
}> | undefined;
|
|
84
|
+
model?: string | undefined;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The host-supplied model transport.
|
|
88
|
+
*
|
|
89
|
+
* Injected rather than imported: producing a summary needs a configured
|
|
90
|
+
* provider and the model-tier policy, both of which live in the host. This
|
|
91
|
+
* mirrors how SAGE takes `getLlmCall` — `packages/tools` stays free of
|
|
92
|
+
* provider wiring, and a host that supplies no port simply gets no concepts.
|
|
93
|
+
*/
|
|
94
|
+
export interface SummarizerPort {
|
|
95
|
+
describeFile(input: SummarizeFileInput): Promise<SummarizeFileResult | null>;
|
|
96
|
+
describeSubsystem?(input: SummarizeSubsystemInput): Promise<SummarizeSubsystemResult | null>;
|
|
97
|
+
}
|
|
98
|
+
/** Source sent per file. Enough for a summary; short enough to stay cheap. */
|
|
99
|
+
export declare const MAX_SOURCE_CHARS = 12000;
|
|
100
|
+
/** Crux span ceiling. Graft uses twelve lines; longer stops being a pointer. */
|
|
101
|
+
export declare const MAX_CRUX_LINES = 12;
|
|
102
|
+
export declare const DEFAULT_CONCURRENCY = 5;
|
|
103
|
+
/** Summary length ceiling, so one verbose model cannot bloat the layer. */
|
|
104
|
+
export declare const MAX_SUMMARY_CHARS = 400;
|
|
105
|
+
export interface EnrichOptions {
|
|
106
|
+
/** Stop after this many files. The natural way to sample the cost first. */
|
|
107
|
+
maxFiles?: number | undefined;
|
|
108
|
+
/** Files summarised in parallel. */
|
|
109
|
+
concurrency?: number | undefined;
|
|
110
|
+
/** Re-summarise files whose summary is already current. */
|
|
111
|
+
force?: boolean | undefined;
|
|
112
|
+
/** Also derive the subsystem layer, when the port supports it. */
|
|
113
|
+
subsystems?: boolean | undefined;
|
|
114
|
+
signal?: AbortSignal | undefined;
|
|
115
|
+
onProgress?: ((done: number, total: number) => void) | undefined;
|
|
116
|
+
}
|
|
117
|
+
export interface EnrichResult {
|
|
118
|
+
/** Files sent to the model. */
|
|
119
|
+
summarised: number;
|
|
120
|
+
/** Files skipped because their stored summary already matched. */
|
|
121
|
+
cached: number;
|
|
122
|
+
/** Files the model declined or failed on. */
|
|
123
|
+
failed: number;
|
|
124
|
+
/** Concepts marked stale before the walk started. */
|
|
125
|
+
markedStale: number;
|
|
126
|
+
/** Concepts dropped because their file left the index. */
|
|
127
|
+
pruned: number;
|
|
128
|
+
subsystems: number;
|
|
129
|
+
durationMs: number;
|
|
130
|
+
errors: string[];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Run one enrichment pass.
|
|
134
|
+
*
|
|
135
|
+
* `relativeOf` is injected for the same reason the retrieval walk takes it —
|
|
136
|
+
* the caller owns what "project-relative" means, and this module stays free of
|
|
137
|
+
* path policy.
|
|
138
|
+
*/
|
|
139
|
+
export declare function enrichConcepts(store: IndexStore, port: SummarizerPort, relativeOf: (file: string) => string, options?: EnrichOptions): Promise<EnrichResult>;
|
|
140
|
+
/** Reported when a project has no index to enrich. */
|
|
141
|
+
export type ConceptIndexMissing = {
|
|
142
|
+
indexed: false;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Enrich a project's concept layer, owning the store lifetime so callers
|
|
146
|
+
* outside this package never touch `indexStorePool`.
|
|
147
|
+
*
|
|
148
|
+
* Refuses to run without an existing index: opening a store CREATES the
|
|
149
|
+
* database, and spending money summarising an empty index helps nobody.
|
|
150
|
+
*/
|
|
151
|
+
export declare function enrichProjectConcepts(projectRoot: string, port: SummarizerPort, options?: EnrichOptions & {
|
|
152
|
+
indexDir?: string | undefined;
|
|
153
|
+
}): Promise<EnrichResult | ConceptIndexMissing>;
|
|
154
|
+
//# sourceMappingURL=concept-enrichment.d.ts.map
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Personalised retrieval — "which files does this task touch?"
|
|
3
|
+
*
|
|
4
|
+
* Lexical search proposes, the graph disposes. A BM25/FTS query produces a set
|
|
5
|
+
* of seed symbols with scores; those scores become the restart distribution of
|
|
6
|
+
* a personalised PageRank walk over the wiring graph. The walk then surfaces
|
|
7
|
+
* what the seeds are structurally attached to: the interface a matched
|
|
8
|
+
* function implements, the module every matched call site imports, the store
|
|
9
|
+
* behind the handler that matched by name.
|
|
10
|
+
*
|
|
11
|
+
* This is the piece that turns the index from a set of primitives an agent has
|
|
12
|
+
* to compose by hand — search, then skeleton, then incoming-calls, then read —
|
|
13
|
+
* into one answer. The composition was previously re-derived by the model on
|
|
14
|
+
* every task, at the cost of several round trips and a great deal of judgement
|
|
15
|
+
* spent on plumbing rather than on the problem.
|
|
16
|
+
*
|
|
17
|
+
* What comes back is declarations, not source: file, relevance, and the
|
|
18
|
+
* matching symbols with their signatures and line numbers. Reading the actual
|
|
19
|
+
* code stays a deliberate `read` — the point is to make that read land in the
|
|
20
|
+
* right place the first time.
|
|
21
|
+
*/
|
|
22
|
+
import type { IndexStore } from './writer.js';
|
|
23
|
+
/** One symbol worth showing inside a returned file. */
|
|
24
|
+
export interface ContextSymbol {
|
|
25
|
+
name: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
line: number;
|
|
28
|
+
signature: string;
|
|
29
|
+
/** True when lexical search matched this symbol directly. */
|
|
30
|
+
seed: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** One file in the answer, most relevant first. */
|
|
33
|
+
export interface ContextEntry {
|
|
34
|
+
/** Project-relative POSIX path. */
|
|
35
|
+
file: string;
|
|
36
|
+
/** Relevance to this query, normalised so the top entry is 1.0. */
|
|
37
|
+
relevance: number;
|
|
38
|
+
/** Whether any symbol here matched the query lexically. */
|
|
39
|
+
matched: boolean;
|
|
40
|
+
symbols: ContextSymbol[];
|
|
41
|
+
}
|
|
42
|
+
export interface ContextResult {
|
|
43
|
+
query: string;
|
|
44
|
+
entries: ContextEntry[];
|
|
45
|
+
/** Lexical hits that seeded the walk. Zero means nothing matched. */
|
|
46
|
+
seedCount: number;
|
|
47
|
+
/** Semantic hits that also seeded it. */
|
|
48
|
+
semanticSeedCount: number;
|
|
49
|
+
/** Files the walk reached before truncation to `limit`. */
|
|
50
|
+
totalCandidates: number;
|
|
51
|
+
indexStatus: 'ok' | 'no-index' | 'no-matches' | 'unranked';
|
|
52
|
+
}
|
|
53
|
+
export interface ContextOptions {
|
|
54
|
+
query: string;
|
|
55
|
+
/**
|
|
56
|
+
* Files a semantic search already matched, with their cosine scores.
|
|
57
|
+
*
|
|
58
|
+
* Supplied by the caller rather than computed here because the embedding
|
|
59
|
+
* model lives host-side — functions cannot cross the daemon's IPC boundary,
|
|
60
|
+
* so only the resulting file scores travel. These become additional restart
|
|
61
|
+
* mass, letting a query phrased in the problem's vocabulary reach code whose
|
|
62
|
+
* identifiers never use those words.
|
|
63
|
+
*/
|
|
64
|
+
vectorFiles?: ReadonlyArray<{
|
|
65
|
+
file: string;
|
|
66
|
+
score: number;
|
|
67
|
+
}> | undefined;
|
|
68
|
+
/** Files to return. */
|
|
69
|
+
limit?: number | undefined;
|
|
70
|
+
/** Symbols to show per file. */
|
|
71
|
+
symbolsPerFile?: number | undefined;
|
|
72
|
+
/** Restrict results to files under this project-relative prefix. */
|
|
73
|
+
pathPrefix?: string | undefined;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Lexical hits used as restart mass. More seeds make the walk broader and
|
|
77
|
+
* blunter; this is enough to cover a multi-word query's separate senses
|
|
78
|
+
* without letting a common token dominate.
|
|
79
|
+
*/
|
|
80
|
+
export declare const SEED_LIMIT = 40;
|
|
81
|
+
export declare const DEFAULT_LIMIT = 12;
|
|
82
|
+
export declare const DEFAULT_SYMBOLS_PER_FILE = 4;
|
|
83
|
+
/**
|
|
84
|
+
* Run the personalised walk and group the winners into files.
|
|
85
|
+
*
|
|
86
|
+
* Returns an empty result rather than throwing whenever the index cannot
|
|
87
|
+
* answer — an unbuilt index and a query nobody matches are ordinary states,
|
|
88
|
+
* and `indexStatus` says which one happened.
|
|
89
|
+
*/
|
|
90
|
+
export declare function retrieveContext(store: IndexStore, projectRoot: string, indexDir: string | undefined, options: ContextOptions, relativeOf: (file: string) => string): ContextResult;
|
|
91
|
+
//# sourceMappingURL=context-retrieval.d.ts.map
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The semantic embedding pass.
|
|
3
|
+
*
|
|
4
|
+
* Embeds one vector per file so the index can answer questions phrased in the
|
|
5
|
+
* problem's vocabulary rather than the code's — "where do we back off after a
|
|
6
|
+
* 429" instead of `retryAfterMsFromHeaders`.
|
|
7
|
+
*
|
|
8
|
+
* ## What gets embedded, and why it is the file
|
|
9
|
+
*
|
|
10
|
+
* A bare declaration is poor material for an embedding: `function resolve(id:
|
|
11
|
+
* string): Widget` carries almost nothing a lexical index does not already
|
|
12
|
+
* have, and BM25 over FTS5 already matches it better. What carries meaning is
|
|
13
|
+
* the concept layer's description of what a file is *for*, so that is the text
|
|
14
|
+
* this pass embeds, falling back to the file's declaration names when no
|
|
15
|
+
* summary exists yet.
|
|
16
|
+
*
|
|
17
|
+
* That also makes it eight times cheaper than a symbol-level pass on this
|
|
18
|
+
* repository — eight thousand files against sixty-six thousand symbols.
|
|
19
|
+
*
|
|
20
|
+
* ## Why it is a pass and not part of indexing
|
|
21
|
+
*
|
|
22
|
+
* Model inference is asynchronous and batched. The indexer's write path is a
|
|
23
|
+
* synchronous SQLite transaction; running inference inside it would hold a
|
|
24
|
+
* write lock open across thousands of inferences. The older char-trigram
|
|
25
|
+
* embedding could live there precisely because it was neither of those things
|
|
26
|
+
* — and it was also not semantic, which is why it is being superseded rather
|
|
27
|
+
* than extended.
|
|
28
|
+
*
|
|
29
|
+
* ## Why the vectors never silently mix
|
|
30
|
+
*
|
|
31
|
+
* Two models produce incomparable spaces. The provider id is stored with every
|
|
32
|
+
* row and checked before a pass; a change wipes the table and re-embeds rather
|
|
33
|
+
* than leaving half the index in one space and half in another.
|
|
34
|
+
*/
|
|
35
|
+
import { type IndexStore } from './writer.js';
|
|
36
|
+
/**
|
|
37
|
+
* The host-supplied embedding model.
|
|
38
|
+
*
|
|
39
|
+
* Structurally identical to the `EmbeddingProvider` that
|
|
40
|
+
* `packages/vector-memory` already defines, so its transformers-backed
|
|
41
|
+
* implementation satisfies this without an adapter. Injected rather than
|
|
42
|
+
* imported for the same reason the summariser is: `packages/tools` must not
|
|
43
|
+
* depend on an optional native model runtime.
|
|
44
|
+
*/
|
|
45
|
+
export interface EmbeddingPort {
|
|
46
|
+
/** Stable id including the model and quantisation. Changing it re-embeds. */
|
|
47
|
+
readonly id: string;
|
|
48
|
+
/** Vector length. Must not change for a given `id`. */
|
|
49
|
+
readonly dimensions: number;
|
|
50
|
+
/** Embed a batch. Must return exactly one vector per input, in order. */
|
|
51
|
+
embed(texts: string[]): Promise<Float32Array[]>;
|
|
52
|
+
}
|
|
53
|
+
/** Texts sent per inference call. */
|
|
54
|
+
export declare const DEFAULT_BATCH_SIZE = 16;
|
|
55
|
+
/** Ceiling on embedded text. Beyond this a summary is not a summary. */
|
|
56
|
+
export declare const MAX_EMBED_CHARS = 2000;
|
|
57
|
+
export interface EmbedOptions {
|
|
58
|
+
/** Stop after this many files. */
|
|
59
|
+
maxFiles?: number | undefined;
|
|
60
|
+
batchSize?: number | undefined;
|
|
61
|
+
/** Re-embed even when the stored text hash still matches. */
|
|
62
|
+
force?: boolean | undefined;
|
|
63
|
+
signal?: AbortSignal | undefined;
|
|
64
|
+
onProgress?: ((done: number, total: number) => void) | undefined;
|
|
65
|
+
}
|
|
66
|
+
export interface EmbedResult {
|
|
67
|
+
embedded: number;
|
|
68
|
+
/** Files whose embedded text was unchanged. */
|
|
69
|
+
cached: number;
|
|
70
|
+
/** Vectors dropped because their file left the index. */
|
|
71
|
+
pruned: number;
|
|
72
|
+
/** True when a provider change forced a full re-embed. */
|
|
73
|
+
providerChanged: boolean;
|
|
74
|
+
/** Files with no summary, embedded from their declaration names instead. */
|
|
75
|
+
fromDeclarations: number;
|
|
76
|
+
durationMs: number;
|
|
77
|
+
errors: string[];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Run one embedding pass. Never throws: an inference failure costs that batch
|
|
81
|
+
* its vectors, is recorded in `errors`, and the walk continues.
|
|
82
|
+
*/
|
|
83
|
+
export declare function embedFiles(store: IndexStore, port: EmbeddingPort, relativeOf: (file: string) => string, options?: EmbedOptions): Promise<EmbedResult>;
|
|
84
|
+
/** Reported when a project has no index to embed. */
|
|
85
|
+
export type EmbedIndexMissing = {
|
|
86
|
+
indexed: false;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Embed a project's files, owning the store lifetime so callers outside this
|
|
90
|
+
* package never touch `indexStorePool`. Refuses to run without an index.
|
|
91
|
+
*/
|
|
92
|
+
export declare function embedProjectFiles(projectRoot: string, port: EmbeddingPort, options?: EmbedOptions & {
|
|
93
|
+
indexDir?: string | undefined;
|
|
94
|
+
}): Promise<EmbedResult | EmbedIndexMissing>;
|
|
95
|
+
//# sourceMappingURL=embedding-pass.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local cache of the wiring graph.
|
|
3
|
+
*
|
|
4
|
+
* Building the graph means pulling ~180k resolved refs, ~66k symbol→file
|
|
5
|
+
* pairs, the homonym counts and the import-visibility map, then laying the
|
|
6
|
+
* whole thing out as CSR — around half a second on this repo. That is fine
|
|
7
|
+
* once per index generation and unacceptable once per query, and the
|
|
8
|
+
* personalised retrieval walk is a per-query operation.
|
|
9
|
+
*
|
|
10
|
+
* The cache holds one graph. In the detached project server that is exactly
|
|
11
|
+
* right: one daemon serves one project. A caller for a different project (or
|
|
12
|
+
* a different index directory) simply replaces the entry rather than growing
|
|
13
|
+
* a map that would keep tens of megabytes alive for a project nobody is
|
|
14
|
+
* querying any more.
|
|
15
|
+
*
|
|
16
|
+
* Freshness is decided by the index's own `last_indexed` stamp plus the row
|
|
17
|
+
* counts, read fresh on every request. That costs three trivial queries and
|
|
18
|
+
* makes the cache self-invalidating from any path — daemon, worker, or
|
|
19
|
+
* inline — without having to be wired into the server's generation plumbing.
|
|
20
|
+
*/
|
|
21
|
+
import { type WiringGraph } from './graph-rank.js';
|
|
22
|
+
import type { IndexStore } from './writer.js';
|
|
23
|
+
/** Everything the walk needs, built together and invalidated together. */
|
|
24
|
+
export interface WiringSnapshot {
|
|
25
|
+
graph: WiringGraph;
|
|
26
|
+
/** Declaring file per symbol id — the walk reports files, not just nodes. */
|
|
27
|
+
fileOf: ReadonlyMap<number, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Return the wiring graph for this store, building it only when the index has
|
|
31
|
+
* changed since the last call.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getWiringSnapshot(store: IndexStore, projectRoot: string, indexDir: string | undefined): WiringSnapshot;
|
|
34
|
+
/** Drop the cached graph. Tests and shutdown paths only. */
|
|
35
|
+
export declare function clearWiringSnapshot(): void;
|
|
36
|
+
//# sourceMappingURL=graph-adjacency-cache.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The index-time centrality pass.
|
|
3
|
+
*
|
|
4
|
+
* Runs inside the indexer's atomic update, immediately after ref resolution
|
|
5
|
+
* and module resolution have settled: `refs.to_id` is only final at that
|
|
6
|
+
* point, and a rank computed from half-resolved refs would describe a graph
|
|
7
|
+
* that never existed.
|
|
8
|
+
*
|
|
9
|
+
* Rank is a property of the whole graph, so this recomputes everything or
|
|
10
|
+
* nothing. That is affordable on a full run and wasteful on a one-file
|
|
11
|
+
* watcher run, which is what {@link shouldRefreshRanks} arbitrates.
|
|
12
|
+
*/
|
|
13
|
+
import type { IndexStore } from './writer.js';
|
|
14
|
+
/**
|
|
15
|
+
* Data-version marker for the rank layer, in the same spirit as
|
|
16
|
+
* `relation_graph_version`: bumping it forces every index to recompute ranks
|
|
17
|
+
* once without a `SCHEMA_VERSION` bump (which would drop and rebuild the
|
|
18
|
+
* entire database). Older processes sharing the DB cannot downgrade it.
|
|
19
|
+
*/
|
|
20
|
+
export declare const RANK_VERSION = "1";
|
|
21
|
+
export declare const RANK_VERSION_KEY = "rank_version";
|
|
22
|
+
/**
|
|
23
|
+
* Above this many files in a targeted run, recompute. A watcher run that
|
|
24
|
+
* touches one file barely moves any score, so leaving ranks one generation
|
|
25
|
+
* stale is the cheaper trade; a bulk targeted run is effectively a full run
|
|
26
|
+
* and should not be served stale ranks.
|
|
27
|
+
*/
|
|
28
|
+
export declare const RANK_REFRESH_FILE_THRESHOLD = 25;
|
|
29
|
+
export interface RankPassResult {
|
|
30
|
+
/** False when the pass decided the existing ranks were good enough. */
|
|
31
|
+
computed: boolean;
|
|
32
|
+
symbols: number;
|
|
33
|
+
files: number;
|
|
34
|
+
durationMs: number;
|
|
35
|
+
}
|
|
36
|
+
export declare function shouldRefreshRanks(store: IndexStore, opts: {
|
|
37
|
+
files?: readonly string[] | undefined;
|
|
38
|
+
force?: boolean | undefined;
|
|
39
|
+
}): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Recompute and persist both rank tables. Never throws: a failed rank pass
|
|
42
|
+
* leaves the previous (or empty) ranks in place and must not take the index
|
|
43
|
+
* run down with it — every consumer treats a missing rank as "unranked".
|
|
44
|
+
*/
|
|
45
|
+
export declare function runGraphRankPass(store: IndexStore, errors: string[]): RankPassResult;
|
|
46
|
+
//# sourceMappingURL=graph-rank-pass.d.ts.map
|