@@ -2,13 +2,98 @@ import { assertFalse, assertStrictEquals } from "jsr:@std/assert@^1.0.0";
22import { describe , it } from "jsr:@std/testing@^1.0.0/bdd" ;
33import { join } from "node:path" ;
44import { loadConfig } from "./config.ts" ;
5+ import type { GraphitiConfig } from "./types/index.ts" ;
6+
7+ async function withTempDir < T > (
8+ fn : ( directory : string ) => T | Promise < T > ,
9+ ) : Promise < T > {
10+ const directory = await Deno . makeTempDir ( ) ;
11+
12+ try {
13+ return await fn ( directory ) ;
14+ } finally {
15+ await Deno . remove ( directory , { recursive : true } ) ;
16+ }
17+ }
18+
19+ function withTempDirAsCwd < T > (
20+ fn : ( directory : string ) => T | Promise < T > ,
21+ ) : Promise < T > {
22+ const previousCwd = Deno . cwd ( ) ;
23+
24+ return withTempDir ( async ( directory ) => {
25+ try {
26+ Deno . chdir ( directory ) ;
27+ return await fn ( directory ) ;
28+ } finally {
29+ Deno . chdir ( previousCwd ) ;
30+ }
31+ } ) ;
32+ }
33+
34+ function assertConfigValues (
35+ config : GraphitiConfig ,
36+ expected : Pick <
37+ GraphitiConfig ,
38+ "endpoint" | "groupIdPrefix" | "driftThreshold" | "factStaleDays"
39+ > ,
40+ ) {
41+ assertStrictEquals ( config . endpoint , expected . endpoint ) ;
42+ assertStrictEquals ( config . groupIdPrefix , expected . groupIdPrefix ) ;
43+ assertStrictEquals ( config . driftThreshold , expected . driftThreshold ) ;
44+ assertStrictEquals ( config . factStaleDays , expected . factStaleDays ) ;
45+ }
46+
47+ const explicitDirectoryConfigCases = [
48+ {
49+ name :
50+ "should load project-local .graphitirc via explicit directory argument" ,
51+ fileName : ".graphitirc" ,
52+ fileContents : {
53+ endpoint : "http://project.local/mcp" ,
54+ driftThreshold : 0.4 ,
55+ factStaleDays : 7 ,
56+ } ,
57+ expected : {
58+ endpoint : "http://project.local/mcp" ,
59+ groupIdPrefix : "opencode" ,
60+ driftThreshold : 0.4 ,
61+ factStaleDays : 7 ,
62+ } ,
63+ } ,
64+ {
65+ name :
66+ "should load project-local package.json graphiti key via explicit directory argument" ,
67+ fileName : "package.json" ,
68+ fileContents : {
69+ name : "my-project" ,
70+ graphiti : {
71+ endpoint : "http://pkg-project.local/mcp" ,
72+ driftThreshold : 0.2 ,
73+ factStaleDays : 5 ,
74+ } ,
75+ } ,
76+ expected : {
77+ endpoint : "http://pkg-project.local/mcp" ,
78+ groupIdPrefix : "opencode" ,
79+ driftThreshold : 0.2 ,
80+ factStaleDays : 5 ,
81+ } ,
82+ } ,
83+ ] satisfies Array < {
84+ name : string ;
85+ fileName : string ;
86+ fileContents : unknown ;
87+ expected : Pick <
88+ GraphitiConfig ,
89+ "endpoint" | "groupIdPrefix" | "driftThreshold" | "factStaleDays"
90+ > ;
91+ } > ;
592
693describe ( "config" , ( ) => {
794 describe ( "loadConfig" , ( ) => {
895 it ( "should load config from package.json graphiti key" , async ( ) => {
9- const cwd = await Deno . makeTempDir ( ) ;
10- const previousCwd = Deno . cwd ( ) ;
11- try {
96+ await withTempDirAsCwd ( async ( cwd ) => {
1297 const packageConfig = {
1398 name : "opencode-graphiti" ,
1499 graphiti : {
@@ -22,21 +107,18 @@ describe("config", () => {
22107 JSON . stringify ( packageConfig , null , 2 ) ,
23108 ) ;
24109
25- Deno . chdir ( cwd ) ;
26110 const config = loadConfig ( ) ;
27- assertStrictEquals ( config . endpoint , "http://example.com" ) ;
28- assertStrictEquals ( config . driftThreshold , 0.3 ) ;
29- assertStrictEquals ( config . factStaleDays , 14 ) ;
30- } finally {
31- Deno . chdir ( previousCwd ) ;
32- await Deno . remove ( cwd , { recursive : true } ) ;
33- }
111+ assertConfigValues ( config , {
112+ endpoint : "http://example.com" ,
113+ groupIdPrefix : "opencode" ,
114+ driftThreshold : 0.3 ,
115+ factStaleDays : 14 ,
116+ } ) ;
117+ } ) ;
34118 } ) ;
35119
36120 it ( "should load config from .graphitirc when present" , async ( ) => {
37- const cwd = await Deno . makeTempDir ( ) ;
38- const previousCwd = Deno . cwd ( ) ;
39- try {
121+ await withTempDirAsCwd ( async ( cwd ) => {
40122 const rcConfig = {
41123 endpoint : "http://rc.local" ,
42124 driftThreshold : 0.7 ,
@@ -47,55 +129,91 @@ describe("config", () => {
47129 JSON . stringify ( rcConfig , null , 2 ) ,
48130 ) ;
49131
50- Deno . chdir ( cwd ) ;
51132 const config = loadConfig ( ) ;
52- assertStrictEquals ( config . endpoint , "http://rc.local" ) ;
53- assertStrictEquals ( config . driftThreshold , 0.7 ) ;
54- assertStrictEquals ( config . factStaleDays , 21 ) ;
55- } finally {
56- Deno . chdir ( previousCwd ) ;
57- await Deno . remove ( cwd , { recursive : true } ) ;
58- }
133+ assertConfigValues ( config , {
134+ endpoint : "http://rc.local" ,
135+ groupIdPrefix : "opencode" ,
136+ driftThreshold : 0.7 ,
137+ factStaleDays : 21 ,
138+ } ) ;
139+ } ) ;
59140 } ) ;
60141
61142 it ( "should return default config when file does not exist" , async ( ) => {
62- const cwd = await Deno . makeTempDir ( ) ;
63- const previousCwd = Deno . cwd ( ) ;
64- try {
65- Deno . chdir ( cwd ) ;
143+ await withTempDirAsCwd ( ( ) => {
66144 const config = loadConfig ( ) ;
67- // Should have all default fields
68- assertStrictEquals ( typeof config . endpoint , "string" ) ;
69- assertStrictEquals ( typeof config . groupIdPrefix , "string" ) ;
70- assertStrictEquals ( typeof config . driftThreshold , "number" ) ;
71- assertStrictEquals ( typeof config . factStaleDays , "number" ) ;
72-
73- // Verify default values
74- assertStrictEquals ( config . endpoint , "http://localhost:8000/mcp" ) ;
75- assertStrictEquals ( config . groupIdPrefix , "opencode" ) ;
76- assertStrictEquals ( config . driftThreshold , 0.5 ) ;
77- assertStrictEquals ( config . factStaleDays , 30 ) ;
78- } finally {
79- Deno . chdir ( previousCwd ) ;
80- await Deno . remove ( cwd , { recursive : true } ) ;
81- }
145+ assertConfigValues ( config , {
146+ endpoint : "http://localhost:8000/mcp" ,
147+ groupIdPrefix : "opencode" ,
148+ driftThreshold : 0.5 ,
149+ factStaleDays : 30 ,
150+ } ) ;
151+ } ) ;
82152 } ) ;
83153
84154 it ( "should return a valid GraphitiConfig type" , async ( ) => {
85- const cwd = await Deno . makeTempDir ( ) ;
86- const previousCwd = Deno . cwd ( ) ;
87- try {
88- Deno . chdir ( cwd ) ;
155+ await withTempDirAsCwd ( ( ) => {
89156 const config = loadConfig ( ) ;
90157 // Type checking via runtime assertions
91158 assertFalse ( config . endpoint === undefined ) ;
92159 assertFalse ( config . groupIdPrefix === undefined ) ;
93160 assertFalse ( config . driftThreshold === undefined ) ;
94161 assertFalse ( config . factStaleDays === undefined ) ;
95- } finally {
96- Deno . chdir ( previousCwd ) ;
97- await Deno . remove ( cwd , { recursive : true } ) ;
98- }
162+ } ) ;
163+ } ) ;
164+
165+ // --- directory-argument tests ---
166+
167+ for ( const testCase of explicitDirectoryConfigCases ) {
168+ it ( testCase . name , async ( ) => {
169+ await withTempDir ( async ( projectDir ) => {
170+ await Deno . writeTextFile (
171+ join ( projectDir , testCase . fileName ) ,
172+ JSON . stringify ( testCase . fileContents , null , 2 ) ,
173+ ) ;
174+
175+ const config = loadConfig ( projectDir ) ;
176+ assertConfigValues ( config , testCase . expected ) ;
177+ } ) ;
178+ } ) ;
179+ }
180+
181+ it ( "should fall back to the same global/default config when directory argument points to a dir with no config" , async ( ) => {
182+ await withTempDirAsCwd ( async ( ) => {
183+ const fallbackConfig = loadConfig ( ) ;
184+
185+ await withTempDir ( ( emptyDir ) => {
186+ const config = loadConfig ( emptyDir ) ;
187+ assertConfigValues ( config , fallbackConfig ) ;
188+ } ) ;
189+ } ) ;
190+ } ) ;
191+
192+ it ( "project-local config overrides when both project and CWD configs differ" , async ( ) => {
193+ await withTempDir ( async ( projectDir ) => {
194+ await withTempDirAsCwd ( async ( otherDir ) => {
195+ // CWD has one endpoint, project dir has another
196+ await Deno . writeTextFile (
197+ join ( otherDir , ".graphitirc" ) ,
198+ JSON . stringify ( { endpoint : "http://cwd.local/mcp" } , null , 2 ) ,
199+ ) ;
200+ await Deno . writeTextFile (
201+ join ( projectDir , ".graphitirc" ) ,
202+ JSON . stringify (
203+ { endpoint : "http://project-override.local/mcp" } ,
204+ null ,
205+ 2 ,
206+ ) ,
207+ ) ;
208+
209+ const config = loadConfig ( projectDir ) ;
210+ // Must pick project dir, not CWD
211+ assertStrictEquals (
212+ config . endpoint ,
213+ "http://project-override.local/mcp" ,
214+ ) ;
215+ } ) ;
216+ } ) ;
99217 } ) ;
100218 } ) ;
101219} ) ;
0 commit comments