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" ;
74import { createOpenAIClient } from "../common/openai-client" ;
85import {
96 type LlmStreamProgress ,
@@ -17,17 +14,11 @@ import {
1714 type UndoTarget ,
1815 type UserPromptContent ,
1916} from "../session" ;
20- import {
21- applyModelConfigSelection ,
22- type DeepcodingSettings ,
23- type ModelConfigSelection ,
24- type ResolvedDeepcodingSettings ,
25- resolveSettingsSources ,
26- } from "../settings" ;
27- import { PromptInput , type PromptDraft , type PromptSubmission } from "./PromptInput" ;
17+ import { type ModelConfigSelection } from "../settings" ;
18+ import { type PromptDraft , PromptInput , type PromptSubmission } from "./PromptInput" ;
2819import { MessageView , RawModeExitPrompt } from "./components" ;
2920import { SessionList } from "./SessionList" ;
30- import { UndoSelector , type UndoRestoreMode } from "./UndoSelector" ;
21+ import { type UndoRestoreMode , UndoSelector } from "./UndoSelector" ;
3122import { buildLoadingText } from "./loadingText" ;
3223import { findExpandedThinkingId } from "./thinkingState" ;
3324import { WelcomeScreen } from "./WelcomeScreen" ;
@@ -43,12 +34,19 @@ import { PermissionPrompt, type PermissionPromptResult } from "./PermissionPromp
4334import { buildExitSummaryText } from "./exitSummary" ;
4435import { RawMode , useRawModeContext } from "./contexts" ;
4536import { renderMessageToStdout } from "./components/MessageView/utils" ;
46- import { renderRawModeMessages } from "./utils" ;
37+ import {
38+ buildPromptDraftFromSessionMessage ,
39+ buildStatusLine ,
40+ buildSyntheticUserMessage ,
41+ formatModelConfig ,
42+ isCollapsedThinking ,
43+ isCurrentSessionEmpty ,
44+ renderRawModeMessages ,
45+ resolveCurrentSettings ,
46+ writeModelConfigSelection ,
47+ } from "./utils" ;
4748import { ANSI_CLEAR_SCREEN } from "./constants" ;
4849
49- const DEFAULT_MODEL = "deepseek-v4-pro" ;
50- const DEFAULT_BASE_URL = "https://api.deepseek.com" ;
51-
5250type View = "chat" | "session-list" | "undo" | "mcp-status" ;
5351
5452type AppProps = {
@@ -807,163 +805,3 @@ function App({ projectRoot, initialPrompt, onRestart }: AppProps): React.ReactEl
807805}
808806
809807export default App ;
810-
811- function isCollapsedThinking ( message : SessionMessage , expandedId : string | null ) : boolean {
812- if ( message . role !== "assistant" ) {
813- return false ;
814- }
815- if ( ! message . meta ?. asThinking ) {
816- return false ;
817- }
818- return message . id !== expandedId ;
819- }
820-
821- function buildSyntheticUserMessage ( content : string , imageCount : number ) : SessionMessage {
822- const now = new Date ( ) . toISOString ( ) ;
823- return {
824- id : `local-${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } ` ,
825- sessionId : "local" ,
826- role : "user" ,
827- content,
828- contentParams :
829- imageCount > 0
830- ? Array . from ( { length : imageCount } , ( ) => ( {
831- type : "image_url" ,
832- image_url : { url : "" } ,
833- } ) )
834- : null ,
835- messageParams : null ,
836- compacted : false ,
837- visible : true ,
838- createTime : now ,
839- updateTime : now ,
840- } ;
841- }
842-
843- export function buildPromptDraftFromSessionMessage ( message : SessionMessage , nonce : number ) : PromptDraft {
844- return {
845- nonce,
846- text : typeof message . content === "string" ? message . content : "" ,
847- imageUrls : extractImageUrlsFromContentParams ( message . contentParams ) ,
848- } ;
849- }
850-
851- function extractImageUrlsFromContentParams ( contentParams : unknown ) : string [ ] {
852- const params = Array . isArray ( contentParams ) ? contentParams : contentParams ? [ contentParams ] : [ ] ;
853- const imageUrls : string [ ] = [ ] ;
854- for ( const param of params ) {
855- if ( ! param || typeof param !== "object" ) {
856- continue ;
857- }
858- const record = param as { type ?: unknown ; image_url ?: { url ?: unknown } } ;
859- const url = record . image_url ?. url ;
860- if ( record . type === "image_url" && typeof url === "string" && url ) {
861- imageUrls . push ( url ) ;
862- }
863- }
864- return imageUrls ;
865- }
866-
867- function isCurrentSessionEmpty ( sessionManager : SessionManager ) : boolean {
868- const activeSessionId = sessionManager . getActiveSessionId ( ) ;
869- return ! activeSessionId || ! sessionManager . getSession ( activeSessionId ) ;
870- }
871-
872- function buildStatusLine ( entry : SessionEntry ) : string {
873- const parts : string [ ] = [ ] ;
874- parts . push ( `status: ${ entry . status } ` ) ;
875- if ( typeof entry . activeTokens === "number" && entry . activeTokens > 0 ) {
876- parts . push ( `tokens: ${ entry . activeTokens } ` ) ;
877- }
878- if ( entry . failReason ) {
879- parts . push ( `fail: ${ entry . failReason } ` ) ;
880- }
881- return parts . join ( " · " ) ;
882- }
883-
884- export function readSettings ( ) : DeepcodingSettings | null {
885- return readSettingsFile ( getUserSettingsPath ( ) ) ;
886- }
887-
888- export function readProjectSettings ( projectRoot : string = process . cwd ( ) ) : DeepcodingSettings | null {
889- return readSettingsFile ( getProjectSettingsPath ( projectRoot ) ) ;
890- }
891-
892- function readSettingsFile ( settingsPath : string ) : DeepcodingSettings | null {
893- try {
894- if ( ! fs . existsSync ( settingsPath ) ) {
895- return null ;
896- }
897- const raw = fs . readFileSync ( settingsPath , "utf8" ) ;
898- return JSON . parse ( raw ) as DeepcodingSettings ;
899- } catch {
900- return null ;
901- }
902- }
903-
904- export function writeSettings ( settings : DeepcodingSettings ) : void {
905- const settingsPath = getUserSettingsPath ( ) ;
906- writeSettingsFile ( settingsPath , settings ) ;
907- }
908-
909- export function writeProjectSettings ( settings : DeepcodingSettings , projectRoot : string = process . cwd ( ) ) : void {
910- const settingsPath = getProjectSettingsPath ( projectRoot ) ;
911- writeSettingsFile ( settingsPath , settings ) ;
912- }
913-
914- function writeSettingsFile ( settingsPath : string , settings : DeepcodingSettings ) : void {
915- fs . mkdirSync ( path . dirname ( settingsPath ) , { recursive : true } ) ;
916- fs . writeFileSync ( settingsPath , `${ JSON . stringify ( settings , null , 2 ) } \n` , "utf8" ) ;
917- }
918-
919- export function writeModelConfigSelection (
920- selection : ModelConfigSelection ,
921- current : ModelConfigSelection = resolveCurrentSettings ( ) ,
922- projectRoot : string = process . cwd ( )
923- ) : { changed : boolean ; settings : DeepcodingSettings } {
924- const projectSettingsPath = getProjectSettingsPath ( projectRoot ) ;
925- const shouldWriteProjectSettings = fs . existsSync ( projectSettingsPath ) ;
926- const rawSettings = shouldWriteProjectSettings ? readProjectSettings ( projectRoot ) : readSettings ( ) ;
927- const result = applyModelConfigSelection ( rawSettings , current , selection ) ;
928- if ( result . changed ) {
929- if ( shouldWriteProjectSettings ) {
930- writeProjectSettings ( result . settings , projectRoot ) ;
931- } else {
932- writeSettings ( result . settings ) ;
933- }
934- }
935- return result ;
936- }
937-
938- export function resolveCurrentSettings ( projectRoot : string = process . cwd ( ) ) : ResolvedDeepcodingSettings {
939- return resolveSettingsSources (
940- readSettings ( ) ,
941- readProjectSettings ( projectRoot ) ,
942- {
943- model : DEFAULT_MODEL ,
944- baseURL : DEFAULT_BASE_URL ,
945- } ,
946- process . env
947- ) ;
948- }
949-
950- export { createOpenAIClient } from "../common/openai-client" ;
951-
952- function getUserSettingsPath ( ) : string {
953- return path . join ( os . homedir ( ) , ".deepcode" , "settings.json" ) ;
954- }
955-
956- function getProjectSettingsPath ( projectRoot : string ) : string {
957- return path . join ( projectRoot , ".deepcode" , "settings.json" ) ;
958- }
959-
960- function formatThinkingMode ( settings : Pick < ModelConfigSelection , "thinkingEnabled" | "reasoningEffort" > ) : string {
961- if ( ! settings . thinkingEnabled ) {
962- return "no thinking" ;
963- }
964- return `thinking ${ settings . reasoningEffort } ` ;
965- }
966-
967- function formatModelConfig ( settings : ModelConfigSelection ) : string {
968- return `${ settings . model } , ${ formatThinkingMode ( settings ) } ` ;
969- }
0 commit comments