coding-tool-x 3.3.7 → 3.3.9
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/CHANGELOG.md +20 -0
- package/README.md +253 -326
- package/dist/web/assets/{Analytics-IW6eAy9u.js → Analytics-D6LzK9hk.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-BPtkTMSc.js → ConfigTemplates-BUDYuxRi.js} +1 -1
- package/dist/web/assets/Home-BQxQ1LhR.css +1 -0
- package/dist/web/assets/Home-D7KX7iF8.js +1 -0
- package/dist/web/assets/{PluginManager-BGx9MSDV.js → PluginManager-DTgQ--vB.js} +1 -1
- package/dist/web/assets/{ProjectList-BCn-mrCx.js → ProjectList-DMCiGmCT.js} +1 -1
- package/dist/web/assets/{SessionList-CzLfebJQ.js → SessionList-CRBsdVRe.js} +1 -1
- package/dist/web/assets/{SkillManager-CXz2vBQx.js → SkillManager-DMwx2Q4k.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-CHtgMfKc.js → WorkspaceManager-DapB4ljL.js} +1 -1
- package/dist/web/assets/{icons-B29onFfZ.js → icons-B5Pl4lrD.js} +1 -1
- package/dist/web/assets/index-CL-qpoJ_.js +2 -0
- package/dist/web/assets/index-D_5dRFOL.css +1 -0
- package/dist/web/assets/{markdown-C9MYpaSi.js → markdown-DyTJGI4N.js} +1 -1
- package/dist/web/assets/{naive-ui-CxpuzdjU.js → naive-ui-Bdxp09n2.js} +1 -1
- package/dist/web/assets/{vendors-DMjSfzlv.js → vendors-CKPV1OAU.js} +2 -2
- package/dist/web/assets/{vue-vendor-DET08QYg.js → vue-vendor-3bf-fPGP.js} +1 -1
- package/dist/web/index.html +7 -7
- package/docs/home.png +0 -0
- package/package.json +14 -5
- package/src/commands/daemon.js +3 -2
- package/src/commands/security.js +1 -2
- package/src/commands/toggle-proxy.js +100 -5
- package/src/config/paths.js +718 -90
- package/src/server/api/agents.js +1 -1
- package/src/server/api/channels.js +9 -0
- package/src/server/api/claude-hooks.js +13 -8
- package/src/server/api/codex-channels.js +9 -0
- package/src/server/api/codex-proxy.js +27 -15
- package/src/server/api/gemini-proxy.js +22 -11
- package/src/server/api/hooks.js +45 -0
- package/src/server/api/oauth-credentials.js +163 -0
- package/src/server/api/opencode-proxy.js +22 -10
- package/src/server/api/plugins.js +2 -1
- package/src/server/api/proxy.js +39 -44
- package/src/server/api/skills.js +91 -13
- package/src/server/api/ui-config.js +5 -0
- package/src/server/codex-proxy-server.js +90 -70
- package/src/server/gemini-proxy-server.js +107 -88
- package/src/server/index.js +2 -0
- package/src/server/opencode-proxy-server.js +381 -225
- package/src/server/proxy-server.js +86 -60
- package/src/server/services/alias.js +3 -3
- package/src/server/services/channels.js +21 -24
- package/src/server/services/codex-channels.js +158 -255
- package/src/server/services/codex-config.js +2 -5
- package/src/server/services/codex-env-manager.js +423 -0
- package/src/server/services/codex-settings-manager.js +21 -357
- package/src/server/services/codex-statistics-service.js +3 -27
- package/src/server/services/config-export-service.js +43 -9
- package/src/server/services/config-registry-service.js +3 -2
- package/src/server/services/config-sync-manager.js +1 -1
- package/src/server/services/favorites.js +4 -3
- package/src/server/services/gemini-channels.js +14 -12
- package/src/server/services/gemini-statistics-service.js +3 -25
- package/src/server/services/mcp-service.js +35 -19
- package/src/server/services/model-detector.js +4 -3
- package/src/server/services/native-keychain.js +243 -0
- package/src/server/services/native-oauth-adapters.js +891 -0
- package/src/server/services/network-access.js +39 -1
- package/src/server/services/notification-hooks.js +951 -0
- package/src/server/services/oauth-credentials-service.js +786 -0
- package/src/server/services/oauth-utils.js +49 -0
- package/src/server/services/opencode-channels.js +19 -15
- package/src/server/services/opencode-sessions.js +2 -2
- package/src/server/services/opencode-settings-manager.js +169 -16
- package/src/server/services/opencode-statistics-service.js +3 -27
- package/src/server/services/plugins-service.js +115 -15
- package/src/server/services/prompts-service.js +2 -3
- package/src/server/services/proxy-log-helper.js +242 -0
- package/src/server/services/proxy-runtime.js +6 -4
- package/src/server/services/repo-scanner-base.js +12 -4
- package/src/server/services/request-logger.js +7 -7
- package/src/server/services/security-config.js +4 -4
- package/src/server/services/session-cache.js +2 -2
- package/src/server/services/sessions.js +2 -2
- package/src/server/services/settings-manager.js +13 -0
- package/src/server/services/skill-service.js +867 -368
- package/src/server/services/statistics-service.js +5 -5
- package/src/server/services/ui-config.js +4 -3
- package/src/server/services/workspace-service.js +1 -1
- package/src/server/websocket-server.js +5 -4
- package/dist/web/assets/Home-BsSioaaB.css +0 -1
- package/dist/web/assets/Home-obifg_9E.js +0 -1
- package/dist/web/assets/index-C7LPdVsN.js +0 -2
- package/dist/web/assets/index-eEmjZKWP.css +0 -1
- package/docs/bannel.png +0 -0
- package/docs/model-redirection.md +0 -251
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
function toNumber(value) {
|
|
2
|
+
const num = Number(value);
|
|
3
|
+
return Number.isFinite(num) ? num : 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function normalizeToolSource(source = '') {
|
|
7
|
+
const normalized = String(source || '').trim().toLowerCase();
|
|
8
|
+
if (normalized === 'claude' || normalized === 'claude-code') return 'claude';
|
|
9
|
+
if (normalized === 'codex') return 'codex';
|
|
10
|
+
if (normalized === 'gemini') return 'gemini';
|
|
11
|
+
if (normalized === 'opencode') return 'opencode';
|
|
12
|
+
return 'claude';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeUsageTokens(source, tokens = {}) {
|
|
16
|
+
const normalizedSource = normalizeToolSource(source);
|
|
17
|
+
const input = toNumber(tokens.input);
|
|
18
|
+
const output = toNumber(tokens.output);
|
|
19
|
+
const cacheCreation = toNumber(tokens.cacheCreation);
|
|
20
|
+
const cacheRead = toNumber(tokens.cacheRead);
|
|
21
|
+
const cached = toNumber(tokens.cached);
|
|
22
|
+
const reasoning = toNumber(tokens.reasoning);
|
|
23
|
+
let total = toNumber(tokens.total);
|
|
24
|
+
|
|
25
|
+
if (total <= 0) {
|
|
26
|
+
if (normalizedSource === 'claude') {
|
|
27
|
+
total = input + output + cacheCreation + cacheRead;
|
|
28
|
+
} else {
|
|
29
|
+
total = input + output;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
input,
|
|
35
|
+
output,
|
|
36
|
+
cacheCreation,
|
|
37
|
+
cacheRead,
|
|
38
|
+
cached,
|
|
39
|
+
reasoning,
|
|
40
|
+
total
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasMeaningfulUsage(source, tokens = {}) {
|
|
45
|
+
const normalized = normalizeUsageTokens(source, tokens);
|
|
46
|
+
if (normalized.total > 0) return true;
|
|
47
|
+
if (normalized.input > 0 || normalized.output > 0) return true;
|
|
48
|
+
if (normalized.cacheCreation > 0 || normalized.cacheRead > 0) return true;
|
|
49
|
+
if (normalized.cached > 0 || normalized.reasoning > 0) return true;
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function formatRealtimeTime(timestamp = Date.now()) {
|
|
54
|
+
return new Date(timestamp).toLocaleTimeString('zh-CN', {
|
|
55
|
+
hour12: false,
|
|
56
|
+
hour: '2-digit',
|
|
57
|
+
minute: '2-digit',
|
|
58
|
+
second: '2-digit'
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildSuccessLogPayload({
|
|
63
|
+
source,
|
|
64
|
+
requestId,
|
|
65
|
+
channel,
|
|
66
|
+
model,
|
|
67
|
+
tokens,
|
|
68
|
+
cost = 0,
|
|
69
|
+
timestamp = Date.now()
|
|
70
|
+
}) {
|
|
71
|
+
const normalized = normalizeUsageTokens(source, tokens);
|
|
72
|
+
return {
|
|
73
|
+
type: 'log',
|
|
74
|
+
status: 'success',
|
|
75
|
+
id: requestId,
|
|
76
|
+
time: formatRealtimeTime(timestamp),
|
|
77
|
+
channel,
|
|
78
|
+
model: model || '',
|
|
79
|
+
inputTokens: normalized.input,
|
|
80
|
+
outputTokens: normalized.output,
|
|
81
|
+
cacheCreation: normalized.cacheCreation,
|
|
82
|
+
cacheRead: normalized.cacheRead,
|
|
83
|
+
cachedTokens: normalized.cached,
|
|
84
|
+
reasoningTokens: normalized.reasoning,
|
|
85
|
+
totalTokens: normalized.total,
|
|
86
|
+
cost,
|
|
87
|
+
source: normalizeToolSource(source),
|
|
88
|
+
timestamp
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function buildFailureLogPayload({
|
|
93
|
+
source,
|
|
94
|
+
requestId,
|
|
95
|
+
channel,
|
|
96
|
+
model,
|
|
97
|
+
message,
|
|
98
|
+
error,
|
|
99
|
+
statusCode,
|
|
100
|
+
stage,
|
|
101
|
+
timestamp = Date.now()
|
|
102
|
+
}) {
|
|
103
|
+
const errorMessage = String(
|
|
104
|
+
error?.message
|
|
105
|
+
|| message
|
|
106
|
+
|| error
|
|
107
|
+
|| 'Request failed'
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
type: 'log',
|
|
112
|
+
status: 'error',
|
|
113
|
+
id: requestId || `${normalizeToolSource(source)}-error-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
114
|
+
time: formatRealtimeTime(timestamp),
|
|
115
|
+
channel: channel || 'Unknown',
|
|
116
|
+
model: model || '',
|
|
117
|
+
message: errorMessage,
|
|
118
|
+
error: errorMessage,
|
|
119
|
+
statusCode: Number.isFinite(Number(statusCode)) ? Number(statusCode) : null,
|
|
120
|
+
stage: stage || 'proxy',
|
|
121
|
+
inputTokens: 0,
|
|
122
|
+
outputTokens: 0,
|
|
123
|
+
cacheCreation: 0,
|
|
124
|
+
cacheRead: 0,
|
|
125
|
+
cachedTokens: 0,
|
|
126
|
+
reasoningTokens: 0,
|
|
127
|
+
totalTokens: 0,
|
|
128
|
+
cost: 0,
|
|
129
|
+
source: normalizeToolSource(source),
|
|
130
|
+
timestamp
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function publishUsageLog({
|
|
135
|
+
source,
|
|
136
|
+
metadata = {},
|
|
137
|
+
model,
|
|
138
|
+
tokens,
|
|
139
|
+
calculateCost,
|
|
140
|
+
broadcastLog,
|
|
141
|
+
recordRequest,
|
|
142
|
+
recordSuccess,
|
|
143
|
+
allowBroadcast = true
|
|
144
|
+
}) {
|
|
145
|
+
if (!hasMeaningfulUsage(source, tokens)) {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const normalizedSource = normalizeToolSource(source);
|
|
150
|
+
const normalizedTokens = normalizeUsageTokens(normalizedSource, tokens);
|
|
151
|
+
const requestId = metadata.id || `${normalizedSource}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
152
|
+
const timestamp = Date.now();
|
|
153
|
+
const cost = typeof calculateCost === 'function'
|
|
154
|
+
? calculateCost(model || '', normalizedTokens)
|
|
155
|
+
: 0;
|
|
156
|
+
|
|
157
|
+
if (allowBroadcast && typeof broadcastLog === 'function') {
|
|
158
|
+
broadcastLog(buildSuccessLogPayload({
|
|
159
|
+
source: normalizedSource,
|
|
160
|
+
requestId,
|
|
161
|
+
channel: metadata.channel,
|
|
162
|
+
model,
|
|
163
|
+
tokens: normalizedTokens,
|
|
164
|
+
cost,
|
|
165
|
+
timestamp
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (typeof recordRequest === 'function') {
|
|
170
|
+
recordRequest({
|
|
171
|
+
id: requestId,
|
|
172
|
+
timestamp: new Date(metadata.startTime || timestamp).toISOString(),
|
|
173
|
+
toolType: normalizedSource === 'claude' ? 'claude-code' : normalizedSource,
|
|
174
|
+
channel: metadata.channel,
|
|
175
|
+
channelId: metadata.channelId,
|
|
176
|
+
model: model || '',
|
|
177
|
+
tokens: {
|
|
178
|
+
input: normalizedTokens.input,
|
|
179
|
+
output: normalizedTokens.output,
|
|
180
|
+
reasoning: normalizedTokens.reasoning,
|
|
181
|
+
cached: normalizedTokens.cached,
|
|
182
|
+
cacheCreation: normalizedTokens.cacheCreation,
|
|
183
|
+
cacheRead: normalizedTokens.cacheRead,
|
|
184
|
+
total: normalizedTokens.total
|
|
185
|
+
},
|
|
186
|
+
duration: Math.max(0, timestamp - toNumber(metadata.startTime || timestamp)),
|
|
187
|
+
success: true,
|
|
188
|
+
cost
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (typeof recordSuccess === 'function' && metadata.channelId) {
|
|
193
|
+
recordSuccess(metadata.channelId, normalizedSource);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
cost,
|
|
198
|
+
tokens: normalizedTokens,
|
|
199
|
+
timestamp
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function publishFailureLog({
|
|
204
|
+
source,
|
|
205
|
+
metadata = {},
|
|
206
|
+
channel,
|
|
207
|
+
model,
|
|
208
|
+
message,
|
|
209
|
+
error,
|
|
210
|
+
statusCode,
|
|
211
|
+
stage,
|
|
212
|
+
broadcastLog
|
|
213
|
+
}) {
|
|
214
|
+
if (typeof broadcastLog !== 'function') {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const payload = buildFailureLogPayload({
|
|
219
|
+
source,
|
|
220
|
+
requestId: metadata.id,
|
|
221
|
+
channel: channel || metadata.channel,
|
|
222
|
+
model: model || metadata.model,
|
|
223
|
+
message,
|
|
224
|
+
error,
|
|
225
|
+
statusCode,
|
|
226
|
+
stage
|
|
227
|
+
});
|
|
228
|
+
broadcastLog(payload);
|
|
229
|
+
return payload;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
module.exports = {
|
|
233
|
+
toNumber,
|
|
234
|
+
normalizeToolSource,
|
|
235
|
+
normalizeUsageTokens,
|
|
236
|
+
hasMeaningfulUsage,
|
|
237
|
+
formatRealtimeTime,
|
|
238
|
+
buildSuccessLogPayload,
|
|
239
|
+
buildFailureLogPayload,
|
|
240
|
+
publishUsageLog,
|
|
241
|
+
publishFailureLog
|
|
242
|
+
};
|
|
@@ -3,11 +3,13 @@ const path = require('path');
|
|
|
3
3
|
const { PATHS } = require('../../config/paths');
|
|
4
4
|
|
|
5
5
|
function getRuntimeFilePath(proxyType) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const filePath = PATHS.proxyRuntime?.[proxyType]
|
|
7
|
+
|| path.join(path.dirname(PATHS.proxyRuntime.claude), `${proxyType}-proxy.json`);
|
|
8
|
+
const dir = path.dirname(filePath);
|
|
9
|
+
if (!fs.existsSync(dir)) {
|
|
10
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9
11
|
}
|
|
10
|
-
return
|
|
12
|
+
return filePath;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
function saveProxyStartTime(proxyType, preserveExisting = false) {
|
|
@@ -11,7 +11,7 @@ const https = require('https');
|
|
|
11
11
|
const http = require('http');
|
|
12
12
|
const { createWriteStream } = require('fs');
|
|
13
13
|
const AdmZip = require('adm-zip');
|
|
14
|
-
const {
|
|
14
|
+
const { PATHS, getRepoScannerReposPath, getRepoScannerCachePath } = require('../../config/paths');
|
|
15
15
|
|
|
16
16
|
// 缓存有效期(5分钟)
|
|
17
17
|
const CACHE_TTL = 5 * 60 * 1000;
|
|
@@ -70,9 +70,9 @@ class RepoScannerBase {
|
|
|
70
70
|
this.fileExtension = options.fileExtension || '.md';
|
|
71
71
|
this.defaultRepos = options.defaultRepos || [];
|
|
72
72
|
|
|
73
|
-
this.configDir =
|
|
74
|
-
this.reposConfigPath =
|
|
75
|
-
this.cachePath =
|
|
73
|
+
this.configDir = PATHS.config;
|
|
74
|
+
this.reposConfigPath = getRepoScannerReposPath(this.type);
|
|
75
|
+
this.cachePath = getRepoScannerCachePath(this.type);
|
|
76
76
|
|
|
77
77
|
// 内存缓存
|
|
78
78
|
this.itemsCache = null;
|
|
@@ -89,6 +89,14 @@ class RepoScannerBase {
|
|
|
89
89
|
if (!fs.existsSync(this.configDir)) {
|
|
90
90
|
fs.mkdirSync(this.configDir, { recursive: true });
|
|
91
91
|
}
|
|
92
|
+
const reposDir = path.dirname(this.reposConfigPath);
|
|
93
|
+
if (!fs.existsSync(reposDir)) {
|
|
94
|
+
fs.mkdirSync(reposDir, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
const cacheDir = path.dirname(this.cachePath);
|
|
97
|
+
if (!fs.existsSync(cacheDir)) {
|
|
98
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
99
|
+
}
|
|
92
100
|
}
|
|
93
101
|
|
|
94
102
|
// ==================== 仓库配置管理 ====================
|
|
@@ -18,7 +18,7 @@ const fs = require('fs');
|
|
|
18
18
|
const path = require('path');
|
|
19
19
|
const { PATHS } = require('../../config/paths');
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
const REQUEST_SNAPSHOTS_DIR = path.dirname(PATHS.requestSnapshots.claude);
|
|
22
22
|
|
|
23
23
|
function ensureDir(dir) {
|
|
24
24
|
if (!fs.existsSync(dir)) {
|
|
@@ -55,8 +55,8 @@ function persistProxyRequestSnapshot(source, payload) {
|
|
|
55
55
|
if (!isProxyRequestLoggingEnabled()) return;
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
const logPath = PATHS.requestSnapshots[source] || path.join(REQUEST_SNAPSHOTS_DIR, `${source}.jsonl`);
|
|
59
|
+
ensureDir(path.dirname(logPath));
|
|
60
60
|
fs.appendFile(logPath, `${JSON.stringify(payload)}\n`, (error) => {
|
|
61
61
|
if (error) {
|
|
62
62
|
console.error(`[request-logger] Failed to persist ${source} request snapshot:`, error);
|
|
@@ -97,8 +97,8 @@ function createApiRequestLogger() {
|
|
|
97
97
|
};
|
|
98
98
|
|
|
99
99
|
try {
|
|
100
|
-
ensureDir(
|
|
101
|
-
const logPath = path.join(
|
|
100
|
+
ensureDir(PATHS.logs);
|
|
101
|
+
const logPath = path.join(PATHS.logs, 'api-requests.jsonl');
|
|
102
102
|
fs.appendFile(logPath, `${JSON.stringify(entry)}\n`, (err) => {
|
|
103
103
|
if (err) {
|
|
104
104
|
console.error('[request-logger] Failed to write API request log:', err);
|
|
@@ -122,7 +122,7 @@ function createApiRequestLogger() {
|
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
const CLAUDE_TEMPLATE_PATH =
|
|
125
|
+
const CLAUDE_TEMPLATE_PATH = PATHS.claudeRequestTemplate;
|
|
126
126
|
const CLAUDE_TEMPLATE_MIN_SYSTEM_CHARS = 100;
|
|
127
127
|
|
|
128
128
|
const FALLBACK_CLAUDE_SYSTEM = Object.freeze([
|
|
@@ -280,7 +280,7 @@ function persistClaudeRequestTemplate(body) {
|
|
|
280
280
|
if (systemCharCount < CLAUDE_TEMPLATE_MIN_SYSTEM_CHARS) return;
|
|
281
281
|
|
|
282
282
|
try {
|
|
283
|
-
ensureDir(
|
|
283
|
+
ensureDir(path.dirname(CLAUDE_TEMPLATE_PATH));
|
|
284
284
|
const template = { updatedAt: Date.now(), userId, system, tools };
|
|
285
285
|
fs.writeFile(CLAUDE_TEMPLATE_PATH, JSON.stringify(template), (err) => {
|
|
286
286
|
if (err) console.error('[request-logger] Failed to write claude-request-template.json:', err);
|
|
@@ -3,8 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const { PATHS } = require('../../config/paths');
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const SECURITY_FILE = path.join(SECURITY_DIR, 'security.json');
|
|
6
|
+
const SECURITY_FILE = PATHS.security;
|
|
8
7
|
|
|
9
8
|
const DEFAULT_SECURITY_CONFIG = {
|
|
10
9
|
passwordHash: '',
|
|
@@ -17,8 +16,9 @@ const PBKDF2_KEYLEN = 64;
|
|
|
17
16
|
const PBKDF2_DIGEST = 'sha512';
|
|
18
17
|
|
|
19
18
|
function ensureSecurityDir() {
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
const dir = path.dirname(SECURITY_FILE);
|
|
20
|
+
if (!fs.existsSync(dir)) {
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -11,7 +11,7 @@ let hasMessagesPersisted = {};
|
|
|
11
11
|
let hasMessagesPersistTimer = null;
|
|
12
12
|
|
|
13
13
|
function getCcToolDir() {
|
|
14
|
-
return PATHS.
|
|
14
|
+
return path.dirname(PATHS.sessionHasCache);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
function ensureDirExists(dir) {
|
|
@@ -52,7 +52,7 @@ function invalidateProjectsCache(configOrPath) {
|
|
|
52
52
|
projectsCache.delete(key);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const hasMessagesCacheFile =
|
|
55
|
+
const hasMessagesCacheFile = PATHS.sessionHasCache;
|
|
56
56
|
loadHasMessagesCacheFromDisk();
|
|
57
57
|
|
|
58
58
|
function loadHasMessagesCacheFromDisk() {
|
|
@@ -29,12 +29,12 @@ function getOrderFilePath() {
|
|
|
29
29
|
|
|
30
30
|
// Get path for storing fork relations
|
|
31
31
|
function getForkRelationsFilePath() {
|
|
32
|
-
return
|
|
32
|
+
return PATHS.forkRelations;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Get path for storing session order
|
|
36
36
|
function getSessionOrderFilePath() {
|
|
37
|
-
return
|
|
37
|
+
return PATHS.sessionOrder;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
// Get saved project order
|
|
@@ -84,6 +84,18 @@ function restoreSettings() {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function deleteBackup() {
|
|
88
|
+
try {
|
|
89
|
+
if (fs.existsSync(getBackupPath())) {
|
|
90
|
+
fs.unlinkSync(getBackupPath());
|
|
91
|
+
}
|
|
92
|
+
return { success: true };
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.warn('Failed to delete Claude backup file:', err.message);
|
|
95
|
+
return { success: false, error: err.message };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
// 设置代理配置
|
|
88
100
|
function setProxyConfig(proxyPort) {
|
|
89
101
|
try {
|
|
@@ -156,6 +168,7 @@ module.exports = {
|
|
|
156
168
|
writeSettings,
|
|
157
169
|
backupSettings,
|
|
158
170
|
restoreSettings,
|
|
171
|
+
deleteBackup,
|
|
159
172
|
setProxyConfig,
|
|
160
173
|
isProxyConfig,
|
|
161
174
|
getCurrentProxyPort
|