@asifkibria/claude-code-toolkit 1.0.7 → 1.3.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/README.md +172 -475
- package/dist/CLAUDE.md +7 -0
- package/dist/__tests__/dashboard.test.d.ts +2 -0
- package/dist/__tests__/dashboard.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard.test.js +606 -0
- package/dist/__tests__/dashboard.test.js.map +1 -0
- package/dist/__tests__/mcp-validator.test.d.ts +2 -0
- package/dist/__tests__/mcp-validator.test.d.ts.map +1 -0
- package/dist/__tests__/mcp-validator.test.js +217 -0
- package/dist/__tests__/mcp-validator.test.js.map +1 -0
- package/dist/__tests__/security.test.d.ts +2 -0
- package/dist/__tests__/security.test.d.ts.map +1 -0
- package/dist/__tests__/security.test.js +375 -0
- package/dist/__tests__/security.test.js.map +1 -0
- package/dist/__tests__/session-recovery.test.d.ts +2 -0
- package/dist/__tests__/session-recovery.test.d.ts.map +1 -0
- package/dist/__tests__/session-recovery.test.js +230 -0
- package/dist/__tests__/session-recovery.test.js.map +1 -0
- package/dist/__tests__/storage.test.d.ts +2 -0
- package/dist/__tests__/storage.test.d.ts.map +1 -0
- package/dist/__tests__/storage.test.js +241 -0
- package/dist/__tests__/storage.test.js.map +1 -0
- package/dist/__tests__/trace.test.d.ts +2 -0
- package/dist/__tests__/trace.test.d.ts.map +1 -0
- package/dist/__tests__/trace.test.js +376 -0
- package/dist/__tests__/trace.test.js.map +1 -0
- package/dist/cli.js +680 -39
- package/dist/cli.js.map +1 -1
- package/dist/index.js +674 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/alerts.d.ts +38 -0
- package/dist/lib/alerts.d.ts.map +1 -0
- package/dist/lib/alerts.js +296 -0
- package/dist/lib/alerts.js.map +1 -0
- package/dist/lib/dashboard-ui.d.ts +2 -0
- package/dist/lib/dashboard-ui.d.ts.map +1 -0
- package/dist/lib/dashboard-ui.js +2267 -0
- package/dist/lib/dashboard-ui.js.map +1 -0
- package/dist/lib/dashboard.d.ts +16 -0
- package/dist/lib/dashboard.d.ts.map +1 -0
- package/dist/lib/dashboard.js +1571 -0
- package/dist/lib/dashboard.js.map +1 -0
- package/dist/lib/git.d.ts +29 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +124 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/logs.d.ts +42 -0
- package/dist/lib/logs.d.ts.map +1 -0
- package/dist/lib/logs.js +166 -0
- package/dist/lib/logs.js.map +1 -0
- package/dist/lib/mcp-validator.d.ts +109 -0
- package/dist/lib/mcp-validator.d.ts.map +1 -0
- package/dist/lib/mcp-validator.js +601 -0
- package/dist/lib/mcp-validator.js.map +1 -0
- package/dist/lib/scanner.d.ts +6 -2
- package/dist/lib/scanner.d.ts.map +1 -1
- package/dist/lib/scanner.js +120 -19
- package/dist/lib/scanner.js.map +1 -1
- package/dist/lib/search.d.ts +56 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +284 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/security.d.ts +96 -0
- package/dist/lib/security.d.ts.map +1 -0
- package/dist/lib/security.js +795 -0
- package/dist/lib/security.js.map +1 -0
- package/dist/lib/session-recovery.d.ts +60 -0
- package/dist/lib/session-recovery.d.ts.map +1 -0
- package/dist/lib/session-recovery.js +433 -0
- package/dist/lib/session-recovery.js.map +1 -0
- package/dist/lib/storage.d.ts +68 -0
- package/dist/lib/storage.d.ts.map +1 -0
- package/dist/lib/storage.js +503 -0
- package/dist/lib/storage.js.map +1 -0
- package/dist/lib/trace.d.ts +119 -0
- package/dist/lib/trace.d.ts.map +1 -0
- package/dist/lib/trace.js +649 -0
- package/dist/lib/trace.js.map +1 -0
- package/package.json +11 -3
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,15 @@ import * as fs from "fs";
|
|
|
7
7
|
import * as path from "path";
|
|
8
8
|
import * as os from "os";
|
|
9
9
|
import { findAllJsonlFiles, findBackupFiles, scanFile, fixFile, getConversationStats, restoreFromBackup, deleteOldBackups, exportConversationToFile, estimateContextSize, formatContextEstimate, generateUsageAnalytics, formatUsageAnalytics, findDuplicates, formatDuplicateReport, findArchiveCandidates, archiveConversations, formatArchiveReport, runMaintenance, formatMaintenanceReport, generateCronSchedule, generateLaunchdPlist, } from "./lib/scanner.js";
|
|
10
|
+
import { analyzeClaudeStorage, cleanClaudeDirectory, findCleanupTargets, formatStorageReport, formatCleanupReport, } from "./lib/storage.js";
|
|
11
|
+
import { diagnoseMcpServers, formatMcpDiagnosticReport, analyzeMcpPerformance, formatMcpPerformanceReport, } from "./lib/mcp-validator.js";
|
|
12
|
+
import { listSessions, diagnoseSession, repairSession, extractSessionContent, formatSessionReport, formatSessionDiagnosticReport, } from "./lib/session-recovery.js";
|
|
13
|
+
import { scanForSecrets, scanForPII, auditSession, enforceRetention, formatSecretsScanReport, formatPIIScanReport, formatAuditReport, formatRetentionReport, } from "./lib/security.js";
|
|
14
|
+
import { inventoryTraces, cleanTraces, wipeAllTraces, generateTraceGuardHooks, formatTraceInventory, formatTraceCleanReport, formatTraceGuardConfig, } from "./lib/trace.js";
|
|
15
|
+
import { startDashboard, stopDashboard, isDashboardRunning } from "./lib/dashboard.js";
|
|
16
|
+
import { searchConversations, formatSearchReport, compareSessionsByCID, formatSessionDiff } from "./lib/search.js";
|
|
17
|
+
import { linkSessionsToGit, formatGitLinkReport } from "./lib/git.js";
|
|
18
|
+
import { checkAlerts, checkQuotas, formatAlertsReport, formatQuotasReport } from "./lib/alerts.js";
|
|
10
19
|
function formatContentType(type) {
|
|
11
20
|
switch (type) {
|
|
12
21
|
case "image": return "🖼️ image";
|
|
@@ -30,57 +39,102 @@ function formatDate(date) {
|
|
|
30
39
|
}
|
|
31
40
|
function printHelp() {
|
|
32
41
|
console.log(`
|
|
33
|
-
Claude Code Toolkit v1.0
|
|
34
|
-
Maintain, optimize, and troubleshoot your Claude Code installation.
|
|
35
|
-
Fixes oversized images, PDFs, documents, and large text content.
|
|
42
|
+
Claude Code Toolkit v1.3.0
|
|
43
|
+
Maintain, optimize, secure, and troubleshoot your Claude Code installation.
|
|
36
44
|
|
|
37
45
|
USAGE:
|
|
38
46
|
cct <command> [options]
|
|
39
47
|
claude-code-toolkit <command> [options]
|
|
40
48
|
|
|
41
49
|
COMMANDS:
|
|
42
|
-
health
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
health Quick health check (start here!)
|
|
51
|
+
search <query> Full-text search across all conversations
|
|
52
|
+
stats Show conversation statistics
|
|
53
|
+
context Estimate context/token usage
|
|
54
|
+
cost Estimate API costs based on token usage
|
|
55
|
+
analytics Usage analytics dashboard
|
|
56
|
+
duplicates Find duplicate content and conversations
|
|
57
|
+
archive Archive old/inactive conversations
|
|
58
|
+
maintenance Run maintenance checks and actions
|
|
59
|
+
scan Scan for issues (dry run)
|
|
60
|
+
fix Fix all detected issues
|
|
61
|
+
watch Monitor sessions for new oversized content
|
|
62
|
+
export Export conversation to markdown or JSON
|
|
63
|
+
backups List backup files
|
|
64
|
+
restore <path> Restore from a backup file
|
|
65
|
+
cleanup Delete old backup files
|
|
66
|
+
clean Analyze and clean .claude directory
|
|
67
|
+
mcp-validate Validate MCP server configurations
|
|
68
|
+
mcp-perf Track MCP server performance and usage
|
|
69
|
+
sessions List all sessions with health status
|
|
70
|
+
diff <id1> <id2> Compare two sessions
|
|
71
|
+
git Link sessions to git branches/commits
|
|
72
|
+
recover <id> Diagnose/repair/extract from a session
|
|
73
|
+
security-scan Scan conversations for leaked secrets
|
|
74
|
+
pii-scan Scan conversations for personal data (PII)
|
|
75
|
+
--details: Show unmasked values (handle with care!)
|
|
76
|
+
audit <id> Audit a session's actions (files, commands, etc.)
|
|
77
|
+
retention Enforce data retention policy
|
|
78
|
+
alerts Check for issues and notifications
|
|
79
|
+
quotas Show usage quotas and limits
|
|
80
|
+
dashboard Open web dashboard in browser
|
|
81
|
+
dashboard --daemon Run dashboard as background process
|
|
82
|
+
dashboard --stop Stop background dashboard
|
|
83
|
+
trace Show full trace inventory
|
|
84
|
+
trace clean Selective trace cleanup
|
|
85
|
+
trace wipe Secure wipe all traces (requires --confirm)
|
|
86
|
+
trace guard Generate trace prevention hooks
|
|
55
87
|
|
|
56
88
|
OPTIONS:
|
|
57
89
|
-f, --file <path> Target a specific file
|
|
58
90
|
-o, --output <path> Output file path (for export)
|
|
91
|
+
-q, --query <text> Search query text
|
|
92
|
+
--role <type> For search: filter by role (user|assistant|all)
|
|
59
93
|
--format <type> Export format: markdown or json (default: markdown)
|
|
60
94
|
--with-tools Include tool results in export
|
|
61
95
|
-d, --dry-run Show what would be done without making changes
|
|
62
96
|
--no-backup Skip creating backups when fixing (not recommended)
|
|
63
|
-
--days <n> For cleanup/archive: days threshold (default: 7/30)
|
|
64
|
-
--limit <n> For stats: limit results (default: 10)
|
|
97
|
+
--days <n> For cleanup/archive/retention: days threshold (default: 7/30)
|
|
98
|
+
--limit <n> For stats/search: limit results (default: 10/50)
|
|
65
99
|
--sort <field> For stats: sort by size|messages|images|modified
|
|
66
100
|
--auto For maintenance: run automatically without prompts
|
|
67
101
|
--schedule For maintenance: show cron/launchd setup
|
|
102
|
+
--category <type> For clean: target specific category
|
|
103
|
+
--test For mcp-validate: test server connectivity
|
|
104
|
+
--extract For recover: extract salvageable content
|
|
105
|
+
--repair For recover: attempt repair
|
|
106
|
+
--confirm For trace wipe: confirm destructive operation
|
|
107
|
+
--keep-settings For trace wipe: preserve settings.json
|
|
108
|
+
--mode <mode> For trace guard: paranoid|moderate|minimal
|
|
109
|
+
--install For trace guard: auto-install hooks
|
|
110
|
+
--categories <list> For trace clean: comma-separated categories
|
|
111
|
+
--port <n> For dashboard: port number (default: 1405)
|
|
112
|
+
--daemon For dashboard: run as background process
|
|
113
|
+
--stop For dashboard: stop background process
|
|
114
|
+
--token <value> Require dashboard auth with bearer token
|
|
115
|
+
--project <path> Filter by project path
|
|
116
|
+
--json Output structured JSON (scan/watch)
|
|
117
|
+
--interval <sec> For watch: polling interval in seconds (default: 15)
|
|
118
|
+
--auto-fix For watch: automatically fix detected issues
|
|
68
119
|
-h, --help Show this help message
|
|
69
120
|
-v, --version Show version
|
|
70
121
|
|
|
71
122
|
EXAMPLES:
|
|
72
123
|
cct health # Quick health check
|
|
73
|
-
cct
|
|
74
|
-
cct
|
|
75
|
-
cct
|
|
76
|
-
cct
|
|
77
|
-
cct
|
|
78
|
-
cct
|
|
79
|
-
cct
|
|
80
|
-
cct scan
|
|
81
|
-
cct
|
|
82
|
-
cct
|
|
83
|
-
cct
|
|
124
|
+
cct search "authentication" # Search all conversations
|
|
125
|
+
cct search "api" --role user # Search only user messages
|
|
126
|
+
cct cost # Estimate API costs
|
|
127
|
+
cct clean --dry-run # Preview .claude directory cleanup
|
|
128
|
+
cct mcp-validate --test # Validate and test MCP servers
|
|
129
|
+
cct sessions # List all sessions
|
|
130
|
+
cct recover abc-123 --repair # Repair a corrupted session
|
|
131
|
+
cct security-scan # Scan for leaked secrets
|
|
132
|
+
cct audit abc-123 # Audit session actions
|
|
133
|
+
cct retention --days 60 --dry-run # Preview retention policy
|
|
134
|
+
cct trace # Show trace inventory
|
|
135
|
+
cct trace clean --days 7 # Clean old traces
|
|
136
|
+
cct trace wipe --confirm # Secure wipe all traces
|
|
137
|
+
cct trace guard --mode moderate # Generate trace prevention hooks
|
|
84
138
|
|
|
85
139
|
For more info: https://github.com/asifkibria/claude-code-toolkit
|
|
86
140
|
`);
|
|
@@ -88,8 +142,11 @@ For more info: https://github.com/asifkibria/claude-code-toolkit
|
|
|
88
142
|
function parseArgs(args) {
|
|
89
143
|
const result = {
|
|
90
144
|
command: "",
|
|
145
|
+
subcommand: undefined,
|
|
91
146
|
file: undefined,
|
|
92
147
|
output: undefined,
|
|
148
|
+
query: undefined,
|
|
149
|
+
role: undefined,
|
|
93
150
|
format: "markdown",
|
|
94
151
|
withTools: false,
|
|
95
152
|
dryRun: false,
|
|
@@ -99,6 +156,24 @@ function parseArgs(args) {
|
|
|
99
156
|
sort: "size",
|
|
100
157
|
auto: false,
|
|
101
158
|
schedule: false,
|
|
159
|
+
category: undefined,
|
|
160
|
+
test: false,
|
|
161
|
+
extract: false,
|
|
162
|
+
repair: false,
|
|
163
|
+
confirm: false,
|
|
164
|
+
keepSettings: false,
|
|
165
|
+
mode: "moderate",
|
|
166
|
+
install: false,
|
|
167
|
+
categories: undefined,
|
|
168
|
+
project: undefined,
|
|
169
|
+
port: 1405,
|
|
170
|
+
daemon: false,
|
|
171
|
+
stop: false,
|
|
172
|
+
token: undefined,
|
|
173
|
+
json: false,
|
|
174
|
+
interval: 15,
|
|
175
|
+
autoFix: false,
|
|
176
|
+
details: false,
|
|
102
177
|
};
|
|
103
178
|
for (let i = 0; i < args.length; i++) {
|
|
104
179
|
const arg = args[i];
|
|
@@ -107,7 +182,7 @@ function parseArgs(args) {
|
|
|
107
182
|
process.exit(0);
|
|
108
183
|
}
|
|
109
184
|
if (arg === "-v" || arg === "--version") {
|
|
110
|
-
console.log("1.0
|
|
185
|
+
console.log("1.3.0");
|
|
111
186
|
process.exit(0);
|
|
112
187
|
}
|
|
113
188
|
if (arg === "-f" || arg === "--file") {
|
|
@@ -118,6 +193,14 @@ function parseArgs(args) {
|
|
|
118
193
|
result.output = args[++i];
|
|
119
194
|
continue;
|
|
120
195
|
}
|
|
196
|
+
if (arg === "-q" || arg === "--query") {
|
|
197
|
+
result.query = args[++i];
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (arg === "--role") {
|
|
201
|
+
result.role = args[++i];
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
121
204
|
if (arg === "--format") {
|
|
122
205
|
const fmt = args[++i];
|
|
123
206
|
if (fmt === "json" || fmt === "markdown") {
|
|
@@ -157,23 +240,122 @@ function parseArgs(args) {
|
|
|
157
240
|
result.schedule = true;
|
|
158
241
|
continue;
|
|
159
242
|
}
|
|
243
|
+
if (arg === "--category") {
|
|
244
|
+
result.category = args[++i];
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (arg === "--test") {
|
|
248
|
+
result.test = true;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (arg === "--extract") {
|
|
252
|
+
result.extract = true;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (arg === "--repair") {
|
|
256
|
+
result.repair = true;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (arg === "--confirm") {
|
|
260
|
+
result.confirm = true;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (arg === "--keep-settings") {
|
|
264
|
+
result.keepSettings = true;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (arg === "--mode") {
|
|
268
|
+
result.mode = args[++i];
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (arg === "--install") {
|
|
272
|
+
result.install = true;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (arg === "--categories") {
|
|
276
|
+
result.categories = args[++i];
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (arg === "--port") {
|
|
280
|
+
result.port = parseInt(args[++i], 10);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (arg === "--daemon") {
|
|
284
|
+
result.daemon = true;
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (arg === "--stop") {
|
|
288
|
+
result.stop = true;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (arg === "--project") {
|
|
292
|
+
result.project = args[++i];
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
if (arg === "--token") {
|
|
296
|
+
result.token = args[++i];
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (arg === "--json") {
|
|
300
|
+
result.json = true;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
if (arg === "--interval") {
|
|
304
|
+
result.interval = parseInt(args[++i], 10);
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (arg === "--auto-fix") {
|
|
308
|
+
result.autoFix = true;
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (arg === "--details") {
|
|
312
|
+
result.details = true;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
160
315
|
if (!arg.startsWith("-") && !result.command) {
|
|
161
316
|
result.command = arg;
|
|
162
317
|
continue;
|
|
163
318
|
}
|
|
164
|
-
if (!arg.startsWith("-") && result.command === "restore") {
|
|
319
|
+
if (!arg.startsWith("-") && (result.command === "restore" || result.command === "recover" || result.command === "audit")) {
|
|
165
320
|
result.file = arg;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (!arg.startsWith("-") && result.command === "search" && !result.query) {
|
|
324
|
+
result.query = arg;
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (!arg.startsWith("-") && result.command === "diff") {
|
|
328
|
+
if (!result.file) {
|
|
329
|
+
result.file = arg;
|
|
330
|
+
}
|
|
331
|
+
else if (!result.subcommand) {
|
|
332
|
+
result.subcommand = arg;
|
|
333
|
+
}
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (!arg.startsWith("-") && result.command === "trace" && !result.subcommand) {
|
|
337
|
+
result.subcommand = arg;
|
|
338
|
+
continue;
|
|
166
339
|
}
|
|
167
340
|
}
|
|
168
341
|
return result;
|
|
169
342
|
}
|
|
170
|
-
async function cmdScan(file) {
|
|
343
|
+
async function cmdScan(file, asJson) {
|
|
171
344
|
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
172
345
|
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
173
346
|
process.exit(1);
|
|
174
347
|
}
|
|
175
348
|
const files = file ? [file] : findAllJsonlFiles(PROJECTS_DIR);
|
|
176
|
-
|
|
349
|
+
const summary = {
|
|
350
|
+
success: true,
|
|
351
|
+
filesScanned: files.length,
|
|
352
|
+
filesWithIssues: 0,
|
|
353
|
+
totalIssues: 0,
|
|
354
|
+
files: [],
|
|
355
|
+
};
|
|
356
|
+
if (!asJson) {
|
|
357
|
+
console.log(`Scanning ${files.length} file(s)...\n`);
|
|
358
|
+
}
|
|
177
359
|
let totalIssues = 0;
|
|
178
360
|
let filesWithIssues = 0;
|
|
179
361
|
for (const f of files) {
|
|
@@ -183,10 +365,21 @@ async function cmdScan(file) {
|
|
|
183
365
|
filesWithIssues++;
|
|
184
366
|
totalIssues += result.issues.length;
|
|
185
367
|
const relPath = path.relative(PROJECTS_DIR, f);
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
368
|
+
if (!asJson) {
|
|
369
|
+
console.log(`\x1b[33m${relPath}\x1b[0m`);
|
|
370
|
+
for (const issue of result.issues) {
|
|
371
|
+
console.log(` Line ${issue.line}: ${formatContentType(issue.contentType)} (~${formatBytes(issue.estimatedSize)})`);
|
|
372
|
+
}
|
|
189
373
|
}
|
|
374
|
+
summary.files.push({
|
|
375
|
+
file: relPath,
|
|
376
|
+
issues: result.issues.map((issue) => ({
|
|
377
|
+
line: issue.line,
|
|
378
|
+
type: issue.contentType,
|
|
379
|
+
location: issue.location,
|
|
380
|
+
size: formatBytes(issue.estimatedSize),
|
|
381
|
+
})),
|
|
382
|
+
});
|
|
190
383
|
}
|
|
191
384
|
}
|
|
192
385
|
catch {
|
|
@@ -194,6 +387,11 @@ async function cmdScan(file) {
|
|
|
194
387
|
}
|
|
195
388
|
}
|
|
196
389
|
console.log();
|
|
390
|
+
summary.totalIssues = totalIssues;
|
|
391
|
+
summary.filesWithIssues = filesWithIssues;
|
|
392
|
+
if (asJson) {
|
|
393
|
+
return summary;
|
|
394
|
+
}
|
|
197
395
|
if (totalIssues === 0) {
|
|
198
396
|
console.log("\x1b[32m✓ No oversized content found.\x1b[0m");
|
|
199
397
|
}
|
|
@@ -202,6 +400,100 @@ async function cmdScan(file) {
|
|
|
202
400
|
console.log("Run 'cct fix' to fix them.");
|
|
203
401
|
}
|
|
204
402
|
}
|
|
403
|
+
async function cmdWatch(asJson, intervalSeconds, autoFix) {
|
|
404
|
+
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
405
|
+
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
const effectiveSeconds = Number.isFinite(intervalSeconds) && intervalSeconds > 0 ? intervalSeconds : 15;
|
|
409
|
+
const intervalMs = Math.max(5, effectiveSeconds) * 1000;
|
|
410
|
+
const seen = new Map();
|
|
411
|
+
const logEvent = (event) => {
|
|
412
|
+
if (asJson) {
|
|
413
|
+
console.log(JSON.stringify(event));
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
const actionText = event.action === "fixed" ? "Fixed" : event.action === "error" ? "Error" : "Detected";
|
|
417
|
+
console.log(`[${event.timestamp}] ${actionText}: ${event.file} (${event.issues} issue(s))${event.details ? ` - ${event.details}` : ""}`);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
const checkFiles = async () => {
|
|
421
|
+
const files = findAllJsonlFiles(PROJECTS_DIR);
|
|
422
|
+
const active = new Set();
|
|
423
|
+
for (const file of files) {
|
|
424
|
+
active.add(file);
|
|
425
|
+
let stat;
|
|
426
|
+
try {
|
|
427
|
+
stat = fs.statSync(file);
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
const last = seen.get(file) || 0;
|
|
433
|
+
if (stat.mtimeMs <= last)
|
|
434
|
+
continue;
|
|
435
|
+
seen.set(file, stat.mtimeMs);
|
|
436
|
+
let result;
|
|
437
|
+
try {
|
|
438
|
+
result = scanFile(file);
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
if (result.issues.length === 0)
|
|
444
|
+
continue;
|
|
445
|
+
const relPath = path.relative(PROJECTS_DIR, file);
|
|
446
|
+
const eventBase = {
|
|
447
|
+
timestamp: new Date().toISOString(),
|
|
448
|
+
file: relPath,
|
|
449
|
+
issues: result.issues.length,
|
|
450
|
+
action: "detected",
|
|
451
|
+
};
|
|
452
|
+
if (autoFix) {
|
|
453
|
+
try {
|
|
454
|
+
const fixResult = fixFile(file);
|
|
455
|
+
if (fixResult.fixed) {
|
|
456
|
+
logEvent({ ...eventBase, action: "fixed" });
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
logEvent({ ...eventBase, action: "error", details: "No changes applied" });
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch (err) {
|
|
463
|
+
logEvent({ ...eventBase, action: "error", details: err instanceof Error ? err.message : String(err) });
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
logEvent(eventBase);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
for (const entry of Array.from(seen.keys())) {
|
|
471
|
+
if (!active.has(entry)) {
|
|
472
|
+
seen.delete(entry);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
await checkFiles();
|
|
477
|
+
if (!asJson) {
|
|
478
|
+
console.log(`Watching ${PROJECTS_DIR} every ${intervalMs / 1000}s. Press Ctrl+C to stop.`);
|
|
479
|
+
if (autoFix) {
|
|
480
|
+
console.log("Auto-fix is enabled. Backups will be created before changes.\n");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
setInterval(() => {
|
|
484
|
+
checkFiles().catch((err) => {
|
|
485
|
+
if (asJson) {
|
|
486
|
+
console.log(JSON.stringify({ timestamp: new Date().toISOString(), action: "error", details: err.message }));
|
|
487
|
+
}
|
|
488
|
+
else {
|
|
489
|
+
console.error("Watch error:", err);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}, intervalMs);
|
|
493
|
+
return new Promise(() => {
|
|
494
|
+
// Keep process alive until Ctrl+C
|
|
495
|
+
});
|
|
496
|
+
}
|
|
205
497
|
async function cmdFix(file, noBackup = false) {
|
|
206
498
|
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
207
499
|
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
@@ -471,7 +763,7 @@ async function cmdArchive(days, dryRun) {
|
|
|
471
763
|
console.log("\x1b[33mRun without --dry-run to archive these conversations.\x1b[0m\n");
|
|
472
764
|
}
|
|
473
765
|
}
|
|
474
|
-
async function cmdMaintenance(
|
|
766
|
+
async function cmdMaintenance(auto, schedule) {
|
|
475
767
|
if (schedule) {
|
|
476
768
|
console.log("Scheduled Maintenance Setup\n");
|
|
477
769
|
console.log("=== For macOS (launchd) ===");
|
|
@@ -493,6 +785,271 @@ async function cmdMaintenance(dryRun, auto, schedule) {
|
|
|
493
785
|
console.log("\x1b[33mRun with --auto to perform maintenance actions automatically.\x1b[0m\n");
|
|
494
786
|
}
|
|
495
787
|
}
|
|
788
|
+
async function cmdClean(dryRun, days, category) {
|
|
789
|
+
const analysis = analyzeClaudeStorage();
|
|
790
|
+
console.log(formatStorageReport(analysis));
|
|
791
|
+
const options = { dryRun: dryRun || true, days, categories: category ? [category] : undefined };
|
|
792
|
+
const targets = findCleanupTargets(undefined, options);
|
|
793
|
+
if (targets.length === 0) {
|
|
794
|
+
console.log("\x1b[32m✓ Nothing to clean.\x1b[0m\n");
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
const result = cleanClaudeDirectory(undefined, { ...options, dryRun });
|
|
798
|
+
console.log(formatCleanupReport(targets, result, dryRun));
|
|
799
|
+
}
|
|
800
|
+
async function cmdMcpValidate(test) {
|
|
801
|
+
const report = await diagnoseMcpServers({ test, projectDir: process.cwd() });
|
|
802
|
+
console.log(formatMcpDiagnosticReport(report));
|
|
803
|
+
}
|
|
804
|
+
async function cmdSessions(project) {
|
|
805
|
+
const sessions = listSessions(undefined, { project });
|
|
806
|
+
if (sessions.length === 0) {
|
|
807
|
+
console.log("No sessions found.\n");
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
console.log(formatSessionReport(sessions));
|
|
811
|
+
}
|
|
812
|
+
async function cmdRecover(sessionId, extract, repair) {
|
|
813
|
+
if (!sessionId) {
|
|
814
|
+
console.error("Usage: cct recover <session-id> [--extract] [--repair]");
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
const sessions = listSessions();
|
|
818
|
+
const session = sessions.find(s => s.id === sessionId || s.id.startsWith(sessionId));
|
|
819
|
+
if (!session) {
|
|
820
|
+
console.error(`Session not found: ${sessionId}`);
|
|
821
|
+
process.exit(1);
|
|
822
|
+
}
|
|
823
|
+
const diag = diagnoseSession(session.filePath);
|
|
824
|
+
console.log(formatSessionDiagnosticReport(diag));
|
|
825
|
+
if (repair) {
|
|
826
|
+
console.log("\nRepairing session...");
|
|
827
|
+
const result = repairSession(session.filePath);
|
|
828
|
+
if (result.success) {
|
|
829
|
+
console.log(`\x1b[32m✓ Repaired. Removed ${result.linesRemoved} invalid lines.\x1b[0m`);
|
|
830
|
+
if (result.backupPath)
|
|
831
|
+
console.log(` Backup: ${result.backupPath}`);
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
console.log(`\x1b[31m✗ Repair failed: ${result.error}\x1b[0m`);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
if (extract) {
|
|
838
|
+
console.log("\nExtracting session content...");
|
|
839
|
+
const content = extractSessionContent(session.filePath);
|
|
840
|
+
console.log(` User messages: ${content.userMessages.length}`);
|
|
841
|
+
console.log(` Assistant messages: ${content.assistantMessages.length}`);
|
|
842
|
+
console.log(` File edits: ${content.fileEdits.length}`);
|
|
843
|
+
console.log(` Commands run: ${content.commandsRun.length}`);
|
|
844
|
+
if (content.fileEdits.length > 0) {
|
|
845
|
+
console.log("\nFile edits:");
|
|
846
|
+
for (const edit of content.fileEdits.slice(0, 10)) {
|
|
847
|
+
console.log(` ${edit.path}`);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (content.commandsRun.length > 0) {
|
|
851
|
+
console.log("\nCommands:");
|
|
852
|
+
for (const cmd of content.commandsRun.slice(0, 10)) {
|
|
853
|
+
const short = cmd.length > 80 ? cmd.slice(0, 77) + "..." : cmd;
|
|
854
|
+
console.log(` $ ${short}`);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
async function cmdSecurityScan(file) {
|
|
860
|
+
console.log("Scanning for secrets in conversation data...\n");
|
|
861
|
+
const result = scanForSecrets(undefined, { file });
|
|
862
|
+
console.log(formatSecretsScanReport(result));
|
|
863
|
+
}
|
|
864
|
+
async function cmdPIIScan(file, details) {
|
|
865
|
+
console.log("Scanning for Personal Identifiable Information (PII)...\n");
|
|
866
|
+
if (details) {
|
|
867
|
+
console.log("\x1b[33m⚠ WARNING: Showing unmasked PII values. Handle with care!\x1b[0m\n");
|
|
868
|
+
}
|
|
869
|
+
const result = scanForPII(undefined, { file, includeFullValues: details });
|
|
870
|
+
console.log(formatPIIScanReport(result, details));
|
|
871
|
+
}
|
|
872
|
+
async function cmdAudit(sessionId) {
|
|
873
|
+
if (!sessionId) {
|
|
874
|
+
console.error("Usage: cct audit <session-id>");
|
|
875
|
+
process.exit(1);
|
|
876
|
+
}
|
|
877
|
+
const sessions = listSessions();
|
|
878
|
+
const session = sessions.find(s => s.id === sessionId || s.id.startsWith(sessionId));
|
|
879
|
+
if (!session) {
|
|
880
|
+
console.error(`Session not found: ${sessionId}`);
|
|
881
|
+
process.exit(1);
|
|
882
|
+
}
|
|
883
|
+
const audit = auditSession(session.filePath);
|
|
884
|
+
console.log(formatAuditReport(audit));
|
|
885
|
+
}
|
|
886
|
+
async function cmdRetention(days, dryRun) {
|
|
887
|
+
const retentionDays = days > 7 ? days : 30;
|
|
888
|
+
const result = enforceRetention(undefined, { days: retentionDays, dryRun });
|
|
889
|
+
console.log(formatRetentionReport(result));
|
|
890
|
+
}
|
|
891
|
+
async function cmdTrace(subcommand, options) {
|
|
892
|
+
if (!subcommand) {
|
|
893
|
+
const inv = inventoryTraces(undefined, { project: options?.project });
|
|
894
|
+
console.log(formatTraceInventory(inv));
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
if (subcommand === "clean") {
|
|
898
|
+
const cleanOpts = {
|
|
899
|
+
dryRun: options?.dryRun ?? true,
|
|
900
|
+
days: options?.days,
|
|
901
|
+
categories: options?.categories?.split(","),
|
|
902
|
+
project: options?.project,
|
|
903
|
+
};
|
|
904
|
+
const result = cleanTraces(undefined, cleanOpts);
|
|
905
|
+
console.log(formatTraceCleanReport(result));
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (subcommand === "wipe") {
|
|
909
|
+
if (!options?.confirm) {
|
|
910
|
+
console.log("\x1b[31m⚠ This will securely wipe ALL Claude Code traces.\x1b[0m");
|
|
911
|
+
console.log("Run with --confirm to execute.\n");
|
|
912
|
+
const inv = inventoryTraces();
|
|
913
|
+
console.log(`Would wipe: ${inv.totalFiles} files (${formatBytes(inv.totalSize)})`);
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const result = wipeAllTraces(undefined, {
|
|
917
|
+
confirm: true,
|
|
918
|
+
keepSettings: options.keepSettings,
|
|
919
|
+
});
|
|
920
|
+
console.log(result.wipeReceipt);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (subcommand === "guard") {
|
|
924
|
+
const mode = (options?.mode || "moderate");
|
|
925
|
+
const config = generateTraceGuardHooks({ mode });
|
|
926
|
+
console.log(formatTraceGuardConfig(config));
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
console.error(`Unknown trace subcommand: ${subcommand}`);
|
|
930
|
+
console.error("Usage: cct trace [clean|wipe|guard]");
|
|
931
|
+
}
|
|
932
|
+
async function cmdSearch(query, options) {
|
|
933
|
+
if (!query || query.length < 2) {
|
|
934
|
+
console.error("Usage: cct search <query> [--role user|assistant|all] [--limit n] [--project name]");
|
|
935
|
+
console.error("Query must be at least 2 characters.");
|
|
936
|
+
process.exit(1);
|
|
937
|
+
}
|
|
938
|
+
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
939
|
+
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
940
|
+
process.exit(1);
|
|
941
|
+
}
|
|
942
|
+
console.log(`Searching for "${query}"...\n`);
|
|
943
|
+
const searchOpts = {
|
|
944
|
+
query,
|
|
945
|
+
limit: options?.limit || 50,
|
|
946
|
+
role: options?.role || "all",
|
|
947
|
+
project: options?.project,
|
|
948
|
+
daysBack: options?.days,
|
|
949
|
+
};
|
|
950
|
+
const report = searchConversations(searchOpts);
|
|
951
|
+
console.log(formatSearchReport(report));
|
|
952
|
+
}
|
|
953
|
+
async function cmdCost() {
|
|
954
|
+
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
955
|
+
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
956
|
+
process.exit(1);
|
|
957
|
+
}
|
|
958
|
+
console.log("Calculating API cost estimates...\n");
|
|
959
|
+
const files = findAllJsonlFiles(PROJECTS_DIR);
|
|
960
|
+
let totalInputTokens = 0;
|
|
961
|
+
let totalOutputTokens = 0;
|
|
962
|
+
let sessionCount = 0;
|
|
963
|
+
const projectCosts = new Map();
|
|
964
|
+
for (const file of files) {
|
|
965
|
+
try {
|
|
966
|
+
const estimate = estimateContextSize(file);
|
|
967
|
+
const projectName = path.basename(path.dirname(file));
|
|
968
|
+
const b = estimate.breakdown;
|
|
969
|
+
const inputTokens = b.userTokens + b.systemTokens + b.toolUseTokens;
|
|
970
|
+
const outputTokens = b.assistantTokens + b.toolResultTokens;
|
|
971
|
+
if (!projectCosts.has(projectName)) {
|
|
972
|
+
projectCosts.set(projectName, { input: 0, output: 0, sessions: 0 });
|
|
973
|
+
}
|
|
974
|
+
const project = projectCosts.get(projectName);
|
|
975
|
+
project.input += inputTokens;
|
|
976
|
+
project.output += outputTokens;
|
|
977
|
+
project.sessions++;
|
|
978
|
+
totalInputTokens += inputTokens;
|
|
979
|
+
totalOutputTokens += outputTokens;
|
|
980
|
+
sessionCount++;
|
|
981
|
+
}
|
|
982
|
+
catch {
|
|
983
|
+
// Skip
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
const inputCostPerMillion = 15;
|
|
987
|
+
const outputCostPerMillion = 75;
|
|
988
|
+
const totalInputCost = (totalInputTokens / 1_000_000) * inputCostPerMillion;
|
|
989
|
+
const totalOutputCost = (totalOutputTokens / 1_000_000) * outputCostPerMillion;
|
|
990
|
+
const totalCost = totalInputCost + totalOutputCost;
|
|
991
|
+
console.log("API Cost Estimate (Claude Sonnet pricing)\n");
|
|
992
|
+
console.log("═".repeat(50));
|
|
993
|
+
console.log(`Sessions analyzed: ${sessionCount}`);
|
|
994
|
+
console.log(`\nToken Usage:`);
|
|
995
|
+
console.log(` Input tokens: ${totalInputTokens.toLocaleString()}`);
|
|
996
|
+
console.log(` Output tokens: ${totalOutputTokens.toLocaleString()}`);
|
|
997
|
+
console.log(` Total tokens: ${(totalInputTokens + totalOutputTokens).toLocaleString()}`);
|
|
998
|
+
console.log(`\nEstimated Cost:`);
|
|
999
|
+
console.log(` Input: $${totalInputCost.toFixed(2)} ($${inputCostPerMillion}/M tokens)`);
|
|
1000
|
+
console.log(` Output: $${totalOutputCost.toFixed(2)} ($${outputCostPerMillion}/M tokens)`);
|
|
1001
|
+
console.log(` \x1b[36mTotal: $${totalCost.toFixed(2)}\x1b[0m\n`);
|
|
1002
|
+
const sortedProjects = Array.from(projectCosts.entries())
|
|
1003
|
+
.sort((a, b) => (b[1].input + b[1].output) - (a[1].input + a[1].output))
|
|
1004
|
+
.slice(0, 10);
|
|
1005
|
+
if (sortedProjects.length > 0) {
|
|
1006
|
+
console.log("Top Projects by Token Usage:\n");
|
|
1007
|
+
for (const [name, data] of sortedProjects) {
|
|
1008
|
+
const projectTotal = data.input + data.output;
|
|
1009
|
+
const projectCost = ((data.input / 1_000_000) * inputCostPerMillion) + ((data.output / 1_000_000) * outputCostPerMillion);
|
|
1010
|
+
console.log(` ${name}`);
|
|
1011
|
+
console.log(` ${projectTotal.toLocaleString()} tokens (~$${projectCost.toFixed(2)}) - ${data.sessions} session(s)`);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
console.log("\n\x1b[33mNote: These are estimates based on stored conversation history.\x1b[0m");
|
|
1015
|
+
console.log("\x1b[33mActual costs depend on your API plan and usage patterns.\x1b[0m\n");
|
|
1016
|
+
}
|
|
1017
|
+
async function cmdDiff(sessionId1, sessionId2) {
|
|
1018
|
+
if (!sessionId1 || !sessionId2) {
|
|
1019
|
+
console.error("Usage: cct diff <session-id-1> <session-id-2>");
|
|
1020
|
+
console.error("Example: cct diff abc123 def456");
|
|
1021
|
+
process.exit(1);
|
|
1022
|
+
}
|
|
1023
|
+
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
1024
|
+
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
1025
|
+
process.exit(1);
|
|
1026
|
+
}
|
|
1027
|
+
const diff = compareSessionsByCID({ sessionId1, sessionId2 });
|
|
1028
|
+
if (!diff) {
|
|
1029
|
+
console.error("One or both sessions not found.");
|
|
1030
|
+
console.error("Use 'cct sessions' to list available sessions.");
|
|
1031
|
+
process.exit(1);
|
|
1032
|
+
}
|
|
1033
|
+
console.log(formatSessionDiff(diff));
|
|
1034
|
+
}
|
|
1035
|
+
async function cmdGit() {
|
|
1036
|
+
console.log("Linking sessions to git repositories...\n");
|
|
1037
|
+
const report = linkSessionsToGit();
|
|
1038
|
+
console.log(formatGitLinkReport(report));
|
|
1039
|
+
}
|
|
1040
|
+
async function cmdMcpPerf() {
|
|
1041
|
+
console.log("Analyzing MCP tool performance...\n");
|
|
1042
|
+
const report = analyzeMcpPerformance();
|
|
1043
|
+
console.log(formatMcpPerformanceReport(report));
|
|
1044
|
+
}
|
|
1045
|
+
async function cmdAlerts() {
|
|
1046
|
+
const report = checkAlerts();
|
|
1047
|
+
console.log(formatAlertsReport(report));
|
|
1048
|
+
}
|
|
1049
|
+
async function cmdQuotas() {
|
|
1050
|
+
const quotas = checkQuotas();
|
|
1051
|
+
console.log(formatQuotasReport(quotas));
|
|
1052
|
+
}
|
|
496
1053
|
async function cmdHealth() {
|
|
497
1054
|
if (!fs.existsSync(PROJECTS_DIR)) {
|
|
498
1055
|
console.error(`Claude projects directory not found: ${PROJECTS_DIR}`);
|
|
@@ -533,13 +1090,14 @@ async function cmdHealth() {
|
|
|
533
1090
|
}
|
|
534
1091
|
async function main() {
|
|
535
1092
|
const args = parseArgs(process.argv.slice(2));
|
|
1093
|
+
let commandResult;
|
|
536
1094
|
if (!args.command) {
|
|
537
1095
|
printHelp();
|
|
538
1096
|
process.exit(0);
|
|
539
1097
|
}
|
|
540
1098
|
switch (args.command) {
|
|
541
1099
|
case "scan":
|
|
542
|
-
await cmdScan(args.file);
|
|
1100
|
+
commandResult = await cmdScan(args.file, args.json);
|
|
543
1101
|
break;
|
|
544
1102
|
case "fix":
|
|
545
1103
|
await cmdFix(args.file, args.noBackup);
|
|
@@ -560,7 +1118,7 @@ async function main() {
|
|
|
560
1118
|
await cmdArchive(args.days, args.dryRun);
|
|
561
1119
|
break;
|
|
562
1120
|
case "maintenance":
|
|
563
|
-
await cmdMaintenance(args.
|
|
1121
|
+
await cmdMaintenance(args.auto, args.schedule);
|
|
564
1122
|
break;
|
|
565
1123
|
case "export":
|
|
566
1124
|
await cmdExport(args.file, args.output, args.format, args.withTools);
|
|
@@ -577,11 +1135,94 @@ async function main() {
|
|
|
577
1135
|
case "health":
|
|
578
1136
|
await cmdHealth();
|
|
579
1137
|
break;
|
|
1138
|
+
case "search":
|
|
1139
|
+
await cmdSearch(args.query, { role: args.role, limit: args.limit, project: args.project, days: args.days });
|
|
1140
|
+
break;
|
|
1141
|
+
case "cost":
|
|
1142
|
+
await cmdCost();
|
|
1143
|
+
break;
|
|
1144
|
+
case "clean":
|
|
1145
|
+
await cmdClean(args.dryRun, args.days, args.category);
|
|
1146
|
+
break;
|
|
1147
|
+
case "mcp-validate":
|
|
1148
|
+
await cmdMcpValidate(args.test);
|
|
1149
|
+
break;
|
|
1150
|
+
case "mcp-perf":
|
|
1151
|
+
await cmdMcpPerf();
|
|
1152
|
+
break;
|
|
1153
|
+
case "sessions":
|
|
1154
|
+
await cmdSessions(args.project);
|
|
1155
|
+
break;
|
|
1156
|
+
case "diff":
|
|
1157
|
+
await cmdDiff(args.file, args.subcommand);
|
|
1158
|
+
break;
|
|
1159
|
+
case "git":
|
|
1160
|
+
await cmdGit();
|
|
1161
|
+
break;
|
|
1162
|
+
case "recover":
|
|
1163
|
+
await cmdRecover(args.file, args.extract, args.repair);
|
|
1164
|
+
break;
|
|
1165
|
+
case "security-scan":
|
|
1166
|
+
await cmdSecurityScan(args.file);
|
|
1167
|
+
break;
|
|
1168
|
+
case "pii-scan":
|
|
1169
|
+
await cmdPIIScan(args.file, args.details);
|
|
1170
|
+
break;
|
|
1171
|
+
case "audit":
|
|
1172
|
+
await cmdAudit(args.file);
|
|
1173
|
+
break;
|
|
1174
|
+
case "retention":
|
|
1175
|
+
await cmdRetention(args.days, args.dryRun);
|
|
1176
|
+
break;
|
|
1177
|
+
case "alerts":
|
|
1178
|
+
await cmdAlerts();
|
|
1179
|
+
break;
|
|
1180
|
+
case "quotas":
|
|
1181
|
+
await cmdQuotas();
|
|
1182
|
+
break;
|
|
1183
|
+
case "trace":
|
|
1184
|
+
await cmdTrace(args.subcommand, {
|
|
1185
|
+
dryRun: args.dryRun,
|
|
1186
|
+
days: args.days,
|
|
1187
|
+
categories: args.categories,
|
|
1188
|
+
project: args.project,
|
|
1189
|
+
confirm: args.confirm,
|
|
1190
|
+
keepSettings: args.keepSettings,
|
|
1191
|
+
mode: args.mode,
|
|
1192
|
+
install: args.install,
|
|
1193
|
+
});
|
|
1194
|
+
break;
|
|
1195
|
+
case "watch":
|
|
1196
|
+
await cmdWatch(args.json, args.interval, args.autoFix);
|
|
1197
|
+
break;
|
|
1198
|
+
case "dashboard":
|
|
1199
|
+
if (args.stop) {
|
|
1200
|
+
const stopped = stopDashboard();
|
|
1201
|
+
if (stopped) {
|
|
1202
|
+
console.log("\x1b[32m✓ Dashboard stopped.\x1b[0m");
|
|
1203
|
+
}
|
|
1204
|
+
else {
|
|
1205
|
+
const status = isDashboardRunning();
|
|
1206
|
+
if (!status.running) {
|
|
1207
|
+
console.log("No dashboard process found.");
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
console.error("Failed to stop dashboard.");
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
else {
|
|
1215
|
+
await startDashboard({ port: args.port, daemon: args.daemon, authToken: args.token });
|
|
1216
|
+
}
|
|
1217
|
+
break;
|
|
580
1218
|
default:
|
|
581
1219
|
console.error(`Unknown command: ${args.command}`);
|
|
582
1220
|
printHelp();
|
|
583
1221
|
process.exit(1);
|
|
584
1222
|
}
|
|
1223
|
+
if (args.json && commandResult !== undefined) {
|
|
1224
|
+
console.log(JSON.stringify(commandResult, null, 2));
|
|
1225
|
+
}
|
|
585
1226
|
}
|
|
586
1227
|
main().catch((err) => {
|
|
587
1228
|
console.error("Error:", err.message);
|