ccjk 12.2.2 → 12.3.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/dist/chunks/agent-teams.mjs +3 -3
- package/dist/chunks/agent.mjs +2 -2
- package/dist/chunks/agents.mjs +4 -5
- package/dist/chunks/api-cli.mjs +5 -5
- package/dist/chunks/api-providers.mjs +1 -1
- package/dist/chunks/api.mjs +4 -4
- package/dist/chunks/auto-bootstrap.mjs +1 -1
- package/dist/chunks/auto-fixer.mjs +3 -3
- package/dist/chunks/auto-init.mjs +3 -3
- package/dist/chunks/auto-updater.mjs +9 -9
- package/dist/chunks/banner.mjs +2 -2
- package/dist/chunks/boost.mjs +4 -4
- package/dist/chunks/ccjk-agents.mjs +3 -3
- package/dist/chunks/ccjk-all.mjs +6 -6
- package/dist/chunks/ccjk-config.mjs +2 -2
- package/dist/chunks/ccjk-hooks.mjs +4 -4
- package/dist/chunks/ccjk-mcp.mjs +5 -5
- package/dist/chunks/ccjk-setup.mjs +5 -5
- package/dist/chunks/ccjk-skills.mjs +5 -5
- package/dist/chunks/ccr.mjs +14 -14
- package/dist/chunks/ccu.mjs +2 -2
- package/dist/chunks/check-updates.mjs +6 -6
- package/dist/chunks/claude-code-config-manager.mjs +4 -4
- package/dist/chunks/claude-code-incremental-manager.mjs +6 -6
- package/dist/chunks/claude-config.mjs +1 -1
- package/dist/chunks/claude-wrapper.mjs +1 -1
- package/dist/chunks/cli-hook.mjs +9 -10
- package/dist/chunks/codex-config-switch.mjs +6 -6
- package/dist/chunks/codex-provider-manager.mjs +6 -6
- package/dist/chunks/codex-uninstaller.mjs +2 -2
- package/dist/chunks/codex.mjs +5 -5
- package/dist/chunks/commands.mjs +2 -2
- package/dist/chunks/commands2.mjs +1 -1
- package/dist/chunks/commit.mjs +2 -2
- package/dist/chunks/completion.mjs +2 -2
- package/dist/chunks/config-consolidator.mjs +2 -2
- package/dist/chunks/config-switch.mjs +7 -7
- package/dist/chunks/config.mjs +3 -3
- package/dist/chunks/config2.mjs +4 -4
- package/dist/chunks/config3.mjs +3 -3
- package/dist/chunks/constants.mjs +1 -1
- package/dist/chunks/context-opt.mjs +442 -0
- package/dist/chunks/convoy-manager.mjs +355 -3
- package/dist/chunks/dashboard.mjs +2 -2
- package/dist/chunks/doctor.mjs +4 -4
- package/dist/chunks/evolution.mjs +2 -2
- package/dist/chunks/health-alerts.mjs +530 -4
- package/dist/chunks/help.mjs +1 -1
- package/dist/chunks/index.mjs +0 -23
- package/dist/chunks/index10.mjs +571 -634
- package/dist/chunks/index11.mjs +569 -1061
- package/dist/chunks/index12.mjs +1076 -914
- package/dist/chunks/index13.mjs +951 -135
- package/dist/chunks/index14.mjs +184 -209
- package/dist/chunks/index15.mjs +218 -0
- package/dist/chunks/index2.mjs +24 -19
- package/dist/chunks/index3.mjs +12 -19085
- package/dist/chunks/index4.mjs +19092 -16
- package/dist/chunks/index5.mjs +16 -7602
- package/dist/chunks/index6.mjs +7590 -159
- package/dist/chunks/index7.mjs +171 -1602
- package/dist/chunks/index8.mjs +1602 -19
- package/dist/chunks/index9.mjs +15 -612
- package/dist/chunks/init.mjs +13 -13
- package/dist/chunks/installer.mjs +5 -5
- package/dist/chunks/installer2.mjs +1 -1
- package/dist/chunks/interview.mjs +4 -4
- package/dist/chunks/manager.mjs +1 -1
- package/dist/chunks/marketplace.mjs +2 -2
- package/dist/chunks/mcp-cli.mjs +9 -9
- package/dist/chunks/mcp.mjs +7 -7
- package/dist/chunks/memory.mjs +3 -3
- package/dist/chunks/menu-hierarchical.mjs +14 -14
- package/dist/chunks/menu.mjs +12 -12
- package/dist/chunks/metrics-display.mjs +1 -1
- package/dist/chunks/migrator.mjs +1 -1
- package/dist/chunks/monitor.mjs +2 -2
- package/dist/chunks/notification.mjs +4 -4
- package/dist/chunks/onboarding-wizard.mjs +2 -2
- package/dist/chunks/onboarding.mjs +4 -4
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/paradigm.mjs +1 -1
- package/dist/chunks/permission-manager.mjs +2 -2
- package/dist/chunks/permissions.mjs +3 -3
- package/dist/chunks/persistence-manager.mjs +3 -3
- package/dist/chunks/plugin.mjs +2 -2
- package/dist/chunks/prompts.mjs +5 -5
- package/dist/chunks/providers.mjs +2 -2
- package/dist/chunks/quick-actions.mjs +2 -2
- package/dist/chunks/quick-provider.mjs +6 -5
- package/dist/chunks/quick-setup.mjs +10 -10
- package/dist/chunks/remote.mjs +5 -5
- package/dist/chunks/session.mjs +2 -2
- package/dist/chunks/sessions.mjs +1 -1
- package/dist/chunks/silent-updater.mjs +1 -1
- package/dist/chunks/simple-config.mjs +1 -1
- package/dist/chunks/skill2.mjs +3 -3
- package/dist/chunks/skills-sync.mjs +4 -4
- package/dist/chunks/skills.mjs +3 -3
- package/dist/chunks/slash-commands.mjs +3 -3
- package/dist/chunks/startup.mjs +1 -1
- package/dist/chunks/stats.mjs +2 -2
- package/dist/chunks/status.mjs +2 -2
- package/dist/chunks/team.mjs +3 -3
- package/dist/chunks/thinking.mjs +4 -4
- package/dist/chunks/trace.mjs +2 -2
- package/dist/chunks/uninstall.mjs +8 -8
- package/dist/chunks/update.mjs +9 -9
- package/dist/chunks/upgrade-manager.mjs +3 -3
- package/dist/chunks/version-checker.mjs +4 -4
- package/dist/chunks/vim.mjs +3 -3
- package/dist/chunks/workflows.mjs +1 -1
- package/dist/chunks/wsl.mjs +1 -1
- package/dist/chunks/zero-config.mjs +3 -3
- package/dist/cli.mjs +56 -23
- package/dist/index.mjs +5 -5
- package/dist/shared/{ccjk.CCcQfbni.mjs → ccjk.B1TwPltj.mjs} +1 -1
- package/dist/shared/{ccjk.CePkJq2S.mjs → ccjk.BfIpomdz.mjs} +1 -1
- package/dist/shared/{ccjk.D8ZLYSZZ.mjs → ccjk.CXzjn01x.mjs} +1 -1
- package/dist/shared/{ccjk.Cjj8SVrn.mjs → ccjk.Cot9p9_n.mjs} +1 -1
- package/dist/shared/{ccjk.CvChMYvB.mjs → ccjk.DCw2WnZU.mjs} +1 -1
- package/dist/shared/{ccjk.DG_o24cZ.mjs → ccjk.DJdmgr2d.mjs} +1 -1
- package/dist/shared/{ccjk.BIxuVL3_.mjs → ccjk.DcKLglJQ.mjs} +2 -2
- package/dist/shared/{ccjk.DLLw-h4Y.mjs → ccjk.DfXjf8EC.mjs} +2 -2
- package/dist/shared/{ccjk.KpFl2RDA.mjs → ccjk.DpstNaeR.mjs} +3 -3
- package/dist/shared/{ccjk.DOBWBkFR.mjs → ccjk.XsJWJuQP.mjs} +5 -5
- package/dist/shared/{ccjk._dESH4Rk.mjs → ccjk.dYDLfmph.mjs} +1 -1
- package/dist/shared/{ccjk.DS7UESmF.mjs → ccjk.hrRv8G6j.mjs} +4 -4
- package/dist/shared/{ccjk.BWFpnOr3.mjs → ccjk.mJpVRDZ8.mjs} +1 -1
- package/dist/templates/claude-code/common/settings.json +3 -1
- package/package.json +20 -18
- package/templates/claude-code/common/settings.json +3 -1
- package/dist/chunks/context-loader.mjs +0 -351
- package/dist/chunks/context.mjs +0 -372
- package/dist/chunks/health-check.mjs +0 -532
|
@@ -1,7 +1,533 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import
|
|
3
|
-
import { j as join, d as dirname } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
4
|
-
|
|
1
|
+
import { existsSync, mkdirSync, statSync, copyFileSync, readdirSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
import { j as join, d as dirname, b as basename } from '../shared/ccjk.bQ7Dh1g4.mjs';
|
|
4
|
+
|
|
5
|
+
const CURRENT_SCHEMA_VERSION = 1;
|
|
6
|
+
class DatabaseHealthMonitor {
|
|
7
|
+
db;
|
|
8
|
+
dbPath;
|
|
9
|
+
backupDir;
|
|
10
|
+
constructor(dbPath) {
|
|
11
|
+
this.dbPath = dbPath;
|
|
12
|
+
this.backupDir = join(dirname(dbPath), "backups");
|
|
13
|
+
if (!existsSync(this.backupDir)) {
|
|
14
|
+
mkdirSync(this.backupDir, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
this.db = new Database(dbPath, { readonly: false });
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Run comprehensive health check
|
|
20
|
+
*/
|
|
21
|
+
async runHealthCheck() {
|
|
22
|
+
const errors = [];
|
|
23
|
+
const recommendations = [];
|
|
24
|
+
try {
|
|
25
|
+
const integrity = await this.checkIntegrity();
|
|
26
|
+
const wal = await this.checkWAL();
|
|
27
|
+
const size = await this.checkSize();
|
|
28
|
+
const performance = await this.checkPerformance();
|
|
29
|
+
recommendations.push(...wal.recommendations);
|
|
30
|
+
recommendations.push(...size.recommendations);
|
|
31
|
+
recommendations.push(...performance.recommendations);
|
|
32
|
+
let status = "healthy" /* HEALTHY */;
|
|
33
|
+
if (!integrity.passed) {
|
|
34
|
+
status = "critical" /* CRITICAL */;
|
|
35
|
+
errors.push("Database integrity check failed");
|
|
36
|
+
} else if (size.utilizationPercent < 50) {
|
|
37
|
+
status = "warning" /* WARNING */;
|
|
38
|
+
recommendations.push("Consider running VACUUM to reclaim space");
|
|
39
|
+
} else if (wal.walSize > 10 * 1024 * 1024) {
|
|
40
|
+
status = "warning" /* WARNING */;
|
|
41
|
+
recommendations.push("WAL file is large, consider checkpointing");
|
|
42
|
+
} else if (performance.queryTime > 100) {
|
|
43
|
+
status = "warning" /* WARNING */;
|
|
44
|
+
recommendations.push("Query performance is degraded");
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
status,
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
checks: {
|
|
50
|
+
integrity,
|
|
51
|
+
wal,
|
|
52
|
+
size,
|
|
53
|
+
performance
|
|
54
|
+
},
|
|
55
|
+
recommendations: [...new Set(recommendations)],
|
|
56
|
+
// Remove duplicates
|
|
57
|
+
errors
|
|
58
|
+
};
|
|
59
|
+
} catch (error) {
|
|
60
|
+
return {
|
|
61
|
+
status: "unknown" /* UNKNOWN */,
|
|
62
|
+
timestamp: Date.now(),
|
|
63
|
+
checks: {
|
|
64
|
+
integrity: { passed: false, errors: [String(error)], corruptedTables: [], duration: 0 },
|
|
65
|
+
wal: { mode: "unknown", walSize: 0, shmSize: 0, checkpointable: false, recommendations: [] },
|
|
66
|
+
size: { dbSize: 0, walSize: 0, totalSize: 0, pageCount: 0, pageSize: 0, freePages: 0, utilizationPercent: 0, recommendations: [] },
|
|
67
|
+
performance: { queryTime: 0, writeTime: 0, indexEfficiency: 0, cacheHitRate: 0, recommendations: [] }
|
|
68
|
+
},
|
|
69
|
+
recommendations: [],
|
|
70
|
+
errors: [`Health check failed: ${error instanceof Error ? error.message : String(error)}`]
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check database integrity
|
|
76
|
+
*/
|
|
77
|
+
async checkIntegrity() {
|
|
78
|
+
const startTime = Date.now();
|
|
79
|
+
const errors = [];
|
|
80
|
+
const corruptedTables = [];
|
|
81
|
+
try {
|
|
82
|
+
const result = this.db.prepare("PRAGMA integrity_check").all();
|
|
83
|
+
const passed = result.length === 1 && result[0].integrity_check === "ok";
|
|
84
|
+
if (!passed) {
|
|
85
|
+
for (const row of result) {
|
|
86
|
+
const msg = row.integrity_check;
|
|
87
|
+
errors.push(msg);
|
|
88
|
+
const tableMatch = msg.match(/table (\w+)/);
|
|
89
|
+
if (tableMatch) {
|
|
90
|
+
corruptedTables.push(tableMatch[1]);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const fkResult = this.db.prepare("PRAGMA foreign_key_check").all();
|
|
95
|
+
if (fkResult.length > 0) {
|
|
96
|
+
errors.push(`Foreign key violations found: ${fkResult.length}`);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
passed: passed && fkResult.length === 0,
|
|
100
|
+
errors,
|
|
101
|
+
corruptedTables: [...new Set(corruptedTables)],
|
|
102
|
+
duration: Date.now() - startTime
|
|
103
|
+
};
|
|
104
|
+
} catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
passed: false,
|
|
107
|
+
errors: [`Integrity check failed: ${error instanceof Error ? error.message : String(error)}`],
|
|
108
|
+
corruptedTables: [],
|
|
109
|
+
duration: Date.now() - startTime
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Check WAL status and recommend checkpoint if needed
|
|
115
|
+
*/
|
|
116
|
+
async checkWAL() {
|
|
117
|
+
const recommendations = [];
|
|
118
|
+
try {
|
|
119
|
+
const modeResult = this.db.prepare("PRAGMA journal_mode").get();
|
|
120
|
+
const mode = modeResult.journal_mode;
|
|
121
|
+
const walPath = `${this.dbPath}-wal`;
|
|
122
|
+
const shmPath = `${this.dbPath}-shm`;
|
|
123
|
+
const walSize = existsSync(walPath) ? statSync(walPath).size : 0;
|
|
124
|
+
const shmSize = existsSync(shmPath) ? statSync(shmPath).size : 0;
|
|
125
|
+
const checkpointable = walSize > 1024 * 1024;
|
|
126
|
+
if (checkpointable) {
|
|
127
|
+
recommendations.push("WAL file is large, run checkpoint to merge changes");
|
|
128
|
+
}
|
|
129
|
+
if (walSize > 10 * 1024 * 1024) {
|
|
130
|
+
recommendations.push("WAL file exceeds 10MB, immediate checkpoint recommended");
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
mode,
|
|
134
|
+
walSize,
|
|
135
|
+
shmSize,
|
|
136
|
+
checkpointable,
|
|
137
|
+
recommendations
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
mode: "unknown",
|
|
142
|
+
walSize: 0,
|
|
143
|
+
shmSize: 0,
|
|
144
|
+
checkpointable: false,
|
|
145
|
+
recommendations: [`WAL check failed: ${error instanceof Error ? error.message : String(error)}`]
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Checkpoint WAL to main database
|
|
151
|
+
*/
|
|
152
|
+
async checkpoint(mode = "RESTART") {
|
|
153
|
+
try {
|
|
154
|
+
const result = this.db.prepare(`PRAGMA wal_checkpoint(${mode})`).get();
|
|
155
|
+
return {
|
|
156
|
+
success: result.busy === 0,
|
|
157
|
+
walFrames: result.log,
|
|
158
|
+
checkpointed: result.checkpointed
|
|
159
|
+
};
|
|
160
|
+
} catch (error) {
|
|
161
|
+
return {
|
|
162
|
+
success: false,
|
|
163
|
+
walFrames: 0,
|
|
164
|
+
checkpointed: 0,
|
|
165
|
+
error: error instanceof Error ? error.message : String(error)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check database size and utilization
|
|
171
|
+
*/
|
|
172
|
+
async checkSize() {
|
|
173
|
+
const recommendations = [];
|
|
174
|
+
try {
|
|
175
|
+
const dbSize = existsSync(this.dbPath) ? statSync(this.dbPath).size : 0;
|
|
176
|
+
const walPath = `${this.dbPath}-wal`;
|
|
177
|
+
const walSize = existsSync(walPath) ? statSync(walPath).size : 0;
|
|
178
|
+
const pageCountResult = this.db.prepare("PRAGMA page_count").get();
|
|
179
|
+
const pageSizeResult = this.db.prepare("PRAGMA page_size").get();
|
|
180
|
+
const freePagesResult = this.db.prepare("PRAGMA freelist_count").get();
|
|
181
|
+
const pageCount = pageCountResult.page_count;
|
|
182
|
+
const pageSize = pageSizeResult.page_size;
|
|
183
|
+
const freePages = freePagesResult.freelist_count;
|
|
184
|
+
const utilizationPercent = pageCount > 0 ? (pageCount - freePages) / pageCount * 100 : 100;
|
|
185
|
+
if (utilizationPercent < 70) {
|
|
186
|
+
recommendations.push(`Database utilization is ${utilizationPercent.toFixed(1)}%, consider VACUUM`);
|
|
187
|
+
}
|
|
188
|
+
if (freePages > pageCount * 0.3) {
|
|
189
|
+
recommendations.push(`${freePages} free pages detected, VACUUM recommended`);
|
|
190
|
+
}
|
|
191
|
+
if (dbSize > 100 * 1024 * 1024) {
|
|
192
|
+
recommendations.push("Database exceeds 100MB, consider archiving old data");
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
dbSize,
|
|
196
|
+
walSize,
|
|
197
|
+
totalSize: dbSize + walSize,
|
|
198
|
+
pageCount,
|
|
199
|
+
pageSize,
|
|
200
|
+
freePages,
|
|
201
|
+
utilizationPercent,
|
|
202
|
+
recommendations
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
return {
|
|
206
|
+
dbSize: 0,
|
|
207
|
+
walSize: 0,
|
|
208
|
+
totalSize: 0,
|
|
209
|
+
pageCount: 0,
|
|
210
|
+
pageSize: 0,
|
|
211
|
+
freePages: 0,
|
|
212
|
+
utilizationPercent: 0,
|
|
213
|
+
recommendations: [`Size check failed: ${error instanceof Error ? error.message : String(error)}`]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Check database performance
|
|
219
|
+
*/
|
|
220
|
+
async checkPerformance() {
|
|
221
|
+
const recommendations = [];
|
|
222
|
+
try {
|
|
223
|
+
const queryStart = Date.now();
|
|
224
|
+
this.db.prepare("SELECT COUNT(*) FROM contexts").get();
|
|
225
|
+
const queryTime = Date.now() - queryStart;
|
|
226
|
+
const writeStart = Date.now();
|
|
227
|
+
this.db.prepare("BEGIN").run();
|
|
228
|
+
this.db.prepare("ROLLBACK").run();
|
|
229
|
+
const writeTime = Date.now() - writeStart;
|
|
230
|
+
const indexes = this.db.prepare(`
|
|
231
|
+
SELECT name FROM sqlite_master WHERE type = 'index' AND sql IS NOT NULL
|
|
232
|
+
`).all();
|
|
233
|
+
const indexEfficiency = indexes.length > 0 ? 100 : 0;
|
|
234
|
+
const cacheHitRate = 95;
|
|
235
|
+
if (queryTime > 50) {
|
|
236
|
+
recommendations.push("Query performance is slow, check indexes");
|
|
237
|
+
}
|
|
238
|
+
if (writeTime > 20) {
|
|
239
|
+
recommendations.push("Write performance is slow, consider optimizing");
|
|
240
|
+
}
|
|
241
|
+
if (indexes.length < 4) {
|
|
242
|
+
recommendations.push("Few indexes detected, query performance may be suboptimal");
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
queryTime,
|
|
246
|
+
writeTime,
|
|
247
|
+
indexEfficiency,
|
|
248
|
+
cacheHitRate,
|
|
249
|
+
recommendations
|
|
250
|
+
};
|
|
251
|
+
} catch (error) {
|
|
252
|
+
return {
|
|
253
|
+
queryTime: 0,
|
|
254
|
+
writeTime: 0,
|
|
255
|
+
indexEfficiency: 0,
|
|
256
|
+
cacheHitRate: 0,
|
|
257
|
+
recommendations: [`Performance check failed: ${error instanceof Error ? error.message : String(error)}`]
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Create database backup
|
|
263
|
+
*/
|
|
264
|
+
async backup(label) {
|
|
265
|
+
const startTime = Date.now();
|
|
266
|
+
try {
|
|
267
|
+
await this.checkpoint("FULL");
|
|
268
|
+
const timestamp = Date.now();
|
|
269
|
+
const dateStr = new Date(timestamp).toISOString().replace(/[:.]/g, "-");
|
|
270
|
+
const labelStr = label ? `-${label}` : "";
|
|
271
|
+
const backupFilename = `contexts-${dateStr}${labelStr}.db`;
|
|
272
|
+
const backupPath = join(this.backupDir, backupFilename);
|
|
273
|
+
copyFileSync(this.dbPath, backupPath);
|
|
274
|
+
const stats = this.db.prepare("SELECT COUNT(*) as count FROM contexts").get();
|
|
275
|
+
const projectStats = this.db.prepare("SELECT COUNT(*) as count FROM projects").get();
|
|
276
|
+
const dbSize = statSync(backupPath).size;
|
|
277
|
+
const metadata = {
|
|
278
|
+
timestamp,
|
|
279
|
+
dbSize,
|
|
280
|
+
contextCount: stats.count,
|
|
281
|
+
projectCount: projectStats.count,
|
|
282
|
+
version: String(CURRENT_SCHEMA_VERSION)
|
|
283
|
+
};
|
|
284
|
+
const metadataPath = `${backupPath}.meta.json`;
|
|
285
|
+
const fs = require("node:fs");
|
|
286
|
+
fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
|
|
287
|
+
await this.cleanupOldBackups(10);
|
|
288
|
+
return {
|
|
289
|
+
success: true,
|
|
290
|
+
backupPath,
|
|
291
|
+
metadata,
|
|
292
|
+
duration: Date.now() - startTime
|
|
293
|
+
};
|
|
294
|
+
} catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
success: false,
|
|
297
|
+
backupPath: "",
|
|
298
|
+
metadata: {
|
|
299
|
+
timestamp: Date.now(),
|
|
300
|
+
dbSize: 0,
|
|
301
|
+
contextCount: 0,
|
|
302
|
+
projectCount: 0,
|
|
303
|
+
version: String(CURRENT_SCHEMA_VERSION)
|
|
304
|
+
},
|
|
305
|
+
duration: Date.now() - startTime,
|
|
306
|
+
error: error instanceof Error ? error.message : String(error)
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Restore database from backup
|
|
312
|
+
*/
|
|
313
|
+
async restore(backupPath) {
|
|
314
|
+
const startTime = Date.now();
|
|
315
|
+
try {
|
|
316
|
+
if (!existsSync(backupPath)) {
|
|
317
|
+
throw new Error(`Backup file not found: ${backupPath}`);
|
|
318
|
+
}
|
|
319
|
+
const metadataPath = `${backupPath}.meta.json`;
|
|
320
|
+
let metadata;
|
|
321
|
+
if (existsSync(metadataPath)) {
|
|
322
|
+
const fs = require("node:fs");
|
|
323
|
+
metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
|
324
|
+
} else {
|
|
325
|
+
metadata = {
|
|
326
|
+
timestamp: statSync(backupPath).mtimeMs,
|
|
327
|
+
dbSize: statSync(backupPath).size,
|
|
328
|
+
contextCount: 0,
|
|
329
|
+
projectCount: 0,
|
|
330
|
+
version: String(CURRENT_SCHEMA_VERSION)
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
this.db.close();
|
|
334
|
+
const currentBackupPath = `${this.dbPath}.pre-restore-${Date.now()}.bak`;
|
|
335
|
+
if (existsSync(this.dbPath)) {
|
|
336
|
+
copyFileSync(this.dbPath, currentBackupPath);
|
|
337
|
+
}
|
|
338
|
+
copyFileSync(backupPath, this.dbPath);
|
|
339
|
+
this.db = new Database(this.dbPath);
|
|
340
|
+
const integrity = await this.checkIntegrity();
|
|
341
|
+
if (!integrity.passed) {
|
|
342
|
+
copyFileSync(currentBackupPath, this.dbPath);
|
|
343
|
+
this.db = new Database(this.dbPath);
|
|
344
|
+
throw new Error("Restored database failed integrity check");
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
success: true,
|
|
348
|
+
restoredFrom: backupPath,
|
|
349
|
+
metadata,
|
|
350
|
+
duration: Date.now() - startTime
|
|
351
|
+
};
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
success: false,
|
|
355
|
+
restoredFrom: backupPath,
|
|
356
|
+
metadata: {
|
|
357
|
+
timestamp: 0,
|
|
358
|
+
dbSize: 0,
|
|
359
|
+
contextCount: 0,
|
|
360
|
+
projectCount: 0,
|
|
361
|
+
version: String(CURRENT_SCHEMA_VERSION)
|
|
362
|
+
},
|
|
363
|
+
duration: Date.now() - startTime,
|
|
364
|
+
error: error instanceof Error ? error.message : String(error)
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* List available backups
|
|
370
|
+
*/
|
|
371
|
+
listBackups() {
|
|
372
|
+
const backups = [];
|
|
373
|
+
if (!existsSync(this.backupDir)) {
|
|
374
|
+
return backups;
|
|
375
|
+
}
|
|
376
|
+
const files = readdirSync(this.backupDir);
|
|
377
|
+
for (const file of files) {
|
|
378
|
+
if (file.endsWith(".db") && !file.endsWith(".bak")) {
|
|
379
|
+
const backupPath = join(this.backupDir, file);
|
|
380
|
+
const metadataPath = `${backupPath}.meta.json`;
|
|
381
|
+
let metadata;
|
|
382
|
+
if (existsSync(metadataPath)) {
|
|
383
|
+
const fs = require("node:fs");
|
|
384
|
+
metadata = JSON.parse(fs.readFileSync(metadataPath, "utf-8"));
|
|
385
|
+
} else {
|
|
386
|
+
metadata = {
|
|
387
|
+
timestamp: statSync(backupPath).mtimeMs,
|
|
388
|
+
dbSize: statSync(backupPath).size,
|
|
389
|
+
contextCount: 0,
|
|
390
|
+
projectCount: 0,
|
|
391
|
+
version: String(CURRENT_SCHEMA_VERSION)
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
backups.push({ path: backupPath, metadata });
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return backups.sort((a, b) => b.metadata.timestamp - a.metadata.timestamp);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Clean up old backups
|
|
401
|
+
*/
|
|
402
|
+
async cleanupOldBackups(keepCount) {
|
|
403
|
+
const backups = this.listBackups();
|
|
404
|
+
if (backups.length <= keepCount) {
|
|
405
|
+
return 0;
|
|
406
|
+
}
|
|
407
|
+
const toDelete = backups.slice(keepCount);
|
|
408
|
+
let deleted = 0;
|
|
409
|
+
for (const backup of toDelete) {
|
|
410
|
+
try {
|
|
411
|
+
unlinkSync(backup.path);
|
|
412
|
+
const metadataPath = `${backup.path}.meta.json`;
|
|
413
|
+
if (existsSync(metadataPath)) {
|
|
414
|
+
unlinkSync(metadataPath);
|
|
415
|
+
}
|
|
416
|
+
deleted++;
|
|
417
|
+
} catch {
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return deleted;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Attempt automatic recovery
|
|
424
|
+
*/
|
|
425
|
+
async attemptRecovery() {
|
|
426
|
+
const actions = [];
|
|
427
|
+
const errors = [];
|
|
428
|
+
try {
|
|
429
|
+
const integrity = await this.checkIntegrity();
|
|
430
|
+
if (!integrity.passed) {
|
|
431
|
+
const backups = this.listBackups();
|
|
432
|
+
if (backups.length > 0) {
|
|
433
|
+
actions.push("Database corruption detected, attempting restore from backup");
|
|
434
|
+
const restoreResult = await this.restore(backups[0].path);
|
|
435
|
+
if (restoreResult.success) {
|
|
436
|
+
actions.push(`Successfully restored from backup: ${basename(backups[0].path)}`);
|
|
437
|
+
return { success: true, actions, errors };
|
|
438
|
+
} else {
|
|
439
|
+
errors.push(`Restore failed: ${restoreResult.error}`);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
errors.push("No backups available for recovery");
|
|
443
|
+
}
|
|
444
|
+
return { success: false, actions, errors };
|
|
445
|
+
}
|
|
446
|
+
const wal = await this.checkWAL();
|
|
447
|
+
if (wal.checkpointable) {
|
|
448
|
+
actions.push("Checkpointing WAL");
|
|
449
|
+
const checkpointResult = await this.checkpoint("RESTART");
|
|
450
|
+
if (checkpointResult.success) {
|
|
451
|
+
actions.push(`Checkpointed ${checkpointResult.checkpointed} frames`);
|
|
452
|
+
} else {
|
|
453
|
+
errors.push(`Checkpoint failed: ${checkpointResult.error}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
const size = await this.checkSize();
|
|
457
|
+
if (size.utilizationPercent < 70) {
|
|
458
|
+
actions.push("Running VACUUM to reclaim space");
|
|
459
|
+
try {
|
|
460
|
+
this.db.prepare("VACUUM").run();
|
|
461
|
+
actions.push("VACUUM completed successfully");
|
|
462
|
+
} catch (error) {
|
|
463
|
+
errors.push(`VACUUM failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return {
|
|
467
|
+
success: errors.length === 0,
|
|
468
|
+
actions,
|
|
469
|
+
errors
|
|
470
|
+
};
|
|
471
|
+
} catch (error) {
|
|
472
|
+
errors.push(`Recovery failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
473
|
+
return { success: false, actions, errors };
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Get schema version
|
|
478
|
+
*/
|
|
479
|
+
getSchemaVersion() {
|
|
480
|
+
try {
|
|
481
|
+
const result = this.db.prepare("PRAGMA user_version").get();
|
|
482
|
+
return result.user_version;
|
|
483
|
+
} catch {
|
|
484
|
+
return 0;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Set schema version
|
|
489
|
+
*/
|
|
490
|
+
setSchemaVersion(version) {
|
|
491
|
+
this.db.prepare(`PRAGMA user_version = ${version}`).run();
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Apply migrations
|
|
495
|
+
*/
|
|
496
|
+
async applyMigrations(migrations) {
|
|
497
|
+
const applied = [];
|
|
498
|
+
const errors = [];
|
|
499
|
+
const currentVersion = this.getSchemaVersion();
|
|
500
|
+
const sortedMigrations = migrations.sort((a, b) => a.version - b.version);
|
|
501
|
+
for (const migration of sortedMigrations) {
|
|
502
|
+
if (migration.version <= currentVersion) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
await this.backup(`pre-migration-v${migration.version}`);
|
|
507
|
+
this.db.prepare("BEGIN").run();
|
|
508
|
+
migration.up(this.db);
|
|
509
|
+
this.setSchemaVersion(migration.version);
|
|
510
|
+
this.db.prepare("COMMIT").run();
|
|
511
|
+
applied.push(migration.version);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
this.db.prepare("ROLLBACK").run();
|
|
514
|
+
errors.push(`Migration v${migration.version} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
515
|
+
break;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
success: errors.length === 0,
|
|
520
|
+
applied,
|
|
521
|
+
errors
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Close database connection
|
|
526
|
+
*/
|
|
527
|
+
close() {
|
|
528
|
+
this.db.close();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
5
531
|
|
|
6
532
|
const DEFAULT_CONFIG = {
|
|
7
533
|
silent: false,
|
package/dist/chunks/help.mjs
CHANGED
package/dist/chunks/index.mjs
CHANGED
|
@@ -1,24 +1 @@
|
|
|
1
|
-
export { c as configureOfficialMode, a as configureSimpleMode, b as configureWithPreset, e as detectCurrentMode, d as displayCurrentStatus, g as getCurrentConfig, q as quickSetup, r as runConfigWizard, t as testApiConnection, v as validateApiKey } from '../shared/ccjk.DLLw-h4Y.mjs';
|
|
2
|
-
export { P as PROVIDER_PRESETS, g as getAllPresets, a as getChinesePresets, b as getPresetById, c as getRecommendedPresets } from '../shared/ccjk.CL4Yat0G.mjs';
|
|
3
|
-
import './index2.mjs';
|
|
4
|
-
import '../shared/ccjk.BAGoDD49.mjs';
|
|
5
|
-
import './index3.mjs';
|
|
6
|
-
import 'node:readline';
|
|
7
|
-
import 'stream';
|
|
8
|
-
import 'node:tty';
|
|
9
|
-
import 'node:process';
|
|
10
|
-
import 'node:async_hooks';
|
|
11
|
-
import '../shared/ccjk.Cjgrln_h.mjs';
|
|
12
|
-
import 'node:util';
|
|
13
|
-
import 'tty';
|
|
14
|
-
import 'fs';
|
|
15
|
-
import 'child_process';
|
|
16
|
-
import 'node:path';
|
|
17
|
-
import 'node:os';
|
|
18
|
-
import 'node:crypto';
|
|
19
|
-
import 'buffer';
|
|
20
|
-
import 'string_decoder';
|
|
21
1
|
import 'node:fs';
|
|
22
|
-
import './fs-operations.mjs';
|
|
23
|
-
import 'node:fs/promises';
|
|
24
|
-
import '../shared/ccjk.bQ7Dh1g4.mjs';
|