@massa-ai/core 1.17.0 → 1.18.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.
- package/dist/services/cache/lru-evict.d.ts +63 -0
- package/dist/services/cache/lru-evict.d.ts.map +1 -0
- package/dist/services/cache/lru-evict.js +76 -0
- package/dist/services/cache/lru-evict.js.map +1 -0
- package/dist/services/file-read/file-content-cache.d.ts +41 -0
- package/dist/services/file-read/file-content-cache.d.ts.map +1 -0
- package/dist/services/file-read/file-content-cache.js +109 -0
- package/dist/services/file-read/file-content-cache.js.map +1 -0
- package/dist/services/file-read/file-metadata.d.ts +23 -0
- package/dist/services/file-read/file-metadata.d.ts.map +1 -0
- package/dist/services/file-read/file-metadata.js +127 -0
- package/dist/services/file-read/file-metadata.js.map +1 -0
- package/dist/services/file-read/line-range.d.ts +91 -0
- package/dist/services/file-read/line-range.d.ts.map +1 -0
- package/dist/services/file-read/line-range.js +146 -0
- package/dist/services/file-read/line-range.js.map +1 -0
- package/dist/services/file-read/path-containment.d.ts +49 -0
- package/dist/services/file-read/path-containment.d.ts.map +1 -0
- package/dist/services/file-read/path-containment.js +128 -0
- package/dist/services/file-read/path-containment.js.map +1 -0
- package/dist/services/file-read/project-root-cache.d.ts +21 -0
- package/dist/services/file-read/project-root-cache.d.ts.map +1 -0
- package/dist/services/file-read/project-root-cache.js +78 -0
- package/dist/services/file-read/project-root-cache.js.map +1 -0
- package/dist/services/file-read/read-file.service.d.ts +68 -0
- package/dist/services/file-read/read-file.service.d.ts.map +1 -0
- package/dist/services/file-read/read-file.service.js +222 -0
- package/dist/services/file-read/read-file.service.js.map +1 -0
- package/dist/services/hooks/co-retrieval-hook.js +1 -1
- package/dist/services/hooks/co-retrieval-hook.js.map +1 -1
- package/dist/services/index.d.ts +5 -5
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +4 -4
- package/dist/services/index.js.map +1 -1
- package/dist/services/indexing/acquire-indexing-lease.d.ts +34 -0
- package/dist/services/indexing/acquire-indexing-lease.d.ts.map +1 -0
- package/dist/services/indexing/acquire-indexing-lease.js +101 -0
- package/dist/services/indexing/acquire-indexing-lease.js.map +1 -0
- package/dist/services/indexing/execute-indexing.d.ts +33 -0
- package/dist/services/indexing/execute-indexing.d.ts.map +1 -0
- package/dist/services/indexing/execute-indexing.js +136 -0
- package/dist/services/indexing/execute-indexing.js.map +1 -0
- package/dist/services/jobs/memory-consolidation-job.js +1 -1
- package/dist/services/jobs/memory-consolidation-job.js.map +1 -1
- package/dist/services/memory/memory-controller.js +1 -1
- package/dist/services/memory/memory-controller.js.map +1 -1
- package/dist/services/memory-graph/graph-queries.d.ts.map +1 -0
- package/dist/services/memory-graph/graph-queries.js.map +1 -0
- package/dist/services/memory-graph/graph-store-factory.d.ts.map +1 -0
- package/dist/services/memory-graph/graph-store-factory.js.map +1 -0
- package/dist/services/memory-graph/graph-store-pg.d.ts.map +1 -0
- package/dist/services/memory-graph/graph-store-pg.js.map +1 -0
- package/dist/services/memory-graph/index.d.ts.map +1 -0
- package/dist/services/memory-graph/index.js.map +1 -0
- package/dist/services/memory-graph/memory-graph.service.d.ts.map +1 -0
- package/dist/services/memory-graph/memory-graph.service.js.map +1 -0
- package/dist/services/memory-graph/relation-extractor.d.ts.map +1 -0
- package/dist/services/memory-graph/relation-extractor.js.map +1 -0
- package/dist/services/memory-graph/types.d.ts.map +1 -0
- package/dist/services/memory-graph/types.js.map +1 -0
- package/dist/services/project-identity/invalidator-registry.d.ts +9 -3
- package/dist/services/project-identity/invalidator-registry.d.ts.map +1 -1
- package/dist/services/project-identity/invalidator-registry.js +9 -3
- package/dist/services/project-identity/invalidator-registry.js.map +1 -1
- package/dist/services/project-identity/production-wiring.d.ts +11 -2
- package/dist/services/project-identity/production-wiring.d.ts.map +1 -1
- package/dist/services/project-identity/production-wiring.js +11 -2
- package/dist/services/project-identity/production-wiring.js.map +1 -1
- package/dist/services/project-identity/project-root-identity.d.ts +11 -0
- package/dist/services/project-identity/project-root-identity.d.ts.map +1 -0
- package/dist/services/project-identity/project-root-identity.js +51 -0
- package/dist/services/project-identity/project-root-identity.js.map +1 -0
- package/dist/services/search/file-filter-cache.d.ts +30 -1
- package/dist/services/search/file-filter-cache.d.ts.map +1 -1
- package/dist/services/search/file-filter-cache.js +32 -13
- package/dist/services/search/file-filter-cache.js.map +1 -1
- package/dist/services/search/graph-stream.js +1 -1
- package/dist/services/search/graph-stream.js.map +1 -1
- package/dist/services/symbol/symbol-graph.service.d.ts +12 -1
- package/dist/services/symbol/symbol-graph.service.d.ts.map +1 -1
- package/dist/services/symbol/symbol-graph.service.js +14 -7
- package/dist/services/symbol/symbol-graph.service.js.map +1 -1
- package/dist/services/web/web-controller.d.ts.map +1 -1
- package/dist/services/web/web-controller.js +6 -7
- package/dist/services/web/web-controller.js.map +1 -1
- package/dist/tools/batch_execute.d.ts +0 -3
- package/dist/tools/batch_execute.d.ts.map +1 -1
- package/dist/tools/batch_execute.js.map +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index_project.d.ts +0 -19
- package/dist/tools/index_project.d.ts.map +1 -1
- package/dist/tools/index_project.js +38 -142
- package/dist/tools/index_project.js.map +1 -1
- package/dist/tools/read_file.d.ts +9 -72
- package/dist/tools/read_file.d.ts.map +1 -1
- package/dist/tools/read_file.js +22 -487
- package/dist/tools/read_file.js.map +1 -1
- package/package.json +2 -2
- package/dist/data/vector/hybrid-search.d.ts +0 -71
- package/dist/data/vector/hybrid-search.d.ts.map +0 -1
- package/dist/data/vector/hybrid-search.js +0 -243
- package/dist/data/vector/hybrid-search.js.map +0 -1
- package/dist/data/vector/index.d.ts +0 -7
- package/dist/data/vector/index.d.ts.map +0 -1
- package/dist/data/vector/index.js +0 -6
- package/dist/data/vector/index.js.map +0 -1
- package/dist/services/graph/graph-queries.d.ts.map +0 -1
- package/dist/services/graph/graph-queries.js.map +0 -1
- package/dist/services/graph/graph-store-factory.d.ts.map +0 -1
- package/dist/services/graph/graph-store-factory.js.map +0 -1
- package/dist/services/graph/graph-store-pg.d.ts.map +0 -1
- package/dist/services/graph/graph-store-pg.js.map +0 -1
- package/dist/services/graph/index.d.ts.map +0 -1
- package/dist/services/graph/index.js.map +0 -1
- package/dist/services/graph/memory-graph.service.d.ts.map +0 -1
- package/dist/services/graph/memory-graph.service.js.map +0 -1
- package/dist/services/graph/relation-extractor.d.ts.map +0 -1
- package/dist/services/graph/relation-extractor.js.map +0 -1
- package/dist/services/graph/types.d.ts.map +0 -1
- package/dist/services/graph/types.js.map +0 -1
- /package/dist/services/{graph → memory-graph}/graph-queries.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/graph-queries.js +0 -0
- /package/dist/services/{graph → memory-graph}/graph-store-factory.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/graph-store-factory.js +0 -0
- /package/dist/services/{graph → memory-graph}/graph-store-pg.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/graph-store-pg.js +0 -0
- /package/dist/services/{graph → memory-graph}/index.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/index.js +0 -0
- /package/dist/services/{graph → memory-graph}/memory-graph.service.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/memory-graph.service.js +0 -0
- /package/dist/services/{graph → memory-graph}/relation-extractor.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/relation-extractor.js +0 -0
- /package/dist/services/{graph → memory-graph}/types.d.ts +0 -0
- /package/dist/services/{graph → memory-graph}/types.js +0 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared insertion-order eviction for the LRU-bounded `Map`s PR-D unifies (RFS-02 AC-2).
|
|
3
|
+
*
|
|
4
|
+
* WHY A FUNCTION AND NOT A CACHE CLASS.
|
|
5
|
+
* The five caches this serves agree on eviction ORDER and disagree on everything else: cap
|
|
6
|
+
* (512 at four sites, 50 at `file-filter-cache`), TTL (enforced at `file-content-cache`'s
|
|
7
|
+
* `fileCache` only) and read-promotion (absent at `file-filter-cache`). A shared cache class would impose
|
|
8
|
+
* one policy on all five, and that IS the behavior change `spec.md` §3.B measured the eviction
|
|
9
|
+
* itself is not. RFS-02 AC-2 therefore fixes this as an eviction function; every site keeps its
|
|
10
|
+
* own cap, its own TTL and its own promotion policy.
|
|
11
|
+
*
|
|
12
|
+
* WHY THE SECOND PARAMETER IS A POST-CALL BOUND AND NOT "the cap".
|
|
13
|
+
* `design.md` §5.1 specifies only "a function taking `(cache, cap)`", and that phrasing does
|
|
14
|
+
* not determine the predicate, because the five sites do not share one:
|
|
15
|
+
*
|
|
16
|
+
* file-content-cache.ts (T10) pre-insert while (size >= 512)
|
|
17
|
+
* project-root-cache.ts (T9) pre-insert while (size >= 512)
|
|
18
|
+
* symbol-graph.service.ts pre-insert while (size >= 512)
|
|
19
|
+
* web-controller.ts post-insert while (size > 512)
|
|
20
|
+
* file-filter-cache.ts post-insert if (size > 50) evict-one
|
|
21
|
+
*
|
|
22
|
+
* `spec.md` §3.B establishes that pre-insert `>=` and post-insert `>` retain the same number.
|
|
23
|
+
* They do — but only while each site keeps BOTH its operator and its call position. Collapsing
|
|
24
|
+
* them onto one operator with every site passing its own literal cap moves the retained count,
|
|
25
|
+
* and it moves in opposite directions depending on which operator wins. Measured against T1's
|
|
26
|
+
* characterization oracle (`tasks.md` §10.7): a shared `>` breaks the three pre-insert sites, a
|
|
27
|
+
* shared `>=` breaks the two post-insert ones.
|
|
28
|
+
*
|
|
29
|
+
* Stating the contract as a POST-CALL BOUND is what lets one function serve both call
|
|
30
|
+
* positions without moving any retained count, because `size > cap - 1` and `size >= cap` are
|
|
31
|
+
* the same predicate over integers:
|
|
32
|
+
*
|
|
33
|
+
* pre-insert caller passes `CAP - 1` — reserves the slot the pending insert will take
|
|
34
|
+
* post-insert caller passes `CAP` — the insert already happened
|
|
35
|
+
*
|
|
36
|
+
* WHAT THIS MODULE DOES NOT CERTIFY, on RFS-01 AC-6's precedent of naming blind spots.
|
|
37
|
+
* It evicts in `Map` insertion order and knows nothing about TTL, read-promotion, or whether a
|
|
38
|
+
* caller's insertion order matches that caller's own notion of "oldest". `file-filter-cache`
|
|
39
|
+
* evicts by `min(createdAt)` today and coincides with insertion order only because it never
|
|
40
|
+
* re-inserts an entry on a read — an invariant unstated in that file, guarded by T1's
|
|
41
|
+
* characterization suite (mutation M5b) and by nothing here. A future read-promotion added
|
|
42
|
+
* there would silently defeat the shared eviction and no structural gate could see it.
|
|
43
|
+
*
|
|
44
|
+
* WHY IT IMPORTS NOTHING, AND WHY THAT IS ASSERTED IN A TEST RATHER THAN BY CI.
|
|
45
|
+
* `spec.md` RFS-02 AC-3 originally placed this in `kernel/`, where `check-core-layering`'s
|
|
46
|
+
* leaf-ness clause would have enforced import-freedom. C30 (`design.md` §5.2) moved it to
|
|
47
|
+
* `services/cache/` because `kernel/`'s admission rule is "serves >= 2 tiers" and 11 of 11
|
|
48
|
+
* shipped members keep it, while this module serves `services/` alone after Phase 3. Nothing
|
|
49
|
+
* in CI now prevents this file from growing a dependency. That is a real loss of enforcement
|
|
50
|
+
* (R-29), recorded rather than glossed, and the replacement is the AST assertion in this
|
|
51
|
+
* module's own unit test.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Evict oldest-first from `cache` until `cache.size <= maxRetained`.
|
|
55
|
+
*
|
|
56
|
+
* @param cache any `Map`; eviction order is the Map's own insertion order, so a caller
|
|
57
|
+
* that promotes on read (delete + re-set) gets LRU and one that does not
|
|
58
|
+
* gets FIFO. That choice stays with the caller.
|
|
59
|
+
* @param maxRetained the number of entries that may remain when this returns. Pre-insert
|
|
60
|
+
* callers pass `CAP - 1`; post-insert callers pass `CAP`.
|
|
61
|
+
*/
|
|
62
|
+
export declare function evictOldest<K, V>(cache: Map<K, V>, maxRetained: number): void;
|
|
63
|
+
//# sourceMappingURL=lru-evict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lru-evict.d.ts","sourceRoot":"","sources":["../../../src/services/cache/lru-evict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAY7E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared insertion-order eviction for the LRU-bounded `Map`s PR-D unifies (RFS-02 AC-2).
|
|
3
|
+
*
|
|
4
|
+
* WHY A FUNCTION AND NOT A CACHE CLASS.
|
|
5
|
+
* The five caches this serves agree on eviction ORDER and disagree on everything else: cap
|
|
6
|
+
* (512 at four sites, 50 at `file-filter-cache`), TTL (enforced at `file-content-cache`'s
|
|
7
|
+
* `fileCache` only) and read-promotion (absent at `file-filter-cache`). A shared cache class would impose
|
|
8
|
+
* one policy on all five, and that IS the behavior change `spec.md` §3.B measured the eviction
|
|
9
|
+
* itself is not. RFS-02 AC-2 therefore fixes this as an eviction function; every site keeps its
|
|
10
|
+
* own cap, its own TTL and its own promotion policy.
|
|
11
|
+
*
|
|
12
|
+
* WHY THE SECOND PARAMETER IS A POST-CALL BOUND AND NOT "the cap".
|
|
13
|
+
* `design.md` §5.1 specifies only "a function taking `(cache, cap)`", and that phrasing does
|
|
14
|
+
* not determine the predicate, because the five sites do not share one:
|
|
15
|
+
*
|
|
16
|
+
* file-content-cache.ts (T10) pre-insert while (size >= 512)
|
|
17
|
+
* project-root-cache.ts (T9) pre-insert while (size >= 512)
|
|
18
|
+
* symbol-graph.service.ts pre-insert while (size >= 512)
|
|
19
|
+
* web-controller.ts post-insert while (size > 512)
|
|
20
|
+
* file-filter-cache.ts post-insert if (size > 50) evict-one
|
|
21
|
+
*
|
|
22
|
+
* `spec.md` §3.B establishes that pre-insert `>=` and post-insert `>` retain the same number.
|
|
23
|
+
* They do — but only while each site keeps BOTH its operator and its call position. Collapsing
|
|
24
|
+
* them onto one operator with every site passing its own literal cap moves the retained count,
|
|
25
|
+
* and it moves in opposite directions depending on which operator wins. Measured against T1's
|
|
26
|
+
* characterization oracle (`tasks.md` §10.7): a shared `>` breaks the three pre-insert sites, a
|
|
27
|
+
* shared `>=` breaks the two post-insert ones.
|
|
28
|
+
*
|
|
29
|
+
* Stating the contract as a POST-CALL BOUND is what lets one function serve both call
|
|
30
|
+
* positions without moving any retained count, because `size > cap - 1` and `size >= cap` are
|
|
31
|
+
* the same predicate over integers:
|
|
32
|
+
*
|
|
33
|
+
* pre-insert caller passes `CAP - 1` — reserves the slot the pending insert will take
|
|
34
|
+
* post-insert caller passes `CAP` — the insert already happened
|
|
35
|
+
*
|
|
36
|
+
* WHAT THIS MODULE DOES NOT CERTIFY, on RFS-01 AC-6's precedent of naming blind spots.
|
|
37
|
+
* It evicts in `Map` insertion order and knows nothing about TTL, read-promotion, or whether a
|
|
38
|
+
* caller's insertion order matches that caller's own notion of "oldest". `file-filter-cache`
|
|
39
|
+
* evicts by `min(createdAt)` today and coincides with insertion order only because it never
|
|
40
|
+
* re-inserts an entry on a read — an invariant unstated in that file, guarded by T1's
|
|
41
|
+
* characterization suite (mutation M5b) and by nothing here. A future read-promotion added
|
|
42
|
+
* there would silently defeat the shared eviction and no structural gate could see it.
|
|
43
|
+
*
|
|
44
|
+
* WHY IT IMPORTS NOTHING, AND WHY THAT IS ASSERTED IN A TEST RATHER THAN BY CI.
|
|
45
|
+
* `spec.md` RFS-02 AC-3 originally placed this in `kernel/`, where `check-core-layering`'s
|
|
46
|
+
* leaf-ness clause would have enforced import-freedom. C30 (`design.md` §5.2) moved it to
|
|
47
|
+
* `services/cache/` because `kernel/`'s admission rule is "serves >= 2 tiers" and 11 of 11
|
|
48
|
+
* shipped members keep it, while this module serves `services/` alone after Phase 3. Nothing
|
|
49
|
+
* in CI now prevents this file from growing a dependency. That is a real loss of enforcement
|
|
50
|
+
* (R-29), recorded rather than glossed, and the replacement is the AST assertion in this
|
|
51
|
+
* module's own unit test.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Evict oldest-first from `cache` until `cache.size <= maxRetained`.
|
|
55
|
+
*
|
|
56
|
+
* @param cache any `Map`; eviction order is the Map's own insertion order, so a caller
|
|
57
|
+
* that promotes on read (delete + re-set) gets LRU and one that does not
|
|
58
|
+
* gets FIFO. That choice stays with the caller.
|
|
59
|
+
* @param maxRetained the number of entries that may remain when this returns. Pre-insert
|
|
60
|
+
* callers pass `CAP - 1`; post-insert callers pass `CAP`.
|
|
61
|
+
*/
|
|
62
|
+
export function evictOldest(cache, maxRetained) {
|
|
63
|
+
while (cache.size > maxRetained) {
|
|
64
|
+
const oldest = cache.keys().next().value;
|
|
65
|
+
// Defensive and unreachable for any `maxRetained >= 0`: the loop condition forces
|
|
66
|
+
// `cache.size >= 1`, so `keys().next()` always yields an entry. Kept because all four
|
|
67
|
+
// original sites carry it, and dropping it inside a behavior-preserving PR would be an
|
|
68
|
+
// unprovable change. It is NOT here for the 90% line-coverage floor — that gate parses
|
|
69
|
+
// `DA:` records only (`scripts/check-coverage.ts:320`), never `BRDA:`, so this line counts
|
|
70
|
+
// as covered the moment it is evaluated, whichever way the branch goes.
|
|
71
|
+
if (oldest === undefined)
|
|
72
|
+
break;
|
|
73
|
+
cache.delete(oldest);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=lru-evict.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lru-evict.js","sourceRoot":"","sources":["../../../src/services/cache/lru-evict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAO,KAAgB,EAAE,WAAmB;IACrE,OAAO,KAAK,CAAC,IAAI,GAAG,WAAW,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACzC,kFAAkF;QAClF,sFAAsF;QACtF,uFAAuF;QACvF,uFAAuF;QACvF,2FAA2F;QAC3F,wEAAwE;QACxE,IAAI,MAAM,KAAK,SAAS;YAAE,MAAM;QAChC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { FileMetadata } from "./file-metadata.js";
|
|
2
|
+
export interface CachedFile {
|
|
3
|
+
content: string;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
metadata?: FileMetadata;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The 4 → 5 edge. Module 7 (`read-file.service.ts`) binds this with the
|
|
9
|
+
* `symbolGraph` forwarded to it from `ReadFileTool`'s constructor parameter.
|
|
10
|
+
* Bound there since T12; `ReadFileTool` itself bound it from T10 until then.
|
|
11
|
+
*/
|
|
12
|
+
export type MetadataExtractor = (content: string, filePath: string, options: {
|
|
13
|
+
includeSymbols: boolean;
|
|
14
|
+
includeImports: boolean;
|
|
15
|
+
projectId?: string;
|
|
16
|
+
relativePath?: string;
|
|
17
|
+
}) => Promise<FileMetadata>;
|
|
18
|
+
export declare class FileContentCache {
|
|
19
|
+
private readonly extractMetadata;
|
|
20
|
+
private fileCache;
|
|
21
|
+
private readonly CACHE_TTL;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum entries retained in the cache. Without a cap, an adversarial caller
|
|
24
|
+
* cycling distinct cache keys grows the map for the process lifetime. Map
|
|
25
|
+
* preserves INSERTION order in JS; we promote a key to most-recently-used on
|
|
26
|
+
* GET via delete+set, and evict the oldest key on SET while over the cap.
|
|
27
|
+
* Mirrors WebController's WEB_CACHE_MAX_ENTRIES.
|
|
28
|
+
*/
|
|
29
|
+
private readonly FILE_CACHE_MAX_ENTRIES;
|
|
30
|
+
constructor(extractMetadata: MetadataExtractor);
|
|
31
|
+
readFileWithCache(filePath: string, options: {
|
|
32
|
+
includeSymbols: boolean;
|
|
33
|
+
includeImports: boolean;
|
|
34
|
+
projectId?: string;
|
|
35
|
+
relativePath?: string;
|
|
36
|
+
}): Promise<{
|
|
37
|
+
content: string;
|
|
38
|
+
metadata: FileMetadata;
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=file-content-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-content-cache.d.ts","sourceRoot":"","sources":["../../../src/services/file-read/file-content-cache.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC9B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;IACP,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,KACE,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,qBAAa,gBAAgB;IAYf,OAAO,CAAC,QAAQ,CAAC,eAAe;IAX5C,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAO;gBAEjB,eAAe,EAAE,iBAAiB;IAEzD,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QACP,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACA,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,YAAY,CAAA;KAAE,CAAC;CAuDxD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @massa-ai/core - File content cache
|
|
3
|
+
*
|
|
4
|
+
* Module 4 of the `tools/read_file.ts` extraction (PR-D, T10). Owns the
|
|
5
|
+
* TTL-and-LRU-bounded file CONTENT cache `ReadFileTool` used to carry as
|
|
6
|
+
* private state: `readFileWithCache`, the `fileCache` Map, `CACHE_TTL`,
|
|
7
|
+
* `FILE_CACHE_MAX_ENTRIES` and the `CachedFile` shape.
|
|
8
|
+
*
|
|
9
|
+
* `readFileWithCache`'s BODY IS MOVED VERBATIM apart from one line. The private
|
|
10
|
+
* `ReadFileTool.evictOldest` wrapper it used to call no longer exists — its body
|
|
11
|
+
* read `this.FILE_CACHE_MAX_ENTRIES`, which this module takes, so the wrapper
|
|
12
|
+
* could not survive this task even as dead code — and the call is now the shared
|
|
13
|
+
* operator directly, on module 3's exact shape:
|
|
14
|
+
* `evictOldest(map, CAP - 1)`. `lru-evict.ts`'s second parameter is a POST-CALL
|
|
15
|
+
* BOUND rather than the cap, so a pre-insert caller passes `CAP - 1` to reserve
|
|
16
|
+
* the slot the pending `set()` takes; `size > CAP - 1` and `size >= CAP` are the
|
|
17
|
+
* same predicate over the integers, so the retained count at this call position
|
|
18
|
+
* is unchanged (C44).
|
|
19
|
+
*
|
|
20
|
+
* IT NEVER NAMES SymbolGraphService. Metadata extraction arrives as a
|
|
21
|
+
* constructor callback (`tasks.md` §4.1, decided there with its rejected
|
|
22
|
+
* option), and the parameter is deliberately named `extractMetadata` so the
|
|
23
|
+
* moved body's two call sites — the legacy-entry repair path and the cache
|
|
24
|
+
* miss — read exactly as they did before the move. The type-only import of
|
|
25
|
+
* `FileMetadata` from module 5 is unavoidable and is not what §4.1 forbids:
|
|
26
|
+
* `SymbolGraphService` is the database-backed collaborator the callback exists
|
|
27
|
+
* to keep out of this file.
|
|
28
|
+
*
|
|
29
|
+
* INSTANTIATED PER ReadFileTool, on module 3's precedent — each tool owned its
|
|
30
|
+
* own `fileCache` Map before the move, so a module singleton would leak cached
|
|
31
|
+
* file content between independently-constructed tools. That is a behavior
|
|
32
|
+
* change, and this extraction is behavior-preserving by contract (RFS-02 AC-1).
|
|
33
|
+
*
|
|
34
|
+
* CACHE_TTL IS ENFORCED HERE and that is the half of RFS-02 AC-4 that holds.
|
|
35
|
+
* `__tests__/read-file-project-root-rename-pin.test.ts` measured it: past 60 s
|
|
36
|
+
* the content re-reads. Its sibling `ROOT_CACHE_TTL` in
|
|
37
|
+
* `project-root-cache.ts` is declared and read nowhere, so that cache is
|
|
38
|
+
* LRU-bounded only. The two constants were never related and are now not even
|
|
39
|
+
* in the same file.
|
|
40
|
+
*/
|
|
41
|
+
import { logger } from "@massa-ai/shared";
|
|
42
|
+
import fs from "fs/promises";
|
|
43
|
+
import { evictOldest } from "../cache/lru-evict.js";
|
|
44
|
+
export class FileContentCache {
|
|
45
|
+
extractMetadata;
|
|
46
|
+
fileCache = new Map();
|
|
47
|
+
CACHE_TTL = 60000; // 1 minute
|
|
48
|
+
/**
|
|
49
|
+
* Maximum entries retained in the cache. Without a cap, an adversarial caller
|
|
50
|
+
* cycling distinct cache keys grows the map for the process lifetime. Map
|
|
51
|
+
* preserves INSERTION order in JS; we promote a key to most-recently-used on
|
|
52
|
+
* GET via delete+set, and evict the oldest key on SET while over the cap.
|
|
53
|
+
* Mirrors WebController's WEB_CACHE_MAX_ENTRIES.
|
|
54
|
+
*/
|
|
55
|
+
FILE_CACHE_MAX_ENTRIES = 512;
|
|
56
|
+
constructor(extractMetadata) {
|
|
57
|
+
this.extractMetadata = extractMetadata;
|
|
58
|
+
}
|
|
59
|
+
async readFileWithCache(filePath, options) {
|
|
60
|
+
// Cache key MUST include every option that changes metadata extraction.
|
|
61
|
+
// Keying on filePath alone returned stale, options-baked metadata for a
|
|
62
|
+
// later read of the same file with different includeSymbols/includeImports/
|
|
63
|
+
// projectId/relativePath (the only e2e red — 08.search F33). Deliberately
|
|
64
|
+
// exclude offset/limit/lineStart/lineEnd/compress/targetRatio/format: those
|
|
65
|
+
// are applied AFTER the cache in handle(), and coalescing them across reads
|
|
66
|
+
// is the cache's purpose.
|
|
67
|
+
const cacheKey = JSON.stringify({
|
|
68
|
+
filePath,
|
|
69
|
+
includeSymbols: options.includeSymbols ?? false,
|
|
70
|
+
includeImports: options.includeImports ?? false,
|
|
71
|
+
projectId: options.projectId ?? null,
|
|
72
|
+
relativePath: options.relativePath ?? null,
|
|
73
|
+
});
|
|
74
|
+
const cached = this.fileCache.get(cacheKey);
|
|
75
|
+
// Check cache validity
|
|
76
|
+
if (cached && Date.now() - cached.timestamp < this.CACHE_TTL) {
|
|
77
|
+
logger.debug("File cache hit", { filePath });
|
|
78
|
+
// LRU touch: promote this key to most-recently-used so hot files survive
|
|
79
|
+
// eviction. delete+set reorders the key to the end (newest).
|
|
80
|
+
this.fileCache.delete(cacheKey);
|
|
81
|
+
this.fileCache.set(cacheKey, cached);
|
|
82
|
+
// Legacy/edge entries may have undefined metadata. Re-extract once and
|
|
83
|
+
// WRITE IT BACK into the cache entry so subsequent hits are served from
|
|
84
|
+
// cache instead of re-extracting on every request.
|
|
85
|
+
if (!cached.metadata) {
|
|
86
|
+
const metadata = await this.extractMetadata(cached.content, filePath, options);
|
|
87
|
+
this.fileCache.set(cacheKey, { ...cached, metadata });
|
|
88
|
+
return { content: cached.content, metadata };
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
content: cached.content,
|
|
92
|
+
metadata: cached.metadata,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
// Read file
|
|
96
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
97
|
+
const metadata = await this.extractMetadata(content, filePath, options);
|
|
98
|
+
// Update cache (evict oldest if at cap).
|
|
99
|
+
evictOldest(this.fileCache, this.FILE_CACHE_MAX_ENTRIES - 1);
|
|
100
|
+
this.fileCache.set(cacheKey, {
|
|
101
|
+
content,
|
|
102
|
+
timestamp: Date.now(),
|
|
103
|
+
metadata,
|
|
104
|
+
});
|
|
105
|
+
logger.debug("File read and cached", { filePath });
|
|
106
|
+
return { content, metadata };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=file-content-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-content-cache.js","sourceRoot":"","sources":["../../../src/services/file-read/file-content-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SymbolGraphService } from "../symbol/symbol-graph.service.js";
|
|
2
|
+
export interface FileMetadata {
|
|
3
|
+
totalLines: number;
|
|
4
|
+
language?: string;
|
|
5
|
+
symbols?: {
|
|
6
|
+
definitions: number;
|
|
7
|
+
references: number;
|
|
8
|
+
};
|
|
9
|
+
imports?: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare class FileMetadataExtractor {
|
|
12
|
+
private readonly symbolGraph?;
|
|
13
|
+
constructor(symbolGraph?: SymbolGraphService | undefined);
|
|
14
|
+
extractMetadata(content: string, filePath: string, options: {
|
|
15
|
+
includeSymbols: boolean;
|
|
16
|
+
includeImports: boolean;
|
|
17
|
+
projectId?: string;
|
|
18
|
+
relativePath?: string;
|
|
19
|
+
}): Promise<FileMetadata>;
|
|
20
|
+
private detectLanguage;
|
|
21
|
+
private extractImports;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=file-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-metadata.d.ts","sourceRoot":"","sources":["../../../src/services/file-read/file-metadata.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAE5E,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,qBAAqB;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;gBAAZ,WAAW,CAAC,EAAE,kBAAkB,YAAA;IAEvD,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE;QACP,cAAc,EAAE,OAAO,CAAC;QACxB,cAAc,EAAE,OAAO,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,GACA,OAAO,CAAC,YAAY,CAAC;IAuCxB,OAAO,CAAC,cAAc;IAsCtB,OAAO,CAAC,cAAc;CAwBvB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @massa-ai/core - File metadata extraction
|
|
3
|
+
*
|
|
4
|
+
* Module 5 of the `tools/read_file.ts` extraction (PR-D, T10). Owns the three
|
|
5
|
+
* private methods `ReadFileTool` used to carry for describing a file's content:
|
|
6
|
+
* `extractMetadata` (the composer), `detectLanguage` (extension → language) and
|
|
7
|
+
* `extractImports` (per-language import scan), together with the `FileMetadata`
|
|
8
|
+
* shape they produce.
|
|
9
|
+
*
|
|
10
|
+
* ALL THREE BODIES ARE MOVED VERBATIM, and so is `interface FileMetadata`.
|
|
11
|
+
*
|
|
12
|
+
* IT NAMES SymbolGraphService AND MODULE 4 DOES NOT, WHICH IS THE WHOLE POINT
|
|
13
|
+
* OF THE 4 → 5 EDGE. `design.md` §5.1 records that `readFileWithCache` calls
|
|
14
|
+
* `extractMetadata` on two of three paths and that `extractMetadata` reaches
|
|
15
|
+
* `symbolGraph.listDefinitions`, so a direct edge would make the file CONTENT
|
|
16
|
+
* cache thread a database-backed collaborator through purely to satisfy this
|
|
17
|
+
* module. `tasks.md` §4.1 decided the mechanism — module 4 takes a
|
|
18
|
+
* `(content, filePath, options) => Promise<FileMetadata>` callback — and
|
|
19
|
+
* rejected inverting the call order on measurement rather than on taste: module
|
|
20
|
+
* 7 pre-computing metadata is eager on all three paths, so every cache HIT
|
|
21
|
+
* would newly run a `listDefinitions` query. That is a behavior change inside a
|
|
22
|
+
* behavior-preserving PR, and the callback keeps the laziness and the
|
|
23
|
+
* legacy-entry write-back exactly where they were.
|
|
24
|
+
*
|
|
25
|
+
* INSTANTIATED PER ReadFileTool, on module 3's precedent. `symbolGraph` is the
|
|
26
|
+
* tool's own optional constructor parameter, forwarded unchanged; a module
|
|
27
|
+
* singleton would have to pick one graph for every tool ever constructed, and
|
|
28
|
+
* the parameter is public surface (`design.md` §3.2, 41 construction sites).
|
|
29
|
+
*/
|
|
30
|
+
import { logger } from "@massa-ai/shared";
|
|
31
|
+
import path from "path";
|
|
32
|
+
export class FileMetadataExtractor {
|
|
33
|
+
symbolGraph;
|
|
34
|
+
constructor(symbolGraph) {
|
|
35
|
+
this.symbolGraph = symbolGraph;
|
|
36
|
+
}
|
|
37
|
+
async extractMetadata(content, filePath, options) {
|
|
38
|
+
const lines = content.split("\n");
|
|
39
|
+
const language = this.detectLanguage(filePath);
|
|
40
|
+
const metadata = {
|
|
41
|
+
totalLines: lines.length,
|
|
42
|
+
language,
|
|
43
|
+
};
|
|
44
|
+
// Extract imports if requested
|
|
45
|
+
if (options.includeImports && language) {
|
|
46
|
+
metadata.imports = this.extractImports(lines, language);
|
|
47
|
+
}
|
|
48
|
+
// Get symbol metadata if symbol graph available
|
|
49
|
+
if (options.includeSymbols && this.symbolGraph && options.projectId) {
|
|
50
|
+
try {
|
|
51
|
+
// Symbol DB stores relative paths — use original relative path for queries
|
|
52
|
+
const queryPath = options.relativePath || filePath;
|
|
53
|
+
const { definitions } = await this.symbolGraph.listDefinitions(options.projectId, {
|
|
54
|
+
file: queryPath,
|
|
55
|
+
limit: 100,
|
|
56
|
+
});
|
|
57
|
+
metadata.symbols = {
|
|
58
|
+
definitions: definitions.length,
|
|
59
|
+
references: 0, // Would need separate query
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
logger.debug("Failed to get symbol metadata", { filePath, error });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return metadata;
|
|
67
|
+
}
|
|
68
|
+
detectLanguage(filePath) {
|
|
69
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
70
|
+
const languageMap = {
|
|
71
|
+
".ts": "TypeScript",
|
|
72
|
+
".tsx": "TypeScript",
|
|
73
|
+
".js": "JavaScript",
|
|
74
|
+
".jsx": "JavaScript",
|
|
75
|
+
".vue": "Vue",
|
|
76
|
+
".py": "Python",
|
|
77
|
+
".go": "Go",
|
|
78
|
+
".rs": "Rust",
|
|
79
|
+
".java": "Java",
|
|
80
|
+
".cpp": "C++",
|
|
81
|
+
".c": "C",
|
|
82
|
+
".h": "C",
|
|
83
|
+
".hpp": "C++",
|
|
84
|
+
".cs": "C#",
|
|
85
|
+
".rb": "Ruby",
|
|
86
|
+
".php": "PHP",
|
|
87
|
+
".swift": "Swift",
|
|
88
|
+
".kt": "Kotlin",
|
|
89
|
+
".kts": "Kotlin",
|
|
90
|
+
".scala": "Scala",
|
|
91
|
+
".md": "Markdown",
|
|
92
|
+
".json": "JSON",
|
|
93
|
+
".yaml": "YAML",
|
|
94
|
+
".yml": "YAML",
|
|
95
|
+
".xml": "XML",
|
|
96
|
+
".html": "HTML",
|
|
97
|
+
".css": "CSS",
|
|
98
|
+
".scss": "SCSS",
|
|
99
|
+
".sql": "SQL",
|
|
100
|
+
".sh": "Shell",
|
|
101
|
+
".bash": "Shell",
|
|
102
|
+
};
|
|
103
|
+
return languageMap[ext];
|
|
104
|
+
}
|
|
105
|
+
extractImports(lines, language) {
|
|
106
|
+
const imports = [];
|
|
107
|
+
const importPatterns = {
|
|
108
|
+
TypeScript: /^(import\s+.*?from\s+['"]|import\s+['"])/,
|
|
109
|
+
JavaScript: /^(import\s+.*?from\s+['"]|import\s+['"]|require\s*\(\s*['"])/,
|
|
110
|
+
Python: /^(import\s+|from\s+\S+\s+import)/,
|
|
111
|
+
Go: /^import\s+/,
|
|
112
|
+
Java: /^import\s+/,
|
|
113
|
+
Rust: /^use\s+/,
|
|
114
|
+
};
|
|
115
|
+
const pattern = importPatterns[language];
|
|
116
|
+
if (!pattern)
|
|
117
|
+
return imports;
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const trimmed = line.trim();
|
|
120
|
+
if (pattern.test(trimmed)) {
|
|
121
|
+
imports.push(trimmed);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return imports;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=file-metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-metadata.js","sourceRoot":"","sources":["../../../src/services/file-read/file-metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @massa-ai/core - Line range selection
|
|
3
|
+
*
|
|
4
|
+
* Module 6 of the `tools/read_file.ts` extraction (PR-D, T11). Owns everything
|
|
5
|
+
* that turns a request into the slice of a file the caller actually receives:
|
|
6
|
+
* `calculateRange` (request → range), `adjustRange` (range → range clamped to
|
|
7
|
+
* the file), `extractLines` (range → line-numbered text), the `ReadRange` shape
|
|
8
|
+
* they pass around, and the N9 output cap — the `MASSA_AI_READ_FILE_MAX_LINES`
|
|
9
|
+
* ceiling together with the clipping block that used to sit inside `handle()`.
|
|
10
|
+
*
|
|
11
|
+
* FREE FUNCTIONS, NOT A CLASS, and that is a decision rather than a default.
|
|
12
|
+
* Modules 2-5 are classes because each owns per-tool state — a Map, a
|
|
13
|
+
* subscription, an injected collaborator. This module owns none: every function
|
|
14
|
+
* here is pure, and the one piece of state is a process-wide constant read from
|
|
15
|
+
* the environment. `services/cache/lru-evict.ts` (module 1) is a bare function
|
|
16
|
+
* for exactly this reason (`design.md` §5.2). A class would also have to be
|
|
17
|
+
* constructed in `ReadFileTool`'s constructor, which is the one surface C64 is
|
|
18
|
+
* about, and would falsely imply per-instance state.
|
|
19
|
+
*
|
|
20
|
+
* IT IMPORTS NOTHING AT ALL, which is `lru-evict.ts`'s property and is asserted
|
|
21
|
+
* by this module's own unit test rather than by any tier rule.
|
|
22
|
+
*
|
|
23
|
+
* `LineRangeRequest` EXISTS BECAUSE `ReadFileParams` IS MODULE 7's. `design.md`
|
|
24
|
+
* §5.1 assigns `interface ReadFileParams` to `read-file.service.ts`, which T12
|
|
25
|
+
* built and which COMPOSES this module — so importing it here would be a 6 → 7
|
|
26
|
+
* edge against the composition direction. It exists now and the rule is
|
|
27
|
+
* unchanged. `calculateRange` reads exactly four fields off its argument, so
|
|
28
|
+
* this module declares those four and `ReadFileParams` satisfies it
|
|
29
|
+
* structurally. The alternative Design's module table hides is that module 6
|
|
30
|
+
* silently depends on module 7's type; naming the subset is what keeps 6
|
|
31
|
+
* standalone. Same shape as the 4 → 5 edge §4.1 decided, which Design handed to
|
|
32
|
+
* Tasks explicitly — this one it handed to nobody.
|
|
33
|
+
*
|
|
34
|
+
* THE CLIPPED PATH RETURNS UNNUMBERED TEXT, AND THAT IS PRESERVED DELIBERATELY.
|
|
35
|
+
* `extractLines` prefixes every line with a padded line number; the cap does NOT
|
|
36
|
+
* slice that string — it re-slices the RAW `lines` array and joins it, so a
|
|
37
|
+
* clipped response loses the prefixes an unclipped one carries. Found by the
|
|
38
|
+
* Plan Challenge gate's red-team lens before this file was written, and
|
|
39
|
+
* confirmed by the evidence audit: no test anywhere asserts content on the
|
|
40
|
+
* clipped path, so composing this as "extract, then slice the extracted text"
|
|
41
|
+
* would have been a silent behavior change inside a behavior-preserving PR.
|
|
42
|
+
* `__tests__/line-range.test.ts` pins both branches' exact format. Whether the
|
|
43
|
+
* asymmetry is intentional is not PR-D's question — it is logged, not fixed
|
|
44
|
+
* (`spec.md` §6, R-07's precedent).
|
|
45
|
+
*/
|
|
46
|
+
/** An inclusive, 1-indexed line range. `end` may be `Infinity` before adjustment. */
|
|
47
|
+
export interface ReadRange {
|
|
48
|
+
start: number;
|
|
49
|
+
end: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The four fields `calculateRange` reads. `ReadFileParams` (module 7, T12)
|
|
53
|
+
* satisfies this structurally; declaring the subset is what stops module 6
|
|
54
|
+
* depending on the module that composes it.
|
|
55
|
+
*/
|
|
56
|
+
export interface LineRangeRequest {
|
|
57
|
+
offset?: number;
|
|
58
|
+
limit?: number;
|
|
59
|
+
lineStart?: number;
|
|
60
|
+
lineEnd?: number;
|
|
61
|
+
}
|
|
62
|
+
/** The result of selecting lines, after the N9 cap has been applied. */
|
|
63
|
+
export interface LineSelection {
|
|
64
|
+
/** The text served to the caller. Line-numbered unless `clipped`. */
|
|
65
|
+
content: string;
|
|
66
|
+
/** `content.split("\n").length` — recomputed after any clipping. */
|
|
67
|
+
lineCount: number;
|
|
68
|
+
/** True when the N9 cap trimmed the selection. Surfaces as `source_clipped`. */
|
|
69
|
+
clipped: boolean;
|
|
70
|
+
}
|
|
71
|
+
export declare function calculateRange(params: LineRangeRequest): ReadRange;
|
|
72
|
+
export declare function adjustRange(range: ReadRange, totalLines: number): ReadRange;
|
|
73
|
+
export declare function extractLines(lines: string[], range: ReadRange): string;
|
|
74
|
+
/**
|
|
75
|
+
* Extract the requested lines and apply the N9 cap, returning the clipped flag
|
|
76
|
+
* rather than mutating the caller's locals.
|
|
77
|
+
*
|
|
78
|
+
* The two steps ship as one function because they were never separable at the
|
|
79
|
+
* call site: before this task the cap read and reassigned the very
|
|
80
|
+
* `selectedContent` and `selectedLineCount` that the `extractLines` call one
|
|
81
|
+
* line above it had produced, inside `handle()`. Deliberately unnumbered — a
|
|
82
|
+
* line citation into `read_file.ts` written here would name a revision that no
|
|
83
|
+
* longer exists the moment this commit lands, and T12 moves that whole region
|
|
84
|
+
* again (T8b's de-numbering precedent). Splitting them would mean passing
|
|
85
|
+
* the already-extracted string and its line count back in as parameters, which
|
|
86
|
+
* duplicates the `.split("\n")` at the call site and adds an argument derivable
|
|
87
|
+
* from another. `extractLines` stays exported so its own contract is pinnable
|
|
88
|
+
* independently.
|
|
89
|
+
*/
|
|
90
|
+
export declare function selectLines(lines: string[], range: ReadRange): LineSelection;
|
|
91
|
+
//# sourceMappingURL=line-range.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-range.d.ts","sourceRoot":"","sources":["../../../src/services/file-read/line-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AA2BH,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAsBlE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,CAK3E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAatE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,aAAa,CA0B5E"}
|