Download src/core/config.ts from teddyoas/Asnip: direct link, hf CLI and curl.
- Browser
- Download file 4.98 kB
-
https://huggingface.co/teddyoas/Asnip/resolve/main/src/core/config.ts
- Command line
-
hf download hf://teddyoas/Asnip/src/core/config.ts
-
curl -L -o config.ts https://huggingface.co/teddyoas/Asnip/resolve/main/src/core/config.ts
4.98 kB
| import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"; | |
| import { homedir } from "os"; | |
| import { resolve } from "path"; | |
| export interface PhantomConfig { | |
| agents: { | |
| maxInstances: number; | |
| defaultModel: string; | |
| defaultProvider: string; | |
| heartbeatInterval: number; | |
| }; | |
| ui: { | |
| borderStyle: string; | |
| animationSpeed: number; | |
| }; | |
| providers: { | |
| openai: { apiKey: string; baseUrl: string }; | |
| anthropic: { apiKey: string }; | |
| ollama: { baseUrl: string; model: string }; | |
| }; | |
| } | |
| const CONFIG_DIR = resolve(homedir(), ".config", "phantom"); | |
| const CONFIG_PATH = resolve(CONFIG_DIR, "config.json"); | |
| export const defaultConfig: PhantomConfig = { | |
| agents: { | |
| maxInstances: 8, | |
| defaultModel: "gpt-4o", | |
| defaultProvider: "openai", | |
| heartbeatInterval: 3000, | |
| }, | |
| ui: { | |
| borderStyle: "line", | |
| animationSpeed: 50, | |
| }, | |
| providers: { | |
| openai: { apiKey: process.env.OPENAI_API_KEY || "", baseUrl: "https://api.openai.com/v1" }, | |
| anthropic: { apiKey: process.env.ANTHROPIC_API_KEY || "" }, | |
| ollama: { baseUrl: process.env.OLLAMA_HOST || "http://localhost:11434", model: "llama3" }, | |
| }, | |
| }; | |
| export function loadConfig(): PhantomConfig { | |
| try { | |
| if (!existsSync(CONFIG_DIR)) { | |
| mkdirSync(CONFIG_DIR, { recursive: true }); | |
| } | |
| if (!existsSync(CONFIG_PATH)) { | |
| writeFileSync(CONFIG_PATH, JSON.stringify(defaultConfig, null, 2)); | |
| return defaultConfig; | |
| } | |
| const raw = readFileSync(CONFIG_PATH, "utf-8"); | |
| const userConfig = JSON.parse(raw); | |
| // Deep merge: user config overrides defaults, preserving nested objects | |
| function deepMerge(target: any, source: any): any { | |
| const result = { ...target }; | |
| for (const key of Object.keys(source)) { | |
| const sourceVal = source[key]; | |
| const targetVal = target[key]; | |
| if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && | |
| targetVal && typeof targetVal === "object" && !Array.isArray(targetVal)) { | |
| result[key] = deepMerge(targetVal, sourceVal); | |
| } else { | |
| result[key] = sourceVal; | |
| } | |
| } | |
| return result; | |
| } | |
| return deepMerge(defaultConfig, userConfig) as PhantomConfig; | |
| } catch { | |
| return defaultConfig; | |
| } | |
| } | |
| export interface EnvInfo { | |
| tty: boolean; | |
| interactive: boolean; | |
| platform: string; | |
| terminal: string; | |
| colors: number; | |
| hasTrueColor: boolean; | |
| has256: boolean; | |
| cols: number; | |
| rows: number; | |
| screenSize: "tiny" | "small" | "medium" | "large" | "huge"; | |
| inputMode: string; | |
| isTermux: boolean; | |
| isTmux: boolean; | |
| isWSL: boolean; | |
| isWindows: boolean; | |
| } | |
| export function detectEnv(): EnvInfo { | |
| const isTTY = !!process.stdin.isTTY; | |
| const isCI = !!process.env.CI || !!process.env.GITHUB_ACTIONS; | |
| const isTermux = !!(process.env.TERMUX_VERSION || process.env.PREFIX?.startsWith("/data/data/com.termux")); | |
| const isWindows = process.platform === "win32"; | |
| const isWSL = !!process.env.WSL_DISTRO_NAME; | |
| const isTmux = !!process.env.TMUX; | |
| const term = (process.env.TERM || "unknown").toLowerCase(); | |
| const colorterm = (process.env.COLORTERM || "").toLowerCase(); | |
| let terminal = "unknown"; | |
| if (isTermux) terminal = "termux"; | |
| else if (term.includes("kitty")) terminal = "kitty"; | |
| else if (term.includes("alacritty")) terminal = "alacritty"; | |
| else if (term.includes("gnome")) terminal = "gnome"; | |
| else if (term.includes("konsole")) terminal = "konsole"; | |
| else if (term.includes("tmux") || isTmux) terminal = "tmux"; | |
| else if (term.includes("screen")) terminal = "screen"; | |
| else if (term.includes("xterm")) terminal = "xterm"; | |
| else if (isWindows) terminal = "windows-console"; | |
| else if (process.env.TERM_PROGRAM === "iterm2") terminal = "iterm2"; | |
| else if (process.env.TERM_PROGRAM === "Apple_Terminal") terminal = "apple-terminal"; | |
| else if (process.env.VSCODE_INJECTION) terminal = "vscode"; | |
| let colors = 16; | |
| if (colorterm === "truecolor" || colorterm === "24bit" || term.includes("truecolor") || term.includes("24bit")) { | |
| colors = 16777216; | |
| } else if (term.includes("256") || term.includes("xterm")) { | |
| colors = 256; | |
| } | |
| let cols = 80, rows = 24; | |
| try { | |
| if (process.stdout.getWindowSize) { | |
| [cols, rows] = process.stdout.getWindowSize(); | |
| cols = Math.max(cols, 20); | |
| rows = Math.max(rows, 10); | |
| } | |
| } catch {} | |
| let screenSize: EnvInfo["screenSize"] = "medium"; | |
| if (cols < 60 || rows < 15) screenSize = "tiny"; | |
| else if (cols < 80 || rows < 24) screenSize = "small"; | |
| else if (cols >= 120 && rows >= 40) screenSize = "large"; | |
| else if (cols >= 160 && rows >= 50) screenSize = "huge"; | |
| return { | |
| tty: isTTY, | |
| interactive: isTTY && !isCI, | |
| platform: isTermux ? "termux" : isWSL ? "wsl" : process.platform, | |
| terminal, | |
| colors, | |
| hasTrueColor: colors >= 16777216, | |
| has256: colors >= 256, | |
| cols, rows, | |
| screenSize, | |
| inputMode: "keyboard", | |
| isTermux, isTmux, isWSL, isWindows, | |
| }; | |
| } | |