import os from "node:os"; import { DEFAULT_UI_LOCALE, type UiLocale, } from "@penclipai/shared"; type ResolveRuntimeLocalizationPromptInput = { locale: UiLocale; platform?: NodeJS.Platform; shell?: string | null; env?: NodeJS.ProcessEnv; osRelease?: string | null; }; type RuntimeEnvironmentDescriptor = { labelZh: string; labelEn: string; }; function readNonEmptyString(value: unknown): string | null { return typeof value === "string" && value.trim().length > 0 ? value : null; } function parseSupportedUiLocale(value: unknown): UiLocale | null { const candidate = readNonEmptyString(value); if (!candidate) return null; const normalized = candidate.trim().toLowerCase(); if (normalized.startsWith("zh")) return "zh-CN"; if (normalized.startsWith("en")) return "en"; return null; } function stripExecutableName(value: string | null | undefined): string | null { const trimmed = value?.trim(); if (!trimmed) return null; const parts = trimmed.split(/[\\/]/g); return parts[parts.length - 1] || trimmed; } function isPowerShellShell(shell: string | null, env: NodeJS.ProcessEnv): boolean { if (shell && /(^|[\\/])(pwsh|powershell)(\.exe)?$/i.test(shell)) { return true; } return Boolean(env.POWERSHELL_DISTRIBUTION_CHANNEL || env.PSExecutionPolicyPreference); } function isCmdShell(shell: string | null): boolean { return Boolean(shell && /(^|[\\/])cmd(\.exe)?$/i.test(shell)); } function isWslRuntime(platform: NodeJS.Platform, env: NodeJS.ProcessEnv, osRelease: string | null): boolean { if (platform !== "linux") return false; return Boolean( env.WSL_DISTRO_NAME || env.WSL_INTEROP || (osRelease && /microsoft/i.test(osRelease)), ); } function resolveRuntimeEnvironment( input: ResolveRuntimeLocalizationPromptInput, ): RuntimeEnvironmentDescriptor { const platform = input.platform ?? process.platform; const env = input.env ?? process.env; const shell = input.shell?.trim() || env.SHELL?.trim() || env.ComSpec?.trim() || env.COMSPEC?.trim() || null; const shellName = stripExecutableName(shell); const osRelease = input.osRelease ?? (platform === "linux" ? os.release() : null); if (isWslRuntime(platform, env, osRelease)) { const wslShell = shellName ?? "sh"; return { labelZh: `WSL ${wslShell}`, labelEn: `WSL ${wslShell}`, }; } if (platform === "win32") { if (isPowerShellShell(shell, env)) { return { labelZh: "Windows PowerShell", labelEn: "Windows PowerShell", }; } if (isCmdShell(shell)) { return { labelZh: "Windows cmd.exe", labelEn: "Windows cmd.exe", }; } if (shellName) { return { labelZh: `Windows shell (${shellName})`, labelEn: `Windows shell (${shellName})`, }; } return { labelZh: "Windows", labelEn: "Windows", }; } if (shellName) { return { labelZh: `${shellName} on ${platform}`, labelEn: `${shellName} on ${platform}`, }; } return { labelZh: platform, labelEn: platform, }; } function buildZhCnRuntimeLocalizationPrompt(environment: RuntimeEnvironmentDescriptor): string { return [ "## 语言与运行时契约", "- 输出契约:除非用户本轮明确要求其他语言,所有面向用户的自然语言输出必须使用简体中文;代码、命令、路径、API 字段名和日志原文保持原样。", `- 宿主环境:${environment.labelZh}。`, "- CLI 契约:执行 Paperclip 命令一律使用 `penclip ...`;仅在逐字引用用户文本、日志或历史文档时保留 `paperclipai ...`。", "- API 契约:优先使用 `penclip` CLI 完成 Paperclip 操作;只有在 CLI 无法覆盖时,才直接调用 API,并确保带上必需的认证与运行标头。", ].join("\n"); } function buildEnRuntimeLocalizationPrompt(environment: RuntimeEnvironmentDescriptor): string { return [ "## Language and Runtime Contract", "- Output contract: unless the current user request explicitly asks for another language, all user-facing natural-language output must be in English. Keep code, commands, file paths, API field names, and raw logs verbatim.", `- Host runtime: ${environment.labelEn}.`, "- CLI contract: use `penclip ...` for Paperclip commands; keep `paperclipai ...` only in verbatim quotes from user text, logs, or historical docs.", "- API contract: prefer the `penclip` CLI for Paperclip operations; only call the HTTP API directly when the CLI cannot cover the action, and always include the required auth and run headers.", ].join("\n"); } export function readRuntimeUiLocaleFromContextSnapshot( contextSnapshot: Record | null | undefined, ): UiLocale | null { return parseSupportedUiLocale(contextSnapshot?.runtimeUiLocale); } export function resolveEffectiveRuntimeUiLocale(input: { requestedUiLocale?: unknown; runtimeUiLocale?: unknown; runtimeDefaultLocale?: unknown; }): UiLocale { return ( parseSupportedUiLocale(input.requestedUiLocale) ?? parseSupportedUiLocale(input.runtimeUiLocale) ?? parseSupportedUiLocale(input.runtimeDefaultLocale) ?? DEFAULT_UI_LOCALE ); } export function resolveEffectiveRuntimeUiLocaleForContextSnapshot( contextSnapshot: Record | null | undefined, runtimeDefaultLocale?: unknown, ): UiLocale { return resolveEffectiveRuntimeUiLocale({ requestedUiLocale: contextSnapshot?.requestedUiLocale, runtimeUiLocale: contextSnapshot?.runtimeUiLocale, runtimeDefaultLocale, }); } export function resolveRuntimeLocalizationPrompt( input: ResolveRuntimeLocalizationPromptInput, ): string { const environment = resolveRuntimeEnvironment(input); return input.locale === "en" ? buildEnRuntimeLocalizationPrompt(environment) : buildZhCnRuntimeLocalizationPrompt(environment); }