11import React , { useCallback , useEffect , useLayoutEffect , useMemo , useRef , useState } from "react" ;
22import { Box , Static , Text , useApp , useStdout , useWindowSize } from "ink" ;
33import chalk from "chalk" ;
4- import * as fs from "fs" ;
5- import * as os from "os" ;
6- import * as path from "path" ;
7- import OpenAI from "openai" ;
84import {
95 type LlmStreamProgress ,
106 type MessageMeta ,
@@ -16,13 +12,9 @@ import {
1612 type UndoTarget ,
1713 type UserPromptContent ,
1814} from "../session" ;
19- import {
20- applyModelConfigSelection ,
21- type DeepcodingSettings ,
22- type ModelConfigSelection ,
23- type ResolvedDeepcodingSettings ,
24- resolveSettingsSources ,
25- } from "../settings" ;
15+ import { type ModelConfigSelection , type ResolvedDeepcodingSettings } from "../settings" ;
16+ import { resolveCurrentSettings , writeModelConfigSelection } from "../common/settings" ;
17+ import { createOpenAIClient } from "../common/openai-client" ;
2618import { PromptInput , type PromptDraft , type PromptSubmission } from "./PromptInput" ;
2719import { MessageView , RawModeExitPrompt } from "./components" ;
2820import { SessionList } from "./SessionList" ;
@@ -42,9 +34,6 @@ import { buildExitSummaryText } from "./exitSummary";
4234import { RawMode , useRawModeContext } from "./contexts" ;
4335import { renderMessageToStdout } from "./components/MessageView/utils" ;
4436
45- const DEFAULT_MODEL = "deepseek-v4-pro" ;
46- const DEFAULT_BASE_URL = "https://api.deepseek.com" ;
47-
4837type View = "chat" | "session-list" | "undo" | "mcp-status" ;
4938
5039type AppProps = {
@@ -772,144 +761,6 @@ function buildStatusLine(entry: SessionEntry): string {
772761 return parts . join ( " · " ) ;
773762}
774763
775- export function readSettings ( ) : DeepcodingSettings | null {
776- return readSettingsFile ( getUserSettingsPath ( ) ) ;
777- }
778-
779- export function readProjectSettings ( projectRoot : string = process . cwd ( ) ) : DeepcodingSettings | null {
780- return readSettingsFile ( getProjectSettingsPath ( projectRoot ) ) ;
781- }
782-
783- function readSettingsFile ( settingsPath : string ) : DeepcodingSettings | null {
784- try {
785- if ( ! fs . existsSync ( settingsPath ) ) {
786- return null ;
787- }
788- const raw = fs . readFileSync ( settingsPath , "utf8" ) ;
789- return JSON . parse ( raw ) as DeepcodingSettings ;
790- } catch {
791- return null ;
792- }
793- }
794-
795- export function writeSettings ( settings : DeepcodingSettings ) : void {
796- const settingsPath = getUserSettingsPath ( ) ;
797- writeSettingsFile ( settingsPath , settings ) ;
798- }
799-
800- export function writeProjectSettings ( settings : DeepcodingSettings , projectRoot : string = process . cwd ( ) ) : void {
801- const settingsPath = getProjectSettingsPath ( projectRoot ) ;
802- writeSettingsFile ( settingsPath , settings ) ;
803- }
804-
805- function writeSettingsFile ( settingsPath : string , settings : DeepcodingSettings ) : void {
806- fs . mkdirSync ( path . dirname ( settingsPath ) , { recursive : true } ) ;
807- fs . writeFileSync ( settingsPath , `${ JSON . stringify ( settings , null , 2 ) } \n` , "utf8" ) ;
808- }
809-
810- export function writeModelConfigSelection (
811- selection : ModelConfigSelection ,
812- current : ModelConfigSelection = resolveCurrentSettings ( ) ,
813- projectRoot : string = process . cwd ( )
814- ) : { changed : boolean ; settings : DeepcodingSettings } {
815- const projectSettingsPath = getProjectSettingsPath ( projectRoot ) ;
816- const shouldWriteProjectSettings = fs . existsSync ( projectSettingsPath ) ;
817- const rawSettings = shouldWriteProjectSettings ? readProjectSettings ( projectRoot ) : readSettings ( ) ;
818- const result = applyModelConfigSelection ( rawSettings , current , selection ) ;
819- if ( result . changed ) {
820- if ( shouldWriteProjectSettings ) {
821- writeProjectSettings ( result . settings , projectRoot ) ;
822- } else {
823- writeSettings ( result . settings ) ;
824- }
825- }
826- return result ;
827- }
828-
829- export function resolveCurrentSettings ( projectRoot : string = process . cwd ( ) ) : ResolvedDeepcodingSettings {
830- return resolveSettingsSources (
831- readSettings ( ) ,
832- readProjectSettings ( projectRoot ) ,
833- {
834- model : DEFAULT_MODEL ,
835- baseURL : DEFAULT_BASE_URL ,
836- } ,
837- process . env
838- ) ;
839- }
840-
841- export function createOpenAIClient ( projectRoot : string = process . cwd ( ) ) : {
842- client : OpenAI | null ;
843- model : string ;
844- baseURL : string ;
845- thinkingEnabled : boolean ;
846- reasoningEffort : "high" | "max" ;
847- debugLogEnabled : boolean ;
848- notify ?: string ;
849- webSearchTool ?: string ;
850- env : Record < string , string > ;
851- machineId ?: string ;
852- } {
853- const settings = resolveCurrentSettings ( projectRoot ) ;
854- if ( ! settings . apiKey ) {
855- return {
856- client : null ,
857- model : settings . model ,
858- baseURL : settings . baseURL ,
859- thinkingEnabled : settings . thinkingEnabled ,
860- reasoningEffort : settings . reasoningEffort ,
861- debugLogEnabled : settings . debugLogEnabled ,
862- notify : settings . notify ,
863- webSearchTool : settings . webSearchTool ,
864- env : settings . env ,
865- machineId : getMachineId ( ) ,
866- } ;
867- }
868-
869- const client = new OpenAI ( {
870- apiKey : settings . apiKey ,
871- baseURL : settings . baseURL || undefined ,
872- } ) ;
873- return {
874- client,
875- model : settings . model ,
876- baseURL : settings . baseURL ,
877- thinkingEnabled : settings . thinkingEnabled ,
878- reasoningEffort : settings . reasoningEffort ,
879- debugLogEnabled : settings . debugLogEnabled ,
880- notify : settings . notify ,
881- webSearchTool : settings . webSearchTool ,
882- env : settings . env ,
883- machineId : getMachineId ( ) ,
884- } ;
885- }
886-
887- function getMachineId ( ) : string | undefined {
888- try {
889- const idPath = path . join ( os . homedir ( ) , ".deepcode" , "machine-id" ) ;
890- if ( fs . existsSync ( idPath ) ) {
891- const raw = fs . readFileSync ( idPath , "utf8" ) . trim ( ) ;
892- if ( raw ) {
893- return raw ;
894- }
895- }
896- const generated = `${ os . hostname ( ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } -${ Date . now ( ) } ` ;
897- fs . mkdirSync ( path . dirname ( idPath ) , { recursive : true } ) ;
898- fs . writeFileSync ( idPath , generated , "utf8" ) ;
899- return generated ;
900- } catch {
901- return undefined ;
902- }
903- }
904-
905- function getUserSettingsPath ( ) : string {
906- return path . join ( os . homedir ( ) , ".deepcode" , "settings.json" ) ;
907- }
908-
909- function getProjectSettingsPath ( projectRoot : string ) : string {
910- return path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
911- }
912-
913764function formatThinkingMode ( settings : Pick < ModelConfigSelection , "thinkingEnabled" | "reasoningEffort" > ) : string {
914765 if ( ! settings . thinkingEnabled ) {
915766 return "no thinking" ;
0 commit comments