@remnic/core 9.3.671 → 9.3.672

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/access-cli.js +8 -8
  2. package/dist/access-http.js +7 -7
  3. package/dist/access-mcp.js +6 -6
  4. package/dist/access-service.js +5 -5
  5. package/dist/{chunk-UOBLE67F.js → chunk-3IE22DJ2.js} +4 -4
  6. package/dist/{chunk-XS2CWEHZ.js → chunk-4QZ7H6FN.js} +2 -2
  7. package/dist/chunk-52LZ42LI.js +25 -0
  8. package/dist/chunk-52LZ42LI.js.map +1 -0
  9. package/dist/{chunk-TGN4M5MB.js → chunk-7O5CFNN4.js} +2 -2
  10. package/dist/{chunk-F7OWUP3G.js → chunk-AYGT6VBC.js} +3 -3
  11. package/dist/{chunk-Z4GALEO3.js → chunk-CXKETYZ7.js} +2 -2
  12. package/dist/{chunk-23EBQ27U.js → chunk-EJYFPRED.js} +2 -2
  13. package/dist/{chunk-CPVV2UEL.js → chunk-FP4ISXI3.js} +2 -2
  14. package/dist/{chunk-CRO4LCQ6.js → chunk-KJOYHNS7.js} +5 -5
  15. package/dist/{chunk-ZI6A7X4V.js → chunk-M3WF2AB6.js} +4 -4
  16. package/dist/{chunk-32RD3GIW.js → chunk-ZQJHKN7J.js} +9 -9
  17. package/dist/{chunk-LXVOZ2O6.js → chunk-ZUPFMHJA.js} +2 -2
  18. package/dist/cli.js +11 -11
  19. package/dist/coding/optional-coding-graph.d.ts +63 -0
  20. package/dist/coding/optional-coding-graph.js +119 -0
  21. package/dist/coding/optional-coding-graph.js.map +1 -0
  22. package/dist/coding-graph-types-Dd2tGrnm.d.ts +106 -0
  23. package/dist/conversation-index/backend.js +2 -2
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +20 -14
  26. package/dist/index.js.map +1 -1
  27. package/dist/lcm/engine.js +2 -2
  28. package/dist/lcm/index.js +2 -2
  29. package/dist/namespaces/migrate.js +5 -5
  30. package/dist/namespaces/search.js +4 -4
  31. package/dist/operator-toolkit.js +6 -6
  32. package/dist/orchestrator.js +7 -7
  33. package/dist/search/factory.js +3 -3
  34. package/dist/search/index.js +3 -3
  35. package/package.json +19 -1
  36. package/src/coding/coding-graph-types.ts +180 -0
  37. package/src/coding/optional-coding-graph-cache.test.ts +86 -0
  38. package/src/coding/optional-coding-graph-cacheread.test.ts +78 -0
  39. package/src/coding/optional-coding-graph-concurrent.test.ts +48 -0
  40. package/src/coding/optional-coding-graph-incompatible.test.ts +98 -0
  41. package/src/coding/optional-coding-graph-probe.test.ts +34 -0
  42. package/src/coding/optional-coding-graph.test.ts +117 -0
  43. package/src/coding/optional-coding-graph.ts +370 -0
  44. package/src/index.ts +22 -0
  45. /package/dist/{chunk-UOBLE67F.js.map → chunk-3IE22DJ2.js.map} +0 -0
  46. /package/dist/{chunk-XS2CWEHZ.js.map → chunk-4QZ7H6FN.js.map} +0 -0
  47. /package/dist/{chunk-TGN4M5MB.js.map → chunk-7O5CFNN4.js.map} +0 -0
  48. /package/dist/{chunk-F7OWUP3G.js.map → chunk-AYGT6VBC.js.map} +0 -0
  49. /package/dist/{chunk-Z4GALEO3.js.map → chunk-CXKETYZ7.js.map} +0 -0
  50. /package/dist/{chunk-23EBQ27U.js.map → chunk-EJYFPRED.js.map} +0 -0
  51. /package/dist/{chunk-CPVV2UEL.js.map → chunk-FP4ISXI3.js.map} +0 -0
  52. /package/dist/{chunk-CRO4LCQ6.js.map → chunk-KJOYHNS7.js.map} +0 -0
  53. /package/dist/{chunk-ZI6A7X4V.js.map → chunk-M3WF2AB6.js.map} +0 -0
  54. /package/dist/{chunk-32RD3GIW.js.map → chunk-ZQJHKN7J.js.map} +0 -0
  55. /package/dist/{chunk-LXVOZ2O6.js.map → chunk-ZUPFMHJA.js.map} +0 -0
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  LcmEngine,
3
3
  extractLcmConfig
4
- } from "../chunk-UOBLE67F.js";
4
+ } from "../chunk-3IE22DJ2.js";
5
+ import "../chunk-TPDBFYEG.js";
5
6
  import "../chunk-KCYE2MZM.js";
6
7
  import "../chunk-MAV46GWQ.js";
7
8
  import "../chunk-5VDJMYTF.js";
8
9
  import "../chunk-HP5FMB6L.js";
9
10
  import "../chunk-7N4KAIGN.js";
10
- import "../chunk-TPDBFYEG.js";
11
11
  import "../chunk-4RA3C3EV.js";
12
12
  import "../chunk-CI7RKSRE.js";
13
13
  import "../chunk-6KYMPV2O.js";
package/dist/lcm/index.js CHANGED
@@ -5,7 +5,8 @@ import {
5
5
  import {
6
6
  LcmEngine,
7
7
  extractLcmConfig
8
- } from "../chunk-UOBLE67F.js";
8
+ } from "../chunk-3IE22DJ2.js";
9
+ import "../chunk-TPDBFYEG.js";
9
10
  import {
10
11
  assembleCompressedHistory
11
12
  } from "../chunk-KCYE2MZM.js";
@@ -23,7 +24,6 @@ import {
23
24
  import {
24
25
  LcmDag
25
26
  } from "../chunk-7N4KAIGN.js";
26
- import "../chunk-TPDBFYEG.js";
27
27
  import "../chunk-4RA3C3EV.js";
28
28
  import "../chunk-CI7RKSRE.js";
29
29
  import "../chunk-6KYMPV2O.js";
@@ -2,10 +2,10 @@ import {
2
2
  listNamespaces,
3
3
  runNamespaceMigration,
4
4
  verifyNamespaces
5
- } from "../chunk-LXVOZ2O6.js";
5
+ } from "../chunk-ZUPFMHJA.js";
6
6
  import "../chunk-LZSMQHXC.js";
7
- import "../chunk-XS2CWEHZ.js";
8
- import "../chunk-23EBQ27U.js";
7
+ import "../chunk-4QZ7H6FN.js";
8
+ import "../chunk-EJYFPRED.js";
9
9
  import "../chunk-OUWAQVDJ.js";
10
10
  import "../chunk-DOCTITOP.js";
11
11
  import "../chunk-CYEPCZN5.js";
@@ -15,10 +15,10 @@ import "../chunk-AER6MT24.js";
15
15
  import "../chunk-RN7MUWON.js";
16
16
  import "../chunk-CINZGPSJ.js";
17
17
  import "../chunk-ZFXCQPNO.js";
18
- import "../chunk-CRO4LCQ6.js";
18
+ import "../chunk-KJOYHNS7.js";
19
+ import "../chunk-OIF36KGD.js";
19
20
  import "../chunk-7DTASS5T.js";
20
21
  import "../chunk-E6ZDCOHM.js";
21
- import "../chunk-OIF36KGD.js";
22
22
  import "../chunk-6RHNCKHG.js";
23
23
  import "../chunk-YNQ6DFSV.js";
24
24
  import "../chunk-O75CRYGF.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  NamespaceSearchRouter,
3
3
  namespaceCollectionName
4
- } from "../chunk-XS2CWEHZ.js";
5
- import "../chunk-23EBQ27U.js";
4
+ } from "../chunk-4QZ7H6FN.js";
5
+ import "../chunk-EJYFPRED.js";
6
6
  import "../chunk-OUWAQVDJ.js";
7
7
  import "../chunk-DOCTITOP.js";
8
8
  import "../chunk-CYEPCZN5.js";
@@ -12,10 +12,10 @@ import "../chunk-AER6MT24.js";
12
12
  import "../chunk-RN7MUWON.js";
13
13
  import "../chunk-CINZGPSJ.js";
14
14
  import "../chunk-ZFXCQPNO.js";
15
- import "../chunk-CRO4LCQ6.js";
15
+ import "../chunk-KJOYHNS7.js";
16
+ import "../chunk-OIF36KGD.js";
16
17
  import "../chunk-7DTASS5T.js";
17
18
  import "../chunk-E6ZDCOHM.js";
18
- import "../chunk-OIF36KGD.js";
19
19
  import "../chunk-6RHNCKHG.js";
20
20
  import "../chunk-YNQ6DFSV.js";
21
21
  import "../chunk-O75CRYGF.js";
@@ -11,8 +11,8 @@ import {
11
11
  summarizeMemoryWorthLegacyCounters,
12
12
  summarizeObservationThroughput,
13
13
  summarizeTierDistribution
14
- } from "./chunk-CPVV2UEL.js";
15
- import "./chunk-LXVOZ2O6.js";
14
+ } from "./chunk-FP4ISXI3.js";
15
+ import "./chunk-ZUPFMHJA.js";
16
16
  import "./chunk-6T4LTI2F.js";
17
17
  import "./chunk-YBPYIAA5.js";
18
18
  import "./chunk-LZSMQHXC.js";
@@ -26,8 +26,8 @@ import "./chunk-PHK3HARR.js";
26
26
  import "./chunk-NDAH7BJ5.js";
27
27
  import "./chunk-Z5LAYHGJ.js";
28
28
  import "./chunk-VL5JJOOY.js";
29
- import "./chunk-XS2CWEHZ.js";
30
- import "./chunk-23EBQ27U.js";
29
+ import "./chunk-4QZ7H6FN.js";
30
+ import "./chunk-EJYFPRED.js";
31
31
  import "./chunk-OUWAQVDJ.js";
32
32
  import "./chunk-DOCTITOP.js";
33
33
  import "./chunk-CYEPCZN5.js";
@@ -37,10 +37,10 @@ import "./chunk-AER6MT24.js";
37
37
  import "./chunk-RN7MUWON.js";
38
38
  import "./chunk-CINZGPSJ.js";
39
39
  import "./chunk-ZFXCQPNO.js";
40
- import "./chunk-CRO4LCQ6.js";
40
+ import "./chunk-KJOYHNS7.js";
41
+ import "./chunk-OIF36KGD.js";
41
42
  import "./chunk-7DTASS5T.js";
42
43
  import "./chunk-E6ZDCOHM.js";
43
- import "./chunk-OIF36KGD.js";
44
44
  import "./chunk-6RHNCKHG.js";
45
45
  import "./chunk-YNQ6DFSV.js";
46
46
  import "./chunk-O75CRYGF.js";
@@ -28,19 +28,19 @@ import {
28
28
  sanitizeSessionKeyForFilename,
29
29
  shouldFilterLifecycleRecallCandidate,
30
30
  summarizeGraphShadowComparison
31
- } from "./chunk-ZI6A7X4V.js";
31
+ } from "./chunk-M3WF2AB6.js";
32
32
  import "./chunk-4SKKVWLQ.js";
33
33
  import "./chunk-7HYPN2GC.js";
34
34
  import "./chunk-666A3MOW.js";
35
35
  import "./chunk-HHLLAQGZ.js";
36
36
  import "./chunk-UWK5OXUJ.js";
37
- import "./chunk-UOBLE67F.js";
37
+ import "./chunk-3IE22DJ2.js";
38
+ import "./chunk-TPDBFYEG.js";
38
39
  import "./chunk-KCYE2MZM.js";
39
40
  import "./chunk-MAV46GWQ.js";
40
41
  import "./chunk-5VDJMYTF.js";
41
42
  import "./chunk-HP5FMB6L.js";
42
43
  import "./chunk-7N4KAIGN.js";
43
- import "./chunk-TPDBFYEG.js";
44
44
  import "./chunk-TECVW3JP.js";
45
45
  import "./chunk-T2PO5MUF.js";
46
46
  import "./chunk-B6IUW76R.js";
@@ -147,8 +147,8 @@ import "./chunk-RS25QOKZ.js";
147
147
  import "./chunk-JGSKJHF7.js";
148
148
  import "./chunk-FF4KLI5W.js";
149
149
  import "./chunk-6VP3YUCS.js";
150
- import "./chunk-XS2CWEHZ.js";
151
- import "./chunk-23EBQ27U.js";
150
+ import "./chunk-4QZ7H6FN.js";
151
+ import "./chunk-EJYFPRED.js";
152
152
  import "./chunk-OUWAQVDJ.js";
153
153
  import "./chunk-DOCTITOP.js";
154
154
  import "./chunk-CYEPCZN5.js";
@@ -158,10 +158,10 @@ import "./chunk-AER6MT24.js";
158
158
  import "./chunk-RN7MUWON.js";
159
159
  import "./chunk-CINZGPSJ.js";
160
160
  import "./chunk-ZFXCQPNO.js";
161
- import "./chunk-CRO4LCQ6.js";
161
+ import "./chunk-KJOYHNS7.js";
162
+ import "./chunk-OIF36KGD.js";
162
163
  import "./chunk-7DTASS5T.js";
163
164
  import "./chunk-E6ZDCOHM.js";
164
- import "./chunk-OIF36KGD.js";
165
165
  import "./chunk-6RHNCKHG.js";
166
166
  import "./chunk-YNQ6DFSV.js";
167
167
  import "./chunk-CI7RKSRE.js";
@@ -2,7 +2,7 @@ import {
2
2
  createConversationIndexRuntime,
3
3
  createConversationSearchBackend,
4
4
  createSearchBackend
5
- } from "../chunk-23EBQ27U.js";
5
+ } from "../chunk-EJYFPRED.js";
6
6
  import "../chunk-OUWAQVDJ.js";
7
7
  import "../chunk-DOCTITOP.js";
8
8
  import "../chunk-CYEPCZN5.js";
@@ -11,10 +11,10 @@ import "../chunk-JOASJWQR.js";
11
11
  import "../chunk-AER6MT24.js";
12
12
  import "../chunk-RN7MUWON.js";
13
13
  import "../chunk-CINZGPSJ.js";
14
- import "../chunk-CRO4LCQ6.js";
14
+ import "../chunk-KJOYHNS7.js";
15
+ import "../chunk-OIF36KGD.js";
15
16
  import "../chunk-7DTASS5T.js";
16
17
  import "../chunk-E6ZDCOHM.js";
17
- import "../chunk-OIF36KGD.js";
18
18
  import "../chunk-6RHNCKHG.js";
19
19
  import "../chunk-YNQ6DFSV.js";
20
20
  import "../chunk-O75CRYGF.js";
@@ -2,7 +2,7 @@ import {
2
2
  createConversationIndexRuntime,
3
3
  createConversationSearchBackend,
4
4
  createSearchBackend
5
- } from "../chunk-23EBQ27U.js";
5
+ } from "../chunk-EJYFPRED.js";
6
6
  import {
7
7
  LanceDbBackend
8
8
  } from "../chunk-OUWAQVDJ.js";
@@ -25,10 +25,10 @@ import {
25
25
  EmbedHelper
26
26
  } from "../chunk-RN7MUWON.js";
27
27
  import "../chunk-CINZGPSJ.js";
28
- import "../chunk-CRO4LCQ6.js";
28
+ import "../chunk-KJOYHNS7.js";
29
+ import "../chunk-OIF36KGD.js";
29
30
  import "../chunk-7DTASS5T.js";
30
31
  import "../chunk-E6ZDCOHM.js";
31
- import "../chunk-OIF36KGD.js";
32
32
  import "../chunk-6RHNCKHG.js";
33
33
  import "../chunk-YNQ6DFSV.js";
34
34
  import "../chunk-O75CRYGF.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.671",
3
+ "version": "9.3.672",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -441,6 +441,16 @@
441
441
  "remnic-source": "./src/codex-thread-key.ts",
442
442
  "import": "./dist/codex-thread-key.js"
443
443
  },
444
+ "./coding/optional-coding-graph": {
445
+ "types": "./dist/coding/optional-coding-graph.d.ts",
446
+ "remnic-source": "./src/coding/optional-coding-graph.ts",
447
+ "import": "./dist/coding/optional-coding-graph.js"
448
+ },
449
+ "./coding/optional-coding-graph.js": {
450
+ "types": "./dist/coding/optional-coding-graph.d.ts",
451
+ "remnic-source": "./src/coding/optional-coding-graph.ts",
452
+ "import": "./dist/coding/optional-coding-graph.js"
453
+ },
444
454
  "./commitment-ledger": {
445
455
  "types": "./dist/commitment-ledger.d.ts",
446
456
  "remnic-source": "./src/commitment-ledger.ts",
@@ -2905,6 +2915,14 @@
2905
2915
  "agent",
2906
2916
  "core"
2907
2917
  ],
2918
+ "peerDependencies": {
2919
+ "@remnic/coding-graph": "^9.3.672"
2920
+ },
2921
+ "peerDependenciesMeta": {
2922
+ "@remnic/coding-graph": {
2923
+ "optional": true
2924
+ }
2925
+ },
2908
2926
  "scripts": {
2909
2927
  "build": "node ./scripts/build-with-heap.mjs",
2910
2928
  "check-types": "tsc --noEmit",
@@ -0,0 +1,180 @@
1
+ // Engine contract types for the optional @remnic/coding-graph package.
2
+ //
3
+ // These types are owned by @remnic/core so the base install compiles even
4
+ // when @remnic/coding-graph is not present (it is an optional peer dep —
5
+ // installed only on host machines that opt in to codebase-graph features).
6
+ //
7
+ // @remnic/coding-graph imports these types and implements them; it does
8
+ // not redefine them. This breaks the type-source-direction cycle that
9
+ // would otherwise require core to import coding-graph at compile time
10
+ // (core's tsup DTS phase emits declarations against the package's
11
+ // compiled output, which would fail when the optional package is not
12
+ // installed in CI's base install).
13
+ //
14
+ // Dependency direction:
15
+ //
16
+ // @remnic/core ──── owns ───► CodingGraphEngine (this file)
17
+ // ▲
18
+ // │ peer + devDep (workspace)
19
+ // │
20
+ // @remnic/coding-graph (implements against these types)
21
+ //
22
+ // Per #1551 PR1 — these are the full contract surface. PR2 fills the
23
+ // extractors; PR3+ lands the walker, determinism, and grammarDir
24
+ // behaviour behind the same `parseFile()` entry point.
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Version constant — surfaced through the engine instance so consumers can
28
+ // advertise what they expect. Bumped in lockstep with the package version
29
+ // during active development.
30
+ // ---------------------------------------------------------------------------
31
+ export const CODING_GRAPH_ENGINE_VERSION = "0.1.0-pr1" as const;
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Tier-1 language list — declared here so consumers can drive their own
35
+ // tools against the engine without touching the optional package. Order is
36
+ // stable; per-language configuration is the engine's concern.
37
+ // ---------------------------------------------------------------------------
38
+ export const TIER_1_LANGUAGES = [
39
+ "typescript",
40
+ "tsx",
41
+ "javascript",
42
+ "python",
43
+ "go",
44
+ "rust",
45
+ "java",
46
+ "c",
47
+ "cpp",
48
+ "csharp",
49
+ "ruby",
50
+ "php",
51
+ "kotlin",
52
+ "swift",
53
+ "bash",
54
+ ] as const;
55
+
56
+ export type CodingGraphLanguage = (typeof TIER_1_LANGUAGES)[number];
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // Tagged error code — the load-bearing signal for programmatic detection of
60
+ // placeholder / install / load failure states. New codes must be added here
61
+ // so consumers see them via TypeScript.
62
+ // ---------------------------------------------------------------------------
63
+ export type CodingGraphErrorCode =
64
+ | "not_implemented"
65
+ | "module_load_failed";
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Engine interface — the contract coding-graph implements against.
69
+ // ---------------------------------------------------------------------------
70
+ export interface CodingGraphEngine {
71
+ /** Engine version reported at construction time. */
72
+ readonly engineVersion: string;
73
+ /** Tier-1 languages this build supports (PR2 narrows by grammar availability). */
74
+ readonly supportedLanguages: readonly CodingGraphLanguage[];
75
+ /**
76
+ * Parse a single source file and emit its FileIR.
77
+ *
78
+ * PR1 throws `CodingGraphError("not_implemented", …)`. PR2 will return
79
+ * `ParseResult`; failure paths come back as
80
+ * `{ ok: false, code: "parse_failed", path, message }` (rule 44) rather
81
+ * than partial / silent IR.
82
+ */
83
+ parseFile(input: ParseFileInput): Promise<ParseResult>;
84
+ /** Engine lifecycle — release any cached parsers/grammars. */
85
+ dispose(): Promise<void>;
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // Parse input/output
90
+ // ---------------------------------------------------------------------------
91
+ export interface ParseFileInput {
92
+ /** Repository-relative path (forward slashes; no leading `./`). */
93
+ readonly path: string;
94
+ /** Raw file bytes; hashing happens inside the engine (rule 23). */
95
+ readonly content: Uint8Array;
96
+ /**
97
+ * Optional override. When omitted the engine sniffs the language from
98
+ * `path` extensions against its built-in tier-1 list (PR2).
99
+ */
100
+ readonly language?: CodingGraphLanguage;
101
+ }
102
+
103
+ export type ParseResult =
104
+ | { readonly ok: true; readonly ir: FileIR }
105
+ | {
106
+ readonly ok: false;
107
+ readonly code: "parse_failed";
108
+ readonly path: string;
109
+ readonly message: string;
110
+ };
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // FileIR — the seam between the parser (optional package) and the graph
114
+ // store (sibling issue #1552). Field types are the minimal viable set per
115
+ // the issue's design section.
116
+ // ---------------------------------------------------------------------------
117
+ export interface FileIR {
118
+ readonly path: string;
119
+ readonly language: CodingGraphLanguage;
120
+ /** SHA-256 of the raw bytes; rule 23 — every consumer hashes the same form. */
121
+ readonly contentHash: string;
122
+ readonly symbols: readonly SymbolIR[];
123
+ readonly imports: readonly ImportIR[];
124
+ readonly exports: readonly ExportIR[];
125
+ readonly callSites: readonly CallSiteIR[];
126
+ readonly routes: readonly RouteIR[];
127
+ }
128
+
129
+ export interface SymbolIR {
130
+ readonly kind:
131
+ | "function"
132
+ | "class"
133
+ | "method"
134
+ | "interface"
135
+ | "enum"
136
+ | "type"
137
+ | "module";
138
+ readonly name: string;
139
+ readonly qualifiedName: string;
140
+ /** Half-open byte span `[startByte, endByte)`. Rule 35. */
141
+ readonly span: { readonly startByte: number; readonly endByte: number };
142
+ readonly parentQualifiedName?: string;
143
+ }
144
+
145
+ export interface ImportIR {
146
+ /** Raw module specifier as written in source. */
147
+ readonly module: string;
148
+ readonly importedNames: readonly string[];
149
+ readonly span: { readonly startByte: number; readonly endByte: number };
150
+ }
151
+
152
+ export interface ExportIR {
153
+ readonly name: string;
154
+ readonly span: { readonly startByte: number; readonly endByte: number };
155
+ }
156
+
157
+ export interface CallSiteIR {
158
+ readonly calleeNameCandidates: readonly string[];
159
+ readonly span: { readonly startByte: number; readonly endByte: number };
160
+ }
161
+
162
+ export interface RouteIR {
163
+ /** HTTP verb in upper-case, or framework-native verb (e.g. "ANY"). */
164
+ readonly verb: string;
165
+ readonly pathTemplate: string;
166
+ readonly handlerQualifiedName: string;
167
+ readonly span: { readonly startByte: number; readonly endByte: number };
168
+ }
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // Factory options
172
+ // ---------------------------------------------------------------------------
173
+ /**
174
+ * Reserved for PR2. Declared now so the public surface is stable; the
175
+ * options object is intentionally empty in PR1.
176
+ */
177
+ export interface CreateCodingGraphEngineOptions {
178
+ /** Reserved for PR2: extra grammar directory supplied by the operator. */
179
+ readonly grammarDir?: never;
180
+ }
@@ -0,0 +1,86 @@
1
+ // Regression tests for Cursor Bugbot P2 round 3 on PR #1588:
2
+ // "Probe poisons loader error path" and the round-5 "Loader skips
3
+ // success cache" follow-up.
4
+ //
5
+ // These tests must work both when @remnic/coding-graph is installed
6
+ // (workspace dev scenario) AND when it is absent (CI base install —
7
+ // the optional peer is not symlinked). Conditional branches keep the
8
+ // tests durable across install scenarios (P2 P2 P2 chatgpt-codex on
9
+ // PR #1588 round 6).
10
+
11
+ import assert from "node:assert/strict";
12
+ import test from "node:test";
13
+
14
+ import {
15
+ isCodingGraphInstalled,
16
+ loadCodingGraphEngineFactory,
17
+ tryLoadCodingGraphModule,
18
+ } from "./optional-coding-graph.js";
19
+
20
+ test("loadCodingGraphEngineFactory fresh-attempts regardless of probe state", async () => {
21
+ // Probe and load side-by-side. Both must agree on the package's
22
+ // presence at this instant. When @remnic/coding-graph is absent
23
+ // (CI base install) the probe returns null and the loader throws
24
+ // the install hint. When present (dev workspace) both succeed.
25
+ const probeResult = await tryLoadCodingGraphModule();
26
+ const installed = await isCodingGraphInstalled();
27
+
28
+ if (probeResult === null) {
29
+ assert.equal(installed, false);
30
+ let threw = false;
31
+ let message = "";
32
+ try {
33
+ await loadCodingGraphEngineFactory();
34
+ } catch (err) {
35
+ threw = true;
36
+ message = err instanceof Error ? err.message : String(err);
37
+ }
38
+ assert.equal(threw, true, "loader must throw install hint when probe returned null");
39
+ assert.match(message, /@remnic\/coding-graph/);
40
+ assert.match(message, /npm install @remnic\/coding-graph/);
41
+ return;
42
+ }
43
+
44
+ // Package present.
45
+ assert.equal(installed, true);
46
+ const factory = await loadCodingGraphEngineFactory();
47
+ assert.equal(typeof factory, "function");
48
+ });
49
+
50
+ test("probe short-circuits to the same answer on repeated calls", async () => {
51
+ // Probe must be deterministic — repeated calls return the same
52
+ // answer. Both branches are valid (present → module, absent → null).
53
+ const a = await tryLoadCodingGraphModule();
54
+ const b = await tryLoadCodingGraphModule();
55
+ const aKind = a === null ? "null" : "module";
56
+ const bKind = b === null ? "null" : "module";
57
+ assert.equal(aKind, bKind, "consecutive probe calls must agree");
58
+ });
59
+
60
+ test("loader path is independent of the probe result", async () => {
61
+ // The Bugbot P2 round 3 bug was: a probe that caught a non-specifier
62
+ // import error was caching `null` into the load-path. That poisoned
63
+ // the user-facing loader path. This test asserts the load-path
64
+ // ALWAYS attempts a fresh import — proven by exercising the path
65
+ // for both present and absent packages.
66
+ const probe = await tryLoadCodingGraphModule();
67
+ if (probe === null) {
68
+ // Absent: loader throws install hint.
69
+ let threw = false;
70
+ try {
71
+ await loadCodingGraphEngineFactory();
72
+ } catch {
73
+ threw = true;
74
+ }
75
+ assert.equal(threw, true, "loader throws when package is absent");
76
+ } else {
77
+ // Present: loader returns a callable factory.
78
+ const factory = await loadCodingGraphEngineFactory();
79
+ assert.equal(typeof factory, "function");
80
+ assert.throws(() => factory(), (err: unknown) => {
81
+ if (!err || typeof err !== "object") return false;
82
+ const e = err as { name?: unknown; code?: unknown };
83
+ return e.name === "CodingGraphError" && e.code === "not_implemented";
84
+ });
85
+ }
86
+ });
@@ -0,0 +1,78 @@
1
+ // Regression tests for Cursor Bugbot P3 round 5 on PR #1588:
2
+ // "Loader skips success cache".
3
+ //
4
+ // These tests must work both when @remnic/coding-graph is installed
5
+ // (workspace dev scenario) AND when it is absent (CI base install —
6
+ // the optional peer is not symlinked). chatgpt-codex round 6 P2:
7
+ // the original test assumed the package is installed and would fail
8
+ // in a core-only install. Every assertion below is conditional.
9
+
10
+ import assert from "node:assert/strict";
11
+ import test from "node:test";
12
+
13
+ import {
14
+ isCodingGraphInstalled,
15
+ loadCodingGraphEngineFactory,
16
+ tryLoadCodingGraphModule,
17
+ } from "./optional-coding-graph.js";
18
+
19
+ test("loadCodingGraphEngineFactory returns a callable factory (install present)", async () => {
20
+ const installed = await isCodingGraphInstalled();
21
+ if (!installed) {
22
+ // Skip when package is absent (CI base install).
23
+ return;
24
+ }
25
+ const factory = await loadCodingGraphEngineFactory();
26
+ assert.equal(typeof factory, "function");
27
+ });
28
+
29
+ test("loadCodingGraphEngineFactory throws install hint when package absent", async () => {
30
+ const installed = await isCodingGraphInstalled();
31
+ if (installed) {
32
+ return;
33
+ }
34
+ let threw = false;
35
+ let message = "";
36
+ try {
37
+ await loadCodingGraphEngineFactory();
38
+ } catch (err) {
39
+ threw = true;
40
+ message = err instanceof Error ? err.message : String(err);
41
+ }
42
+ assert.equal(threw, true);
43
+ assert.match(message, /@remnic\/coding-graph/);
44
+ assert.match(message, /npm install @remnic\/coding-graph/);
45
+ });
46
+
47
+ test("after a successful load, tryLoadCodingGraphModule returns the same module (cache fast-path)", async () => {
48
+ const installed = await isCodingGraphInstalled();
49
+ if (!installed) return;
50
+ // Seed the success cache by calling loadCodingGraphEngineFactory.
51
+ const factory = await loadCodingGraphEngineFactory();
52
+ assert.equal(typeof factory, "function");
53
+ // A fresh probe call should return the cached module reference.
54
+ const probeResult = await tryLoadCodingGraphModule();
55
+ assert.ok(probeResult !== null);
56
+ // Invoking the factory throws the placeholder (PR1 contract).
57
+ assert.throws(() => factory(), (err: unknown) => {
58
+ if (!err || typeof err !== "object") return false;
59
+ const e = err as { name?: unknown; code?: unknown };
60
+ return e.name === "CodingGraphError" && e.code === "not_implemented";
61
+ });
62
+ });
63
+
64
+ test("loader fresh-attempts after the package is detected as missing", async () => {
65
+ // If present, loader returns a factory.
66
+ // If absent, loader throws the install hint.
67
+ try {
68
+ const factory = await loadCodingGraphEngineFactory();
69
+ assert.equal(typeof factory, "function");
70
+ } catch (err) {
71
+ if (err instanceof Error) {
72
+ assert.match(err.message, /@remnic\/coding-graph/);
73
+ assert.match(err.message, /npm install @remnic\/coding-graph/);
74
+ return;
75
+ }
76
+ throw err;
77
+ }
78
+ });
@@ -0,0 +1,48 @@
1
+ // Regression tests for Cursor Bugbot P2 round 4 on PR #1588:
2
+ // "Concurrent probe calls return null".
3
+ //
4
+ // These tests assert concurrent probes observe the same kind of
5
+ // outcome (module-or-null), independent of whether the package is
6
+ // installed. chatgpt-codex round 6 P2: previous tests assumed the
7
+ // package was installed and would fail in a core-only install.
8
+ // Every assertion below is conditional on the current install state.
9
+
10
+ import assert from "node:assert/strict";
11
+ import test from "node:test";
12
+
13
+ import {
14
+ isCodingGraphInstalled,
15
+ tryLoadCodingGraphModule,
16
+ } from "./optional-coding-graph.js";
17
+
18
+ test("two probes fired in the same tick must observe the same outcome kind", async () => {
19
+ // Kick off two probes back-to-back. They both observe the same
20
+ // outcome (module-or-null), regardless of presence.
21
+ const a = await tryLoadCodingGraphModule();
22
+ const b = await tryLoadCodingGraphModule();
23
+ const aKind = a === null ? "null" : "module";
24
+ const bKind = b === null ? "null" : "module";
25
+ assert.equal(aKind, bKind, "concurrent probes must produce the same kind of outcome");
26
+ });
27
+
28
+ test("many parallel probes never observe a transient null", async () => {
29
+ // 8 parallel probes; every one must observe the same outcome kind.
30
+ const probes = Array.from({ length: 8 }, () => tryLoadCodingGraphModule());
31
+ const results = await Promise.all(probes);
32
+ const nullCount = results.filter((r) => r === null).length;
33
+ const moduleCount = results.filter((r) => r !== null).length;
34
+ // All-or-nothing: every probe must agree.
35
+ assert.ok(
36
+ nullCount === 0 || moduleCount === 0,
37
+ "no probe in a parallel batch may report a different outcome than the others",
38
+ );
39
+ assert.equal(nullCount + moduleCount, 8);
40
+ });
41
+
42
+ test("isCodingGraphInstalled stays truthful under parallel calls", async () => {
43
+ const flags = await Promise.all(Array.from({ length: 8 }, () => isCodingGraphInstalled()));
44
+ // All parallel invocations must agree on the boolean.
45
+ const allTrue = flags.every((f) => f === true);
46
+ const allFalse = flags.every((f) => f === false);
47
+ assert.ok(allTrue || allFalse, "parallel probes must all agree on the boolean");
48
+ });