@xagent-ai/cli 1.2.0 → 1.2.2
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 +1 -1
- package/README_CN.md +1 -1
- package/dist/agents.js +164 -164
- package/dist/agents.js.map +1 -1
- package/dist/ai-client.d.ts +4 -6
- package/dist/ai-client.d.ts.map +1 -1
- package/dist/ai-client.js +137 -115
- package/dist/ai-client.js.map +1 -1
- package/dist/auth.js +4 -4
- package/dist/auth.js.map +1 -1
- package/dist/cli.js +184 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +65 -81
- package/dist/context-compressor.js.map +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +5 -31
- package/dist/conversation.js.map +1 -1
- package/dist/memory.d.ts +5 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +77 -37
- package/dist/memory.js.map +1 -1
- package/dist/remote-ai-client.d.ts +1 -8
- package/dist/remote-ai-client.d.ts.map +1 -1
- package/dist/remote-ai-client.js +55 -65
- package/dist/remote-ai-client.js.map +1 -1
- package/dist/retry.d.ts +35 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +166 -0
- package/dist/retry.js.map +1 -0
- package/dist/session.d.ts +0 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +243 -312
- package/dist/session.js.map +1 -1
- package/dist/slash-commands.d.ts +1 -0
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +91 -9
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +18 -17
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.d.ts.map +1 -1
- package/dist/system-prompt-generator.js +149 -139
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/theme.d.ts +48 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +254 -0
- package/dist/theme.js.map +1 -1
- package/dist/tools/edit-diff.d.ts +32 -0
- package/dist/tools/edit-diff.d.ts.map +1 -0
- package/dist/tools/edit-diff.js +185 -0
- package/dist/tools/edit-diff.js.map +1 -0
- package/dist/tools/edit.d.ts +11 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +129 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools.d.ts +19 -5
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +979 -631
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +6 -31
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/agents.ts +504 -504
- package/src/ai-client.ts +1559 -1458
- package/src/auth.ts +4 -4
- package/src/cli.ts +195 -1
- package/src/config.ts +3 -3
- package/src/memory.ts +55 -14
- package/src/remote-ai-client.ts +663 -683
- package/src/retry.ts +217 -0
- package/src/session.ts +1736 -1840
- package/src/slash-commands.ts +98 -9
- package/src/smart-approval.ts +626 -625
- package/src/system-prompt-generator.ts +853 -843
- package/src/theme.ts +284 -0
- package/src/tools.ts +390 -70
package/src/smart-approval.ts
CHANGED
|
@@ -1,626 +1,627 @@
|
|
|
1
|
-
import inquirer from 'inquirer';
|
|
2
|
-
import { AIClient, Message } from './ai-client.js';
|
|
3
|
-
import { getConfigManager } from './config.js';
|
|
4
|
-
import { AuthType } from './types.js';
|
|
5
|
-
import { getLogger } from './logger.js';
|
|
6
|
-
import { colors, icons } from './theme.js';
|
|
7
|
-
|
|
8
|
-
const logger = getLogger();
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Approval result type
|
|
12
|
-
*/
|
|
13
|
-
export enum ApprovalDecision {
|
|
14
|
-
APPROVED = 'approved',
|
|
15
|
-
REJECTED = 'rejected',
|
|
16
|
-
REQUIRES_CONFIRMATION = 'requires_confirmation',
|
|
17
|
-
AI_REVIEW = 'ai_review'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Risk level
|
|
22
|
-
*/
|
|
23
|
-
export enum RiskLevel {
|
|
24
|
-
LOW = 'LOW',
|
|
25
|
-
MEDIUM = 'MEDIUM',
|
|
26
|
-
HIGH = 'HIGH',
|
|
27
|
-
CRITICAL = 'CRITICAL'
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Approval result
|
|
32
|
-
*/
|
|
33
|
-
export interface ApprovalResult {
|
|
34
|
-
decision: ApprovalDecision;
|
|
35
|
-
riskLevel: RiskLevel;
|
|
36
|
-
detectionMethod: 'whitelist' | 'blacklist' | 'ai_review' | 'manual';
|
|
37
|
-
description: string;
|
|
38
|
-
latency: number;
|
|
39
|
-
aiAnalysis?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Tool call context
|
|
44
|
-
*/
|
|
45
|
-
export interface ToolCallContext {
|
|
46
|
-
toolName: string;
|
|
47
|
-
params: any;
|
|
48
|
-
timestamp: number;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Whitelist checker
|
|
53
|
-
*/
|
|
54
|
-
export class WhitelistChecker {
|
|
55
|
-
private static readonly WHITELISTED_TOOLS: Set<string> = new Set([
|
|
56
|
-
// Information reading tools
|
|
57
|
-
'Read',
|
|
58
|
-
'ListDirectory',
|
|
59
|
-
'
|
|
60
|
-
'Grep',
|
|
61
|
-
'image_read',
|
|
62
|
-
|
|
63
|
-
// Task management tools
|
|
64
|
-
'todo_write',
|
|
65
|
-
'todo_read',
|
|
66
|
-
'task',
|
|
67
|
-
'exit_plan_mode',
|
|
68
|
-
'web_search',
|
|
69
|
-
|
|
70
|
-
// File editing tools
|
|
71
|
-
'
|
|
72
|
-
'Write',
|
|
73
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
-
private
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
//
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
return
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
const
|
|
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
|
-
prompt
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
private
|
|
462
|
-
private
|
|
463
|
-
private
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
this.
|
|
468
|
-
this.
|
|
469
|
-
this.
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
console.log(
|
|
549
|
-
console.log(colors.
|
|
550
|
-
console.log(
|
|
551
|
-
console.log(
|
|
552
|
-
console.log(colors.textMuted(
|
|
553
|
-
console.log(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
console.log(colors.
|
|
558
|
-
console.log(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
console.log(
|
|
563
|
-
console.log(
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
[RiskLevel.
|
|
589
|
-
[RiskLevel.
|
|
590
|
-
[RiskLevel.
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import { AIClient, Message } from './ai-client.js';
|
|
3
|
+
import { getConfigManager } from './config.js';
|
|
4
|
+
import { AuthType } from './types.js';
|
|
5
|
+
import { getLogger } from './logger.js';
|
|
6
|
+
import { colors, icons } from './theme.js';
|
|
7
|
+
|
|
8
|
+
const logger = getLogger();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Approval result type
|
|
12
|
+
*/
|
|
13
|
+
export enum ApprovalDecision {
|
|
14
|
+
APPROVED = 'approved',
|
|
15
|
+
REJECTED = 'rejected',
|
|
16
|
+
REQUIRES_CONFIRMATION = 'requires_confirmation',
|
|
17
|
+
AI_REVIEW = 'ai_review'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Risk level
|
|
22
|
+
*/
|
|
23
|
+
export enum RiskLevel {
|
|
24
|
+
LOW = 'LOW',
|
|
25
|
+
MEDIUM = 'MEDIUM',
|
|
26
|
+
HIGH = 'HIGH',
|
|
27
|
+
CRITICAL = 'CRITICAL'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Approval result
|
|
32
|
+
*/
|
|
33
|
+
export interface ApprovalResult {
|
|
34
|
+
decision: ApprovalDecision;
|
|
35
|
+
riskLevel: RiskLevel;
|
|
36
|
+
detectionMethod: 'whitelist' | 'blacklist' | 'ai_review' | 'manual';
|
|
37
|
+
description: string;
|
|
38
|
+
latency: number;
|
|
39
|
+
aiAnalysis?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Tool call context
|
|
44
|
+
*/
|
|
45
|
+
export interface ToolCallContext {
|
|
46
|
+
toolName: string;
|
|
47
|
+
params: any;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Whitelist checker
|
|
53
|
+
*/
|
|
54
|
+
export class WhitelistChecker {
|
|
55
|
+
private static readonly WHITELISTED_TOOLS: Set<string> = new Set([
|
|
56
|
+
// Information reading tools
|
|
57
|
+
'Read',
|
|
58
|
+
'ListDirectory',
|
|
59
|
+
'SearchFiles',
|
|
60
|
+
'Grep',
|
|
61
|
+
'image_read',
|
|
62
|
+
|
|
63
|
+
// Task management tools
|
|
64
|
+
'todo_write',
|
|
65
|
+
'todo_read',
|
|
66
|
+
'task',
|
|
67
|
+
'exit_plan_mode',
|
|
68
|
+
'web_search',
|
|
69
|
+
|
|
70
|
+
// File editing tools
|
|
71
|
+
'Edit',
|
|
72
|
+
'Write',
|
|
73
|
+
'DeleteFile',
|
|
74
|
+
|
|
75
|
+
// Other safe tools
|
|
76
|
+
'web_fetch',
|
|
77
|
+
'ask_user_question',
|
|
78
|
+
'save_memory',
|
|
79
|
+
'xml_escape',
|
|
80
|
+
'Skill'
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Check if tool is in whitelist
|
|
85
|
+
*/
|
|
86
|
+
check(toolName: string): boolean {
|
|
87
|
+
return WhitelistChecker.WHITELISTED_TOOLS.has(toolName);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Get list of whitelisted tools
|
|
92
|
+
*/
|
|
93
|
+
getWhitelistedTools(): string[] {
|
|
94
|
+
return Array.from(WhitelistChecker.WHITELISTED_TOOLS);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Blacklist rules
|
|
100
|
+
*/
|
|
101
|
+
interface BlacklistRule {
|
|
102
|
+
pattern: RegExp;
|
|
103
|
+
category: string;
|
|
104
|
+
riskLevel: RiskLevel;
|
|
105
|
+
description: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Blacklist checker
|
|
110
|
+
*/
|
|
111
|
+
export class BlacklistChecker {
|
|
112
|
+
private static readonly RULES: BlacklistRule[] = [
|
|
113
|
+
// System destruction
|
|
114
|
+
{
|
|
115
|
+
pattern: /rm\s+-rf\s+\/$/,
|
|
116
|
+
category: 'System destruction',
|
|
117
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
118
|
+
description: 'Delete root directory'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
pattern: /rm\s+-rf\s+(\/etc|\/usr|\/bin|\/sbin|\/lib|\/lib64)/,
|
|
122
|
+
category: 'System destruction',
|
|
123
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
124
|
+
description: 'Delete system directories'
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
pattern: /rm\s+-rf\s+.*\*/,
|
|
128
|
+
category: 'System destruction',
|
|
129
|
+
riskLevel: RiskLevel.HIGH,
|
|
130
|
+
description: 'Batch delete files'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
pattern: /(mkfs|format)\s+/,
|
|
134
|
+
category: 'System destruction',
|
|
135
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
136
|
+
description: 'Format disk'
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
pattern: /dd\s+.*of=\/dev\/(sd[a-z]|nvme[0-9]n[0-9])/,
|
|
140
|
+
category: 'System destruction',
|
|
141
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
142
|
+
description: 'Overwrite disk data'
|
|
143
|
+
},
|
|
144
|
+
|
|
145
|
+
// Privilege escalation
|
|
146
|
+
{
|
|
147
|
+
pattern: /chmod\s+777\s+/,
|
|
148
|
+
category: 'Privilege escalation',
|
|
149
|
+
riskLevel: RiskLevel.HIGH,
|
|
150
|
+
description: 'Set file permissions to 777'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
pattern: /chmod\s+[45][0-9]{3}\s+/,
|
|
154
|
+
category: 'Privilege escalation',
|
|
155
|
+
riskLevel: RiskLevel.HIGH,
|
|
156
|
+
description: 'Set SUID/SGID permissions'
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
pattern: /vi\s+\/etc\/sudoers/,
|
|
160
|
+
category: 'Privilege escalation',
|
|
161
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
162
|
+
description: 'Modify sudo permissions'
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
pattern: /echo.*>>.*\/etc\/sudoers/,
|
|
166
|
+
category: 'Privilege escalation',
|
|
167
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
168
|
+
description: 'Modify sudo permissions'
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Data theft
|
|
172
|
+
{
|
|
173
|
+
pattern: /cat\s+\/etc\/passwd/,
|
|
174
|
+
category: 'Data theft',
|
|
175
|
+
riskLevel: RiskLevel.HIGH,
|
|
176
|
+
description: 'Read password file'
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
pattern: /cat\s+\/etc\/shadow/,
|
|
180
|
+
category: 'Data theft',
|
|
181
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
182
|
+
description: 'Read shadow file'
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
pattern: /cat\s+.*\/\.ssh\/id_rsa/,
|
|
186
|
+
category: 'Data theft',
|
|
187
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
188
|
+
description: 'Read SSH private key'
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
pattern: /grep\s+-[rRi].*password/,
|
|
192
|
+
category: 'Data theft',
|
|
193
|
+
riskLevel: RiskLevel.HIGH,
|
|
194
|
+
description: 'Search for password information'
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
pattern: /(curl|wget).*\|(sh|bash|python|perl)/,
|
|
198
|
+
category: 'Data theft',
|
|
199
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
200
|
+
description: 'Remote code execution'
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
// Network attacks
|
|
204
|
+
{
|
|
205
|
+
pattern: /nmap\s+-[sS].*/,
|
|
206
|
+
category: 'Network attacks',
|
|
207
|
+
riskLevel: RiskLevel.MEDIUM,
|
|
208
|
+
description: 'Network scanning'
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
pattern: /nc\s+.*-l/,
|
|
212
|
+
category: 'Network attacks',
|
|
213
|
+
riskLevel: RiskLevel.HIGH,
|
|
214
|
+
description: 'Create network listener'
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
pattern: /iptables\s+-F/,
|
|
218
|
+
category: 'Network attacks',
|
|
219
|
+
riskLevel: RiskLevel.HIGH,
|
|
220
|
+
description: 'Clear firewall rules'
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
// Resource exhaustion
|
|
224
|
+
{
|
|
225
|
+
pattern: /:\)\s*{\s*:\s*\|\s*:&\s*};/,
|
|
226
|
+
category: 'Resource exhaustion',
|
|
227
|
+
riskLevel: RiskLevel.CRITICAL,
|
|
228
|
+
description: 'Fork bomb'
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
pattern: /while\s+true\s*;\s*do\s+.*done/,
|
|
232
|
+
category: 'Resource exhaustion',
|
|
233
|
+
riskLevel: RiskLevel.HIGH,
|
|
234
|
+
description: 'Infinite loop'
|
|
235
|
+
}
|
|
236
|
+
];
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Check if tool call matches blacklist rules
|
|
240
|
+
*/
|
|
241
|
+
check(context: ToolCallContext): { matched: boolean; rule?: BlacklistRule } {
|
|
242
|
+
const { toolName, params } = context;
|
|
243
|
+
|
|
244
|
+
// For Bash tool, check command content
|
|
245
|
+
if (toolName === 'Bash' && params.command) {
|
|
246
|
+
const command = params.command as string;
|
|
247
|
+
|
|
248
|
+
for (const rule of BlacklistChecker.RULES) {
|
|
249
|
+
if (rule.pattern.test(command)) {
|
|
250
|
+
return { matched: true, rule };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// For file operation tools, check path
|
|
256
|
+
if (['Write', 'DeleteFile', 'Edit'].includes(toolName)) {
|
|
257
|
+
const filePath = params.filePath || params.file_path || '';
|
|
258
|
+
if (this.isSystemPath(filePath)) {
|
|
259
|
+
return {
|
|
260
|
+
matched: true,
|
|
261
|
+
rule: {
|
|
262
|
+
pattern: /system-path/,
|
|
263
|
+
category: 'System destruction',
|
|
264
|
+
riskLevel: RiskLevel.HIGH,
|
|
265
|
+
description: 'Modify system files'
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return { matched: false };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Check if it's a system path
|
|
276
|
+
*/
|
|
277
|
+
private isSystemPath(filePath: string): boolean {
|
|
278
|
+
const systemPaths = [
|
|
279
|
+
'/etc',
|
|
280
|
+
'/usr',
|
|
281
|
+
'/bin',
|
|
282
|
+
'/sbin',
|
|
283
|
+
'/lib',
|
|
284
|
+
'/lib64',
|
|
285
|
+
'/boot',
|
|
286
|
+
'/sys',
|
|
287
|
+
'/proc',
|
|
288
|
+
'/dev'
|
|
289
|
+
];
|
|
290
|
+
|
|
291
|
+
const normalizedPath = filePath.toLowerCase().replace(/\\/g, '/');
|
|
292
|
+
return systemPaths.some(sysPath => normalizedPath.startsWith(sysPath));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Get all blacklist rules
|
|
297
|
+
*/
|
|
298
|
+
getRules(): BlacklistRule[] {
|
|
299
|
+
return [...BlacklistChecker.RULES];
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* AI approval checker
|
|
305
|
+
*/
|
|
306
|
+
export class AIApprovalChecker {
|
|
307
|
+
private aiClient: AIClient | null = null;
|
|
308
|
+
private isRemoteMode: boolean = false;
|
|
309
|
+
|
|
310
|
+
constructor() {
|
|
311
|
+
this.initializeAIClient();
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Initialize AI client(s)
|
|
316
|
+
*/
|
|
317
|
+
private async initializeAIClient(): Promise<void> {
|
|
318
|
+
try {
|
|
319
|
+
const configManager = getConfigManager();
|
|
320
|
+
const authConfig = configManager.getAuthConfig();
|
|
321
|
+
|
|
322
|
+
// Check if Remote mode (OAuth XAGENT)
|
|
323
|
+
this.isRemoteMode = authConfig.type === AuthType.OAUTH_XAGENT;
|
|
324
|
+
|
|
325
|
+
// Remote mode: AI review handled by remote LLM, no local AIClient needed
|
|
326
|
+
// Local mode: use local AIClient
|
|
327
|
+
if (!this.isRemoteMode && authConfig.apiKey) {
|
|
328
|
+
this.aiClient = new AIClient(authConfig);
|
|
329
|
+
}
|
|
330
|
+
} catch (error) {
|
|
331
|
+
logger.error('Failed to initialize AI approval checker', error instanceof Error ? error.message : String(error));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Use AI for intelligent review
|
|
337
|
+
*/
|
|
338
|
+
async check(context: ToolCallContext): Promise<{ approved: boolean; analysis: string; riskLevel: RiskLevel }> {
|
|
339
|
+
// In Remote mode, the remote LLM has already approved the tool_calls
|
|
340
|
+
// Local AI review approves directly, no need to repeat
|
|
341
|
+
if (this.isRemoteMode) {
|
|
342
|
+
return {
|
|
343
|
+
approved: true,
|
|
344
|
+
analysis: 'Remote mode: tool approval handled by remote LLM',
|
|
345
|
+
riskLevel: RiskLevel.LOW
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!this.aiClient) {
|
|
350
|
+
// If AI client is not initialized, default to medium risk, requires user confirmation
|
|
351
|
+
return {
|
|
352
|
+
approved: false,
|
|
353
|
+
analysis: 'AI review not available (no local LLM configured), requires manual user confirmation',
|
|
354
|
+
riskLevel: RiskLevel.MEDIUM
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const prompt = this.buildApprovalPrompt(context);
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
const messages: Message[] = [
|
|
362
|
+
{
|
|
363
|
+
role: 'system',
|
|
364
|
+
content: `You are a security review expert. Your task is to evaluate the security of tool calls.
|
|
365
|
+
|
|
366
|
+
Please analyze from the following dimensions:
|
|
367
|
+
1. Whether the operation has malicious intent
|
|
368
|
+
2. Whether it may cause data leakage
|
|
369
|
+
3. Whether it may compromise system integrity
|
|
370
|
+
4. Whether it follows best practices
|
|
371
|
+
|
|
372
|
+
Please return results in JSON format:
|
|
373
|
+
{
|
|
374
|
+
"approved": boolean,
|
|
375
|
+
"riskLevel": "LOW" | "MEDIUM" | "HIGH" | "CRITICAL",
|
|
376
|
+
"analysis": "Detailed analysis description"
|
|
377
|
+
}`
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
role: 'user',
|
|
381
|
+
content: prompt
|
|
382
|
+
}
|
|
383
|
+
];
|
|
384
|
+
|
|
385
|
+
const response = await this.aiClient.chatCompletion(messages, {
|
|
386
|
+
temperature: 0.3,
|
|
387
|
+
// maxTokens: 500
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
const content = typeof response.choices[0].message.content === 'string'
|
|
391
|
+
? response.choices[0].message.content
|
|
392
|
+
: '{}';
|
|
393
|
+
|
|
394
|
+
// Parse AI response
|
|
395
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
396
|
+
if (jsonMatch) {
|
|
397
|
+
const result = JSON.parse(jsonMatch[0]);
|
|
398
|
+
return {
|
|
399
|
+
approved: result.approved || false,
|
|
400
|
+
analysis: result.analysis || 'No detailed analysis',
|
|
401
|
+
riskLevel: result.riskLevel || RiskLevel.MEDIUM
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// If unable to parse, return medium risk
|
|
406
|
+
return {
|
|
407
|
+
approved: false,
|
|
408
|
+
analysis: 'Unable to parse AI response, requires manual confirmation',
|
|
409
|
+
riskLevel: RiskLevel.MEDIUM
|
|
410
|
+
};
|
|
411
|
+
} catch (error: any) {
|
|
412
|
+
logger.error('AI approval check failed', error instanceof Error ? error.message : String(error));
|
|
413
|
+
|
|
414
|
+
// In Remote mode, remote LLM already approved, local failure means auto-approve
|
|
415
|
+
const configManager = getConfigManager();
|
|
416
|
+
const authConfig = configManager.getAuthConfig();
|
|
417
|
+
const isRemoteMode = authConfig.type === AuthType.OAUTH_XAGENT;
|
|
418
|
+
|
|
419
|
+
if (isRemoteMode) {
|
|
420
|
+
return {
|
|
421
|
+
approved: true,
|
|
422
|
+
analysis: 'Remote mode: approved (remote LLM handled approval)',
|
|
423
|
+
riskLevel: RiskLevel.LOW
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
approved: false,
|
|
429
|
+
analysis: `AI review failed: ${error.message}, requires manual confirmation`,
|
|
430
|
+
riskLevel: RiskLevel.MEDIUM
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Build review prompt
|
|
437
|
+
*/
|
|
438
|
+
private buildApprovalPrompt(context: ToolCallContext): string {
|
|
439
|
+
const { toolName, params } = context;
|
|
440
|
+
|
|
441
|
+
let prompt = `Tool name: ${toolName}\n`;
|
|
442
|
+
prompt += `Parameters: ${JSON.stringify(params, null, 2)}\n\n`;
|
|
443
|
+
|
|
444
|
+
// Add specific analysis guidance based on tool type
|
|
445
|
+
if (toolName === 'Bash') {
|
|
446
|
+
prompt += `This is a Shell command execution request. Please check if the command contains:\n- Dangerous system operations (such as deletion, formatting)\n- Privilege escalation operations\n- Data theft operations\n- Remote code execution\n- Resource exhaustion attacks`;
|
|
447
|
+
} else if (['Write', 'Edit', 'DeleteFile'].includes(toolName)) {
|
|
448
|
+
prompt += `This is a file operation request. Please check:\n- Whether the target path is a system path\n- Whether the operation may damage system files\n- Whether it involves sensitive configuration files`;
|
|
449
|
+
} else if (toolName === 'web_fetch' || toolName === 'web_search') {
|
|
450
|
+
prompt += `This is a network request. Please check:\n- Whether the URL is a malicious website\n- Whether it may leak sensitive information\n- Whether it may execute remote code`;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return prompt;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Smart approval engine
|
|
459
|
+
*/
|
|
460
|
+
export class SmartApprovalEngine {
|
|
461
|
+
private whitelistChecker: WhitelistChecker;
|
|
462
|
+
private blacklistChecker: BlacklistChecker;
|
|
463
|
+
private aiChecker: AIApprovalChecker;
|
|
464
|
+
private debugMode: boolean;
|
|
465
|
+
|
|
466
|
+
constructor(debugMode: boolean = false) {
|
|
467
|
+
this.whitelistChecker = new WhitelistChecker();
|
|
468
|
+
this.blacklistChecker = new BlacklistChecker();
|
|
469
|
+
this.aiChecker = new AIApprovalChecker();
|
|
470
|
+
this.debugMode = debugMode;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Evaluate tool call
|
|
475
|
+
*/
|
|
476
|
+
async evaluate(context: ToolCallContext): Promise<ApprovalResult> {
|
|
477
|
+
const startTime = Date.now();
|
|
478
|
+
|
|
479
|
+
if (this.debugMode) {
|
|
480
|
+
logger.debug(`[SmartApprovalEngine] Evaluating tool call: ${context.toolName}`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// First layer: Whitelist check
|
|
484
|
+
const whitelistCheck = this.whitelistChecker.check(context.toolName);
|
|
485
|
+
if (whitelistCheck) {
|
|
486
|
+
const latency = Date.now() - startTime;
|
|
487
|
+
if (this.debugMode) {
|
|
488
|
+
logger.debug(`[WhitelistChecker] Tool '${context.toolName}' in whitelist, latency: ${latency}ms`);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
decision: ApprovalDecision.APPROVED,
|
|
493
|
+
riskLevel: RiskLevel.LOW,
|
|
494
|
+
detectionMethod: 'whitelist',
|
|
495
|
+
description: `Tool '${context.toolName}' is in the whitelist, executing directly`,
|
|
496
|
+
latency
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (this.debugMode) {
|
|
501
|
+
logger.debug(`[WhitelistChecker] Tool '${context.toolName}' not in whitelist`);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Second layer: Blacklist check
|
|
505
|
+
const blacklistCheck = this.blacklistChecker.check(context);
|
|
506
|
+
if (blacklistCheck.matched && blacklistCheck.rule) {
|
|
507
|
+
const latency = Date.now() - startTime;
|
|
508
|
+
if (this.debugMode) {
|
|
509
|
+
logger.debug(`[BlacklistChecker] Matched rule: ${blacklistCheck.rule.description}, Risk: ${blacklistCheck.rule.riskLevel}, latency: ${latency}ms`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return {
|
|
513
|
+
decision: ApprovalDecision.REQUIRES_CONFIRMATION,
|
|
514
|
+
riskLevel: blacklistCheck.rule.riskLevel,
|
|
515
|
+
detectionMethod: 'blacklist',
|
|
516
|
+
description: `Detected potentially risky operation: ${blacklistCheck.rule.description}`,
|
|
517
|
+
latency
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (this.debugMode) {
|
|
522
|
+
logger.debug(`[BlacklistChecker] No blacklist rule matched`);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// Third layer: AI intelligent review
|
|
526
|
+
const aiCheck = await this.aiChecker.check(context);
|
|
527
|
+
const latency = Date.now() - startTime;
|
|
528
|
+
|
|
529
|
+
if (this.debugMode) {
|
|
530
|
+
logger.debug(`[AIApprovalChecker] AI review result: approved=${aiCheck.approved}, risk=${aiCheck.riskLevel}, latency: ${latency}ms`);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
decision: aiCheck.approved ? ApprovalDecision.APPROVED : ApprovalDecision.REQUIRES_CONFIRMATION,
|
|
535
|
+
riskLevel: aiCheck.riskLevel,
|
|
536
|
+
detectionMethod: 'ai_review',
|
|
537
|
+
description: aiCheck.analysis,
|
|
538
|
+
latency,
|
|
539
|
+
aiAnalysis: aiCheck.analysis
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Request user confirmation
|
|
545
|
+
*/
|
|
546
|
+
async requestConfirmation(result: ApprovalResult): Promise<boolean> {
|
|
547
|
+
const separator = icons.separator.repeat(40);
|
|
548
|
+
console.log('');
|
|
549
|
+
console.log(colors.warning(`${icons.warning} [Smart Mode] Detected potentially risky operation`));
|
|
550
|
+
console.log(colors.border(separator));
|
|
551
|
+
console.log('');
|
|
552
|
+
console.log(colors.textMuted(`📊 Risk Level: ${this.getRiskLevelDisplay(result.riskLevel)}`));
|
|
553
|
+
console.log(colors.textMuted(`🔍 Detection Method: ${this.getDetectionMethodDisplay(result.detectionMethod)}`));
|
|
554
|
+
console.log('');
|
|
555
|
+
|
|
556
|
+
if (result.aiAnalysis) {
|
|
557
|
+
console.log(colors.textMuted(`🤖 AI Analysis:`));
|
|
558
|
+
console.log(colors.textDim(` ${result.aiAnalysis}`));
|
|
559
|
+
console.log('');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(colors.textMuted(`⚠️ Risk Description: ${result.description}`));
|
|
563
|
+
console.log('');
|
|
564
|
+
console.log(colors.warning('Potentially risky operation detected, continue execution?'));
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
const { confirmed } = await inquirer.prompt([
|
|
568
|
+
{
|
|
569
|
+
type: 'confirm',
|
|
570
|
+
name: 'confirmed',
|
|
571
|
+
message: 'Continue execution?',
|
|
572
|
+
default: false
|
|
573
|
+
}
|
|
574
|
+
]);
|
|
575
|
+
|
|
576
|
+
return confirmed;
|
|
577
|
+
} catch (error) {
|
|
578
|
+
logger.error('Failed to get user confirmation', error instanceof Error ? error.message : String(error));
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* Get risk level display
|
|
585
|
+
*/
|
|
586
|
+
private getRiskLevelDisplay(riskLevel: RiskLevel): string {
|
|
587
|
+
const displays = {
|
|
588
|
+
[RiskLevel.LOW]: colors.success('LOW'),
|
|
589
|
+
[RiskLevel.MEDIUM]: colors.warning('MEDIUM'),
|
|
590
|
+
[RiskLevel.HIGH]: colors.error('HIGH'),
|
|
591
|
+
[RiskLevel.CRITICAL]: colors.error('CRITICAL')
|
|
592
|
+
};
|
|
593
|
+
return displays[riskLevel];
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/**
|
|
597
|
+
* Get detection method display
|
|
598
|
+
*/
|
|
599
|
+
private getDetectionMethodDisplay(method: string): string {
|
|
600
|
+
const displays = {
|
|
601
|
+
whitelist: 'Whitelist rules',
|
|
602
|
+
blacklist: 'Blacklist rules',
|
|
603
|
+
ai_review: 'AI intelligent review',
|
|
604
|
+
manual: 'Manual review'
|
|
605
|
+
};
|
|
606
|
+
return displays[method as keyof typeof displays] || method;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Set debug mode
|
|
611
|
+
*/
|
|
612
|
+
setDebugMode(enabled: boolean): void {
|
|
613
|
+
this.debugMode = enabled;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Get smart approval engine instance
|
|
619
|
+
*/
|
|
620
|
+
let smartApprovalEngineInstance: SmartApprovalEngine | null = null;
|
|
621
|
+
|
|
622
|
+
export function getSmartApprovalEngine(debugMode: boolean = false): SmartApprovalEngine {
|
|
623
|
+
if (!smartApprovalEngineInstance) {
|
|
624
|
+
smartApprovalEngineInstance = new SmartApprovalEngine(debugMode);
|
|
625
|
+
}
|
|
626
|
+
return smartApprovalEngineInstance;
|
|
626
627
|
}
|