@massa-ai/core 1.17.0 → 1.19.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/data/memory/observation-contract.d.ts +14 -2
- package/dist/data/memory/observation-contract.d.ts.map +1 -1
- package/dist/data/memory/observation-contract.js.map +1 -1
- package/dist/data/memory/observation-repository-pg.d.ts +2 -2
- package/dist/data/memory/observation-repository-pg.d.ts.map +1 -1
- package/dist/data/memory/observation-repository-pg.js.map +1 -1
- package/dist/kernel/sanitize/credential-scrub.d.ts +63 -0
- package/dist/kernel/sanitize/credential-scrub.d.ts.map +1 -0
- package/dist/kernel/sanitize/credential-scrub.js +119 -0
- package/dist/kernel/sanitize/credential-scrub.js.map +1 -0
- 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/hooks/hook-service.d.ts.map +1 -1
- package/dist/services/hooks/hook-service.js +14 -1
- package/dist/services/hooks/hook-service.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/compact_snapshot.d.ts.map +1 -1
- package/dist/tools/compact_snapshot.js +18 -7
- package/dist/tools/compact_snapshot.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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SanitizedPayloadJson } from "../../kernel/sanitize/credential-scrub.js";
|
|
1
2
|
export declare const LIFECYCLE_EVENTS: readonly ["session-start", "user-prompt", "pre-tool-use", "post-tool-use", "pre-compact", "session-end"];
|
|
2
3
|
export type LifecycleEventKind = (typeof LIFECYCLE_EVENTS)[number];
|
|
3
4
|
export declare const OBSERVATION_CATEGORIES: readonly ["files-read", "files-written", "file-search", "tool-calls", "git-changes", "tasks", "plan-changes", "errors", "error-resolution", "iteration-loop", "decisions", "constraints", "rejected-approaches", "user-prompts", "intent", "goal", "role", "blocked-on", "rules", "skills-invoked", "subagents-spawned", "env-changes", "cwd-changes", "session-settings", "external-refs", "web-fetch", "searches", "memories-stored", "compaction-snapshots", "mcp-calls", "agent-findings", "cost-telemetry", "lifecycle-raw"];
|
|
@@ -16,6 +17,17 @@ export interface Observation {
|
|
|
16
17
|
agentId?: string | null;
|
|
17
18
|
attributionSource?: AttributionSource | null;
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Observation shape accepted by {@link ObservationStore.insert}. Identical to
|
|
22
|
+
* {@link Observation} except `payloadJson` must be the branded
|
|
23
|
+
* `SanitizedPayloadJson` produced by `kernel/sanitize/credential-scrub.ts`'s
|
|
24
|
+
* `scrubCredentials()` — the only way to construct that brand. Read shapes
|
|
25
|
+
* (`Observation`, `ObservationRow`, `listRecent`/`listBySession` results)
|
|
26
|
+
* stay plain `string`: rows read back are not re-branded (XP-02 / AD-014).
|
|
27
|
+
*/
|
|
28
|
+
export type InsertableObservation = Omit<Observation, "payloadJson"> & {
|
|
29
|
+
payloadJson: SanitizedPayloadJson;
|
|
30
|
+
};
|
|
19
31
|
export interface ObservationRow {
|
|
20
32
|
id: string;
|
|
21
33
|
project_id: string;
|
|
@@ -29,7 +41,7 @@ export interface ObservationRow {
|
|
|
29
41
|
attribution_source?: string | null;
|
|
30
42
|
}
|
|
31
43
|
export interface ObservationStore {
|
|
32
|
-
insert(obs:
|
|
44
|
+
insert(obs: InsertableObservation): void;
|
|
33
45
|
listRecent(projectId: string, limit: number): Observation[];
|
|
34
46
|
listBySession(sessionId: string, limit: number): Observation[];
|
|
35
47
|
countByProject(projectId: string): number;
|
|
@@ -37,7 +49,7 @@ export interface ObservationStore {
|
|
|
37
49
|
}
|
|
38
50
|
export declare class MemoryObservationStore implements ObservationStore {
|
|
39
51
|
rows: Observation[];
|
|
40
|
-
insert(row:
|
|
52
|
+
insert(row: InsertableObservation): void;
|
|
41
53
|
listRecent(projectId: string, limit: number): Observation[];
|
|
42
54
|
listBySession(sessionId: string, limit: number): Observation[];
|
|
43
55
|
countByProject(projectId: string): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation-contract.d.ts","sourceRoot":"","sources":["../../../src/data/memory/observation-contract.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,0GAA2G,CAAC;AACzI,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AACnE,eAAO,MAAM,sBAAsB,mgBAAogB,CAAC;AACxiB,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,eAAO,MAAM,mBAAmB,wEAAyE,CAAC;AAC1G,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACrE,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAAE;AACxR,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAAE;AACnQ,MAAM,WAAW,gBAAgB;IAAG,MAAM,CAAC,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"observation-contract.d.ts","sourceRoot":"","sources":["../../../src/data/memory/observation-contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEtF,eAAO,MAAM,gBAAgB,0GAA2G,CAAC;AACzI,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AACnE,eAAO,MAAM,sBAAsB,mgBAAogB,CAAC;AACxiB,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAC1E,eAAO,MAAM,mBAAmB,wEAAyE,CAAC;AAC1G,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AACrE,MAAM,WAAW,WAAW;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAC;IAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAAE;AACxR;;;;;;;GAOG;AACH,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,GAAG;IAAE,WAAW,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAC7G,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAAE;AACnQ,MAAM,WAAW,gBAAgB;IAAG,MAAM,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAAC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,CAAC;IAAC,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,CAAC;IAAC,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,WAAW,IAAI,MAAM,CAAC;CAAE;AAC9Q,qBAAa,sBAAuB,YAAW,gBAAgB;IAAU,IAAI,EAAE,WAAW,EAAE,CAAM;IAAC,MAAM,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI;IAA2C,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE;IAAiK,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE;IAAiK,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAA2E,WAAW,IAAI,MAAM;CAAuB;AACjxB,wBAAgB,gBAAgB,IAAI,MAAM,CAAyC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation-contract.js","sourceRoot":"","sources":["../../../src/data/memory/observation-contract.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"observation-contract.js","sourceRoot":"","sources":["../../../src/data/memory/observation-contract.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,CAAU,CAAC;AAEzI,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,qBAAqB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,CAAU,CAAC;AAExiB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AAc1G,MAAM,OAAO,sBAAsB;IAAsC,IAAI,GAAkB,EAAE,CAAC;IAAC,MAAM,CAAC,GAA0B,IAAU,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,UAAU,CAAC,SAAiB,EAAE,KAAa,IAAmB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,aAAa,CAAC,SAAiB,EAAE,KAAa,IAAmB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAAC,cAAc,CAAC,SAAiB,IAAY,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAAC,WAAW,KAAa,OAAO,QAAQ,CAAC,CAAC,CAAC;CAAE;AACjxB,MAAM,UAAU,gBAAgB,KAAa,OAAO,OAAO,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC"}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* BIGINT ms-epoch to match the store's `createdAt: number` contract (NOT the
|
|
27
27
|
* Prisma model's DateTime — see the migration note).
|
|
28
28
|
*/
|
|
29
|
-
import type { Observation, ObservationStore } from "./observation-contract.js";
|
|
29
|
+
import type { Observation, ObservationStore, InsertableObservation } from "./observation-contract.js";
|
|
30
30
|
export declare class PgObservationStore implements ObservationStore {
|
|
31
31
|
private prisma;
|
|
32
32
|
/**
|
|
@@ -51,7 +51,7 @@ export declare class PgObservationStore implements ObservationStore {
|
|
|
51
51
|
* PgScheduledJobStore's inflight-merge).
|
|
52
52
|
*/
|
|
53
53
|
private ensureHydrated;
|
|
54
|
-
insert(obs:
|
|
54
|
+
insert(obs: InsertableObservation): void;
|
|
55
55
|
listRecent(projectId: string, limit: number): Observation[];
|
|
56
56
|
listBySession(sessionId: string, limit: number): Observation[];
|
|
57
57
|
countByProject(projectId: string): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation-repository-pg.d.ts","sourceRoot":"","sources":["../../../src/data/memory/observation-repository-pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,
|
|
1
|
+
{"version":3,"file":"observation-repository-pg.d.ts","sourceRoot":"","sources":["../../../src/data/memory/observation-repository-pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAEhB,qBAAqB,EACtB,MAAM,2BAA2B,CAAC;AAmDnC,qBAAa,kBAAmB,YAAW,gBAAgB;IACzD,OAAO,CAAC,MAAM,CAAgB;IAC9B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAuC;IACrD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAA8B;IAC/C;;;;OAIG;IACH,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAElD,OAAO,CAAC,SAAS;IAKjB;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAgDtB,MAAM,CAAC,GAAG,EAAE,qBAAqB,GAAG,IAAI;IAuFxC,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE;IAS3D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE;IAS9D,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAOzC,WAAW,IAAI,MAAM;IAIrB,0EAA0E;IACpE,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,mEAAmE;IAC7D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAM/B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observation-repository-pg.js","sourceRoot":"","sources":["../../../src/data/memory/observation-repository-pg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"observation-repository-pg.js","sourceRoot":"","sources":["../../../src/data/memory/observation-repository-pg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential scrubber — kernel leaf (XP-02 / TASK-XP-003).
|
|
3
|
+
*
|
|
4
|
+
* Narrow, recognizable credential-shape redaction for hook-ingested payloads.
|
|
5
|
+
* Consumed by `services/hooks` and `tools/` (the two production writers) and
|
|
6
|
+
* by `data/memory/observation-contract.ts`'s insert seam (which is what
|
|
7
|
+
* enforces the branded type below) — a cross-tier leaf, which is exactly
|
|
8
|
+
* what `kernel/` exists for (CLAUDE.md "Architecture" section: membership is
|
|
9
|
+
* the path prefix, there is no allowlist).
|
|
10
|
+
*
|
|
11
|
+
* v1 rule set is deliberately narrow (spec.md "XP-02 redaction v1 rule set"):
|
|
12
|
+
* PEM private-key blocks, JWTs, AWS access-key ids, OpenAI-style `sk-` keys,
|
|
13
|
+
* GitHub tokens, Slack tokens, and Bearer-scheme tokens. General PII/entropy
|
|
14
|
+
* detection is explicitly out of scope — over-redaction of legitimate code
|
|
15
|
+
* is the adjacent regression class this v1 deliberately avoids.
|
|
16
|
+
*
|
|
17
|
+
* No `assertSanitized` escape hatch: the branded `SanitizedPayloadJson` type
|
|
18
|
+
* is only constructible by running the real scrubber below. An assertion
|
|
19
|
+
* constructor would reopen the hole the brand exists to close.
|
|
20
|
+
*
|
|
21
|
+
* Non-growth invariant: scrubbing never makes the payload longer, keeping it
|
|
22
|
+
* sound against the pre-scrub `HOOKS_MAX_PAYLOAD_BYTES` cap in
|
|
23
|
+
* `hook-service.ts` (checked before this module ever runs). Each rule's
|
|
24
|
+
* `[REDACTED:<id>]` marker is sized to be no longer than that shape's
|
|
25
|
+
* minimum possible match. Two rules needed a small adjustment from
|
|
26
|
+
* design.md C1's literal draft to hold that exactly:
|
|
27
|
+
* - `aws-key` (design: `aws-key-id`): a real AWS access-key id is FIXED at
|
|
28
|
+
* exactly 20 characters (4-char prefix + 16 alphanumeric), so the
|
|
29
|
+
* unabridged id's marker (21 chars) would have made every redaction grow
|
|
30
|
+
* the payload by one byte. Dropping the "-id" suffix brings the marker
|
|
31
|
+
* to 18 chars, comfortably under 20.
|
|
32
|
+
* - `slack-token`: the near-miss floor is `{18,}` here, not design's
|
|
33
|
+
* literal `{10,}` — at 10 the marker (22 chars) exceeds the minimum
|
|
34
|
+
* match (15 chars). Slack tokens are not format-fixed the way an AWS key
|
|
35
|
+
* id is, and real tokens run well past 18 characters past the prefix in
|
|
36
|
+
* practice, so this costs nothing against genuine matches while holding
|
|
37
|
+
* the invariant.
|
|
38
|
+
* (SPEC_DEVIATION from design.md C1's literal id/floor for these two rules;
|
|
39
|
+
* reasoned above — reported to the workflow.)
|
|
40
|
+
*/
|
|
41
|
+
declare const SanitizedBrand: unique symbol;
|
|
42
|
+
/**
|
|
43
|
+
* JSON-serialized payload that has passed {@link scrubCredentials}. Only
|
|
44
|
+
* constructible by calling that function.
|
|
45
|
+
*/
|
|
46
|
+
export type SanitizedPayloadJson = string & {
|
|
47
|
+
readonly [SanitizedBrand]: true;
|
|
48
|
+
};
|
|
49
|
+
export interface ScrubResult {
|
|
50
|
+
sanitized: SanitizedPayloadJson;
|
|
51
|
+
/** Count of replacements, per rule id. 0 for every rule on clean input. */
|
|
52
|
+
redactions: Record<string, number>;
|
|
53
|
+
total: number;
|
|
54
|
+
}
|
|
55
|
+
/** Every rule id, in the fixed order rules run — used to build the 0-map. */
|
|
56
|
+
export declare const RULE_IDS: readonly string[];
|
|
57
|
+
/**
|
|
58
|
+
* Scrub every v1 credential shape from `payloadJson`. Pure — identical input
|
|
59
|
+
* always produces identical output, with no IO or shared state.
|
|
60
|
+
*/
|
|
61
|
+
export declare function scrubCredentials(payloadJson: string): ScrubResult;
|
|
62
|
+
export {};
|
|
63
|
+
//# sourceMappingURL=credential-scrub.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-scrub.d.ts","sourceRoot":"","sources":["../../../src/kernel/sanitize/credential-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,CAAC,MAAM,cAAc,EAAE,OAAO,MAAM,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEhF,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,oBAAoB,CAAC;IAChC,2EAA2E;IAC3E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAmED,6EAA6E;AAC7E,eAAO,MAAM,QAAQ,EAAE,SAAS,MAAM,EAA2B,CAAC;AAElE;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAkBjE"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential scrubber — kernel leaf (XP-02 / TASK-XP-003).
|
|
3
|
+
*
|
|
4
|
+
* Narrow, recognizable credential-shape redaction for hook-ingested payloads.
|
|
5
|
+
* Consumed by `services/hooks` and `tools/` (the two production writers) and
|
|
6
|
+
* by `data/memory/observation-contract.ts`'s insert seam (which is what
|
|
7
|
+
* enforces the branded type below) — a cross-tier leaf, which is exactly
|
|
8
|
+
* what `kernel/` exists for (CLAUDE.md "Architecture" section: membership is
|
|
9
|
+
* the path prefix, there is no allowlist).
|
|
10
|
+
*
|
|
11
|
+
* v1 rule set is deliberately narrow (spec.md "XP-02 redaction v1 rule set"):
|
|
12
|
+
* PEM private-key blocks, JWTs, AWS access-key ids, OpenAI-style `sk-` keys,
|
|
13
|
+
* GitHub tokens, Slack tokens, and Bearer-scheme tokens. General PII/entropy
|
|
14
|
+
* detection is explicitly out of scope — over-redaction of legitimate code
|
|
15
|
+
* is the adjacent regression class this v1 deliberately avoids.
|
|
16
|
+
*
|
|
17
|
+
* No `assertSanitized` escape hatch: the branded `SanitizedPayloadJson` type
|
|
18
|
+
* is only constructible by running the real scrubber below. An assertion
|
|
19
|
+
* constructor would reopen the hole the brand exists to close.
|
|
20
|
+
*
|
|
21
|
+
* Non-growth invariant: scrubbing never makes the payload longer, keeping it
|
|
22
|
+
* sound against the pre-scrub `HOOKS_MAX_PAYLOAD_BYTES` cap in
|
|
23
|
+
* `hook-service.ts` (checked before this module ever runs). Each rule's
|
|
24
|
+
* `[REDACTED:<id>]` marker is sized to be no longer than that shape's
|
|
25
|
+
* minimum possible match. Two rules needed a small adjustment from
|
|
26
|
+
* design.md C1's literal draft to hold that exactly:
|
|
27
|
+
* - `aws-key` (design: `aws-key-id`): a real AWS access-key id is FIXED at
|
|
28
|
+
* exactly 20 characters (4-char prefix + 16 alphanumeric), so the
|
|
29
|
+
* unabridged id's marker (21 chars) would have made every redaction grow
|
|
30
|
+
* the payload by one byte. Dropping the "-id" suffix brings the marker
|
|
31
|
+
* to 18 chars, comfortably under 20.
|
|
32
|
+
* - `slack-token`: the near-miss floor is `{18,}` here, not design's
|
|
33
|
+
* literal `{10,}` — at 10 the marker (22 chars) exceeds the minimum
|
|
34
|
+
* match (15 chars). Slack tokens are not format-fixed the way an AWS key
|
|
35
|
+
* id is, and real tokens run well past 18 characters past the prefix in
|
|
36
|
+
* practice, so this costs nothing against genuine matches while holding
|
|
37
|
+
* the invariant.
|
|
38
|
+
* (SPEC_DEVIATION from design.md C1's literal id/floor for these two rules;
|
|
39
|
+
* reasoned above — reported to the workflow.)
|
|
40
|
+
*/
|
|
41
|
+
function markerFor(id) {
|
|
42
|
+
return `[REDACTED:${id}]`;
|
|
43
|
+
}
|
|
44
|
+
/** A rule whose whole match is replaced by its marker. */
|
|
45
|
+
function fullMatchRule(id, pattern) {
|
|
46
|
+
const marker = markerFor(id);
|
|
47
|
+
return {
|
|
48
|
+
id,
|
|
49
|
+
replace(text) {
|
|
50
|
+
let count = 0;
|
|
51
|
+
const replaced = text.replace(pattern, () => {
|
|
52
|
+
count++;
|
|
53
|
+
return marker;
|
|
54
|
+
});
|
|
55
|
+
return { text: replaced, count };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// PEM content is bounded to 8192 chars between BEGIN/END so a run of
|
|
60
|
+
// unterminated "-----BEGIN...-----" occurrences (adversarial input) cannot
|
|
61
|
+
// force each one to lazily scan the rest of a large payload looking for a
|
|
62
|
+
// match that never comes — real PEM bodies (even RSA-4096) are a few KiB at
|
|
63
|
+
// most, so this bound never clips a genuine key.
|
|
64
|
+
const PEM_PATTERN = /-----BEGIN [A-Z ]{0,32}PRIVATE KEY-----[\s\S]{0,8192}?-----END [A-Z ]{0,32}PRIVATE KEY-----/g;
|
|
65
|
+
const JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
|
|
66
|
+
const AWS_KEY_PATTERN = /\b(?:AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}\b/g;
|
|
67
|
+
const SK_KEY_PATTERN = /\bsk-[A-Za-z0-9_-]{20,}\b/g;
|
|
68
|
+
const GITHUB_TOKEN_PATTERN = /\bgh[pousr]_[A-Za-z0-9]{36,}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g;
|
|
69
|
+
const SLACK_TOKEN_PATTERN = /\bxox[baprs]-[A-Za-z0-9-]{18,}\b/g;
|
|
70
|
+
const BEARER_PATTERN = /(Bearer\s+)([A-Za-z0-9._~+/=-]{20,})/g;
|
|
71
|
+
const RULES = [
|
|
72
|
+
// PEM first: fully consumes the block before any other rule can see
|
|
73
|
+
// inside it, and the substituted marker cannot itself match another rule.
|
|
74
|
+
fullMatchRule("pem", PEM_PATTERN),
|
|
75
|
+
fullMatchRule("jwt", JWT_PATTERN),
|
|
76
|
+
fullMatchRule("aws-key", AWS_KEY_PATTERN),
|
|
77
|
+
fullMatchRule("sk-key", SK_KEY_PATTERN),
|
|
78
|
+
fullMatchRule("github-token", GITHUB_TOKEN_PATTERN),
|
|
79
|
+
fullMatchRule("slack-token", SLACK_TOKEN_PATTERN),
|
|
80
|
+
// Runs last and keeps the `Bearer ` prefix literal, replacing only the
|
|
81
|
+
// token — running it last means a more specific rule above (e.g. a JWT
|
|
82
|
+
// used as a bearer token) already replaced its match with a marker whose
|
|
83
|
+
// characters fall outside this rule's charset, so it is not re-matched.
|
|
84
|
+
{
|
|
85
|
+
id: "bearer",
|
|
86
|
+
replace(text) {
|
|
87
|
+
let count = 0;
|
|
88
|
+
const replaced = text.replace(BEARER_PATTERN, (_m, prefix) => {
|
|
89
|
+
count++;
|
|
90
|
+
return `${prefix}${markerFor("bearer")}`;
|
|
91
|
+
});
|
|
92
|
+
return { text: replaced, count };
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
/** Every rule id, in the fixed order rules run — used to build the 0-map. */
|
|
97
|
+
export const RULE_IDS = RULES.map((r) => r.id);
|
|
98
|
+
/**
|
|
99
|
+
* Scrub every v1 credential shape from `payloadJson`. Pure — identical input
|
|
100
|
+
* always produces identical output, with no IO or shared state.
|
|
101
|
+
*/
|
|
102
|
+
export function scrubCredentials(payloadJson) {
|
|
103
|
+
const redactions = {};
|
|
104
|
+
for (const id of RULE_IDS)
|
|
105
|
+
redactions[id] = 0;
|
|
106
|
+
let text = payloadJson;
|
|
107
|
+
for (const rule of RULES) {
|
|
108
|
+
const { text: next, count } = rule.replace(text);
|
|
109
|
+
text = next;
|
|
110
|
+
redactions[rule.id] += count;
|
|
111
|
+
}
|
|
112
|
+
const total = Object.values(redactions).reduce((sum, n) => sum + n, 0);
|
|
113
|
+
return {
|
|
114
|
+
sanitized: text,
|
|
115
|
+
redactions,
|
|
116
|
+
total,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=credential-scrub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-scrub.js","sourceRoot":"","sources":["../../../src/kernel/sanitize/credential-scrub.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|