cc-goto-work 0.8.0 → 0.8.3
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/README.md +21 -21
- package/bin/cli.js +711 -483
- package/package.json +30 -30
package/README.md
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# cc-goto-work
|
|
2
|
-
|
|
3
|
-
让 Claude Code 自动继续未完成的工作。
|
|
4
|
-
|
|
5
|
-
## 使用
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx cc-goto-work
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
运行后会显示交互式菜单,可以选择:
|
|
12
|
-
|
|
13
|
-
- **1** - 完整安装 (下载 + 配置 API + 配置 Hook)
|
|
14
|
-
- **2** - 仅下载二进制文件
|
|
15
|
-
- **3** - 仅配置 API 设置
|
|
16
|
-
- **4** - 仅配置 Claude Code Hook
|
|
17
|
-
- **0** - 退出
|
|
18
|
-
|
|
19
|
-
## 许可证
|
|
20
|
-
|
|
21
|
-
MIT License
|
|
1
|
+
# cc-goto-work
|
|
2
|
+
|
|
3
|
+
让 Claude Code 自动继续未完成的工作。
|
|
4
|
+
|
|
5
|
+
## 使用
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx cc-goto-work
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
运行后会显示交互式菜单,可以选择:
|
|
12
|
+
|
|
13
|
+
- **1** - 完整安装 (下载 + 配置 API + 配置 Hook)
|
|
14
|
+
- **2** - 仅下载二进制文件
|
|
15
|
+
- **3** - 仅配置 API 设置
|
|
16
|
+
- **4** - 仅配置 Claude Code Hook
|
|
17
|
+
- **0** - 退出
|
|
18
|
+
|
|
19
|
+
## 许可证
|
|
20
|
+
|
|
21
|
+
MIT License
|
package/bin/cli.js
CHANGED
|
@@ -1,483 +1,711 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const readline = require('readline');
|
|
4
|
-
const https = require('https');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
const { spawn } = require('child_process');
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// Constants
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
const REPO = 'pdxxxx/cc-goto-work';
|
|
15
|
-
const INSTALL_DIR = path.join(os.homedir(), '.claude', 'cc-goto-work');
|
|
16
|
-
const CONFIG_FILE = path.join(INSTALL_DIR, 'config.yaml');
|
|
17
|
-
const CLAUDE_SETTINGS_DIR = path.join(os.homedir(), '.claude');
|
|
18
|
-
const CLAUDE_SETTINGS_FILE = path.join(CLAUDE_SETTINGS_DIR, 'settings.json');
|
|
19
|
-
|
|
20
|
-
// Colors (ANSI escape codes)
|
|
21
|
-
const colors = {
|
|
22
|
-
reset: '\x1b[0m',
|
|
23
|
-
red: '\x1b[31m',
|
|
24
|
-
green: '\x1b[32m',
|
|
25
|
-
yellow: '\x1b[33m',
|
|
26
|
-
blue: '\x1b[34m',
|
|
27
|
-
cyan: '\x1b[36m',
|
|
28
|
-
bold: '\x1b[1m',
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// ============================================================================
|
|
32
|
-
// Utilities
|
|
33
|
-
// ============================================================================
|
|
34
|
-
|
|
35
|
-
function print(msg) {
|
|
36
|
-
console.log(msg);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function printBanner() {
|
|
40
|
-
print(`${colors.cyan}${colors.bold}`);
|
|
41
|
-
print('╔════════════════════════════════════════════════════════════╗');
|
|
42
|
-
print('║ cc-goto-work 安装程序 ║');
|
|
43
|
-
print('║ 让 Claude Code 自动继续未完成的工作 ║');
|
|
44
|
-
print('╚════════════════════════════════════════════════════════════╝');
|
|
45
|
-
print(`${colors.reset}`);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function printStep(msg) {
|
|
49
|
-
print(`${colors.green}▶${colors.reset} ${msg}`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function printSuccess(msg) {
|
|
53
|
-
print(`${colors.green}✔${colors.reset} ${msg}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function printWarning(msg) {
|
|
57
|
-
print(`${colors.yellow}⚠${colors.reset} ${msg}`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function printError(msg) {
|
|
61
|
-
print(`${colors.red}✖${colors.reset} ${msg}`);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function printMenu() {
|
|
65
|
-
print('');
|
|
66
|
-
print(`${colors.bold}请选择操作:${colors.reset}`);
|
|
67
|
-
print('');
|
|
68
|
-
print(` ${colors.cyan}1${colors.reset} - 完整安装 (下载 + 配置 API + 配置 Hook)`);
|
|
69
|
-
print(` ${colors.cyan}2${colors.reset} - 仅下载二进制文件`);
|
|
70
|
-
print(` ${colors.cyan}3${colors.reset} - 仅配置 API 设置`);
|
|
71
|
-
print(` ${colors.cyan}4${colors.reset} - 仅配置 Claude Code Hook`);
|
|
72
|
-
print(` ${colors.cyan}
|
|
73
|
-
print(
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
// ============================================================================
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// ============================================================================
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (arch === '
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (arch === '
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
// ============================================================================
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
res.on('
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// ============================================================================
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
#
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
#
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return false;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
return true;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async function
|
|
401
|
-
printStep('配置
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
const https = require('https');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Constants
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
const REPO = 'pdxxxx/cc-goto-work';
|
|
15
|
+
const INSTALL_DIR = path.join(os.homedir(), '.claude', 'cc-goto-work');
|
|
16
|
+
const CONFIG_FILE = path.join(INSTALL_DIR, 'config.yaml');
|
|
17
|
+
const CLAUDE_SETTINGS_DIR = path.join(os.homedir(), '.claude');
|
|
18
|
+
const CLAUDE_SETTINGS_FILE = path.join(CLAUDE_SETTINGS_DIR, 'settings.json');
|
|
19
|
+
|
|
20
|
+
// Colors (ANSI escape codes)
|
|
21
|
+
const colors = {
|
|
22
|
+
reset: '\x1b[0m',
|
|
23
|
+
red: '\x1b[31m',
|
|
24
|
+
green: '\x1b[32m',
|
|
25
|
+
yellow: '\x1b[33m',
|
|
26
|
+
blue: '\x1b[34m',
|
|
27
|
+
cyan: '\x1b[36m',
|
|
28
|
+
bold: '\x1b[1m',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Utilities
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
function print(msg) {
|
|
36
|
+
console.log(msg);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function printBanner() {
|
|
40
|
+
print(`${colors.cyan}${colors.bold}`);
|
|
41
|
+
print('╔════════════════════════════════════════════════════════════╗');
|
|
42
|
+
print('║ cc-goto-work 安装程序 ║');
|
|
43
|
+
print('║ 让 Claude Code 自动继续未完成的工作 ║');
|
|
44
|
+
print('╚════════════════════════════════════════════════════════════╝');
|
|
45
|
+
print(`${colors.reset}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function printStep(msg) {
|
|
49
|
+
print(`${colors.green}▶${colors.reset} ${msg}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function printSuccess(msg) {
|
|
53
|
+
print(`${colors.green}✔${colors.reset} ${msg}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function printWarning(msg) {
|
|
57
|
+
print(`${colors.yellow}⚠${colors.reset} ${msg}`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function printError(msg) {
|
|
61
|
+
print(`${colors.red}✖${colors.reset} ${msg}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function printMenu() {
|
|
65
|
+
print('');
|
|
66
|
+
print(`${colors.bold}请选择操作:${colors.reset}`);
|
|
67
|
+
print('');
|
|
68
|
+
print(` ${colors.cyan}1${colors.reset} - 完整安装 (下载 + 配置 API + 配置 Hook)`);
|
|
69
|
+
print(` ${colors.cyan}2${colors.reset} - 仅下载二进制文件`);
|
|
70
|
+
print(` ${colors.cyan}3${colors.reset} - 仅配置 API 设置`);
|
|
71
|
+
print(` ${colors.cyan}4${colors.reset} - 仅配置 Claude Code Hook`);
|
|
72
|
+
print(` ${colors.cyan}5${colors.reset} - ${colors.blue}检查更新${colors.reset}`);
|
|
73
|
+
print(` ${colors.cyan}6${colors.reset} - ${colors.red}卸载 cc-goto-work${colors.reset}`);
|
|
74
|
+
print(` ${colors.cyan}0${colors.reset} - 退出`);
|
|
75
|
+
print('');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Readline Interface
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
function createRL() {
|
|
83
|
+
return readline.createInterface({
|
|
84
|
+
input: process.stdin,
|
|
85
|
+
output: process.stdout,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function question(rl, prompt) {
|
|
90
|
+
return new Promise((resolve) => {
|
|
91
|
+
rl.question(prompt, (answer) => {
|
|
92
|
+
resolve(answer.trim());
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function promptInput(rl, prompt, defaultValue = '') {
|
|
98
|
+
const displayDefault = defaultValue ? ` [${defaultValue}]` : '';
|
|
99
|
+
const answer = await question(rl, `${prompt}${displayDefault}: `);
|
|
100
|
+
return answer || defaultValue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function promptConfirm(rl, prompt, defaultYes = true) {
|
|
104
|
+
const hint = defaultYes ? '[Y/n]' : '[y/N]';
|
|
105
|
+
const answer = await question(rl, `${prompt} ${hint}: `);
|
|
106
|
+
if (!answer) return defaultYes;
|
|
107
|
+
return answer.toLowerCase().startsWith('y');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Platform Detection
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
function detectPlatform() {
|
|
115
|
+
const platform = os.platform();
|
|
116
|
+
const arch = os.arch();
|
|
117
|
+
|
|
118
|
+
if (platform === 'linux') {
|
|
119
|
+
if (arch === 'x64') return 'linux-amd64';
|
|
120
|
+
if (arch === 'arm64') return 'linux-arm64';
|
|
121
|
+
} else if (platform === 'darwin') {
|
|
122
|
+
if (arch === 'x64') return 'macos-amd64';
|
|
123
|
+
if (arch === 'arm64') return 'macos-arm64';
|
|
124
|
+
} else if (platform === 'win32') {
|
|
125
|
+
if (arch === 'x64') return 'windows-amd64';
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function getBinaryName(platformStr) {
|
|
132
|
+
if (platformStr.startsWith('windows')) {
|
|
133
|
+
return 'cc-goto-work.exe';
|
|
134
|
+
}
|
|
135
|
+
return 'cc-goto-work';
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ============================================================================
|
|
139
|
+
// GitHub API
|
|
140
|
+
// ============================================================================
|
|
141
|
+
|
|
142
|
+
function httpsGet(url) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const options = {
|
|
145
|
+
headers: { 'User-Agent': 'cc-goto-work-installer' },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
https.get(url, options, (res) => {
|
|
149
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
150
|
+
// Follow redirect
|
|
151
|
+
httpsGet(res.headers.location).then(resolve).catch(reject);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (res.statusCode !== 200) {
|
|
156
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const chunks = [];
|
|
161
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
162
|
+
res.on('end', () => resolve(Buffer.concat(chunks)));
|
|
163
|
+
res.on('error', reject);
|
|
164
|
+
}).on('error', reject);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function getLatestVersion() {
|
|
169
|
+
const url = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
170
|
+
const data = await httpsGet(url);
|
|
171
|
+
const json = JSON.parse(data.toString());
|
|
172
|
+
return json.tag_name;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ============================================================================
|
|
176
|
+
// Download Binary
|
|
177
|
+
// ============================================================================
|
|
178
|
+
|
|
179
|
+
async function downloadBinary(version, platformStr) {
|
|
180
|
+
const binaryName = getBinaryName(platformStr);
|
|
181
|
+
const fileName = platformStr.startsWith('windows')
|
|
182
|
+
? `cc-goto-work-${platformStr}.exe`
|
|
183
|
+
: `cc-goto-work-${platformStr}`;
|
|
184
|
+
|
|
185
|
+
const url = `https://github.com/${REPO}/releases/download/${version}/${fileName}`;
|
|
186
|
+
const destPath = path.join(INSTALL_DIR, binaryName);
|
|
187
|
+
|
|
188
|
+
printStep(`正在下载 ${version} (${platformStr})...`);
|
|
189
|
+
|
|
190
|
+
// Ensure directory exists
|
|
191
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
192
|
+
|
|
193
|
+
const data = await httpsGet(url);
|
|
194
|
+
fs.writeFileSync(destPath, data);
|
|
195
|
+
|
|
196
|
+
// Make executable on Unix
|
|
197
|
+
if (!platformStr.startsWith('windows')) {
|
|
198
|
+
fs.chmodSync(destPath, 0o755);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Save version info
|
|
202
|
+
const versionFile = path.join(INSTALL_DIR, '.version');
|
|
203
|
+
fs.writeFileSync(versionFile, version);
|
|
204
|
+
|
|
205
|
+
printSuccess(`二进制文件已下载到: ${destPath}`);
|
|
206
|
+
return destPath;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// Configuration
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
function createConfig(apiBase, apiKey, model) {
|
|
214
|
+
const configContent = `# cc-goto-work configuration
|
|
215
|
+
# https://github.com/${REPO}
|
|
216
|
+
|
|
217
|
+
# OpenAI compatible API base URL
|
|
218
|
+
api_base: ${apiBase}
|
|
219
|
+
|
|
220
|
+
# API key for authentication
|
|
221
|
+
api_key: ${apiKey}
|
|
222
|
+
|
|
223
|
+
# Model name to use
|
|
224
|
+
model: ${model}
|
|
225
|
+
|
|
226
|
+
# Request timeout in seconds (optional)
|
|
227
|
+
timeout: 30
|
|
228
|
+
|
|
229
|
+
# Enable debug logging (optional)
|
|
230
|
+
debug: false
|
|
231
|
+
`;
|
|
232
|
+
|
|
233
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
234
|
+
fs.writeFileSync(CONFIG_FILE, configContent, { mode: 0o600 });
|
|
235
|
+
printSuccess(`配置文件已创建: ${CONFIG_FILE}`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function configureAPI(rl) {
|
|
239
|
+
print('');
|
|
240
|
+
print('此工具使用 AI 模型来检测未完成的会话。');
|
|
241
|
+
print('请提供 OpenAI 兼容的 API 端点信息。');
|
|
242
|
+
print('');
|
|
243
|
+
|
|
244
|
+
const apiBase = await promptInput(rl, 'API 地址', 'https://api.openai.com/v1');
|
|
245
|
+
const apiKey = await promptInput(rl, 'API 密钥', '');
|
|
246
|
+
const model = await promptInput(rl, '模型名称', 'gpt-4o-mini');
|
|
247
|
+
|
|
248
|
+
if (!apiKey) {
|
|
249
|
+
printWarning('未提供 API 密钥,请在使用前编辑配置文件');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
createConfig(apiBase, apiKey, model);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ============================================================================
|
|
256
|
+
// Claude Settings
|
|
257
|
+
// ============================================================================
|
|
258
|
+
|
|
259
|
+
function configureClaudeSettings(binaryPath) {
|
|
260
|
+
fs.mkdirSync(CLAUDE_SETTINGS_DIR, { recursive: true });
|
|
261
|
+
|
|
262
|
+
const hookConfig = {
|
|
263
|
+
hooks: {
|
|
264
|
+
Stop: [
|
|
265
|
+
{
|
|
266
|
+
hooks: [
|
|
267
|
+
{
|
|
268
|
+
type: 'command',
|
|
269
|
+
command: binaryPath,
|
|
270
|
+
timeout: 120,
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
},
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
let settings = {};
|
|
279
|
+
|
|
280
|
+
if (fs.existsSync(CLAUDE_SETTINGS_FILE)) {
|
|
281
|
+
try {
|
|
282
|
+
const content = fs.readFileSync(CLAUDE_SETTINGS_FILE, 'utf8');
|
|
283
|
+
if (content.trim()) {
|
|
284
|
+
settings = JSON.parse(content);
|
|
285
|
+
|
|
286
|
+
// Backup existing
|
|
287
|
+
fs.writeFileSync(`${CLAUDE_SETTINGS_FILE}.backup`, content);
|
|
288
|
+
printWarning(`已备份现有配置到: ${CLAUDE_SETTINGS_FILE}.backup`);
|
|
289
|
+
|
|
290
|
+
// Check if Stop hook exists
|
|
291
|
+
if (settings.hooks && settings.hooks.Stop) {
|
|
292
|
+
printWarning('Stop hook 已存在,正在更新...');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
} catch (e) {
|
|
296
|
+
printWarning('无法解析现有配置,将创建新配置');
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Merge hooks
|
|
301
|
+
settings.hooks = settings.hooks || {};
|
|
302
|
+
settings.hooks.Stop = hookConfig.hooks.Stop;
|
|
303
|
+
|
|
304
|
+
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
305
|
+
printSuccess(`Claude Code 配置已更新: ${CLAUDE_SETTINGS_FILE}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ============================================================================
|
|
309
|
+
// Installation Actions
|
|
310
|
+
// ============================================================================
|
|
311
|
+
|
|
312
|
+
async function fullInstall(rl) {
|
|
313
|
+
printStep('开始完整安装...');
|
|
314
|
+
print('');
|
|
315
|
+
|
|
316
|
+
// Detect platform
|
|
317
|
+
const platformStr = detectPlatform();
|
|
318
|
+
if (!platformStr) {
|
|
319
|
+
printError(`不支持的平台: ${os.platform()} ${os.arch()}`);
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
print(` 平台: ${platformStr}`);
|
|
323
|
+
|
|
324
|
+
// Get latest version
|
|
325
|
+
printStep('获取最新版本...');
|
|
326
|
+
let version;
|
|
327
|
+
try {
|
|
328
|
+
version = await getLatestVersion();
|
|
329
|
+
print(` 版本: ${version}`);
|
|
330
|
+
} catch (e) {
|
|
331
|
+
printError(`获取版本失败: ${e.message}`);
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
print('');
|
|
336
|
+
if (!(await promptConfirm(rl, `确认安装 cc-goto-work ${version}?`))) {
|
|
337
|
+
print('安装已取消');
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Download binary
|
|
342
|
+
print('');
|
|
343
|
+
let binaryPath;
|
|
344
|
+
try {
|
|
345
|
+
binaryPath = await downloadBinary(version, platformStr);
|
|
346
|
+
} catch (e) {
|
|
347
|
+
printError(`下载失败: ${e.message}`);
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Configure API
|
|
352
|
+
print('');
|
|
353
|
+
await configureAPI(rl);
|
|
354
|
+
|
|
355
|
+
// Configure Claude settings
|
|
356
|
+
print('');
|
|
357
|
+
if (await promptConfirm(rl, '自动配置 Claude Code?')) {
|
|
358
|
+
configureClaudeSettings(binaryPath);
|
|
359
|
+
} else {
|
|
360
|
+
print('');
|
|
361
|
+
print('请手动添加以下配置到 Claude Code:');
|
|
362
|
+
print(` 命令: ${binaryPath}`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function downloadOnly(rl) {
|
|
369
|
+
printStep('仅下载二进制文件...');
|
|
370
|
+
print('');
|
|
371
|
+
|
|
372
|
+
const platformStr = detectPlatform();
|
|
373
|
+
if (!platformStr) {
|
|
374
|
+
printError(`不支持的平台: ${os.platform()} ${os.arch()}`);
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
print(` 平台: ${platformStr}`);
|
|
378
|
+
|
|
379
|
+
printStep('获取最新版本...');
|
|
380
|
+
let version;
|
|
381
|
+
try {
|
|
382
|
+
version = await getLatestVersion();
|
|
383
|
+
print(` 版本: ${version}`);
|
|
384
|
+
} catch (e) {
|
|
385
|
+
printError(`获取版本失败: ${e.message}`);
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
print('');
|
|
390
|
+
try {
|
|
391
|
+
await downloadBinary(version, platformStr);
|
|
392
|
+
} catch (e) {
|
|
393
|
+
printError(`下载失败: ${e.message}`);
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return true;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function configureAPIOnly(rl) {
|
|
401
|
+
printStep('配置 API 设置...');
|
|
402
|
+
await configureAPI(rl);
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async function configureHookOnly(rl) {
|
|
407
|
+
printStep('配置 Claude Code Hook...');
|
|
408
|
+
print('');
|
|
409
|
+
|
|
410
|
+
const platformStr = detectPlatform();
|
|
411
|
+
const binaryName = getBinaryName(platformStr || 'linux-amd64');
|
|
412
|
+
const binaryPath = path.join(INSTALL_DIR, binaryName);
|
|
413
|
+
|
|
414
|
+
if (!fs.existsSync(binaryPath)) {
|
|
415
|
+
printWarning(`二进制文件不存在: ${binaryPath}`);
|
|
416
|
+
if (!(await promptConfirm(rl, '是否继续配置?', false))) {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
configureClaudeSettings(binaryPath);
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// ============================================================================
|
|
426
|
+
// Update
|
|
427
|
+
// ============================================================================
|
|
428
|
+
|
|
429
|
+
const VERSION_FILE = path.join(INSTALL_DIR, '.version');
|
|
430
|
+
|
|
431
|
+
function getInstalledVersion() {
|
|
432
|
+
try {
|
|
433
|
+
if (fs.existsSync(VERSION_FILE)) {
|
|
434
|
+
return fs.readFileSync(VERSION_FILE, 'utf8').trim();
|
|
435
|
+
}
|
|
436
|
+
} catch (e) {
|
|
437
|
+
// Ignore
|
|
438
|
+
}
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function saveInstalledVersion(version) {
|
|
443
|
+
try {
|
|
444
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
445
|
+
fs.writeFileSync(VERSION_FILE, version);
|
|
446
|
+
} catch (e) {
|
|
447
|
+
// Ignore
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function compareVersions(v1, v2) {
|
|
452
|
+
// Remove 'v' prefix if present
|
|
453
|
+
const normalize = (v) => v.replace(/^v/, '').split('.').map(Number);
|
|
454
|
+
const parts1 = normalize(v1);
|
|
455
|
+
const parts2 = normalize(v2);
|
|
456
|
+
|
|
457
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
458
|
+
const p1 = parts1[i] || 0;
|
|
459
|
+
const p2 = parts2[i] || 0;
|
|
460
|
+
if (p1 > p2) return 1;
|
|
461
|
+
if (p1 < p2) return -1;
|
|
462
|
+
}
|
|
463
|
+
return 0;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
async function checkUpdate(rl) {
|
|
467
|
+
printStep('检查更新...');
|
|
468
|
+
print('');
|
|
469
|
+
|
|
470
|
+
const platformStr = detectPlatform();
|
|
471
|
+
if (!platformStr) {
|
|
472
|
+
printError(`不支持的平台: ${os.platform()} ${os.arch()}`);
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const binaryName = getBinaryName(platformStr);
|
|
477
|
+
const binaryPath = path.join(INSTALL_DIR, binaryName);
|
|
478
|
+
|
|
479
|
+
if (!fs.existsSync(binaryPath)) {
|
|
480
|
+
printWarning('未检测到安装,请先安装');
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Get installed version
|
|
485
|
+
const installedVersion = getInstalledVersion();
|
|
486
|
+
if (installedVersion) {
|
|
487
|
+
print(` 当前版本: ${installedVersion}`);
|
|
488
|
+
} else {
|
|
489
|
+
print(` 当前版本: ${colors.yellow}未知${colors.reset}`);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Get latest version
|
|
493
|
+
printStep('获取最新版本...');
|
|
494
|
+
let latestVersion;
|
|
495
|
+
try {
|
|
496
|
+
latestVersion = await getLatestVersion();
|
|
497
|
+
print(` 最新版本: ${latestVersion}`);
|
|
498
|
+
} catch (e) {
|
|
499
|
+
printError(`获取版本失败: ${e.message}`);
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
print('');
|
|
504
|
+
|
|
505
|
+
// Compare versions
|
|
506
|
+
if (installedVersion && compareVersions(installedVersion, latestVersion) >= 0) {
|
|
507
|
+
printSuccess('已是最新版本,无需更新');
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Ask to update
|
|
512
|
+
const updateMsg = installedVersion
|
|
513
|
+
? `发现新版本!是否从 ${installedVersion} 更新到 ${latestVersion}?`
|
|
514
|
+
: `是否更新到 ${latestVersion}?`;
|
|
515
|
+
|
|
516
|
+
if (!(await promptConfirm(rl, updateMsg))) {
|
|
517
|
+
print('更新已取消');
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Download new version
|
|
522
|
+
print('');
|
|
523
|
+
try {
|
|
524
|
+
await downloadBinary(latestVersion, platformStr);
|
|
525
|
+
saveInstalledVersion(latestVersion);
|
|
526
|
+
printSuccess(`已更新到 ${latestVersion}`);
|
|
527
|
+
return true;
|
|
528
|
+
} catch (e) {
|
|
529
|
+
printError(`更新失败: ${e.message}`);
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// ============================================================================
|
|
535
|
+
// Uninstall
|
|
536
|
+
// ============================================================================
|
|
537
|
+
|
|
538
|
+
function removeStopHook() {
|
|
539
|
+
if (!fs.existsSync(CLAUDE_SETTINGS_FILE)) {
|
|
540
|
+
printWarning('Claude Code 配置文件不存在');
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
try {
|
|
545
|
+
const content = fs.readFileSync(CLAUDE_SETTINGS_FILE, 'utf8');
|
|
546
|
+
if (!content.trim()) {
|
|
547
|
+
printWarning('Claude Code 配置文件为空');
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
const settings = JSON.parse(content);
|
|
552
|
+
|
|
553
|
+
if (!settings.hooks || !settings.hooks.Stop) {
|
|
554
|
+
printWarning('Stop hook 不存在,无需移除');
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Backup before modifying
|
|
559
|
+
fs.writeFileSync(`${CLAUDE_SETTINGS_FILE}.backup`, content);
|
|
560
|
+
printWarning(`已备份现有配置到: ${CLAUDE_SETTINGS_FILE}.backup`);
|
|
561
|
+
|
|
562
|
+
// Remove Stop hook
|
|
563
|
+
delete settings.hooks.Stop;
|
|
564
|
+
|
|
565
|
+
// Remove hooks object if empty
|
|
566
|
+
if (Object.keys(settings.hooks).length === 0) {
|
|
567
|
+
delete settings.hooks;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
571
|
+
printSuccess('已从 Claude Code 配置中移除 Stop hook');
|
|
572
|
+
return true;
|
|
573
|
+
} catch (e) {
|
|
574
|
+
printError(`移除 Stop hook 失败: ${e.message}`);
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function removeDirectory(dirPath) {
|
|
580
|
+
if (!fs.existsSync(dirPath)) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
try {
|
|
585
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
586
|
+
return true;
|
|
587
|
+
} catch (e) {
|
|
588
|
+
printError(`删除目录失败: ${e.message}`);
|
|
589
|
+
return false;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async function uninstall(rl) {
|
|
594
|
+
printStep('卸载 cc-goto-work...');
|
|
595
|
+
print('');
|
|
596
|
+
|
|
597
|
+
// Check what exists
|
|
598
|
+
const platformStr = detectPlatform();
|
|
599
|
+
const binaryName = getBinaryName(platformStr || 'linux-amd64');
|
|
600
|
+
const binaryPath = path.join(INSTALL_DIR, binaryName);
|
|
601
|
+
|
|
602
|
+
const binaryExists = fs.existsSync(binaryPath);
|
|
603
|
+
const configExists = fs.existsSync(CONFIG_FILE);
|
|
604
|
+
const dirExists = fs.existsSync(INSTALL_DIR);
|
|
605
|
+
|
|
606
|
+
if (!binaryExists && !configExists && !dirExists) {
|
|
607
|
+
printWarning('未检测到安装,无需卸载');
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
print('检测到以下已安装内容:');
|
|
612
|
+
if (binaryExists) print(` - 二进制文件: ${binaryPath}`);
|
|
613
|
+
if (configExists) print(` - 配置文件: ${CONFIG_FILE}`);
|
|
614
|
+
if (dirExists) print(` - 安装目录: ${INSTALL_DIR}`);
|
|
615
|
+
print('');
|
|
616
|
+
|
|
617
|
+
if (!(await promptConfirm(rl, `${colors.red}确认卸载 cc-goto-work?${colors.reset}`, false))) {
|
|
618
|
+
print('卸载已取消');
|
|
619
|
+
return false;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
print('');
|
|
623
|
+
|
|
624
|
+
// Remove Stop hook from Claude settings
|
|
625
|
+
printStep('移除 Claude Code Hook...');
|
|
626
|
+
removeStopHook();
|
|
627
|
+
|
|
628
|
+
// Remove installation directory
|
|
629
|
+
printStep('删除安装目录...');
|
|
630
|
+
if (dirExists) {
|
|
631
|
+
if (removeDirectory(INSTALL_DIR)) {
|
|
632
|
+
printSuccess(`已删除: ${INSTALL_DIR}`);
|
|
633
|
+
}
|
|
634
|
+
} else {
|
|
635
|
+
printWarning('安装目录不存在');
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// ============================================================================
|
|
642
|
+
// Main
|
|
643
|
+
// ============================================================================
|
|
644
|
+
|
|
645
|
+
async function main() {
|
|
646
|
+
printBanner();
|
|
647
|
+
|
|
648
|
+
const rl = createRL();
|
|
649
|
+
|
|
650
|
+
try {
|
|
651
|
+
while (true) {
|
|
652
|
+
printMenu();
|
|
653
|
+
|
|
654
|
+
const choice = await question(rl, '请输入选项 (0-6): ');
|
|
655
|
+
|
|
656
|
+
let success = false;
|
|
657
|
+
|
|
658
|
+
switch (choice) {
|
|
659
|
+
case '1':
|
|
660
|
+
success = await fullInstall(rl);
|
|
661
|
+
break;
|
|
662
|
+
case '2':
|
|
663
|
+
success = await downloadOnly(rl);
|
|
664
|
+
break;
|
|
665
|
+
case '3':
|
|
666
|
+
success = await configureAPIOnly(rl);
|
|
667
|
+
break;
|
|
668
|
+
case '4':
|
|
669
|
+
success = await configureHookOnly(rl);
|
|
670
|
+
break;
|
|
671
|
+
case '5':
|
|
672
|
+
success = await checkUpdate(rl);
|
|
673
|
+
break;
|
|
674
|
+
case '6':
|
|
675
|
+
success = await uninstall(rl);
|
|
676
|
+
break;
|
|
677
|
+
case '0':
|
|
678
|
+
case 'q':
|
|
679
|
+
case 'exit':
|
|
680
|
+
print('');
|
|
681
|
+
print('再见!');
|
|
682
|
+
rl.close();
|
|
683
|
+
return;
|
|
684
|
+
default:
|
|
685
|
+
printError('无效选项,请输入 0-6');
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (success) {
|
|
690
|
+
print('');
|
|
691
|
+
printSuccess('操作完成!');
|
|
692
|
+
print('');
|
|
693
|
+
print('请重启 Claude Code 以使配置生效。');
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
print('');
|
|
697
|
+
if (!(await promptConfirm(rl, '继续其他操作?', false))) {
|
|
698
|
+
print('');
|
|
699
|
+
print('再见!');
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
} finally {
|
|
704
|
+
rl.close();
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
main().catch((err) => {
|
|
709
|
+
printError(`发生错误: ${err.message}`);
|
|
710
|
+
process.exit(1);
|
|
711
|
+
});
|
package/package.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "cc-goto-work",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "让 Claude Code 自动继续未完成的工作",
|
|
5
|
-
"bin": {
|
|
6
|
-
"cc-goto-work": "./bin/cli.js"
|
|
7
|
-
},
|
|
8
|
-
"scripts": {
|
|
9
|
-
"test": "node bin/cli.js"
|
|
10
|
-
},
|
|
11
|
-
"keywords": [
|
|
12
|
-
"claude",
|
|
13
|
-
"claude-code",
|
|
14
|
-
"hook",
|
|
15
|
-
"ai",
|
|
16
|
-
"automation"
|
|
17
|
-
],
|
|
18
|
-
"author": "",
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "https://github.com/pdxxxx/cc-goto-work.git"
|
|
23
|
-
},
|
|
24
|
-
"engines": {
|
|
25
|
-
"node": ">=14.0.0"
|
|
26
|
-
},
|
|
27
|
-
"files": [
|
|
28
|
-
"bin/"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "cc-goto-work",
|
|
3
|
+
"version": "0.8.3",
|
|
4
|
+
"description": "让 Claude Code 自动继续未完成的工作",
|
|
5
|
+
"bin": {
|
|
6
|
+
"cc-goto-work": "./bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "node bin/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"claude",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"hook",
|
|
15
|
+
"ai",
|
|
16
|
+
"automation"
|
|
17
|
+
],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/pdxxxx/cc-goto-work.git"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=14.0.0"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"bin/"
|
|
29
|
+
]
|
|
30
|
+
}
|