@mison/wecom-cleaner 1.0.0
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 +323 -0
- package/docs/IMPLEMENTATION_PLAN.md +162 -0
- package/docs/releases/v1.0.0.md +32 -0
- package/native/README.md +9 -0
- package/native/bin/darwin-arm64/wecom-cleaner-core +0 -0
- package/native/bin/darwin-x64/wecom-cleaner-core +0 -0
- package/native/manifest.json +15 -0
- package/native/zig/build.sh +68 -0
- package/native/zig/src/main.zig +96 -0
- package/package.json +62 -0
- package/src/analysis.js +58 -0
- package/src/cleanup.js +217 -0
- package/src/cli.js +2619 -0
- package/src/config.js +270 -0
- package/src/constants.js +309 -0
- package/src/doctor.js +366 -0
- package/src/error-taxonomy.js +73 -0
- package/src/lock.js +102 -0
- package/src/native-bridge.js +403 -0
- package/src/recycle-maintenance.js +335 -0
- package/src/restore.js +533 -0
- package/src/scanner.js +1277 -0
- package/src/utils.js +365 -0
package/src/config.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { DEFAULT_PROFILE_ROOT, DEFAULT_STATE_ROOT } from './constants.js';
|
|
3
|
+
import { ensureDir, expandHome, readJson, writeJson } from './utils.js';
|
|
4
|
+
import { normalizeRecycleRetention } from './recycle-maintenance.js';
|
|
5
|
+
|
|
6
|
+
const ALLOWED_THEMES = new Set(['auto', 'light', 'dark']);
|
|
7
|
+
|
|
8
|
+
export class CliArgError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'CliArgError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeTheme(theme) {
|
|
16
|
+
if (typeof theme !== 'string') {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
const normalized = theme.trim().toLowerCase();
|
|
20
|
+
if (!ALLOWED_THEMES.has(normalized)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function defaultConfig() {
|
|
27
|
+
const stateRoot = DEFAULT_STATE_ROOT;
|
|
28
|
+
const recycleRetention = normalizeRecycleRetention({
|
|
29
|
+
enabled: true,
|
|
30
|
+
maxAgeDays: 30,
|
|
31
|
+
minKeepBatches: 20,
|
|
32
|
+
sizeThresholdGB: 20,
|
|
33
|
+
lastRunAt: 0,
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
rootDir: DEFAULT_PROFILE_ROOT,
|
|
37
|
+
externalStorageRoots: [],
|
|
38
|
+
externalStorageAutoDetect: true,
|
|
39
|
+
stateRoot,
|
|
40
|
+
recycleRoot: path.join(stateRoot, 'recycle-bin'),
|
|
41
|
+
indexPath: path.join(stateRoot, 'index.jsonl'),
|
|
42
|
+
aliasPath: path.join(stateRoot, 'account-aliases.json'),
|
|
43
|
+
dryRunDefault: true,
|
|
44
|
+
defaultCategories: [],
|
|
45
|
+
spaceGovernance: {
|
|
46
|
+
autoSuggest: {
|
|
47
|
+
sizeThresholdMB: 512,
|
|
48
|
+
idleDays: 7,
|
|
49
|
+
},
|
|
50
|
+
cooldownSeconds: 5,
|
|
51
|
+
lastSelectedTargets: [],
|
|
52
|
+
},
|
|
53
|
+
recycleRetention,
|
|
54
|
+
theme: 'auto',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function normalizePositiveInt(rawValue, fallbackValue, minValue = 1) {
|
|
59
|
+
const num = Number.parseInt(String(rawValue ?? ''), 10);
|
|
60
|
+
if (!Number.isFinite(num) || num < minValue) {
|
|
61
|
+
return fallbackValue;
|
|
62
|
+
}
|
|
63
|
+
return num;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeSpaceGovernance(input, fallback) {
|
|
67
|
+
const source = input && typeof input === 'object' ? input : {};
|
|
68
|
+
const autoSuggest = source.autoSuggest && typeof source.autoSuggest === 'object' ? source.autoSuggest : {};
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
autoSuggest: {
|
|
72
|
+
sizeThresholdMB: normalizePositiveInt(
|
|
73
|
+
autoSuggest.sizeThresholdMB,
|
|
74
|
+
fallback.autoSuggest.sizeThresholdMB
|
|
75
|
+
),
|
|
76
|
+
idleDays: normalizePositiveInt(autoSuggest.idleDays, fallback.autoSuggest.idleDays),
|
|
77
|
+
},
|
|
78
|
+
cooldownSeconds: normalizePositiveInt(source.cooldownSeconds, fallback.cooldownSeconds),
|
|
79
|
+
lastSelectedTargets: Array.isArray(source.lastSelectedTargets)
|
|
80
|
+
? source.lastSelectedTargets.filter((x) => typeof x === 'string' && x.trim())
|
|
81
|
+
: fallback.lastSelectedTargets,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function parseCliArgs(argv) {
|
|
86
|
+
const parsed = {
|
|
87
|
+
rootDir: null,
|
|
88
|
+
externalStorageRoots: null,
|
|
89
|
+
externalStorageAutoDetect: null,
|
|
90
|
+
stateRoot: null,
|
|
91
|
+
dryRunDefault: null,
|
|
92
|
+
mode: null,
|
|
93
|
+
theme: null,
|
|
94
|
+
jsonOutput: false,
|
|
95
|
+
force: false,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const takeValue = (flag, index) => {
|
|
99
|
+
const value = argv[index + 1];
|
|
100
|
+
if (!value || value.startsWith('-')) {
|
|
101
|
+
throw new CliArgError(`参数 ${flag} 缺少值`);
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const parseBooleanFlag = (flag, rawValue) => {
|
|
107
|
+
const normalized = String(rawValue).trim().toLowerCase();
|
|
108
|
+
if (['1', 'true', 'yes', 'y', 'on'].includes(normalized)) {
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
if (['0', 'false', 'no', 'n', 'off'].includes(normalized)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
throw new CliArgError(`参数 ${flag} 的值无效: ${rawValue}`);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
118
|
+
const token = argv[i];
|
|
119
|
+
if (token === '--root') {
|
|
120
|
+
parsed.rootDir = takeValue(token, i);
|
|
121
|
+
i += 1;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (token === '--state-root') {
|
|
125
|
+
parsed.stateRoot = takeValue(token, i);
|
|
126
|
+
i += 1;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (token === '--external-storage-root') {
|
|
130
|
+
parsed.externalStorageRoots = takeValue(token, i);
|
|
131
|
+
i += 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (token === '--external-storage-auto-detect') {
|
|
135
|
+
parsed.externalStorageAutoDetect = parseBooleanFlag(token, takeValue(token, i));
|
|
136
|
+
i += 1;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (token === '--dry-run-default') {
|
|
140
|
+
parsed.dryRunDefault = parseBooleanFlag(token, takeValue(token, i));
|
|
141
|
+
i += 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (token === '--mode') {
|
|
145
|
+
parsed.mode = takeValue(token, i);
|
|
146
|
+
i += 1;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (token === '--theme') {
|
|
150
|
+
const theme = normalizeTheme(takeValue(token, i));
|
|
151
|
+
if (!theme) {
|
|
152
|
+
throw new CliArgError(`参数 --theme 的值无效: ${argv[i + 1]}`);
|
|
153
|
+
}
|
|
154
|
+
parsed.theme = theme;
|
|
155
|
+
i += 1;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (token === '--json') {
|
|
159
|
+
parsed.jsonOutput = true;
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (token === '--force') {
|
|
163
|
+
parsed.force = true;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (token.startsWith('-')) {
|
|
167
|
+
throw new CliArgError(`不支持的参数: ${token}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return parsed;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function normalizePathList(value) {
|
|
175
|
+
if (Array.isArray(value)) {
|
|
176
|
+
return value.map((item) => expandHome(String(item || '').trim())).filter((item) => item && item.trim());
|
|
177
|
+
}
|
|
178
|
+
if (typeof value === 'string') {
|
|
179
|
+
return value
|
|
180
|
+
.split(/[,\n;]/)
|
|
181
|
+
.map((item) => expandHome(String(item || '').trim()))
|
|
182
|
+
.filter((item) => item && item.trim());
|
|
183
|
+
}
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function loadConfig(cliArgs = {}, options = {}) {
|
|
188
|
+
const base = defaultConfig();
|
|
189
|
+
const bootstrapStateRoot = expandHome(cliArgs.stateRoot || base.stateRoot);
|
|
190
|
+
const bootstrapConfigPath = path.join(bootstrapStateRoot, 'config.json');
|
|
191
|
+
|
|
192
|
+
let fileConfig = await readJson(bootstrapConfigPath, {});
|
|
193
|
+
const preferredStateRoot = expandHome(cliArgs.stateRoot || fileConfig.stateRoot || base.stateRoot);
|
|
194
|
+
const configPath = path.join(preferredStateRoot, 'config.json');
|
|
195
|
+
if (preferredStateRoot !== bootstrapStateRoot) {
|
|
196
|
+
fileConfig = await readJson(configPath, fileConfig);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const stateRoot = preferredStateRoot;
|
|
200
|
+
|
|
201
|
+
const merged = {
|
|
202
|
+
...base,
|
|
203
|
+
...fileConfig,
|
|
204
|
+
rootDir: expandHome(cliArgs.rootDir || fileConfig.rootDir || base.rootDir),
|
|
205
|
+
externalStorageRoots:
|
|
206
|
+
normalizePathList(cliArgs.externalStorageRoots).length > 0
|
|
207
|
+
? normalizePathList(cliArgs.externalStorageRoots)
|
|
208
|
+
: normalizePathList(fileConfig.externalStorageRoots),
|
|
209
|
+
externalStorageAutoDetect:
|
|
210
|
+
typeof cliArgs.externalStorageAutoDetect === 'boolean'
|
|
211
|
+
? cliArgs.externalStorageAutoDetect
|
|
212
|
+
: typeof fileConfig.externalStorageAutoDetect === 'boolean'
|
|
213
|
+
? fileConfig.externalStorageAutoDetect
|
|
214
|
+
: base.externalStorageAutoDetect,
|
|
215
|
+
stateRoot,
|
|
216
|
+
dryRunDefault:
|
|
217
|
+
typeof cliArgs.dryRunDefault === 'boolean'
|
|
218
|
+
? cliArgs.dryRunDefault
|
|
219
|
+
: typeof fileConfig.dryRunDefault === 'boolean'
|
|
220
|
+
? fileConfig.dryRunDefault
|
|
221
|
+
: base.dryRunDefault,
|
|
222
|
+
theme: normalizeTheme(cliArgs.theme || fileConfig.theme || base.theme) || base.theme,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
merged.spaceGovernance = normalizeSpaceGovernance(fileConfig.spaceGovernance, base.spaceGovernance);
|
|
226
|
+
merged.recycleRetention = normalizeRecycleRetention(fileConfig.recycleRetention, base.recycleRetention);
|
|
227
|
+
|
|
228
|
+
merged.recycleRoot = expandHome(fileConfig.recycleRoot || path.join(stateRoot, 'recycle-bin'));
|
|
229
|
+
merged.indexPath = expandHome(fileConfig.indexPath || path.join(stateRoot, 'index.jsonl'));
|
|
230
|
+
merged.aliasPath = expandHome(fileConfig.aliasPath || path.join(stateRoot, 'account-aliases.json'));
|
|
231
|
+
merged.configPath = configPath;
|
|
232
|
+
|
|
233
|
+
if (!options.readOnly) {
|
|
234
|
+
await ensureDir(merged.stateRoot);
|
|
235
|
+
await ensureDir(merged.recycleRoot);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return merged;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export async function saveConfig(config) {
|
|
242
|
+
const payload = {
|
|
243
|
+
rootDir: config.rootDir,
|
|
244
|
+
externalStorageRoots: normalizePathList(config.externalStorageRoots),
|
|
245
|
+
externalStorageAutoDetect:
|
|
246
|
+
typeof config.externalStorageAutoDetect === 'boolean' ? config.externalStorageAutoDetect : true,
|
|
247
|
+
stateRoot: config.stateRoot,
|
|
248
|
+
recycleRoot: config.recycleRoot,
|
|
249
|
+
indexPath: config.indexPath,
|
|
250
|
+
aliasPath: config.aliasPath,
|
|
251
|
+
dryRunDefault: Boolean(config.dryRunDefault),
|
|
252
|
+
defaultCategories: Array.isArray(config.defaultCategories) ? config.defaultCategories : [],
|
|
253
|
+
spaceGovernance: normalizeSpaceGovernance(config.spaceGovernance, defaultConfig().spaceGovernance),
|
|
254
|
+
recycleRetention: normalizeRecycleRetention(config.recycleRetention, defaultConfig().recycleRetention),
|
|
255
|
+
theme: normalizeTheme(config.theme) || 'auto',
|
|
256
|
+
};
|
|
257
|
+
await writeJson(config.configPath, payload);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export async function loadAliases(aliasPath) {
|
|
261
|
+
const raw = await readJson(aliasPath, {});
|
|
262
|
+
if (!raw || typeof raw !== 'object') {
|
|
263
|
+
return {};
|
|
264
|
+
}
|
|
265
|
+
return raw;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export async function saveAliases(aliasPath, aliases) {
|
|
269
|
+
await writeJson(aliasPath, aliases || {});
|
|
270
|
+
}
|
package/src/constants.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const APP_NAME = 'wecom-cleaner';
|
|
5
|
+
export const PACKAGE_NAME = '@mison/wecom-cleaner';
|
|
6
|
+
export const APP_ASCII_LOGO = {
|
|
7
|
+
wecom: [
|
|
8
|
+
'██ ██ ███████ ██████ ██████ ███ ███',
|
|
9
|
+
'██ ██ ██ ██ ██ ██ ████ ████',
|
|
10
|
+
'██ █ ██ █████ ██ ██ ██ ██ ████ ██',
|
|
11
|
+
'██ ███ ██ ██ ██ ██ ██ ██ ██ ██',
|
|
12
|
+
' ███ ███ ███████ ██████ ██████ ██ ██',
|
|
13
|
+
],
|
|
14
|
+
cleaner: [
|
|
15
|
+
' ██████ ██ ███████ █████ ███ ██ ███████ ██████',
|
|
16
|
+
'██ ██ ██ ██ ██ ████ ██ ██ ██ ██',
|
|
17
|
+
'██ ██ █████ ███████ ██ ██ ██ █████ ██████',
|
|
18
|
+
'██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██',
|
|
19
|
+
' ██████ ███████ ███████ ██ ██ ██ ████ ███████ ██ ██',
|
|
20
|
+
],
|
|
21
|
+
subtitle: 'WeCom Cache Cleaner',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const DEFAULT_PROFILE_ROOT = path.join(
|
|
25
|
+
os.homedir(),
|
|
26
|
+
'Library/Containers/com.tencent.WeWorkMac/Data/Documents/Profiles'
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const DEFAULT_STATE_ROOT = path.join(os.homedir(), '.wecom-cleaner-state');
|
|
30
|
+
|
|
31
|
+
export const MONTH_RE = /^(?<y>\d{4})-(?<m>\d{1,2})$/;
|
|
32
|
+
|
|
33
|
+
export const CACHE_CATEGORIES = [
|
|
34
|
+
{
|
|
35
|
+
key: 'images',
|
|
36
|
+
label: '聊天图片',
|
|
37
|
+
desc: '会话中的图片、截图等缓存。',
|
|
38
|
+
relativePath: 'Caches/Images',
|
|
39
|
+
defaultSelected: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
key: 'videos',
|
|
43
|
+
label: '聊天视频',
|
|
44
|
+
desc: '会话中的视频缓存。',
|
|
45
|
+
relativePath: 'Caches/Videos',
|
|
46
|
+
defaultSelected: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
key: 'files',
|
|
50
|
+
label: '聊天文件',
|
|
51
|
+
desc: '会话文件缓存(文档、压缩包等)。',
|
|
52
|
+
relativePath: 'Caches/Files',
|
|
53
|
+
defaultSelected: true,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: 'emotions',
|
|
57
|
+
label: '表情资源',
|
|
58
|
+
desc: '表情大图、表情资源缓存。',
|
|
59
|
+
relativePath: 'Caches/Emotions',
|
|
60
|
+
defaultSelected: true,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: 'emotion_thumbnails',
|
|
64
|
+
label: '表情缩略图',
|
|
65
|
+
desc: '表情预览图缓存。',
|
|
66
|
+
relativePath: 'Caches/Emotion_Thumbnail',
|
|
67
|
+
defaultSelected: true,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
key: 'video_thumbnails',
|
|
71
|
+
label: '视频缩略图',
|
|
72
|
+
desc: '视频封面和预览图缓存。',
|
|
73
|
+
relativePath: 'Caches/Video_Thumbnail',
|
|
74
|
+
defaultSelected: true,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
key: 'link_thumbnails',
|
|
78
|
+
label: '链接缩略图',
|
|
79
|
+
desc: '网页卡片预览图缓存。',
|
|
80
|
+
relativePath: 'Caches/Link_Thumbnail',
|
|
81
|
+
defaultSelected: true,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
key: 'voices',
|
|
85
|
+
label: '语音消息',
|
|
86
|
+
desc: '语音消息音频缓存。',
|
|
87
|
+
relativePath: 'Caches/Voices',
|
|
88
|
+
defaultSelected: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: 'wwsecurity',
|
|
92
|
+
label: '受保护截图缓存',
|
|
93
|
+
desc: 'wwsecurity 多层截图缓存。默认仅分析,清理需手动勾选。',
|
|
94
|
+
relativePath: 'Caches/wwsecurity',
|
|
95
|
+
defaultSelected: false,
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
export const CATEGORY_MAP = new Map(CACHE_CATEGORIES.map((item) => [item.key, item]));
|
|
100
|
+
|
|
101
|
+
export const MODES = {
|
|
102
|
+
START: 'start',
|
|
103
|
+
CLEANUP_MONTHLY: 'cleanup_monthly',
|
|
104
|
+
ANALYSIS_ONLY: 'analysis_only',
|
|
105
|
+
SPACE_GOVERNANCE: 'space_governance',
|
|
106
|
+
RESTORE: 'restore',
|
|
107
|
+
DOCTOR: 'doctor',
|
|
108
|
+
RECYCLE_MAINTAIN: 'recycle_maintain',
|
|
109
|
+
SETTINGS: 'settings',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const SPACE_GOVERNANCE_TIERS = {
|
|
113
|
+
SAFE: 'safe',
|
|
114
|
+
CAUTION: 'caution',
|
|
115
|
+
PROTECTED: 'protected',
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const SPACE_GOVERNANCE_TIER_LABELS = new Map([
|
|
119
|
+
[SPACE_GOVERNANCE_TIERS.SAFE, '安全层'],
|
|
120
|
+
[SPACE_GOVERNANCE_TIERS.CAUTION, '谨慎层'],
|
|
121
|
+
[SPACE_GOVERNANCE_TIERS.PROTECTED, '受保护层'],
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
export const SPACE_GOVERNANCE_TARGETS = [
|
|
125
|
+
{
|
|
126
|
+
key: 'wxwork_temp_screencapture',
|
|
127
|
+
label: '临时截图',
|
|
128
|
+
desc: '企业微信截图临时目录,长期积累明显。',
|
|
129
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
130
|
+
scope: 'data_root',
|
|
131
|
+
relativePath: 'Library/Application Support/WXWork/Temp/ScreenCapture',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
key: 'wxwork_temp_wetype_realpic',
|
|
135
|
+
label: '临时图片输入缓存',
|
|
136
|
+
desc: '输入法临时图片缓存。',
|
|
137
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
138
|
+
scope: 'data_root',
|
|
139
|
+
relativePath: 'Library/Application Support/WXWork/Temp/wetype/realPic',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
key: 'wxwork_temp_ftn_local_cache',
|
|
143
|
+
label: '文件传输临时缓存',
|
|
144
|
+
desc: '文件传输临时目录。',
|
|
145
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
146
|
+
scope: 'data_root',
|
|
147
|
+
relativePath: 'Library/Application Support/WXWork/Temp/FtnLocalCache',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
key: 'wxwork_temp_voip',
|
|
151
|
+
label: '音视频临时目录',
|
|
152
|
+
desc: '音视频临时缓存目录。',
|
|
153
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
154
|
+
scope: 'data_root',
|
|
155
|
+
relativePath: 'Library/Application Support/WXWork/Temp/Voip',
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
key: 'container_tmp',
|
|
159
|
+
label: '容器临时目录(tmp)',
|
|
160
|
+
desc: '应用容器临时目录,通常可安全清理。',
|
|
161
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
162
|
+
scope: 'data_root',
|
|
163
|
+
relativePath: 'tmp',
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
key: 'documents_log',
|
|
167
|
+
label: '运行日志目录(log)',
|
|
168
|
+
desc: '企业微信运行日志目录,清理后会按需重新生成。',
|
|
169
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
170
|
+
scope: 'data_root',
|
|
171
|
+
relativePath: 'Documents/log',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
key: 'documents_gylog',
|
|
175
|
+
label: 'GY日志目录',
|
|
176
|
+
desc: '企业微信内部日志目录,通常可安全清理。',
|
|
177
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
178
|
+
scope: 'data_root',
|
|
179
|
+
relativePath: 'Documents/GYLog',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
key: 'documents_gyosslog',
|
|
183
|
+
label: 'GYOss日志目录',
|
|
184
|
+
desc: '企业微信内部日志目录,通常可安全清理。',
|
|
185
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
186
|
+
scope: 'data_root',
|
|
187
|
+
relativePath: 'Documents/GYOssLog',
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: 'documents_user_avatar_url',
|
|
191
|
+
label: '头像URL缓存',
|
|
192
|
+
desc: '头像 URL 映射缓存,清理后会自动重建。',
|
|
193
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
194
|
+
scope: 'data_root',
|
|
195
|
+
relativePath: 'Documents/UserAvatarUrl',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
key: 'profiles_secsdk_tmp',
|
|
199
|
+
label: '安全SDK临时目录',
|
|
200
|
+
desc: '账号目录下 SecSdk 临时文件。',
|
|
201
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
202
|
+
scope: 'profile',
|
|
203
|
+
relativePath: 'SecSdk/tmp',
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
key: 'profiles_sqlite_temp_dir',
|
|
207
|
+
label: 'SQLite临时目录',
|
|
208
|
+
desc: '账号目录下 sqlite_temp_dir 临时文件。',
|
|
209
|
+
tier: SPACE_GOVERNANCE_TIERS.SAFE,
|
|
210
|
+
scope: 'profile',
|
|
211
|
+
relativePath: 'sqlite_temp_dir',
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
key: 'profiles_publishsys_pkg',
|
|
215
|
+
label: '文档组件缓存(Publishsys/pkg)',
|
|
216
|
+
desc: '在线文档组件与脚本缓存,清理后首次打开会重新下载。',
|
|
217
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
218
|
+
scope: 'profile',
|
|
219
|
+
relativePath: 'Publishsys/pkg',
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
key: 'profiles_voip',
|
|
223
|
+
label: '账号音视频目录(VOIP)',
|
|
224
|
+
desc: '账号目录下音视频缓存,清理后可能触发重新拉取。',
|
|
225
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
226
|
+
scope: 'profile',
|
|
227
|
+
relativePath: 'VOIP',
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
key: 'wxwork_log',
|
|
231
|
+
label: 'WXWork日志目录',
|
|
232
|
+
desc: '应用日志目录,可清理但建议保留近期日志用于排障。',
|
|
233
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
234
|
+
scope: 'data_root',
|
|
235
|
+
relativePath: 'Library/Application Support/WXWork/Log',
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
key: 'wedrive_temp',
|
|
239
|
+
label: '微盘临时目录(.Temp)',
|
|
240
|
+
desc: '微盘临时传输目录,清理前请确认无正在同步任务。',
|
|
241
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
242
|
+
scope: 'data_root',
|
|
243
|
+
relativePath: 'WeDrive/.Temp',
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
key: 'wedrive_upload_temp',
|
|
247
|
+
label: '微盘上传临时目录(.C2CUploadTemp)',
|
|
248
|
+
desc: '微盘上传临时目录,清理前请确认无正在上传任务。',
|
|
249
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
250
|
+
scope: 'data_root',
|
|
251
|
+
relativePath: 'WeDrive/.C2CUploadTemp',
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
key: 'wedrive_trash',
|
|
255
|
+
label: '微盘回收目录(.WeDriveTrash-*)',
|
|
256
|
+
desc: '微盘回收区目录,清理后不能在微盘回收区找回。',
|
|
257
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
258
|
+
scope: 'data_root',
|
|
259
|
+
relativePath: 'WeDrive/.WeDriveTrash-*',
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
key: 'documents_cefcache',
|
|
263
|
+
label: '内置网页缓存',
|
|
264
|
+
desc: 'Web 内核缓存目录,清理后可能短时触发重新加载。',
|
|
265
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
266
|
+
scope: 'data_root',
|
|
267
|
+
relativePath: 'Documents/cefcache',
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
key: 'webkit_website_data_store',
|
|
271
|
+
label: 'WebsiteDataStore 缓存',
|
|
272
|
+
desc: 'WebKit 网站数据缓存,清理后会重新建立。',
|
|
273
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
274
|
+
scope: 'data_root',
|
|
275
|
+
relativePath: 'Library/WebKit/WebsiteDataStore',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
key: 'library_caches',
|
|
279
|
+
label: '容器通用缓存',
|
|
280
|
+
desc: '应用容器下系统级缓存目录。',
|
|
281
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
282
|
+
scope: 'data_root',
|
|
283
|
+
relativePath: 'Library/Caches',
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
key: 'profiles_wwsecurity',
|
|
287
|
+
label: '受保护截图缓存(wwsecurity)',
|
|
288
|
+
desc: 'Profiles 下多层截图缓存目录。',
|
|
289
|
+
tier: SPACE_GOVERNANCE_TIERS.CAUTION,
|
|
290
|
+
scope: 'profile',
|
|
291
|
+
relativePath: 'Caches/wwsecurity',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
key: 'wxwork_data_core',
|
|
295
|
+
label: '核心业务数据目录',
|
|
296
|
+
desc: '核心数据区,仅支持分析,不允许删除。',
|
|
297
|
+
tier: SPACE_GOVERNANCE_TIERS.PROTECTED,
|
|
298
|
+
scope: 'data_root',
|
|
299
|
+
relativePath: 'Library/Application Support/WXWork/Data',
|
|
300
|
+
deletable: false,
|
|
301
|
+
},
|
|
302
|
+
];
|
|
303
|
+
|
|
304
|
+
export const USER_LABEL_STOPWORDS = new Set(['真实姓名', '企业介绍', '我的业务', '新学期准备', '帮助企业']);
|
|
305
|
+
|
|
306
|
+
export const CORP_LABEL_STOPWORDS = new Set(['新学期准备', '腾讯科技股份有限公司', '其他']);
|
|
307
|
+
|
|
308
|
+
export const CJK_TEXT_RE = /[\u4e00-\u9fff]{2,24}/g;
|
|
309
|
+
export const EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
|