mirror of
https://github.com/zhukunpenglinyutong/jetbrains-cc-gui.git
synced 2026-08-29 00:41:38 +08:00
docs: translate Chinese comments and JSDoc to English across 14 files
Standardize code documentation language to English for better international collaboration, covering ai-bridge services, Java backend, webview scripts, and frontend utilities.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 收藏服务模块
|
||||
* 负责管理会话收藏功能
|
||||
* Favorites service module
|
||||
* Responsible for managing session favorites
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -11,7 +11,7 @@ const FAVORITES_DIR = getCodemossDir();
|
||||
const FAVORITES_FILE = path.join(FAVORITES_DIR, 'favorites.json');
|
||||
|
||||
/**
|
||||
* 确保收藏目录存在
|
||||
* Ensure the favorites directory exists
|
||||
*/
|
||||
function ensureFavoritesDir() {
|
||||
if (!fs.existsSync(FAVORITES_DIR)) {
|
||||
@@ -20,8 +20,8 @@ function ensureFavoritesDir() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载收藏数据
|
||||
* @returns {Object} 收藏数据,格式: { "sessionId": { "favoritedAt": timestamp } }
|
||||
* Load favorites data
|
||||
* @returns {Object} Favorites data in the format: { "sessionId": { "favoritedAt": timestamp } }
|
||||
*/
|
||||
function loadFavorites() {
|
||||
try {
|
||||
@@ -40,8 +40,8 @@ function loadFavorites() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存收藏数据
|
||||
* @param {Object} favorites - 收藏数据
|
||||
* Save favorites data
|
||||
* @param {Object} favorites - Favorites data
|
||||
*/
|
||||
function saveFavorites(favorites) {
|
||||
try {
|
||||
@@ -54,9 +54,9 @@ function saveFavorites(favorites) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加收藏
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {boolean} 是否成功
|
||||
* Add a favorite
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {boolean} Whether the operation succeeded
|
||||
*/
|
||||
function addFavorite(sessionId) {
|
||||
try {
|
||||
@@ -81,9 +81,9 @@ function addFavorite(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除收藏
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {boolean} 是否成功
|
||||
* Remove a favorite
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {boolean} Whether the operation succeeded
|
||||
*/
|
||||
function removeFavorite(sessionId) {
|
||||
try {
|
||||
@@ -106,8 +106,8 @@ function removeFavorite(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换收藏状态
|
||||
* @param {string} sessionId - 会话ID
|
||||
* Toggle favorite status
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {Object} { success: boolean, isFavorited: boolean }
|
||||
*/
|
||||
function toggleFavorite(sessionId) {
|
||||
@@ -136,8 +136,8 @@ function toggleFavorite(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查会话是否已收藏
|
||||
* @param {string} sessionId - 会话ID
|
||||
* Check whether a session is favorited
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isFavorited(sessionId) {
|
||||
@@ -146,9 +146,9 @@ function isFavorited(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收藏时间
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {number|null} 收藏时间戳,未收藏返回 null
|
||||
* Get the favorite timestamp
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {number|null} Favorite timestamp, or null if not favorited
|
||||
*/
|
||||
function getFavoritedAt(sessionId) {
|
||||
const favorites = loadFavorites();
|
||||
@@ -156,7 +156,7 @@ function getFavoritedAt(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有收藏的会话ID列表(按收藏时间倒序)
|
||||
* Get all favorited session IDs in reverse favorite-time order
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function getFavoritedSessionIds() {
|
||||
@@ -167,7 +167,7 @@ function getFavoritedSessionIds() {
|
||||
.map(([sessionId]) => sessionId);
|
||||
}
|
||||
|
||||
// 使用 CommonJS 导出
|
||||
// Export via CommonJS
|
||||
module.exports = {
|
||||
loadFavorites,
|
||||
addFavorite,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* 输入历史记录服务模块
|
||||
* 负责管理用户输入历史记录的持久化存储
|
||||
* 存储位置: ~/.codemoss/inputHistory.json
|
||||
* Input history service module
|
||||
* Responsible for persistent storage of user input history
|
||||
* Storage location: ~/.codemoss/inputHistory.json
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -11,14 +11,14 @@ const { getCodemossDir } = require('../utils/path-utils.cjs');
|
||||
const CODEMOSS_DIR = getCodemossDir();
|
||||
const HISTORY_FILE = path.join(CODEMOSS_DIR, 'inputHistory.json');
|
||||
|
||||
/** 最大历史记录条数 */
|
||||
/** Maximum number of history items */
|
||||
const MAX_HISTORY_ITEMS = 200;
|
||||
|
||||
/** 最大计数记录条数 */
|
||||
/** Maximum number of count records */
|
||||
const MAX_COUNT_RECORDS = 200;
|
||||
|
||||
/**
|
||||
* 确保目录存在
|
||||
* Ensure the directory exists
|
||||
*/
|
||||
function ensureDir() {
|
||||
if (!fs.existsSync(CODEMOSS_DIR)) {
|
||||
@@ -27,7 +27,7 @@ function ensureDir() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取历史数据文件
|
||||
* Read the history data file
|
||||
* @returns {{ items: string[], counts: Record<string, number> }}
|
||||
*/
|
||||
function readHistoryFile() {
|
||||
@@ -52,7 +52,7 @@ function readHistoryFile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入历史数据文件
|
||||
* Write the history data file
|
||||
* @param {{ items: string[], counts: Record<string, number> }} data
|
||||
*/
|
||||
function writeHistoryFile(data) {
|
||||
@@ -66,7 +66,7 @@ function writeHistoryFile(data) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载历史记录列表
|
||||
* Load the history item list
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function loadHistory() {
|
||||
@@ -75,7 +75,7 @@ function loadHistory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载使用计数
|
||||
* Load usage counts
|
||||
* @returns {Record<string, number>}
|
||||
*/
|
||||
function loadCounts() {
|
||||
@@ -84,7 +84,7 @@ function loadCounts() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理计数记录,保留使用频率最高的
|
||||
* Trim count records and keep the most frequently used entries
|
||||
* @param {Record<string, number>} counts
|
||||
* @returns {Record<string, number>}
|
||||
*/
|
||||
@@ -92,15 +92,15 @@ function cleanupCounts(counts) {
|
||||
const entries = Object.entries(counts);
|
||||
if (entries.length <= MAX_COUNT_RECORDS) return counts;
|
||||
|
||||
// 按计数降序排序,保留前 MAX_COUNT_RECORDS 条
|
||||
// Sort by count in descending order and keep the top MAX_COUNT_RECORDS entries
|
||||
entries.sort((a, b) => b[1] - a[1]);
|
||||
const kept = entries.slice(0, MAX_COUNT_RECORDS);
|
||||
return Object.fromEntries(kept);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录历史(包括拆分片段)
|
||||
* @param {string[]} fragments - 要记录的片段数组
|
||||
* Record history, including split fragments
|
||||
* @param {string[]} fragments - Array of fragments to record
|
||||
* @returns {{ success: boolean, items: string[] }}
|
||||
*/
|
||||
function recordHistory(fragments) {
|
||||
@@ -112,21 +112,21 @@ function recordHistory(fragments) {
|
||||
const data = readHistoryFile();
|
||||
let { items, counts } = data;
|
||||
|
||||
// 增加每个片段的使用计数
|
||||
// Increment the usage count for each fragment
|
||||
for (const fragment of fragments) {
|
||||
counts[fragment] = (counts[fragment] || 0) + 1;
|
||||
}
|
||||
|
||||
// 清理计数
|
||||
// Trim count records
|
||||
counts = cleanupCounts(counts);
|
||||
|
||||
// 创建新片段集合用于快速查找
|
||||
// Create a set of incoming fragments for fast lookups
|
||||
const newFragmentsSet = new Set(fragments);
|
||||
|
||||
// 移除已存在的片段以避免重复
|
||||
// Remove existing fragments to avoid duplicates
|
||||
const filteredItems = items.filter(item => !newFragmentsSet.has(item));
|
||||
|
||||
// 添加新片段到末尾
|
||||
// Append new fragments to the end
|
||||
const newItems = [...filteredItems, ...fragments].slice(-MAX_HISTORY_ITEMS);
|
||||
|
||||
writeHistoryFile({ items: newItems, counts });
|
||||
@@ -139,8 +139,8 @@ function recordHistory(fragments) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单条历史记录
|
||||
* @param {string} item - 要删除的记录
|
||||
* Delete a single history entry
|
||||
* @param {string} item - Entry to delete
|
||||
* @returns {{ success: boolean, items: string[] }}
|
||||
*/
|
||||
function deleteHistoryItem(item) {
|
||||
@@ -148,10 +148,10 @@ function deleteHistoryItem(item) {
|
||||
const data = readHistoryFile();
|
||||
let { items, counts } = data;
|
||||
|
||||
// 从列表中移除
|
||||
// Remove it from the item list
|
||||
items = items.filter(i => i !== item);
|
||||
|
||||
// 从计数中移除
|
||||
// Remove it from the count map
|
||||
delete counts[item];
|
||||
|
||||
writeHistoryFile({ items, counts });
|
||||
@@ -164,7 +164,7 @@ function deleteHistoryItem(item) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有历史记录
|
||||
* Clear all history entries
|
||||
* @returns {{ success: boolean }}
|
||||
*/
|
||||
function clearAllHistory() {
|
||||
@@ -178,14 +178,14 @@ function clearAllHistory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有历史数据(用于设置页面展示)
|
||||
* Get all history data for the settings page
|
||||
* @returns {{ items: string[], counts: Record<string, number> }}
|
||||
*/
|
||||
function getAllHistoryData() {
|
||||
return readHistoryFile();
|
||||
}
|
||||
|
||||
// 使用 CommonJS 导出
|
||||
// Export via CommonJS
|
||||
module.exports = {
|
||||
loadHistory,
|
||||
loadCounts,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* 会话标题服务模块
|
||||
* 负责管理会话自定义标题功能
|
||||
* Session title service module
|
||||
* Responsible for managing custom session titles
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -11,7 +11,7 @@ const TITLES_DIR = getCodemossDir();
|
||||
const TITLES_FILE = path.join(TITLES_DIR, 'session-titles.json');
|
||||
|
||||
/**
|
||||
* 确保标题目录存在
|
||||
* Ensure the title directory exists
|
||||
*/
|
||||
function ensureTitlesDir() {
|
||||
if (!fs.existsSync(TITLES_DIR)) {
|
||||
@@ -20,8 +20,8 @@ function ensureTitlesDir() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载标题数据
|
||||
* @returns {Object} 标题数据,格式: { "sessionId": { "customTitle": "标题", "updatedAt": timestamp } }
|
||||
* Load title data
|
||||
* @returns {Object} Title data in the format: { "sessionId": { "customTitle": "Title", "updatedAt": timestamp } }
|
||||
*/
|
||||
function loadTitles() {
|
||||
try {
|
||||
@@ -40,8 +40,9 @@ function loadTitles() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存标题数据(原子写入:先写临时文件再 rename,防止写入中途崩溃导致数据丢失)
|
||||
* @param {Object} titles - 标题数据
|
||||
* Save title data using an atomic write:
|
||||
* write to a temporary file first, then rename it to avoid data loss if a write crashes midway.
|
||||
* @param {Object} titles - Title data
|
||||
*/
|
||||
function saveTitles(titles) {
|
||||
try {
|
||||
@@ -56,16 +57,16 @@ function saveTitles(titles) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话标题
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @param {string} customTitle - 自定义标题
|
||||
* Update a session title
|
||||
* @param {string} sessionId - Session ID
|
||||
* @param {string} customTitle - Custom title
|
||||
* @returns {Object} { success: boolean, title: string }
|
||||
*/
|
||||
function updateTitle(sessionId, customTitle) {
|
||||
try {
|
||||
const titles = loadTitles();
|
||||
|
||||
// 验证标题长度(最多50个字符)
|
||||
// Validate title length (maximum 50 characters)
|
||||
if (customTitle && customTitle.length > 50) {
|
||||
return {
|
||||
success: false,
|
||||
@@ -94,9 +95,9 @@ function updateTitle(sessionId, customTitle) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取会话标题
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {string|null} 自定义标题,未设置返回 null
|
||||
* Get the session title
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {string|null} Custom title, or null if unset
|
||||
*/
|
||||
function getTitle(sessionId) {
|
||||
const titles = loadTitles();
|
||||
@@ -104,9 +105,9 @@ function getTitle(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除会话标题
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {boolean} 是否成功
|
||||
* Delete a session title
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {boolean} Whether the operation succeeded
|
||||
*/
|
||||
function deleteTitle(sessionId) {
|
||||
try {
|
||||
@@ -129,16 +130,16 @@ function deleteTitle(sessionId) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取更新时间
|
||||
* @param {string} sessionId - 会话ID
|
||||
* @returns {number|null} 更新时间戳,未设置返回 null
|
||||
* Get the last updated timestamp
|
||||
* @param {string} sessionId - Session ID
|
||||
* @returns {number|null} Updated timestamp, or null if unset
|
||||
*/
|
||||
function getUpdatedAt(sessionId) {
|
||||
const titles = loadTitles();
|
||||
return titles[sessionId]?.updatedAt || null;
|
||||
}
|
||||
|
||||
// 使用 CommonJS 导出
|
||||
// Export via CommonJS
|
||||
module.exports = {
|
||||
loadTitles,
|
||||
updateTitle,
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/**
|
||||
* 路径处理工具模块 (CommonJS 版本)
|
||||
* 负责路径规范化、用户目录处理
|
||||
* Path utility module (CommonJS version)
|
||||
* Responsible for path normalization and home directory handling
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
// 缓存真实的用户目录路径,避免重复计算
|
||||
// Cache the resolved home directory path to avoid repeated lookups
|
||||
let cachedRealHomeDir = null;
|
||||
|
||||
/**
|
||||
* 获取真实的用户目录路径.
|
||||
* 解决 Windows 上用户目录被移动或使用符号链接/Junction 的问题。
|
||||
* @returns {string} 真实的用户目录路径
|
||||
* Get the resolved home directory path.
|
||||
* Handles cases on Windows where the user directory is moved or uses a symlink/junction.
|
||||
* @returns {string} Resolved home directory path
|
||||
*/
|
||||
function getRealHomeDir() {
|
||||
if (cachedRealHomeDir) {
|
||||
@@ -32,16 +32,16 @@ function getRealHomeDir() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 .codemoss 配置目录路径.
|
||||
* @returns {string} ~/.codemoss 目录路径
|
||||
* Get the .codemoss configuration directory path.
|
||||
* @returns {string} ~/.codemoss directory path
|
||||
*/
|
||||
function getCodemossDir() {
|
||||
return path.join(getRealHomeDir(), '.codemoss');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 .claude 配置目录路径.
|
||||
* @returns {string} ~/.claude 目录路径
|
||||
* Get the .claude configuration directory path.
|
||||
* @returns {string} ~/.claude directory path
|
||||
*/
|
||||
function getClaudeDir() {
|
||||
return path.join(getRealHomeDir(), '.claude');
|
||||
|
||||
@@ -26,7 +26,7 @@ public class ClaudeNotifier {
|
||||
public static void showSuccess(@NotNull Project project, String message) {
|
||||
show(project, "Claude ✓", message, 5000);
|
||||
|
||||
// 播放任务完成提示音
|
||||
// Play the task completion notification sound
|
||||
SoundNotificationService.getInstance().playTaskCompleteSound();
|
||||
}
|
||||
|
||||
|
||||
@@ -666,12 +666,12 @@ public class ProviderManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 归一化 Claude 当前 Provider。
|
||||
* 首次启动或旧配置未设置 current 时,默认回退到本地 settings.json,
|
||||
* 这样前端初始化时就能拿到稳定的模型映射来源。
|
||||
* Normalize the current Claude provider.
|
||||
* On first launch, or when older configs do not define current, default back to the local
|
||||
* settings.json so the frontend initializes with a stable source for model mapping.
|
||||
*
|
||||
* @param config 当前插件配置
|
||||
* @return 可用的 current provider id
|
||||
* @param config current plugin configuration
|
||||
* @return available current provider id
|
||||
*/
|
||||
private String normalizeCurrentClaudeProviderId(JsonObject config) {
|
||||
boolean changed = false;
|
||||
@@ -696,7 +696,7 @@ public class ProviderManager {
|
||||
currentId = claude.get("current").getAsString();
|
||||
}
|
||||
|
||||
// current 为空,或指向了已删除的 provider 时,统一回退到本地 settings.json。
|
||||
// If current is blank or points to a deleted provider, fall back to the local settings.json provider.
|
||||
if (currentId == null
|
||||
|| currentId.trim().isEmpty()
|
||||
|| (!LOCAL_SETTINGS_PROVIDER_ID.equals(currentId) && !providers.has(currentId))) {
|
||||
|
||||
@@ -24,8 +24,8 @@ import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 声音通知服务
|
||||
* 负责在任务完成时播放提示音
|
||||
* Sound notification service
|
||||
* Responsible for playing notification sounds when a task completes
|
||||
*/
|
||||
public class SoundNotificationService {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class SoundNotificationService {
|
||||
SOUND_RESOURCES = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
// 单例模式
|
||||
// Singleton pattern
|
||||
private static volatile SoundNotificationService instance;
|
||||
|
||||
private SoundNotificationService() {
|
||||
@@ -130,7 +130,7 @@ public class SoundNotificationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从资源文件播放音频
|
||||
* Play audio from a bundled resource.
|
||||
*/
|
||||
private void playFromResource(String resourcePath) throws Exception {
|
||||
try (InputStream rawStream = getClass().getResourceAsStream(resourcePath)) {
|
||||
@@ -139,7 +139,7 @@ public class SoundNotificationService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用 BufferedInputStream 包装,因为 AudioSystem 需要 mark/reset 支持
|
||||
// Wrap with BufferedInputStream because AudioSystem requires mark/reset support
|
||||
try (BufferedInputStream bufferedStream = new BufferedInputStream(rawStream);
|
||||
AudioInputStream audioIn = AudioSystem.getAudioInputStream(bufferedStream)) {
|
||||
playAudioStream(audioIn);
|
||||
@@ -177,7 +177,7 @@ public class SoundNotificationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件播放音频
|
||||
* Play audio from a file.
|
||||
*/
|
||||
private void playFromFile(String rawPath) throws Exception {
|
||||
String normalizedPath = normalizeSoundPath(rawPath);
|
||||
@@ -194,13 +194,13 @@ public class SoundNotificationService {
|
||||
|
||||
String fileName = file.getName().toLowerCase(Locale.ROOT);
|
||||
|
||||
// MP3 格式使用 JLayer 在后台线程解码播放
|
||||
// Decode and play MP3 files with JLayer on a background thread
|
||||
if (fileName.endsWith(".mp3")) {
|
||||
playMp3(file);
|
||||
return;
|
||||
}
|
||||
|
||||
// WAV 和 AIFF 格式使用 Java 标准库播放
|
||||
// Play WAV and AIFF files with the Java standard library
|
||||
try (AudioInputStream audioIn = AudioSystem.getAudioInputStream(file)) {
|
||||
playAudioStream(audioIn);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public class SoundNotificationService {
|
||||
private static final int MP3_PLAYBACK_TIMEOUT_SECONDS = 30;
|
||||
|
||||
/**
|
||||
* 使用 JLayer 播放 MP3(后台线程调用,阻塞直到播放结束或超时)。
|
||||
* Play MP3 with JLayer (called from a background thread and blocks until playback completes or times out).
|
||||
*/
|
||||
private void playMp3(File file) throws Exception {
|
||||
try (BufferedInputStream bufferedStream = new BufferedInputStream(new FileInputStream(file))) {
|
||||
@@ -265,15 +265,15 @@ public class SoundNotificationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证音频文件是否可用
|
||||
* Validate whether an audio file is usable.
|
||||
*
|
||||
* @param filePath 文件路径
|
||||
* @return 验证结果,包含成功状态和错误信息
|
||||
* @param filePath file path
|
||||
* @return validation result, including success state and error information
|
||||
*/
|
||||
public ValidationResult validateSoundFile(String filePath) {
|
||||
String normalizedPath = normalizeSoundPath(filePath);
|
||||
if (normalizedPath == null || normalizedPath.isEmpty()) {
|
||||
return new ValidationResult(true, null); // 空路径表示使用默认声音
|
||||
return new ValidationResult(true, null); // An empty path means the default sound should be used
|
||||
}
|
||||
|
||||
File file = new File(normalizedPath);
|
||||
@@ -291,7 +291,7 @@ public class SoundNotificationService {
|
||||
return new ValidationResult(false, "Only WAV, MP3, AIFF formats are supported");
|
||||
}
|
||||
|
||||
// MP3 使用 JLayer 播放,跳过 AudioSystem 格式校验
|
||||
// MP3 playback uses JLayer, so skip AudioSystem format validation
|
||||
if (lowerPath.endsWith(".mp3")) {
|
||||
return new ValidationResult(true, null);
|
||||
}
|
||||
@@ -307,7 +307,7 @@ public class SoundNotificationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证结果
|
||||
* Validation result
|
||||
*/
|
||||
public record ValidationResult(boolean valid, String errorMessage) {
|
||||
}
|
||||
|
||||
@@ -13,11 +13,11 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* ProviderManager 回归测试。
|
||||
* Regression tests for ProviderManager.
|
||||
*/
|
||||
public class ProviderManagerTest {
|
||||
/**
|
||||
* current 为空时,应默认启用本地 settings.json Provider。
|
||||
* When current is blank, the local settings.json provider should be enabled by default.
|
||||
*/
|
||||
@Test
|
||||
public void shouldDefaultActiveProviderToLocalSettingsWhenCurrentIsBlank() {
|
||||
@@ -35,7 +35,7 @@ public class ProviderManagerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* current 缺失时,Provider 列表里也应把本地 settings.json 标记为启用状态。
|
||||
* When current is missing, the provider list should also mark the local settings.json provider as active.
|
||||
*/
|
||||
@Test
|
||||
public void shouldMarkLocalProviderAsActiveWhenCurrentIsMissing() {
|
||||
@@ -58,7 +58,7 @@ public class ProviderManagerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造仅使用内存配置的 ProviderManager,避免测试依赖真实文件系统。
|
||||
* Build a ProviderManager backed only by in-memory config to avoid depending on the real filesystem in tests.
|
||||
*/
|
||||
private ProviderManager createProviderManager(AtomicReference<JsonObject> configRef) {
|
||||
Gson gson = new Gson();
|
||||
@@ -81,7 +81,7 @@ public class ProviderManagerTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造最小 Claude 配置。
|
||||
* Build the minimal Claude configuration.
|
||||
*/
|
||||
private JsonObject createConfigWithCurrent(String current) {
|
||||
JsonObject config = new JsonObject();
|
||||
|
||||
+4
-4
@@ -92,10 +92,10 @@ function getProcesses() {
|
||||
|
||||
if (!isClaude && !isDaemon && !isStreamJson) continue
|
||||
|
||||
// 排除 MCP 插件进程
|
||||
// Exclude MCP plugin processes
|
||||
if (isMcp) continue
|
||||
|
||||
// 排除系统 daemon(cloudd, cfprefsd 等)
|
||||
// Exclude system daemons (cloudd, cfprefsd, etc.)
|
||||
if (command.includes('cloudd') || command.includes('cfprefsd')) continue
|
||||
|
||||
let type = '未知'
|
||||
@@ -193,7 +193,7 @@ function ask(question) {
|
||||
return new Promise(resolve => rl.question(question, answer => { rl.close(); resolve(answer.trim()) }))
|
||||
}
|
||||
|
||||
// --- 主流程 ---
|
||||
// --- Main flow ---
|
||||
console.log('\n Claude 进程管理工具')
|
||||
console.log(' ==================\n')
|
||||
|
||||
@@ -217,7 +217,7 @@ if (answer.toLowerCase() === 'y') {
|
||||
}
|
||||
}
|
||||
|
||||
// 关闭后再查一次
|
||||
// Check again after closing processes
|
||||
const remaining = getProcesses()
|
||||
if (remaining.length > 0) {
|
||||
console.log(' 关闭后剩余进程:')
|
||||
|
||||
@@ -20,9 +20,9 @@ const content = fs.readFileSync(changelogPath, 'utf8');
|
||||
/**
|
||||
* Parse CHANGELOG.md into structured entries.
|
||||
* Handles three format eras:
|
||||
* - Newer (v0.1.7+): Bilingual with English:/中文: markers and emoji section headers
|
||||
* - Mid (v0.1.4-v0.1.6): Bilingual with English:/中文: markers and checkbox items
|
||||
* - Older (< v0.1.4): Chinese only with checkbox items or plain text
|
||||
* - Newer (v0.1.7+): Bilingual with English and Chinese markers plus emoji section headers
|
||||
* - Mid (v0.1.4-v0.1.6): Bilingual with English and Chinese markers plus checkbox items
|
||||
* - Older (< v0.1.4): Chinese-only entries with checkbox items or plain text
|
||||
*/
|
||||
function parseChangelog(raw) {
|
||||
const entries = [];
|
||||
@@ -45,7 +45,7 @@ function parseChangelog(raw) {
|
||||
const nextIndex = i + 1 < headers.length ? headers[i + 1].index : raw.length;
|
||||
const sectionContent = raw.substring(header.endIndex, nextIndex).trim();
|
||||
|
||||
// Extract version from header like "2026年2月19日(v0.1.9)" or "12月25日(v0.1.2-beta5)"
|
||||
// Extract the version from headers that use localized date formats with the version in parentheses
|
||||
const versionMatch = header.fullMatch.match(/[((]v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)[))]/);
|
||||
if (!versionMatch) continue;
|
||||
|
||||
@@ -77,8 +77,8 @@ function parseChangelog(raw) {
|
||||
* Split section content into English and Chinese parts.
|
||||
*/
|
||||
function splitBilingual(text) {
|
||||
// Try to find English/中文 markers
|
||||
// Patterns: "English:" / "中文:" or "中文:"
|
||||
// Try to find the English and Chinese section markers
|
||||
// Patterns: "English:" and the localized Chinese marker with either colon form
|
||||
const enMarkerRegex = /^English\s*[::]/im;
|
||||
const zhMarkerRegex = /^中文\s*[::]/im;
|
||||
|
||||
|
||||
@@ -4,22 +4,22 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
// 获取当前目录
|
||||
// Get the current directory
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// 获取项目根目录 (webview 的父目录)
|
||||
// Get the project root directory (the parent of webview)
|
||||
const projectRoot = path.resolve(__dirname, '../..');
|
||||
const buildGradlePath = path.join(projectRoot, 'build.gradle');
|
||||
|
||||
// 读取 build.gradle 文件
|
||||
// Read the build.gradle file
|
||||
const buildGradleContent = fs.readFileSync(buildGradlePath, 'utf8');
|
||||
|
||||
// 提取版本号
|
||||
// 查找类似 version = '0.1.0-beta3' 这样的行
|
||||
// Extract the version number
|
||||
// Look for a line like: version = '0.1.0-beta3'
|
||||
let versionMatch = buildGradleContent.match(/^version\s*=\s*'(.+)'$/m);
|
||||
if (!versionMatch) {
|
||||
// 如果上面的正则失败,尝试另一种方式
|
||||
// If the regex above fails, try a fallback approach
|
||||
const lines = buildGradleContent.split('\n');
|
||||
const versionLine = lines.find(line => line.trim().startsWith('version ='));
|
||||
if (versionLine) {
|
||||
@@ -37,7 +37,7 @@ if (!versionMatch) {
|
||||
const version = versionMatch[1];
|
||||
console.log(`Found version: ${version}`);
|
||||
|
||||
// 创建版本文件供 webview 使用
|
||||
// Create the version file for the webview
|
||||
const versionDir = path.join(__dirname, '../src/version');
|
||||
if (!fs.existsSync(versionDir)) {
|
||||
fs.mkdirSync(versionDir, { recursive: true });
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { PromptConfig, PromptScope } from '../../../types/prompt';
|
||||
import styles from './style.module.less';
|
||||
|
||||
interface PromptScopeSectionProps {
|
||||
/** Section title (e.g., "全局提示词" or "项目提示词 - ProjectName") */
|
||||
/** Section title (e.g., "Global Prompts" or "Project Prompts - ProjectName") */
|
||||
title: string;
|
||||
/** Prompt scope (global or project) */
|
||||
scope: PromptScope;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { STORAGE_KEYS } from '../types/provider';
|
||||
|
||||
/**
|
||||
* Claude 模型映射配置。
|
||||
* Claude model mapping configuration.
|
||||
*/
|
||||
export interface ClaudeModelMapping {
|
||||
main?: string;
|
||||
@@ -12,7 +12,7 @@ export interface ClaudeModelMapping {
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取 Claude 模型映射。
|
||||
* Read the Claude model mapping.
|
||||
*/
|
||||
export function readClaudeModelMapping(): ClaudeModelMapping {
|
||||
try {
|
||||
@@ -28,14 +28,14 @@ export function readClaudeModelMapping(): ClaudeModelMapping {
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断映射里是否至少包含一个有效模型值。
|
||||
* Check whether the mapping contains at least one valid model value.
|
||||
*/
|
||||
function hasMappingValue(mapping: ClaudeModelMapping): boolean {
|
||||
return Object.values(mapping).some(value => value && value.trim().length > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入 Claude 模型映射,并主动通知同 tab 监听器刷新。
|
||||
* Write the Claude model mapping and proactively notify listeners in the same tab to refresh.
|
||||
*/
|
||||
export function writeClaudeModelMapping(mapping: ClaudeModelMapping): void {
|
||||
try {
|
||||
@@ -45,11 +45,11 @@ export function writeClaudeModelMapping(mapping: ClaudeModelMapping): void {
|
||||
localStorage.removeItem(STORAGE_KEYS.CLAUDE_MODEL_MAPPING);
|
||||
}
|
||||
|
||||
// 同 tab 的 localStorage 写入不会触发原生 storage 事件,这里手动补发一次。
|
||||
// localStorage writes in the same tab do not trigger the native storage event, so dispatch one manually here.
|
||||
window.dispatchEvent(new CustomEvent('localStorageChange', {
|
||||
detail: { key: STORAGE_KEYS.CLAUDE_MODEL_MAPPING },
|
||||
}));
|
||||
} catch {
|
||||
// localStorage 不可用或写入失败时静默降级
|
||||
// Gracefully degrade when localStorage is unavailable or the write fails
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ export function getMessageKey(message: ClaudeMessage, index: number): string {
|
||||
* Returns the combined content: "command-message content command-args content"
|
||||
*
|
||||
* Example:
|
||||
* Input: "<command-message>aimax:auto</command-message>\n<command-name>/aimax:auto</command-name>\n<command-args>你好啊</command-args>"
|
||||
* Output: "aimax:auto 你好啊"
|
||||
* Input: "<command-message>aimax:auto</command-message>\n<command-name>/aimax:auto</command-name>\n<command-args>hello there</command-args>"
|
||||
* Output: "aimax:auto hello there"
|
||||
*/
|
||||
export function extractCommandMessageContent(text: string): string {
|
||||
if (!text) return text;
|
||||
|
||||
Reference in New Issue
Block a user