ccjk 10.1.0 → 10.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 +28 -0
- package/dist/chunks/agent-teams.mjs +1 -1
- package/dist/chunks/agent.mjs +1 -1
- package/dist/chunks/api-providers.mjs +1 -1
- package/dist/chunks/api.mjs +3 -3
- package/dist/chunks/auto-bootstrap.mjs +1 -1
- package/dist/chunks/auto-updater.mjs +1 -1
- package/dist/{shared/ccjk.Br91zBIG.mjs → chunks/banner.mjs} +52 -3
- package/dist/chunks/boost.mjs +2 -2
- package/dist/chunks/ccjk-agents.mjs +1 -1
- package/dist/chunks/ccjk-all.mjs +1 -1
- package/dist/chunks/ccjk-config.mjs +1 -1
- package/dist/chunks/ccjk-hooks.mjs +1 -1
- package/dist/chunks/ccjk-mcp.mjs +2 -2
- package/dist/chunks/ccjk-setup.mjs +1 -1
- package/dist/chunks/ccjk-skills.mjs +1 -1
- package/dist/chunks/ccr.mjs +11 -10
- package/dist/chunks/ccu.mjs +1 -1
- package/dist/chunks/check-updates.mjs +4 -3
- package/dist/chunks/claude-code-config-manager.mjs +8 -7
- package/dist/chunks/claude-code-incremental-manager.mjs +3 -2
- package/dist/chunks/claude-config.mjs +3 -3
- package/dist/chunks/claude-wrapper.mjs +2 -2
- package/dist/chunks/codex-config-switch.mjs +3 -2
- package/dist/chunks/codex-provider-manager.mjs +3 -2
- package/dist/chunks/codex-uninstaller.mjs +2 -2
- package/dist/chunks/codex.mjs +5 -5
- package/dist/chunks/commands.mjs +88 -391
- package/dist/chunks/commands2.mjs +391 -88
- package/dist/chunks/completion.mjs +1 -1
- package/dist/chunks/config-consolidator.mjs +2 -2
- package/dist/chunks/config-switch.mjs +4 -3
- package/dist/chunks/config.mjs +6 -98
- package/dist/chunks/config2.mjs +411 -400
- package/dist/chunks/config3.mjs +401 -410
- package/dist/chunks/constants.mjs +1 -1
- package/dist/chunks/context.mjs +283 -1
- package/dist/chunks/dashboard.mjs +365 -0
- package/dist/chunks/doctor.mjs +4 -4
- package/dist/chunks/features.mjs +12 -11
- package/dist/chunks/fs-operations.mjs +1 -1
- package/dist/chunks/health-alerts.mjs +304 -0
- package/dist/chunks/health-check.mjs +532 -0
- package/dist/chunks/index.mjs +10 -177
- package/dist/chunks/index2.mjs +168 -1162
- package/dist/chunks/index3.mjs +1076 -910
- package/dist/chunks/index4.mjs +947 -137
- package/dist/chunks/index5.mjs +167 -635
- package/dist/chunks/index6.mjs +663 -0
- package/dist/chunks/init.mjs +19 -19
- package/dist/chunks/installer.mjs +649 -147
- package/dist/chunks/installer2.mjs +147 -649
- package/dist/chunks/interview.mjs +2 -2
- package/dist/chunks/marketplace.mjs +1 -1
- package/dist/chunks/mcp.mjs +5 -4
- package/dist/chunks/menu.mjs +22 -9
- package/dist/chunks/metrics-display.mjs +152 -0
- package/dist/chunks/migrator.mjs +1 -1
- package/dist/chunks/monitor.mjs +2 -2
- package/dist/chunks/notification.mjs +1 -1
- package/dist/chunks/onboarding.mjs +2 -2
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/permission-manager.mjs +2 -2
- package/dist/chunks/permissions.mjs +1 -1
- package/dist/chunks/persistence-manager.mjs +781 -0
- package/dist/chunks/persistence.mjs +667 -0
- package/dist/chunks/platform.mjs +1 -1
- package/dist/chunks/plugin.mjs +1 -1
- package/dist/chunks/prompts.mjs +1 -1
- package/dist/chunks/providers.mjs +1 -1
- package/dist/chunks/quick-actions.mjs +321 -0
- package/dist/chunks/quick-provider.mjs +2 -0
- package/dist/chunks/quick-setup.mjs +9 -8
- package/dist/chunks/silent-updater.mjs +1 -1
- package/dist/chunks/simple-config.mjs +3 -8
- package/dist/chunks/skill.mjs +1 -1
- package/dist/chunks/skills-sync.mjs +1 -1
- package/dist/chunks/skills.mjs +1 -1
- package/dist/chunks/slash-commands.mjs +208 -0
- package/dist/chunks/smart-defaults.mjs +1 -1
- package/dist/chunks/startup.mjs +1 -1
- package/dist/chunks/stats.mjs +1 -1
- package/dist/chunks/status.mjs +31 -2
- package/dist/chunks/team.mjs +1 -1
- package/dist/chunks/thinking.mjs +2 -2
- package/dist/chunks/uninstall.mjs +5 -5
- package/dist/chunks/update.mjs +8 -7
- package/dist/chunks/upgrade-manager.mjs +2 -2
- package/dist/chunks/version-checker.mjs +3 -3
- package/dist/chunks/vim.mjs +1 -1
- package/dist/chunks/zero-config.mjs +359 -0
- package/dist/cli.mjs +212 -21
- package/dist/i18n/locales/en/cli.json +14 -1
- package/dist/i18n/locales/en/common.json +27 -0
- package/dist/i18n/locales/en/configuration.json +33 -0
- package/dist/i18n/locales/en/context.json +54 -1
- package/dist/i18n/locales/en/dashboard.json +78 -0
- package/dist/i18n/locales/en/persistence.json +127 -0
- package/dist/i18n/locales/en/quick-actions.json +78 -0
- package/dist/i18n/locales/zh-CN/cli.json +14 -1
- package/dist/i18n/locales/zh-CN/common.json +27 -0
- package/dist/i18n/locales/zh-CN/configuration.json +33 -0
- package/dist/i18n/locales/zh-CN/context.json +54 -1
- package/dist/i18n/locales/zh-CN/dashboard.json +78 -0
- package/dist/i18n/locales/zh-CN/persistence.json +127 -0
- package/dist/i18n/locales/zh-CN/quick-actions.json +78 -0
- package/dist/index.mjs +3 -2
- package/dist/shared/{ccjk.DE91nClQ.mjs → ccjk.BKoi8-Hy.mjs} +1 -1
- package/dist/shared/ccjk.BiCrMV5O.mjs +94 -0
- package/dist/shared/{ccjk.Dpw86UX0.mjs → ccjk.CxtuJxaS.mjs} +1 -1
- package/dist/shared/{ccjk.ClzTOz9n.mjs → ccjk.DB2UYcq0.mjs} +5 -5
- package/dist/shared/{ccjk.CmsW23FN.mjs → ccjk.DVBW2wxp.mjs} +4 -3
- package/dist/shared/{ccjk.Bndhan7G.mjs → ccjk.DfwJOEok.mjs} +1 -1
- package/dist/shared/{ccjk.DvIrK0wz.mjs → ccjk.DrMygfCF.mjs} +1 -1
- package/package.json +19 -19
package/dist/chunks/doctor.mjs
CHANGED
|
@@ -5,14 +5,14 @@ import inquirer from 'inquirer';
|
|
|
5
5
|
import { resolve, join, dirname } from 'pathe';
|
|
6
6
|
import { getApiProviderPresets } from './api-providers.mjs';
|
|
7
7
|
import { SETTINGS_FILE, CLAUDE_DIR } from './constants.mjs';
|
|
8
|
-
import { i18n } from './
|
|
8
|
+
import { i18n } from './index2.mjs';
|
|
9
9
|
import { g as getPermissionManager } from '../shared/ccjk.h7_W-wTs.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import { h as commandExists } from './platform.mjs';
|
|
11
11
|
import { P as ProviderHealthMonitor } from '../shared/ccjk.J8YiPsOw.mjs';
|
|
12
12
|
import { platform, userInfo, homedir } from 'node:os';
|
|
13
13
|
import ora from 'ora';
|
|
14
14
|
import { exec } from 'tinyexec';
|
|
15
|
-
import {
|
|
15
|
+
import { STATUS } from './banner.mjs';
|
|
16
16
|
import { writeFileAtomic } from './fs-operations.mjs';
|
|
17
17
|
import 'node:url';
|
|
18
18
|
import 'i18next';
|
|
@@ -799,7 +799,7 @@ async function checkPermissionRules() {
|
|
|
799
799
|
}
|
|
800
800
|
async function fixSettingsFile() {
|
|
801
801
|
const isZh = i18n.language === "zh-CN";
|
|
802
|
-
const { copyConfigFiles } = await import('./config.mjs').then(function (n) { return n.
|
|
802
|
+
const { copyConfigFiles } = await import('./config.mjs').then(function (n) { return n.j; });
|
|
803
803
|
console.log("");
|
|
804
804
|
console.log(ansis.bold.cyan("\u{1F527} Fixing settings.json"));
|
|
805
805
|
console.log(ansis.dim("\u2500".repeat(50)));
|
package/dist/chunks/features.mjs
CHANGED
|
@@ -4,15 +4,15 @@ import process__default from 'node:process';
|
|
|
4
4
|
import ansis from 'ansis';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import { join } from 'pathe';
|
|
7
|
-
import {
|
|
7
|
+
import { d as selectMcpServices, g as getMcpServices } from './codex.mjs';
|
|
8
8
|
import { SUPPORTED_LANGS, LANG_LABELS } from './constants.mjs';
|
|
9
|
-
import { ensureI18nInitialized, i18n, changeLanguage } from './
|
|
9
|
+
import { ensureI18nInitialized, i18n, changeLanguage } from './index2.mjs';
|
|
10
10
|
import { updateZcfConfig, readZcfConfig } from './ccjk-config.mjs';
|
|
11
|
-
import { setupCcrConfiguration } from './
|
|
11
|
+
import { setupCcrConfiguration } from './config2.mjs';
|
|
12
12
|
import { a as isCcrInstalled, b as installCcr } from './init.mjs';
|
|
13
|
-
import { r as readMcpConfig, f as fixWindowsMcpConfig, w as writeMcpConfig, b as backupMcpConfig,
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
13
|
+
import { r as readMcpConfig, f as fixWindowsMcpConfig, w as writeMcpConfig, b as backupMcpConfig, a as buildMcpServerConfig, m as mergeMcpServers } from './claude-config.mjs';
|
|
14
|
+
import { a as applyAiLanguageDirective, g as getExistingModelConfig, u as updateCustomModel, d as updateDefaultModel, e as getExistingApiConfig, p as promptApiConfigurationAction, f as configureApi, s as switchToOfficialLogin } from './config.mjs';
|
|
15
|
+
import { c as configureOutputStyle, a as modifyApiConfigPartially, v as validateApiKey, f as formatApiKeyDisplay } from '../shared/ccjk.DVBW2wxp.mjs';
|
|
16
16
|
import { i as isWindows } from './platform.mjs';
|
|
17
17
|
import { a as addNumbersToChoices } from '../shared/ccjk.BFQ7yr5S.mjs';
|
|
18
18
|
import { openSettingsJson, importRecommendedPermissions, importRecommendedEnv } from './simple-config.mjs';
|
|
@@ -33,16 +33,17 @@ import 'node:child_process';
|
|
|
33
33
|
import 'i18next';
|
|
34
34
|
import 'i18next-fs-backend';
|
|
35
35
|
import 'node:util';
|
|
36
|
-
import '
|
|
36
|
+
import './banner.mjs';
|
|
37
37
|
import './auto-updater.mjs';
|
|
38
38
|
import './version-checker.mjs';
|
|
39
39
|
import 'node:path';
|
|
40
|
-
import '../shared/ccjk.
|
|
40
|
+
import '../shared/ccjk.CxtuJxaS.mjs';
|
|
41
41
|
import './smart-defaults.mjs';
|
|
42
42
|
import '../shared/ccjk.DKojSRzw.mjs';
|
|
43
|
-
import '../shared/ccjk.
|
|
44
|
-
import './
|
|
45
|
-
import '../shared/ccjk.
|
|
43
|
+
import '../shared/ccjk.DrMygfCF.mjs';
|
|
44
|
+
import './installer.mjs';
|
|
45
|
+
import '../shared/ccjk.BKoi8-Hy.mjs';
|
|
46
|
+
import '../shared/ccjk.BiCrMV5O.mjs';
|
|
46
47
|
import 'inquirer-toggle';
|
|
47
48
|
|
|
48
49
|
async function handleCancellation() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync, renameSync, unlinkSync,
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync, copyFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
3
|
import { mkdir, writeFile as writeFile$1, rename, unlink } from 'node:fs/promises';
|
|
4
4
|
import { dirname, join } from 'pathe';
|
|
5
5
|
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'pathe';
|
|
3
|
+
import { DatabaseHealthMonitor } from './health-check.mjs';
|
|
4
|
+
import 'better-sqlite3';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_CONFIG = {
|
|
7
|
+
silent: false,
|
|
8
|
+
walThresholdMB: 10,
|
|
9
|
+
diskUtilizationThreshold: 70,
|
|
10
|
+
backupAgeThresholdDays: 7,
|
|
11
|
+
enableHistory: true
|
|
12
|
+
};
|
|
13
|
+
class HealthAlertsManager {
|
|
14
|
+
monitor;
|
|
15
|
+
config;
|
|
16
|
+
historyPath;
|
|
17
|
+
dbPath;
|
|
18
|
+
constructor(dbPath, config) {
|
|
19
|
+
this.dbPath = dbPath;
|
|
20
|
+
this.monitor = new DatabaseHealthMonitor(dbPath);
|
|
21
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
22
|
+
this.historyPath = join(dirname(dbPath), "alert-history.json");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Run health checks and generate alerts
|
|
26
|
+
*/
|
|
27
|
+
async checkHealth() {
|
|
28
|
+
const alerts = [];
|
|
29
|
+
try {
|
|
30
|
+
const health = await this.monitor.runHealthCheck();
|
|
31
|
+
if (!health.checks.integrity.passed) {
|
|
32
|
+
alerts.push({
|
|
33
|
+
severity: "critical" /* CRITICAL */,
|
|
34
|
+
category: "corruption",
|
|
35
|
+
message: "Database corruption detected",
|
|
36
|
+
action: "Run: ccjk context recover",
|
|
37
|
+
timestamp: Date.now()
|
|
38
|
+
});
|
|
39
|
+
for (const error of health.checks.integrity.errors) {
|
|
40
|
+
alerts.push({
|
|
41
|
+
severity: "critical" /* CRITICAL */,
|
|
42
|
+
category: "corruption",
|
|
43
|
+
message: error,
|
|
44
|
+
timestamp: Date.now()
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const walSizeMB = health.checks.wal.walSize / (1024 * 1024);
|
|
49
|
+
if (walSizeMB > this.config.walThresholdMB) {
|
|
50
|
+
alerts.push({
|
|
51
|
+
severity: "warning" /* WARNING */,
|
|
52
|
+
category: "wal",
|
|
53
|
+
message: `WAL file is ${walSizeMB.toFixed(1)}MB (threshold: ${this.config.walThresholdMB}MB)`,
|
|
54
|
+
action: "Run: ccjk context checkpoint",
|
|
55
|
+
timestamp: Date.now()
|
|
56
|
+
});
|
|
57
|
+
} else if (walSizeMB > this.config.walThresholdMB / 2) {
|
|
58
|
+
alerts.push({
|
|
59
|
+
severity: "info" /* INFO */,
|
|
60
|
+
category: "wal",
|
|
61
|
+
message: `WAL file is ${walSizeMB.toFixed(1)}MB`,
|
|
62
|
+
action: "Consider checkpointing soon",
|
|
63
|
+
timestamp: Date.now()
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (health.checks.size.utilizationPercent < this.config.diskUtilizationThreshold) {
|
|
67
|
+
alerts.push({
|
|
68
|
+
severity: "warning" /* WARNING */,
|
|
69
|
+
category: "disk",
|
|
70
|
+
message: `Disk utilization is ${health.checks.size.utilizationPercent.toFixed(1)}% (threshold: ${this.config.diskUtilizationThreshold}%)`,
|
|
71
|
+
action: "Run: ccjk context vacuum",
|
|
72
|
+
timestamp: Date.now()
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const backupAlert = await this.checkBackupStatus();
|
|
76
|
+
if (backupAlert) {
|
|
77
|
+
alerts.push(backupAlert);
|
|
78
|
+
}
|
|
79
|
+
if (health.checks.performance.queryTime > 100) {
|
|
80
|
+
alerts.push({
|
|
81
|
+
severity: "warning" /* WARNING */,
|
|
82
|
+
category: "performance",
|
|
83
|
+
message: `Query performance is slow (${health.checks.performance.queryTime}ms)`,
|
|
84
|
+
action: "Check database indexes",
|
|
85
|
+
timestamp: Date.now()
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (this.config.enableHistory && alerts.length > 0) {
|
|
89
|
+
await this.logToHistory(alerts, health.status);
|
|
90
|
+
}
|
|
91
|
+
return alerts;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return [{
|
|
94
|
+
severity: "critical" /* CRITICAL */,
|
|
95
|
+
category: "corruption",
|
|
96
|
+
message: `Health check failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
97
|
+
timestamp: Date.now()
|
|
98
|
+
}];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check backup status
|
|
103
|
+
*/
|
|
104
|
+
async checkBackupStatus() {
|
|
105
|
+
try {
|
|
106
|
+
const backups = this.monitor.listBackups();
|
|
107
|
+
if (backups.length === 0) {
|
|
108
|
+
return {
|
|
109
|
+
severity: "warning" /* WARNING */,
|
|
110
|
+
category: "backup",
|
|
111
|
+
message: "No backups found",
|
|
112
|
+
action: "Run: ccjk context backup",
|
|
113
|
+
timestamp: Date.now()
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const latestBackup = backups[0];
|
|
117
|
+
const ageMs = Date.now() - latestBackup.metadata.timestamp;
|
|
118
|
+
const ageDays = ageMs / (1e3 * 60 * 60 * 24);
|
|
119
|
+
if (ageDays > this.config.backupAgeThresholdDays) {
|
|
120
|
+
return {
|
|
121
|
+
severity: "warning" /* WARNING */,
|
|
122
|
+
category: "backup",
|
|
123
|
+
message: `Latest backup is ${Math.floor(ageDays)} days old (threshold: ${this.config.backupAgeThresholdDays} days)`,
|
|
124
|
+
action: "Run: ccjk context backup",
|
|
125
|
+
timestamp: Date.now()
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (ageDays > this.config.backupAgeThresholdDays / 2) {
|
|
129
|
+
return {
|
|
130
|
+
severity: "info" /* INFO */,
|
|
131
|
+
category: "backup",
|
|
132
|
+
message: `Latest backup is ${Math.floor(ageDays)} days old`,
|
|
133
|
+
action: "Consider creating a new backup",
|
|
134
|
+
timestamp: Date.now()
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Display alerts with emoji indicators
|
|
144
|
+
*/
|
|
145
|
+
displayAlerts(alerts) {
|
|
146
|
+
if (alerts.length === 0) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
console.log("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
150
|
+
console.log("\u{1F4CA} Database Health Alerts");
|
|
151
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
152
|
+
const critical = alerts.filter((a) => a.severity === "critical" /* CRITICAL */);
|
|
153
|
+
const warnings = alerts.filter((a) => a.severity === "warning" /* WARNING */);
|
|
154
|
+
const info = alerts.filter((a) => a.severity === "info" /* INFO */);
|
|
155
|
+
if (critical.length > 0) {
|
|
156
|
+
for (const alert of critical) {
|
|
157
|
+
console.log(`\u{1F534} CRITICAL: ${alert.message}`);
|
|
158
|
+
if (alert.action) {
|
|
159
|
+
console.log(` \u2192 ${alert.action}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
console.log();
|
|
163
|
+
}
|
|
164
|
+
if (warnings.length > 0) {
|
|
165
|
+
for (const alert of warnings) {
|
|
166
|
+
console.log(`\u{1F7E1} WARNING: ${alert.message}`);
|
|
167
|
+
if (alert.action) {
|
|
168
|
+
console.log(` \u2192 ${alert.action}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
console.log();
|
|
172
|
+
}
|
|
173
|
+
if (info.length > 0) {
|
|
174
|
+
for (const alert of info) {
|
|
175
|
+
console.log(`\u{1F4A1} INFO: ${alert.message}`);
|
|
176
|
+
if (alert.action) {
|
|
177
|
+
console.log(` \u2192 ${alert.action}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
console.log();
|
|
181
|
+
}
|
|
182
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Log alerts to history
|
|
186
|
+
*/
|
|
187
|
+
async logToHistory(alerts, healthStatus) {
|
|
188
|
+
try {
|
|
189
|
+
const fs = await import('node:fs/promises');
|
|
190
|
+
let history = [];
|
|
191
|
+
if (existsSync(this.historyPath)) {
|
|
192
|
+
const content = await fs.readFile(this.historyPath, "utf-8");
|
|
193
|
+
history = JSON.parse(content);
|
|
194
|
+
}
|
|
195
|
+
history.unshift({
|
|
196
|
+
timestamp: Date.now(),
|
|
197
|
+
alerts,
|
|
198
|
+
healthStatus,
|
|
199
|
+
resolved: false
|
|
200
|
+
});
|
|
201
|
+
history = history.slice(0, 100);
|
|
202
|
+
await fs.writeFile(this.historyPath, JSON.stringify(history, null, 2));
|
|
203
|
+
} catch {
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Get alert history
|
|
208
|
+
*/
|
|
209
|
+
async getHistory(limit = 10) {
|
|
210
|
+
try {
|
|
211
|
+
if (!existsSync(this.historyPath)) {
|
|
212
|
+
return [];
|
|
213
|
+
}
|
|
214
|
+
const fs = await import('node:fs/promises');
|
|
215
|
+
const content = await fs.readFile(this.historyPath, "utf-8");
|
|
216
|
+
const history = JSON.parse(content);
|
|
217
|
+
return history.slice(0, limit);
|
|
218
|
+
} catch {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Mark alerts as resolved
|
|
224
|
+
*/
|
|
225
|
+
async markResolved(timestamp) {
|
|
226
|
+
try {
|
|
227
|
+
if (!existsSync(this.historyPath)) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const fs = await import('node:fs/promises');
|
|
231
|
+
const content = await fs.readFile(this.historyPath, "utf-8");
|
|
232
|
+
const history = JSON.parse(content);
|
|
233
|
+
const entry = history.find((e) => e.timestamp === timestamp);
|
|
234
|
+
if (entry) {
|
|
235
|
+
entry.resolved = true;
|
|
236
|
+
await fs.writeFile(this.historyPath, JSON.stringify(history, null, 2));
|
|
237
|
+
}
|
|
238
|
+
} catch {
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Clear alert history
|
|
243
|
+
*/
|
|
244
|
+
async clearHistory() {
|
|
245
|
+
try {
|
|
246
|
+
if (existsSync(this.historyPath)) {
|
|
247
|
+
const fs = await import('node:fs/promises');
|
|
248
|
+
await fs.unlink(this.historyPath);
|
|
249
|
+
}
|
|
250
|
+
} catch {
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get summary statistics
|
|
255
|
+
*/
|
|
256
|
+
async getSummary() {
|
|
257
|
+
const history = await this.getHistory(100);
|
|
258
|
+
if (history.length === 0) {
|
|
259
|
+
return {
|
|
260
|
+
totalAlerts: 0,
|
|
261
|
+
criticalCount: 0,
|
|
262
|
+
warningCount: 0,
|
|
263
|
+
infoCount: 0,
|
|
264
|
+
unresolvedCount: 0
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const unresolved = history.filter((e) => !e.resolved);
|
|
268
|
+
const allAlerts = unresolved.flatMap((e) => e.alerts);
|
|
269
|
+
return {
|
|
270
|
+
totalAlerts: allAlerts.length,
|
|
271
|
+
criticalCount: allAlerts.filter((a) => a.severity === "critical" /* CRITICAL */).length,
|
|
272
|
+
warningCount: allAlerts.filter((a) => a.severity === "warning" /* WARNING */).length,
|
|
273
|
+
infoCount: allAlerts.filter((a) => a.severity === "info" /* INFO */).length,
|
|
274
|
+
unresolvedCount: unresolved.length,
|
|
275
|
+
lastCheckTime: history[0]?.timestamp
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Close monitor
|
|
280
|
+
*/
|
|
281
|
+
close() {
|
|
282
|
+
this.monitor.close();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function runStartupHealthCheck(dbPath, config) {
|
|
286
|
+
if (!existsSync(dbPath)) {
|
|
287
|
+
return [];
|
|
288
|
+
}
|
|
289
|
+
if (config?.silent) {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
const manager = new HealthAlertsManager(dbPath, config);
|
|
293
|
+
try {
|
|
294
|
+
const alerts = await manager.checkHealth();
|
|
295
|
+
if (alerts.length > 0) {
|
|
296
|
+
manager.displayAlerts(alerts);
|
|
297
|
+
}
|
|
298
|
+
return alerts;
|
|
299
|
+
} finally {
|
|
300
|
+
manager.close();
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export { HealthAlertsManager, runStartupHealthCheck };
|