@eruoxi/csm-test 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +217 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +43 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/backup.d.ts +3 -0
- package/dist/commands/backup.d.ts.map +1 -0
- package/dist/commands/backup.js +99 -0
- package/dist/commands/backup.js.map +1 -0
- package/dist/commands/backups.d.ts +3 -0
- package/dist/commands/backups.d.ts.map +1 -0
- package/dist/commands/backups.js +109 -0
- package/dist/commands/backups.js.map +1 -0
- package/dist/commands/copy.d.ts +3 -0
- package/dist/commands/copy.d.ts.map +1 -0
- package/dist/commands/copy.js +36 -0
- package/dist/commands/copy.js.map +1 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +102 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/current.d.ts +3 -0
- package/dist/commands/current.d.ts.map +1 -0
- package/dist/commands/current.js +45 -0
- package/dist/commands/current.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +111 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/edit.d.ts +3 -0
- package/dist/commands/edit.d.ts.map +1 -0
- package/dist/commands/edit.js +86 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/export.d.ts +3 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +43 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/import.d.ts +3 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +74 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +13 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +66 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/rename.d.ts +3 -0
- package/dist/commands/rename.d.ts.map +1 -0
- package/dist/commands/rename.js +30 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/restore.d.ts +3 -0
- package/dist/commands/restore.d.ts.map +1 -0
- package/dist/commands/restore.js +184 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/show.d.ts +3 -0
- package/dist/commands/show.d.ts.map +1 -0
- package/dist/commands/show.js +24 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/use.d.ts +3 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +234 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/merge.d.ts +20 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/merge.js +146 -0
- package/dist/lib/merge.js.map +1 -0
- package/dist/lib/profile.d.ts +65 -0
- package/dist/lib/profile.d.ts.map +1 -0
- package/dist/lib/profile.js +158 -0
- package/dist/lib/profile.js.map +1 -0
- package/dist/lib/settings.d.ts +72 -0
- package/dist/lib/settings.d.ts.map +1 -0
- package/dist/lib/settings.js +270 -0
- package/dist/lib/settings.js.map +1 -0
- package/dist/lib/state.d.ts +55 -0
- package/dist/lib/state.d.ts.map +1 -0
- package/dist/lib/state.js +145 -0
- package/dist/lib/state.js.map +1 -0
- package/dist/types/index.d.ts +37 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/atomicWrite.d.ts +24 -0
- package/dist/utils/atomicWrite.d.ts.map +1 -0
- package/dist/utils/atomicWrite.js +67 -0
- package/dist/utils/atomicWrite.js.map +1 -0
- package/dist/utils/backupValidator.d.ts +32 -0
- package/dist/utils/backupValidator.d.ts.map +1 -0
- package/dist/utils/backupValidator.js +144 -0
- package/dist/utils/backupValidator.js.map +1 -0
- package/dist/utils/errors.d.ts +63 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +117 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/file.d.ts +8 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +54 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +37 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/normalize.d.ts +13 -0
- package/dist/utils/normalize.d.ts.map +1 -0
- package/dist/utils/normalize.js +31 -0
- package/dist/utils/normalize.js.map +1 -0
- package/dist/utils/validator.d.ts +24 -0
- package/dist/utils/validator.d.ts.map +1 -0
- package/dist/utils/validator.js +178 -0
- package/dist/utils/validator.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SettingsManager - 管理 Claude Code 设置文件
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.SettingsManager = void 0;
|
|
40
|
+
const fs = __importStar(require("fs-extra"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const file_1 = require("../utils/file");
|
|
43
|
+
const atomicWrite_1 = require("../utils/atomicWrite");
|
|
44
|
+
const merge_1 = require("./merge");
|
|
45
|
+
const normalize_1 = require("../utils/normalize");
|
|
46
|
+
/** 默认最大备份数量 */
|
|
47
|
+
const DEFAULT_MAX_BACKUPS = 10;
|
|
48
|
+
/**
|
|
49
|
+
* Claude Code 设置管理器
|
|
50
|
+
*/
|
|
51
|
+
class SettingsManager {
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
// 自定义目录用于测试,否则使用真实路径
|
|
54
|
+
this.claudeDir = options.claudeDir || (0, file_1.getClaudeDir)();
|
|
55
|
+
this.settingsPath = options.claudeDir
|
|
56
|
+
? path.join(options.claudeDir, 'settings.json')
|
|
57
|
+
: (0, file_1.getSettingsPath)(); // 生产环境: ~/.claude/settings.json
|
|
58
|
+
this.backupDir = options.claudeDir
|
|
59
|
+
? path.join(options.claudeDir, 'backups')
|
|
60
|
+
: (0, file_1.getBackupsDir)(); // 生产环境: ~/.claude/csm/backups
|
|
61
|
+
this.maxBackups = options.maxBackups ?? DEFAULT_MAX_BACKUPS;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 读取当前 settings
|
|
65
|
+
*/
|
|
66
|
+
async read() {
|
|
67
|
+
try {
|
|
68
|
+
if (!(await fs.pathExists(this.settingsPath))) {
|
|
69
|
+
return {};
|
|
70
|
+
}
|
|
71
|
+
const content = await fs.readJson(this.settingsPath);
|
|
72
|
+
return content;
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw new Error(`Failed to read settings: ${error instanceof Error ? error.message : String(error)}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 写入 settings(使用原子写入)
|
|
80
|
+
*/
|
|
81
|
+
async write(settings) {
|
|
82
|
+
try {
|
|
83
|
+
await fs.ensureDir(this.claudeDir);
|
|
84
|
+
const normalized = (0, normalize_1.normalizeSettings)(settings);
|
|
85
|
+
await (0, atomicWrite_1.writeJsonAtomic)(this.settingsPath, normalized, { spaces: 2 });
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throw new Error(`Failed to write settings: ${error instanceof Error ? error.message : String(error)}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 应用 Profile(支持合并)
|
|
93
|
+
* 具有原子性:先备份再写入,失败时可以恢复
|
|
94
|
+
*/
|
|
95
|
+
async applyProfile(profileSettings, options = {}) {
|
|
96
|
+
// 读取现有 settings
|
|
97
|
+
const currentSettings = await this.read();
|
|
98
|
+
// 合并 settings
|
|
99
|
+
const mergedSettings = (0, merge_1.mergeSettings)(currentSettings, profileSettings, options);
|
|
100
|
+
// 如果 settings 文件存在,先创建备份
|
|
101
|
+
let backupPath = null;
|
|
102
|
+
const settingsExists = await fs.pathExists(this.settingsPath);
|
|
103
|
+
if (settingsExists) {
|
|
104
|
+
try {
|
|
105
|
+
backupPath = await this.backup();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// 备份失败时继续,但记录警告
|
|
109
|
+
console.warn('警告: 无法创建备份,将直接写入');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
// 写入合并后的 settings
|
|
114
|
+
await this.write(mergedSettings);
|
|
115
|
+
return mergedSettings;
|
|
116
|
+
}
|
|
117
|
+
catch (writeError) {
|
|
118
|
+
// 写入失败,尝试恢复备份
|
|
119
|
+
if (backupPath && await fs.pathExists(backupPath)) {
|
|
120
|
+
try {
|
|
121
|
+
await fs.copy(backupPath, this.settingsPath);
|
|
122
|
+
console.warn('写入失败,已从备份恢复');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// 恢复失败,严重错误
|
|
126
|
+
throw new Error(`写入失败且无法恢复备份: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
throw writeError;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 备份当前 settings
|
|
134
|
+
* @returns 备份文件路径
|
|
135
|
+
*/
|
|
136
|
+
async backup() {
|
|
137
|
+
// 检查 settings 文件是否存在
|
|
138
|
+
if (!(await fs.pathExists(this.settingsPath))) {
|
|
139
|
+
throw new Error('Settings file does not exist, nothing to backup');
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
// 确保备份目录存在
|
|
143
|
+
await fs.ensureDir(this.backupDir);
|
|
144
|
+
// 清理旧备份
|
|
145
|
+
await this.cleanOldBackups();
|
|
146
|
+
// 生成备份文件名
|
|
147
|
+
const timestamp = this.getTimestamp();
|
|
148
|
+
const backupFileName = `settings-${timestamp}.json`;
|
|
149
|
+
const backupPath = path.join(this.backupDir, backupFileName);
|
|
150
|
+
// 复制文件
|
|
151
|
+
await fs.copy(this.settingsPath, backupPath);
|
|
152
|
+
return backupPath;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
throw new Error(`Failed to create backup: ${error instanceof Error ? error.message : String(error)}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 清理旧备份文件,保留最新的 maxBackups 个
|
|
160
|
+
*/
|
|
161
|
+
async cleanOldBackups() {
|
|
162
|
+
if (!(await fs.pathExists(this.backupDir))) {
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
// 获取所有备份文件
|
|
167
|
+
const files = await fs.readdir(this.backupDir);
|
|
168
|
+
const backupFiles = files
|
|
169
|
+
.filter(f => f.startsWith('settings-') && f.endsWith('.json'))
|
|
170
|
+
.map(f => ({
|
|
171
|
+
name: f,
|
|
172
|
+
path: path.join(this.backupDir, f)
|
|
173
|
+
}));
|
|
174
|
+
// 如果备份数量未超过限制,不需要清理
|
|
175
|
+
if (backupFiles.length <= this.maxBackups) {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
// 按文件名排序(时间戳格式,字符串排序即可)
|
|
179
|
+
backupFiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
180
|
+
// 删除最旧的备份
|
|
181
|
+
const toDelete = backupFiles.slice(0, backupFiles.length - this.maxBackups);
|
|
182
|
+
let deletedCount = 0;
|
|
183
|
+
for (const file of toDelete) {
|
|
184
|
+
try {
|
|
185
|
+
await fs.remove(file.path);
|
|
186
|
+
deletedCount++;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// 忽略单个文件删除失败
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return deletedCount;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 获取备份文件列表
|
|
200
|
+
*/
|
|
201
|
+
async listBackups() {
|
|
202
|
+
if (!(await fs.pathExists(this.backupDir))) {
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const files = await fs.readdir(this.backupDir);
|
|
207
|
+
const backupFiles = files.filter(f => f.startsWith('settings-') && f.endsWith('.json'));
|
|
208
|
+
// 并行获取所有文件状态
|
|
209
|
+
const statsPromises = backupFiles.map(async (name) => {
|
|
210
|
+
const filePath = path.join(this.backupDir, name);
|
|
211
|
+
try {
|
|
212
|
+
const stats = await fs.stat(filePath);
|
|
213
|
+
// 从文件名解析时间戳
|
|
214
|
+
const timestampMatch = name.match(/settings-(\d+)\.json/);
|
|
215
|
+
let createdAt = stats.birthtime;
|
|
216
|
+
if (timestampMatch) {
|
|
217
|
+
const ts = timestampMatch[1];
|
|
218
|
+
// 解析时间戳 YYYYMMDDHHmmssSSS
|
|
219
|
+
createdAt = new Date(parseInt(ts.slice(0, 4)), parseInt(ts.slice(4, 6)) - 1, parseInt(ts.slice(6, 8)), parseInt(ts.slice(8, 10)), parseInt(ts.slice(10, 12)), parseInt(ts.slice(12, 14)), parseInt(ts.slice(14, 17)) || 0);
|
|
220
|
+
}
|
|
221
|
+
return { name, path: filePath, size: stats.size, createdAt };
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
const results = (await Promise.all(statsPromises)).filter((r) => r !== null);
|
|
228
|
+
// 按创建时间倒序
|
|
229
|
+
return results.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* 生成时间戳字符串
|
|
237
|
+
* 格式: YYYYMMDDHHmmssSSS (毫秒级精度)
|
|
238
|
+
*/
|
|
239
|
+
getTimestamp() {
|
|
240
|
+
const now = new Date();
|
|
241
|
+
const year = now.getFullYear();
|
|
242
|
+
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
243
|
+
const day = String(now.getDate()).padStart(2, '0');
|
|
244
|
+
const hours = String(now.getHours()).padStart(2, '0');
|
|
245
|
+
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
246
|
+
const seconds = String(now.getSeconds()).padStart(2, '0');
|
|
247
|
+
const ms = String(now.getMilliseconds()).padStart(3, '0');
|
|
248
|
+
return `${year}${month}${day}${hours}${minutes}${seconds}${ms}`;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 获取 settings 文件路径
|
|
252
|
+
*/
|
|
253
|
+
getSettingsPath() {
|
|
254
|
+
return this.settingsPath;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* 获取备份目录路径
|
|
258
|
+
*/
|
|
259
|
+
getBackupDir() {
|
|
260
|
+
return this.backupDir;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* 获取 Claude 目录路径
|
|
264
|
+
*/
|
|
265
|
+
getClaudeDir() {
|
|
266
|
+
return this.claudeDir;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.SettingsManager = SettingsManager;
|
|
270
|
+
//# sourceMappingURL=settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/lib/settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSM 状态管理模块
|
|
3
|
+
*/
|
|
4
|
+
import type { CsmState } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* 状态文件读取结果
|
|
7
|
+
*/
|
|
8
|
+
interface StateReadResult {
|
|
9
|
+
state: CsmState;
|
|
10
|
+
isCorrupted: boolean;
|
|
11
|
+
corruptionError?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* CSM 状态管理器
|
|
15
|
+
*/
|
|
16
|
+
export declare class StateManager {
|
|
17
|
+
private csmDir;
|
|
18
|
+
private stateFile;
|
|
19
|
+
constructor();
|
|
20
|
+
/**
|
|
21
|
+
* 读取状态
|
|
22
|
+
* @returns 状态读取结果,包含是否损坏的信息
|
|
23
|
+
*/
|
|
24
|
+
read(): Promise<CsmState>;
|
|
25
|
+
/**
|
|
26
|
+
* 读取状态并返回详细信息
|
|
27
|
+
*/
|
|
28
|
+
readWithStatus(): Promise<StateReadResult>;
|
|
29
|
+
/**
|
|
30
|
+
* 检查状态文件是否损坏
|
|
31
|
+
*/
|
|
32
|
+
isStateCorrupted(): Promise<{
|
|
33
|
+
corrupted: boolean;
|
|
34
|
+
error?: string;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* 重置损坏的状态文件
|
|
38
|
+
*/
|
|
39
|
+
resetCorruptedState(): Promise<boolean>;
|
|
40
|
+
/**
|
|
41
|
+
* 写入状态(使用原子写入)
|
|
42
|
+
*/
|
|
43
|
+
write(state: CsmState): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* 设置当前激活的 Profile
|
|
46
|
+
*/
|
|
47
|
+
setActiveProfile(name: string | null): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* 获取当前激活的 Profile
|
|
50
|
+
*/
|
|
51
|
+
getActiveProfile(): Promise<string | null>;
|
|
52
|
+
}
|
|
53
|
+
export declare const stateManager: StateManager;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/lib/state.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQzC;;GAEG;AACH,UAAU,eAAe;IACrB,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,YAAY;IACrB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;;IAO1B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,QAAQ,CAAC;IAK/B;;OAEG;IACG,cAAc,IAAI,OAAO,CAAC,eAAe,CAAC;IAiEhD;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAQzE;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAe7C;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C;;OAEG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAM1D;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAInD;AAGD,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CSM 状态管理模块
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.stateManager = exports.StateManager = void 0;
|
|
7
|
+
const fs_extra_1 = require("fs-extra");
|
|
8
|
+
const file_1 = require("../utils/file");
|
|
9
|
+
const atomicWrite_1 = require("../utils/atomicWrite");
|
|
10
|
+
// 默认状态
|
|
11
|
+
const DEFAULT_STATE = {
|
|
12
|
+
activeProfile: null,
|
|
13
|
+
version: '1.0.0'
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* CSM 状态管理器
|
|
17
|
+
*/
|
|
18
|
+
class StateManager {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.csmDir = (0, file_1.getCsmDir)();
|
|
21
|
+
this.stateFile = (0, file_1.getStatePath)();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 读取状态
|
|
25
|
+
* @returns 状态读取结果,包含是否损坏的信息
|
|
26
|
+
*/
|
|
27
|
+
async read() {
|
|
28
|
+
const result = await this.readWithStatus();
|
|
29
|
+
return result.state;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 读取状态并返回详细信息
|
|
33
|
+
*/
|
|
34
|
+
async readWithStatus() {
|
|
35
|
+
try {
|
|
36
|
+
const exists = await (0, fs_extra_1.pathExists)(this.stateFile);
|
|
37
|
+
if (!exists) {
|
|
38
|
+
return { state: { ...DEFAULT_STATE }, isCorrupted: false };
|
|
39
|
+
}
|
|
40
|
+
const content = await (0, fs_extra_1.readJson)(this.stateFile);
|
|
41
|
+
// 验证状态格式
|
|
42
|
+
if (typeof content !== 'object' || content === null) {
|
|
43
|
+
return {
|
|
44
|
+
state: { ...DEFAULT_STATE },
|
|
45
|
+
isCorrupted: true,
|
|
46
|
+
corruptionError: '状态文件内容不是有效对象'
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// 检查必要字段
|
|
50
|
+
const state = { ...DEFAULT_STATE, ...content };
|
|
51
|
+
// 验证 activeProfile 字段
|
|
52
|
+
if (state.activeProfile !== null && typeof state.activeProfile !== 'string') {
|
|
53
|
+
return {
|
|
54
|
+
state: { ...DEFAULT_STATE },
|
|
55
|
+
isCorrupted: true,
|
|
56
|
+
corruptionError: 'activeProfile 字段类型无效'
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return { state, isCorrupted: false };
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
// 区分错误类型
|
|
63
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
+
const nodeError = error;
|
|
65
|
+
// 权限错误 - 使用 error.code 检测
|
|
66
|
+
if (nodeError.code === 'EACCES' || nodeError.code === 'EPERM') {
|
|
67
|
+
console.warn(`警告: 无法读取状态文件 (权限问题): ${errorMessage}`);
|
|
68
|
+
return {
|
|
69
|
+
state: { ...DEFAULT_STATE },
|
|
70
|
+
isCorrupted: true,
|
|
71
|
+
corruptionError: '权限不足,无法读取状态文件'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// JSON 解析错误 - 检查是否为 SyntaxError
|
|
75
|
+
if (error instanceof SyntaxError) {
|
|
76
|
+
console.warn(`警告: 状态文件已损坏,将使用默认状态: ${errorMessage}`);
|
|
77
|
+
return {
|
|
78
|
+
state: { ...DEFAULT_STATE },
|
|
79
|
+
isCorrupted: true,
|
|
80
|
+
corruptionError: '状态文件格式损坏'
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// 其他错误
|
|
84
|
+
return {
|
|
85
|
+
state: { ...DEFAULT_STATE },
|
|
86
|
+
isCorrupted: true,
|
|
87
|
+
corruptionError: errorMessage
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 检查状态文件是否损坏
|
|
93
|
+
*/
|
|
94
|
+
async isStateCorrupted() {
|
|
95
|
+
const result = await this.readWithStatus();
|
|
96
|
+
if (result.isCorrupted) {
|
|
97
|
+
return { corrupted: true, error: result.corruptionError };
|
|
98
|
+
}
|
|
99
|
+
return { corrupted: false };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 重置损坏的状态文件
|
|
103
|
+
*/
|
|
104
|
+
async resetCorruptedState() {
|
|
105
|
+
const { isCorrupted } = await this.readWithStatus();
|
|
106
|
+
if (isCorrupted) {
|
|
107
|
+
try {
|
|
108
|
+
await (0, fs_extra_1.remove)(this.stateFile);
|
|
109
|
+
console.log('已重置损坏的状态文件');
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error(`无法删除损坏的状态文件: ${error instanceof Error ? error.message : String(error)}`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 写入状态(使用原子写入)
|
|
121
|
+
*/
|
|
122
|
+
async write(state) {
|
|
123
|
+
await (0, fs_extra_1.ensureDir)(this.csmDir);
|
|
124
|
+
await (0, atomicWrite_1.writeJsonAtomic)(this.stateFile, state, { spaces: 2 });
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 设置当前激活的 Profile
|
|
128
|
+
*/
|
|
129
|
+
async setActiveProfile(name) {
|
|
130
|
+
const state = await this.read();
|
|
131
|
+
state.activeProfile = name;
|
|
132
|
+
await this.write(state);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* 获取当前激活的 Profile
|
|
136
|
+
*/
|
|
137
|
+
async getActiveProfile() {
|
|
138
|
+
const state = await this.read();
|
|
139
|
+
return state.activeProfile;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.StateManager = StateManager;
|
|
143
|
+
// 导出默认实例
|
|
144
|
+
exports.stateManager = new StateManager();
|
|
145
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/lib/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSM 类型定义
|
|
3
|
+
*/
|
|
4
|
+
export interface ClaudeSettings {
|
|
5
|
+
env?: Record<string, string>;
|
|
6
|
+
permissions?: {
|
|
7
|
+
allow?: string[];
|
|
8
|
+
deny?: string[];
|
|
9
|
+
};
|
|
10
|
+
enabledPlugins?: Record<string, boolean>;
|
|
11
|
+
language?: string;
|
|
12
|
+
effortLevel?: string;
|
|
13
|
+
autoUpdatesChannel?: string;
|
|
14
|
+
autoMemoryEnabled?: boolean;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface CsmState {
|
|
18
|
+
activeProfile: string | null;
|
|
19
|
+
version: string;
|
|
20
|
+
}
|
|
21
|
+
export interface MergeOptions {
|
|
22
|
+
merge?: string[];
|
|
23
|
+
noMerge?: boolean;
|
|
24
|
+
keepPermissions?: boolean;
|
|
25
|
+
keepPlugins?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface BackupInfo {
|
|
28
|
+
name: string;
|
|
29
|
+
path: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
size: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ValidationResult {
|
|
34
|
+
valid: boolean;
|
|
35
|
+
errors: string[];
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAGD,MAAM,WAAW,QAAQ;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAGD,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAGD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":";AAAA;;GAEG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 原子写入工具
|
|
3
|
+
*
|
|
4
|
+
* 通过"写入临时文件 + 原子重命名"的方式确保写入操作的安全性,
|
|
5
|
+
* 防止写入过程中崩溃导致的数据损坏。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 原子写入 JSON 文件
|
|
9
|
+
*
|
|
10
|
+
* @param filePath - 目标文件路径
|
|
11
|
+
* @param data - 要写入的数据
|
|
12
|
+
* @param options - 写入选项
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeJsonAtomic(filePath: string, data: unknown, options?: {
|
|
15
|
+
spaces?: number | string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* 原子写入文本文件
|
|
19
|
+
*
|
|
20
|
+
* @param filePath - 目标文件路径
|
|
21
|
+
* @param content - 要写入的内容
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeFileAtomic(filePath: string, content: string): Promise<void>;
|
|
24
|
+
//# sourceMappingURL=atomicWrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomicWrite.d.ts","sourceRoot":"","sources":["../../src/utils/atomicWrite.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsCH;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GACrC,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 原子写入工具
|
|
4
|
+
*
|
|
5
|
+
* 通过"写入临时文件 + 原子重命名"的方式确保写入操作的安全性,
|
|
6
|
+
* 防止写入过程中崩溃导致的数据损坏。
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.writeJsonAtomic = writeJsonAtomic;
|
|
13
|
+
exports.writeFileAtomic = writeFileAtomic;
|
|
14
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
15
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
16
|
+
/**
|
|
17
|
+
* 生成安全的临时文件路径
|
|
18
|
+
* 使用加密安全的随机数避免冲突
|
|
19
|
+
*/
|
|
20
|
+
function generateTempPath(filePath) {
|
|
21
|
+
const randomId = crypto_1.default.randomBytes(8).toString('hex');
|
|
22
|
+
return `${filePath}.tmp-${Date.now()}-${randomId}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 安全写入文件的核心逻辑
|
|
26
|
+
*/
|
|
27
|
+
async function safeWrite(tempPath, filePath, writeFn) {
|
|
28
|
+
try {
|
|
29
|
+
await writeFn();
|
|
30
|
+
// 原子重命名(POSIX 系统上是原子操作)
|
|
31
|
+
// Windows 上 rename 不是严格原子的,但仍然是安全的最佳实践
|
|
32
|
+
await fs_extra_1.default.rename(tempPath, filePath);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// 清理可能残留的临时文件
|
|
36
|
+
try {
|
|
37
|
+
await fs_extra_1.default.remove(tempPath);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// 忽略清理错误
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 原子写入 JSON 文件
|
|
47
|
+
*
|
|
48
|
+
* @param filePath - 目标文件路径
|
|
49
|
+
* @param data - 要写入的数据
|
|
50
|
+
* @param options - 写入选项
|
|
51
|
+
*/
|
|
52
|
+
async function writeJsonAtomic(filePath, data, options) {
|
|
53
|
+
const spaces = options?.spaces ?? 2;
|
|
54
|
+
const tempPath = generateTempPath(filePath);
|
|
55
|
+
await safeWrite(tempPath, filePath, () => fs_extra_1.default.writeJson(tempPath, data, { spaces }));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 原子写入文本文件
|
|
59
|
+
*
|
|
60
|
+
* @param filePath - 目标文件路径
|
|
61
|
+
* @param content - 要写入的内容
|
|
62
|
+
*/
|
|
63
|
+
async function writeFileAtomic(filePath, content) {
|
|
64
|
+
const tempPath = generateTempPath(filePath);
|
|
65
|
+
await safeWrite(tempPath, filePath, () => fs_extra_1.default.writeFile(tempPath, content, 'utf-8'));
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=atomicWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atomicWrite.js","sourceRoot":"","sources":["../../src/utils/atomicWrite.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AA6CH,0CASC;AAQD,0CAOC;AAnED,wDAA0B;AAC1B,oDAA4B;AAE5B;;;GAGG;AACH,SAAS,gBAAgB,CAAC,QAAgB;IACxC,MAAM,QAAQ,GAAG,gBAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,GAAG,QAAQ,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;AACrD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,SAAS,CACtB,QAAgB,EAChB,QAAgB,EAChB,OAA4B;IAE5B,IAAI,CAAC;QACH,MAAM,OAAO,EAAE,CAAC;QAChB,wBAAwB;QACxB,uCAAuC;QACvC,MAAM,kBAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc;QACd,IAAI,CAAC;YACH,MAAM,kBAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,IAAa,EACb,OAAsC;IAEtC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,CAAC,CAAC;IACpC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE5C,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;AACtF,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,OAAe;IAEf,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE5C,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,kBAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AACtF,CAAC"}
|