@@ -14,6 +14,18 @@ function dsDataHome(): string {
1414 return process . env . DSCODE_DATA_HOME ?? join ( homedir ( ) , ".dscode" ) ;
1515}
1616
17+ function userConfigPath ( ) : string {
18+ return join ( dsConfigHome ( ) , "config.json" ) ;
19+ }
20+
21+ function userSettingsPath ( ) : string {
22+ return join ( dsConfigHome ( ) , "settings.json" ) ;
23+ }
24+
25+ function projectSettingsPath ( projectPath : string ) : string {
26+ return join ( projectPath , ".dscode" , "settings.json" ) ;
27+ }
28+
1729function loadJsonSafe ( path : string ) : Record < string , unknown > {
1830 if ( ! existsSync ( path ) ) return { } ;
1931 try {
@@ -34,52 +46,65 @@ export function maskApiKey(key: string | undefined): string {
3446 return key . slice ( 0 , 3 ) + "****" + key . slice ( - 4 ) ;
3547}
3648
37- export function saveUserConfig ( partial : Record < string , unknown > ) : void {
38- const path = join ( dsConfigHome ( ) , "config.json" ) ;
39- const existing = loadJsonSafe ( path ) ;
40- saveJsonSafe ( path , { ...existing , ...partial } ) ;
49+ function loadUserCommandConfig ( ) : Record < string , unknown > {
50+ return loadJsonSafe ( userConfigPath ( ) ) ;
4151}
4252
43- export function saveProjectConfig ( partial : Record < string , unknown > , projectPath : string ) : void {
44- const path = join ( projectPath , ".dscode" , "config.json" ) ;
45- const existing = loadJsonSafe ( path ) ;
53+ function loadScopedSettings ( settingsPath : string ) : Record < string , unknown > {
54+ return loadJsonSafe ( settingsPath ) ;
55+ }
56+
57+ export function saveUserConfig ( partial : Record < string , unknown > ) : void {
58+ const path = userConfigPath ( ) ;
59+ const existing = loadUserCommandConfig ( ) ;
4660 saveJsonSafe ( path , { ...existing , ...partial } ) ;
4761}
4862
4963export function loadConfig ( ) : HarnessConfig {
50- const projectPath = resolve ( process . env . DSCODE_PROJECT_PATH ?? process . cwd ( ) ) ;
64+ const startupPath = resolve ( process . env . DSCODE_PROJECT_PATH ?? process . cwd ( ) ) ;
65+ const configDir = dsConfigHome ( ) ;
66+ const dataDir = join ( dsDataHome ( ) , "data" ) ;
67+
68+ const userConfig = loadUserCommandConfig ( ) ;
69+ const userSettings = loadScopedSettings ( userSettingsPath ( ) ) ;
70+
71+ let projectPath = startupPath ;
72+ const configuredCwd = userConfig . cwd ;
73+ if ( typeof configuredCwd === "string" && configuredCwd . trim ( ) !== "" ) {
74+ const nextProjectPath = resolve ( configuredCwd ) ;
75+ if ( existsSync ( nextProjectPath ) ) {
76+ projectPath = nextProjectPath ;
77+ }
78+ }
79+
5180 if ( projectPath !== process . cwd ( ) ) {
5281 process . chdir ( projectPath ) ;
5382 }
5483
55- const configDir = dsConfigHome ( ) ;
56- const dataDir = join ( dsDataHome ( ) , "data" ) ;
57-
58- const userConfig = loadJsonSafe ( join ( configDir , "config.json" ) ) ;
59- const projectConfig = loadJsonSafe ( join ( projectPath , ".dscode" , "config.json" ) ) ;
60- const merged = { ...userConfig , ...projectConfig } ;
84+ const projectSettings = loadScopedSettings ( projectSettingsPath ( projectPath ) ) ;
85+ const merged = { ...userSettings , ...projectSettings } ;
6186
6287 const provider = ( process . env . AGENT_PROVIDER as string ) ?? ( merged . provider as string ) ?? "deepseek" ;
63- const modelId = ( process . env . AGENT_MODEL as string ) ?? ( process . env . DEEPSEEK_MODEL as string ) ?? ( merged . modelId as string ) ?? "deepseek-v4-flash" ;
88+ const modelId = ( process . env . AGENT_MODEL as string ) ?? ( process . env . DEEPSEEK_MODEL as string ) ?? ( userConfig . modelId as string ) ?? ( merged . modelId as string ) ?? "deepseek-v4-flash" ;
6489 const maxTokens = Number ( process . env . DSCODE_MAX_TOKENS ) || ( merged . maxTokens as number ) || 16384 ;
6590
6691 // API key: env var > user config (never project config for security)
6792 const apiKey = process . env . DEEPSEEK_API_KEY ?? ( userConfig . apiKey as string | undefined ) ;
6893
69- const userDeny = ( ( userConfig . permissions as any ) ?. deny as string [ ] ) ?? [ ] ;
70- const projectDeny = ( ( projectConfig . permissions as any ) ?. deny as string [ ] ) ?? [ ] ;
94+ const userDeny = ( ( userSettings . permissions as any ) ?. deny as string [ ] ) ?? [ ] ;
95+ const projectDeny = ( ( projectSettings . permissions as any ) ?. deny as string [ ] ) ?? [ ] ;
7196 const denyPatterns = [ ...new Set ( [ ...userDeny , ...projectDeny ] ) ] ;
7297
73- const userSkills = ( ( userConfig . skills as string [ ] ) ?? [ ] ) ;
74- const projectSkills = ( ( projectConfig . skills as string [ ] ) ?? [ ] ) ;
98+ const userSkills = ( ( userSettings . skills as string [ ] ) ?? [ ] ) ;
99+ const projectSkills = ( ( projectSettings . skills as string [ ] ) ?? [ ] ) ;
75100 const skills = [ ...new Set ( [ ...userSkills , ...projectSkills ] ) ] ;
76101
77102 const userSkillsDir = join ( configDir , "skills" ) ;
78103 const projectSkillsDir = join ( projectPath , ".dscode" , "skills" ) ;
79104
80105 const validThinkingLevels = new Set ( [ "off" , "minimal" , "low" , "medium" , "high" , "xhigh" ] ) ;
81106 const defaultThinkingLevel : ThinkingLevel = modelId . includes ( "pro" ) ? "medium" : "off" ;
82- const rawThinkingLevel = process . env . AGENT_THINKING_LEVEL ?? merged . thinkingLevel ;
107+ const rawThinkingLevel = process . env . AGENT_THINKING_LEVEL ?? userConfig . thinkingLevel ?? merged . thinkingLevel ;
83108 const thinkingLevel : ThinkingLevel = rawThinkingLevel !== undefined && validThinkingLevels . has ( rawThinkingLevel as string )
84109 ? ( rawThinkingLevel as ThinkingLevel )
85110 : defaultThinkingLevel ;
0 commit comments