Skip to content

Commit 135046f

Browse files
authored
Merge pull request #122 from hqwlkj/refactor/tidy-up
refactor(ui): 重构代码结构,调整文件路径和导入引用
2 parents d07d225 + e25cb9e commit 135046f

65 files changed

Lines changed: 567 additions & 471 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/cli.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { render } from "ink";
33
import { setShellIfWindows } from "./common/shell-utils";
4-
import { checkForNpmUpdate, promptForPendingUpdate, type PackageInfo } from "./updateCheck";
4+
import { checkForNpmUpdate, promptForPendingUpdate, type PackageInfo } from "./common/update-check";
55
import { AppContainer } from "./ui";
66

77
const args = process.argv.slice(2);

src/common/openai-client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as os from "os";
33
import * as path from "path";
44
import OpenAI from "openai";
55
import { Agent, fetch as undiciFetch } from "undici";
6-
import { resolveCurrentSettings } from "../ui/App";
6+
import { resolveCurrentSettings } from "../settings";
77

88
// Custom undici Agent with a 180-second keepAlive timeout. The default
99
// global fetch (undici) only keeps connections alive for 4 seconds, which
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import * as os from "os";
55
import * as path from "path";
66
import { render, type Instance } from "ink";
77
import chalk from "chalk";
8-
import { UpdatePrompt, type UpdatePromptChoice } from "./ui";
9-
import { killProcessTree } from "./common/process-tree";
8+
import { UpdatePrompt, type UpdatePromptChoice } from "../ui";
9+
import { killProcessTree } from "./process-tree";
1010

1111
export type PackageInfo = {
1212
name: string;

src/prompt.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { execFileSync, execSync } from "child_process";
22
import * as fs from "fs";
33
import * as os from "os";
44
import * as path from "path";
5-
import { fileURLToPath } from "url";
65
import ejs from "ejs";
6+
import { fileURLToPath } from "url";
77
import type { SessionMessage } from "./session";
88
import { findGitBashPath, resolveShellPath } from "./common/shell-utils";
99
import { supportsMultimodal } from "./common/model-capabilities";
@@ -166,8 +166,7 @@ function getCurrentDateAndModelPrompt(model?: string): string {
166166

167167
export function getSystemPrompt(_projectRoot: string, options: PromptToolOptions = {}): string {
168168
const toolDocs = readToolDocs(getExtensionRoot(), options);
169-
const basePrompt = toolDocs ? `${SYSTEM_PROMPT_BASE}\n\n# Available Tools\n\n${toolDocs}` : SYSTEM_PROMPT_BASE;
170-
return basePrompt;
169+
return toolDocs ? `${SYSTEM_PROMPT_BASE}\n\n# Available Tools\n\n${toolDocs}` : SYSTEM_PROMPT_BASE;
171170
}
172171

173172
export function getCompactPrompt(sessionMessages: SessionMessage[]): string {
@@ -287,7 +286,7 @@ function getUnameInfo(): string {
287286
}
288287
}
289288

290-
function getExtensionRoot(): string {
289+
export function getExtensionRoot(): string {
291290
// Prefer `__dirname` which is always available in the CJS bundle output.
292291
// Fall back to `import.meta.url` for ESM test environments (tsx --test).
293292
if (typeof __dirname !== "undefined") {

src/session.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import * as fs from "fs";
22
import * as path from "path";
33
import * as os from "os";
44
import * as crypto from "crypto";
5-
import { fileURLToPath } from "url";
65
import matter from "gray-matter";
76
import ejs from "ejs";
87
import type { ChatCompletionMessageParam, ChatCompletionContentPart } from "openai/resources/chat/completions";
@@ -12,6 +11,7 @@ import { DEEPSEEK_V4_MODELS, supportsMultimodal } from "./common/model-capabilit
1211
import {
1312
getCompactPrompt,
1413
getDefaultSkillPrompt,
14+
getExtensionRoot,
1515
getRuntimeContext,
1616
getSystemPrompt,
1717
getTools,
@@ -135,15 +135,6 @@ function accumulateUsagePerModel(
135135
return usagePerModel;
136136
}
137137

138-
function getExtensionRoot(): string {
139-
if (typeof __dirname !== "undefined") {
140-
return path.resolve(__dirname, "..");
141-
}
142-
143-
const currentFilePath = fileURLToPath(import.meta.url);
144-
return path.resolve(path.dirname(currentFilePath), "..");
145-
}
146-
147138
function getTotalTokens(usage: ModelUsage | null | undefined): number {
148139
if (!isUsageRecord(usage)) {
149140
return 0;

src/settings.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { defaultsToThinkingMode } from "./common/model-capabilities";
2+
import * as fs from "fs";
3+
import * as os from "os";
4+
import * as path from "path";
25

36
export type DeepcodingEnv = Record<string, string | undefined> & {
47
MODEL?: string;
@@ -370,3 +373,88 @@ export function applyModelConfigSelection(
370373

371374
return { settings: next, changed: true };
372375
}
376+
377+
// ---------------------------------------------------------------------------
378+
// Default constants
379+
// ---------------------------------------------------------------------------
380+
381+
export const DEFAULT_MODEL = "deepseek-v4-pro";
382+
export const DEFAULT_BASE_URL = "https://api.deepseek.com";
383+
384+
// ---------------------------------------------------------------------------
385+
// Settings file I/O
386+
// ---------------------------------------------------------------------------
387+
388+
export function getUserSettingsPath(): string {
389+
return path.join(os.homedir(), ".deepcode", "settings.json");
390+
}
391+
392+
export function getProjectSettingsPath(projectRoot: string): string {
393+
return path.join(projectRoot, ".deepcode", "settings.json");
394+
}
395+
396+
export function readSettingsFile(settingsPath: string): DeepcodingSettings | null {
397+
try {
398+
if (!fs.existsSync(settingsPath)) {
399+
return null;
400+
}
401+
const raw = fs.readFileSync(settingsPath, "utf8");
402+
return JSON.parse(raw) as DeepcodingSettings;
403+
} catch {
404+
return null;
405+
}
406+
}
407+
408+
export function readSettings(): DeepcodingSettings | null {
409+
return readSettingsFile(getUserSettingsPath());
410+
}
411+
412+
export function readProjectSettings(projectRoot: string = process.cwd()): DeepcodingSettings | null {
413+
return readSettingsFile(getProjectSettingsPath(projectRoot));
414+
}
415+
416+
function writeSettingsFile(settingsPath: string, settings: DeepcodingSettings): void {
417+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
418+
fs.writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
419+
}
420+
421+
export function writeSettings(settings: DeepcodingSettings): void {
422+
const settingsPath = getUserSettingsPath();
423+
writeSettingsFile(settingsPath, settings);
424+
}
425+
426+
export function writeProjectSettings(settings: DeepcodingSettings, projectRoot: string = process.cwd()): void {
427+
const settingsPath = getProjectSettingsPath(projectRoot);
428+
writeSettingsFile(settingsPath, settings);
429+
}
430+
431+
export function writeModelConfigSelection(
432+
selection: ModelConfigSelection,
433+
current: ModelConfigSelection = resolveCurrentSettings(),
434+
projectRoot: string = process.cwd()
435+
): { changed: boolean; settings: DeepcodingSettings } {
436+
const projectSettingsPath = getProjectSettingsPath(projectRoot);
437+
const shouldWriteProjectSettings = fs.existsSync(projectSettingsPath);
438+
const rawSettings = shouldWriteProjectSettings ? readProjectSettings(projectRoot) : readSettings();
439+
const result = applyModelConfigSelection(rawSettings, current, selection);
440+
if (result.changed) {
441+
if (shouldWriteProjectSettings) {
442+
writeProjectSettings(result.settings, projectRoot);
443+
} else {
444+
writeSettings(result.settings);
445+
}
446+
}
447+
return result;
448+
}
449+
450+
export function resolveCurrentSettings(projectRoot: string = process.cwd()): ResolvedDeepcodingSettings {
451+
return resolveSettingsSources(
452+
readSettings(),
453+
readProjectSettings(projectRoot),
454+
{
455+
model: DEFAULT_MODEL,
456+
baseURL: DEFAULT_BASE_URL,
457+
},
458+
process.env
459+
);
460+
}

src/tests/clipboard.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as os from "os";
55
import * as path from "path";
66

77
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
8-
type ClipboardModule = typeof import("../ui/clipboard");
8+
type ClipboardModule = typeof import("../ui/core/clipboard");
99

1010
const ORIGINAL_PATH = process.env.PATH;
1111
const ORIGINAL_PLATFORM = process.platform;
@@ -30,7 +30,7 @@ function withPlatform<T>(platform: NodeJS.Platform, fn: () => T): T {
3030

3131
test("readClipboardImage returns null when no clipboard helpers are installed", async () => {
3232
// Reload module so it picks up the patched PATH at spawn time.
33-
const moduleUrl = new URL(`../ui/clipboard.ts?t=${Date.now()}`, import.meta.url).href;
33+
const moduleUrl = new URL(`../ui/core/clipboard.ts?t=${Date.now()}`, import.meta.url).href;
3434
const { readClipboardImage } = (await import(moduleUrl)) as ClipboardModule;
3535
const result = withCleanPath(() => readClipboardImage());
3636
assert.equal(result, null);
@@ -63,7 +63,7 @@ test(
6363
{ mode: 0o755 }
6464
);
6565

66-
const moduleUrl = new URL(`../ui/clipboard.ts?t=${Date.now()}`, import.meta.url).href;
66+
const moduleUrl = new URL(`../ui/core/clipboard.ts?t=${Date.now()}`, import.meta.url).href;
6767
const { readClipboardImage } = (await import(moduleUrl)) as ClipboardModule;
6868

6969
process.env.PATH = binDir;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test } from "node:test";
22
import assert from "node:assert/strict";
3-
import { calculateVisibleStart } from "../ui/DropdownMenu";
3+
import { calculateVisibleStart } from "../ui/components/DropdownMenu";
44

55
test("calculateVisibleStart centers active item when possible", () => {
66
// 10 items, max 5 visible, active index 4 (middle)

0 commit comments

Comments
 (0)