jinzd-ai-cli 0.4.218 → 0.4.219
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 -0
- package/dist/{batch-7V7OTMUP.js → batch-CHAPYRVM.js} +2 -2
- package/dist/chunk-3I4RZYYO.js +638 -0
- package/dist/{chunk-L4UREAID.js → chunk-4ZN6L6K5.js} +3 -3
- package/dist/{chunk-VGFTM3XT.js → chunk-64NUW3WL.js} +1 -1
- package/dist/{chunk-C2Z42DI5.js → chunk-EGMORH5W.js} +1 -1
- package/dist/{chunk-GX3HSGJX.js → chunk-GEN4O5QH.js} +165 -637
- package/dist/chunk-GGKQHPB3.js +604 -0
- package/dist/{chunk-P4VBLXKS.js → chunk-KIEZBTVD.js} +1 -1
- package/dist/{chunk-H2UIHGHH.js → chunk-QUFYBR6Q.js} +29 -189
- package/dist/{chunk-NTCB7CMT.js → chunk-U7KVU25H.js} +1 -1
- package/dist/{chunk-5CA2TJ5F.js → chunk-VADHBW7T.js} +1 -1
- package/dist/{ci-L6GH2WVC.js → ci-QPP66T53.js} +4 -4
- package/dist/{ci-format-WW7454AY.js → ci-format-5S3EEYRK.js} +2 -2
- package/dist/{constants-NCTFSHDU.js → constants-FJOLBABC.js} +1 -1
- package/dist/doctor-cli-KB2LUDF3.js +17 -0
- package/dist/electron-server.js +419 -116
- package/dist/{hub-CDL6T7CP.js → hub-DIM7SKKY.js} +1 -1
- package/dist/index.js +71 -181
- package/dist/{pr-D6PEKEGK.js → pr-YQGH72N6.js} +4 -4
- package/dist/{run-tests-SWU2XEV7.js → run-tests-GEZSSNJM.js} +2 -2
- package/dist/{run-tests-NXVVKAK2.js → run-tests-O76JIBCW.js} +1 -1
- package/dist/{server-LHYSS6CK.js → server-5E2AIXVX.js} +39 -75
- package/dist/{server-WUT7VYTD.js → server-Z6O3G2LY.js} +9 -9
- package/dist/{task-orchestrator-C5AA2BI5.js → task-orchestrator-5HBW4O64.js} +9 -9
- package/dist/{usage-6ZUUJBI2.js → usage-BMK6M5U3.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-MWKE2TNS.js +0 -129
- package/dist/chunk-OUC75QCF.js +0 -166
- package/dist/doctor-cli-EWMFBP5Q.js +0 -226
package/dist/electron-server.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
VERSION,
|
|
39
39
|
buildUserIdentityPrompt,
|
|
40
40
|
runTestsTool
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-EGMORH5W.js";
|
|
42
42
|
import {
|
|
43
43
|
hasSemanticIndex,
|
|
44
44
|
semanticSearch
|
|
@@ -64,8 +64,8 @@ import {
|
|
|
64
64
|
import express from "express";
|
|
65
65
|
import { createServer } from "http";
|
|
66
66
|
import { WebSocketServer } from "ws";
|
|
67
|
-
import { join as
|
|
68
|
-
import { existsSync as
|
|
67
|
+
import { join as join25, dirname as dirname8, resolve as resolve11, relative as relative4, sep as sep3 } from "path";
|
|
68
|
+
import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync15, statSync as statSync12, realpathSync } from "fs";
|
|
69
69
|
import { networkInterfaces } from "os";
|
|
70
70
|
|
|
71
71
|
// src/config/config-manager.ts
|
|
@@ -6629,6 +6629,21 @@ function flush() {
|
|
|
6629
6629
|
} catch {
|
|
6630
6630
|
}
|
|
6631
6631
|
}
|
|
6632
|
+
function getStatsSnapshot() {
|
|
6633
|
+
const s = ensureLoaded();
|
|
6634
|
+
return Object.values(s.entries).map((e) => ({ ...e }));
|
|
6635
|
+
}
|
|
6636
|
+
function getTopFailingTools(limit = 5) {
|
|
6637
|
+
return getStatsSnapshot().filter((e) => e.failures > 0).sort((a, b) => {
|
|
6638
|
+
const rateA = a.failures / Math.max(1, a.calls);
|
|
6639
|
+
const rateB = b.failures / Math.max(1, b.calls);
|
|
6640
|
+
if (rateB !== rateA) return rateB - rateA;
|
|
6641
|
+
return b.failures - a.failures;
|
|
6642
|
+
}).slice(0, limit);
|
|
6643
|
+
}
|
|
6644
|
+
function getTopUsedTools(limit = 5) {
|
|
6645
|
+
return getStatsSnapshot().sort((a, b) => b.calls - a.calls).slice(0, limit);
|
|
6646
|
+
}
|
|
6632
6647
|
|
|
6633
6648
|
// src/tools/action-classifier.ts
|
|
6634
6649
|
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "fs";
|
|
@@ -13586,8 +13601,8 @@ function loadContextFiles(options) {
|
|
|
13586
13601
|
}
|
|
13587
13602
|
|
|
13588
13603
|
// src/web/session-handler.ts
|
|
13589
|
-
import { existsSync as
|
|
13590
|
-
import { join as
|
|
13604
|
+
import { existsSync as existsSync28, readFileSync as readFileSync21, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync13, statSync as statSync11, createWriteStream } from "fs";
|
|
13605
|
+
import { join as join23, resolve as resolve10, dirname as dirname7 } from "path";
|
|
13591
13606
|
|
|
13592
13607
|
// src/cli/review-prompts.ts
|
|
13593
13608
|
function buildReviewPrompt(diff, gitContextStr, detailed) {
|
|
@@ -14232,6 +14247,334 @@ var DiscussionOrchestrator = class {
|
|
|
14232
14247
|
}
|
|
14233
14248
|
};
|
|
14234
14249
|
|
|
14250
|
+
// src/diagnostics/doctor-report.ts
|
|
14251
|
+
import { existsSync as existsSync27, statSync as statSync10 } from "fs";
|
|
14252
|
+
import { join as join21 } from "path";
|
|
14253
|
+
import { arch as arch2, platform as platform6, release as release2 } from "os";
|
|
14254
|
+
|
|
14255
|
+
// src/diagnostics/crash-log.ts
|
|
14256
|
+
import {
|
|
14257
|
+
existsSync as existsSync26,
|
|
14258
|
+
mkdirSync as mkdirSync12,
|
|
14259
|
+
readdirSync as readdirSync12,
|
|
14260
|
+
readFileSync as readFileSync20,
|
|
14261
|
+
statSync as statSync9,
|
|
14262
|
+
unlinkSync as unlinkSync5,
|
|
14263
|
+
writeFileSync as writeFileSync2
|
|
14264
|
+
} from "fs";
|
|
14265
|
+
import { join as join20 } from "path";
|
|
14266
|
+
import { homedir as homedir8, platform as platform5, release, arch } from "os";
|
|
14267
|
+
var LOGS_DIR_NAME = "logs";
|
|
14268
|
+
var CRASH_LOG_PREFIX = "crash-";
|
|
14269
|
+
function getLogsDir(configDir) {
|
|
14270
|
+
const base = configDir ?? join20(homedir8(), CONFIG_DIR_NAME);
|
|
14271
|
+
return join20(base, LOGS_DIR_NAME);
|
|
14272
|
+
}
|
|
14273
|
+
function truncate(s, n) {
|
|
14274
|
+
return s.length <= n ? s : s.slice(0, n) + "\u2026";
|
|
14275
|
+
}
|
|
14276
|
+
function listRecentCrashes(limit = 10, configDir) {
|
|
14277
|
+
const dir = getLogsDir(configDir);
|
|
14278
|
+
if (!existsSync26(dir)) return [];
|
|
14279
|
+
const files = [];
|
|
14280
|
+
let names;
|
|
14281
|
+
try {
|
|
14282
|
+
names = readdirSync12(dir);
|
|
14283
|
+
} catch {
|
|
14284
|
+
return [];
|
|
14285
|
+
}
|
|
14286
|
+
for (const name of names) {
|
|
14287
|
+
if (!name.startsWith(CRASH_LOG_PREFIX) || !name.endsWith(".log")) continue;
|
|
14288
|
+
const full = join20(dir, name);
|
|
14289
|
+
try {
|
|
14290
|
+
const st = statSync9(full);
|
|
14291
|
+
const head = readFileSync20(full, "utf-8").split("\n").slice(0, 20);
|
|
14292
|
+
const tsLine = head.find((l) => l.startsWith("timestamp:"));
|
|
14293
|
+
const kindLine = head.find((l) => l.startsWith("kind:"));
|
|
14294
|
+
const msgIdx = head.findIndex((l) => l.trim() === "## message");
|
|
14295
|
+
const message = msgIdx >= 0 && head[msgIdx + 1] ? head[msgIdx + 1] : "";
|
|
14296
|
+
files.push({
|
|
14297
|
+
file: full,
|
|
14298
|
+
timestamp: tsLine ? tsLine.replace("timestamp:", "").trim() : st.mtime.toISOString(),
|
|
14299
|
+
kind: kindLine ? kindLine.replace("kind:", "").trim() : "unknown",
|
|
14300
|
+
message: truncate(message, 200),
|
|
14301
|
+
sizeBytes: st.size
|
|
14302
|
+
});
|
|
14303
|
+
} catch {
|
|
14304
|
+
}
|
|
14305
|
+
}
|
|
14306
|
+
files.sort((a, b) => a.timestamp < b.timestamp ? 1 : -1);
|
|
14307
|
+
return files.slice(0, limit);
|
|
14308
|
+
}
|
|
14309
|
+
function getConfigDirUsage(configDir) {
|
|
14310
|
+
const base = configDir ?? join20(homedir8(), CONFIG_DIR_NAME);
|
|
14311
|
+
if (!existsSync26(base)) return { totalBytes: 0, entries: [] };
|
|
14312
|
+
const entries = [];
|
|
14313
|
+
let total = 0;
|
|
14314
|
+
let names;
|
|
14315
|
+
try {
|
|
14316
|
+
names = readdirSync12(base);
|
|
14317
|
+
} catch {
|
|
14318
|
+
return { totalBytes: 0, entries: [] };
|
|
14319
|
+
}
|
|
14320
|
+
for (const name of names) {
|
|
14321
|
+
const full = join20(base, name);
|
|
14322
|
+
const bytes = dirSize(full);
|
|
14323
|
+
entries.push({ name, bytes });
|
|
14324
|
+
total += bytes;
|
|
14325
|
+
}
|
|
14326
|
+
entries.sort((a, b) => b.bytes - a.bytes);
|
|
14327
|
+
return { totalBytes: total, entries };
|
|
14328
|
+
}
|
|
14329
|
+
function dirSize(path3) {
|
|
14330
|
+
try {
|
|
14331
|
+
const st = statSync9(path3);
|
|
14332
|
+
if (st.isFile()) return st.size;
|
|
14333
|
+
if (!st.isDirectory()) return 0;
|
|
14334
|
+
let sum = 0;
|
|
14335
|
+
for (const name of readdirSync12(path3)) {
|
|
14336
|
+
sum += dirSize(join20(path3, name));
|
|
14337
|
+
}
|
|
14338
|
+
return sum;
|
|
14339
|
+
} catch {
|
|
14340
|
+
return 0;
|
|
14341
|
+
}
|
|
14342
|
+
}
|
|
14343
|
+
|
|
14344
|
+
// src/diagnostics/doctor-report.ts
|
|
14345
|
+
function checkFile(label, path3) {
|
|
14346
|
+
const exists = existsSync27(path3);
|
|
14347
|
+
let sizeBytes = null;
|
|
14348
|
+
if (exists) {
|
|
14349
|
+
try {
|
|
14350
|
+
sizeBytes = statSync10(path3).size;
|
|
14351
|
+
} catch {
|
|
14352
|
+
}
|
|
14353
|
+
}
|
|
14354
|
+
return { label, path: path3, exists, sizeBytes };
|
|
14355
|
+
}
|
|
14356
|
+
function buildDoctorReport(options) {
|
|
14357
|
+
const config = options.config;
|
|
14358
|
+
const cwd = options.cwd ?? process.cwd();
|
|
14359
|
+
const configDir = config.getConfigDir();
|
|
14360
|
+
const projectRoot = getGitRoot(cwd) ?? cwd;
|
|
14361
|
+
const contextCfg = config.get("context");
|
|
14362
|
+
const contextSetting = config.get("contextFile");
|
|
14363
|
+
const context = loadContextFiles({
|
|
14364
|
+
cwd,
|
|
14365
|
+
configDir,
|
|
14366
|
+
projectRoot,
|
|
14367
|
+
setting: contextSetting,
|
|
14368
|
+
maxBytes: contextCfg.projectDocMaxBytes,
|
|
14369
|
+
fallbackFilenames: contextCfg.projectDocFallbackFilenames
|
|
14370
|
+
});
|
|
14371
|
+
const hooksConfig = config.get("hooks");
|
|
14372
|
+
const hooks = listHooks(hooksConfig, configDir);
|
|
14373
|
+
const pendingHooks = getPendingHookTrust(hooksConfig, configDir);
|
|
14374
|
+
const plugins = listInstalledPlugins(configDir);
|
|
14375
|
+
const activeAssets = getActivePluginAssets(configDir);
|
|
14376
|
+
const network = config.get("networkPolicy");
|
|
14377
|
+
const mcpServers = config.get("mcpServers");
|
|
14378
|
+
const allStats = getStatsSnapshot();
|
|
14379
|
+
return {
|
|
14380
|
+
version: VERSION,
|
|
14381
|
+
npmCheck: options.npmCheck,
|
|
14382
|
+
node: process.version,
|
|
14383
|
+
platform: `${platform6()} ${release2()} (${arch2()})`,
|
|
14384
|
+
cwd,
|
|
14385
|
+
projectRoot,
|
|
14386
|
+
configDir,
|
|
14387
|
+
providers: options.providers.listAll().map((p) => ({ id: p.id, displayName: p.displayName, configured: p.configured })),
|
|
14388
|
+
files: [
|
|
14389
|
+
checkFile("config.json", join21(configDir, "config.json")),
|
|
14390
|
+
checkFile("memory.md", join21(configDir, MEMORY_FILE_NAME)),
|
|
14391
|
+
checkFile("memory.jsonl", join21(configDir, "memory.jsonl")),
|
|
14392
|
+
checkFile("dev-state.md", join21(configDir, DEV_STATE_FILE_NAME)),
|
|
14393
|
+
checkFile("hooks-trust.json", join21(configDir, "hooks-trust.json")),
|
|
14394
|
+
checkFile("plugin-state.json", join21(configDir, "plugins", "plugin-state.json"))
|
|
14395
|
+
],
|
|
14396
|
+
context: {
|
|
14397
|
+
enabled: contextSetting !== false,
|
|
14398
|
+
setting: contextSetting,
|
|
14399
|
+
candidates: context.candidates,
|
|
14400
|
+
maxBytes: context.maxBytes,
|
|
14401
|
+
layers: context.layers.map((l) => ({ level: l.level, fileName: l.fileName, displayPath: l.displayPath, bytes: l.byteCount, chars: l.charCount, truncated: l.truncated })),
|
|
14402
|
+
skipped: context.skipped.map((s) => ({ level: s.level, fileName: s.fileName, displayPath: s.displayPath, reason: s.reason, message: s.message }))
|
|
14403
|
+
},
|
|
14404
|
+
permissions: {
|
|
14405
|
+
defaultProfile: config.get("defaultPermissionProfile"),
|
|
14406
|
+
allowedProfiles: config.get("allowedPermissionProfiles"),
|
|
14407
|
+
customProfileCount: Object.keys(config.get("permissionProfiles")).length,
|
|
14408
|
+
legacyDefaultAction: config.get("defaultPermission"),
|
|
14409
|
+
ruleCount: config.get("permissionRules").length
|
|
14410
|
+
},
|
|
14411
|
+
networkPolicy: {
|
|
14412
|
+
enabled: network.enabled,
|
|
14413
|
+
defaultAction: network.defaultAction,
|
|
14414
|
+
allowDomains: network.allowDomains.length,
|
|
14415
|
+
denyDomains: network.denyDomains.length,
|
|
14416
|
+
allowPorts: network.allowPorts.length,
|
|
14417
|
+
denyPorts: network.denyPorts.length,
|
|
14418
|
+
allowPrivateNetwork: network.allowPrivateNetwork,
|
|
14419
|
+
toolOverrides: Object.fromEntries(Object.entries(network.tools).filter(([, v]) => v !== void 0))
|
|
14420
|
+
},
|
|
14421
|
+
hooks: {
|
|
14422
|
+
enabled: hooksConfig?.enabled !== false,
|
|
14423
|
+
total: hooks.length,
|
|
14424
|
+
project: hooks.filter((h) => h.source === "project").length,
|
|
14425
|
+
pendingTrust: pendingHooks.length,
|
|
14426
|
+
disabled: hooks.filter((h) => h.disabled).length
|
|
14427
|
+
},
|
|
14428
|
+
plugins: {
|
|
14429
|
+
root: join21(configDir, "plugins"),
|
|
14430
|
+
installed: plugins.length,
|
|
14431
|
+
active: activeAssets.plugins.length,
|
|
14432
|
+
invalid: plugins.filter((p) => !p.valid).length,
|
|
14433
|
+
untrusted: plugins.filter((p) => p.valid && !p.trusted).length,
|
|
14434
|
+
disabled: plugins.filter((p) => p.valid && !p.enabled).length,
|
|
14435
|
+
mcpServers: Object.keys(activeAssets.mcpServers).length,
|
|
14436
|
+
skillDirs: activeAssets.skillDirs.length,
|
|
14437
|
+
commandDirs: activeAssets.commandDirs.length,
|
|
14438
|
+
agentDirs: activeAssets.agentDirs.length,
|
|
14439
|
+
entries: plugins.map((p) => ({ name: p.name, version: p.manifest.version, enabled: p.enabled, trusted: p.trusted, valid: p.valid, error: p.error }))
|
|
14440
|
+
},
|
|
14441
|
+
mcp: {
|
|
14442
|
+
enabled: config.get("mcpEnabled"),
|
|
14443
|
+
configured: Object.keys(mcpServers).length,
|
|
14444
|
+
projectConfigExists: existsSync27(join21(projectRoot, MCP_PROJECT_CONFIG_NAME)),
|
|
14445
|
+
statuses: options.mcpStatuses ?? []
|
|
14446
|
+
},
|
|
14447
|
+
recentCrashes: listRecentCrashes(5, configDir),
|
|
14448
|
+
diskUsage: getConfigDirUsage(configDir),
|
|
14449
|
+
toolStats: {
|
|
14450
|
+
totalCalls: allStats.reduce((a, b) => a + b.calls, 0),
|
|
14451
|
+
totalFailures: allStats.reduce((a, b) => a + b.failures, 0),
|
|
14452
|
+
topUsed: getTopUsedTools(5),
|
|
14453
|
+
topFailing: getTopFailingTools(5)
|
|
14454
|
+
}
|
|
14455
|
+
};
|
|
14456
|
+
}
|
|
14457
|
+
|
|
14458
|
+
// src/diagnostics/doctor-cli.ts
|
|
14459
|
+
function formatBytes(n) {
|
|
14460
|
+
if (n < 1024) return `${n} B`;
|
|
14461
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
14462
|
+
if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
14463
|
+
return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
14464
|
+
}
|
|
14465
|
+
function formatDoctorReport(report, ansi = true) {
|
|
14466
|
+
const wrap = (code, s) => ansi ? `${code}${s}\x1B[0m` : s;
|
|
14467
|
+
const B = (s) => wrap("\x1B[1m", s);
|
|
14468
|
+
const D = (s) => wrap("\x1B[2m", s);
|
|
14469
|
+
const G = (s) => wrap("\x1B[32m", s);
|
|
14470
|
+
const Y = (s) => wrap("\x1B[33m", s);
|
|
14471
|
+
const R = (s) => wrap("\x1B[31m", s);
|
|
14472
|
+
const out = [];
|
|
14473
|
+
out.push("");
|
|
14474
|
+
out.push(B("\u{1FA7A} AI-CLI Health Check"));
|
|
14475
|
+
out.push("");
|
|
14476
|
+
const nc = report.npmCheck;
|
|
14477
|
+
let versionLine = ` version: ${report.version}`;
|
|
14478
|
+
if (nc?.status === "up-to-date") versionLine += ` ${D("(latest on npm)")}`;
|
|
14479
|
+
else if (nc?.status === "outdated" && nc.latest) versionLine += ` ${Y(`\u2192 ${nc.latest} available`)} ${D("(npm i -g jinzd-ai-cli@latest)")}`;
|
|
14480
|
+
else if (nc?.status === "skipped") versionLine += ` ${D(`(npm check skipped: ${nc.reason ?? "unknown"})`)}`;
|
|
14481
|
+
out.push(versionLine);
|
|
14482
|
+
out.push(` node: ${report.node}`);
|
|
14483
|
+
out.push(` platform: ${report.platform}`);
|
|
14484
|
+
out.push(` cwd: ${report.cwd}`);
|
|
14485
|
+
out.push(` project: ${report.projectRoot}`);
|
|
14486
|
+
out.push(` config: ${report.configDir}`);
|
|
14487
|
+
out.push("");
|
|
14488
|
+
out.push(B("API Keys:"));
|
|
14489
|
+
for (const p of report.providers) {
|
|
14490
|
+
out.push(` ${p.configured ? G("\u2713") : D("\u25CB")} ${p.id.padEnd(14)} ${p.configured ? G("configured") : D("not configured")}`);
|
|
14491
|
+
}
|
|
14492
|
+
out.push("");
|
|
14493
|
+
out.push(B("Context Files:"));
|
|
14494
|
+
out.push(` status: ${report.context.enabled ? G("enabled") : D("disabled")} \xB7 max ${formatBytes(report.context.maxBytes)}`);
|
|
14495
|
+
if (report.context.layers.length === 0) out.push(` ${D("(no context files loaded)")}`);
|
|
14496
|
+
for (const l of report.context.layers) {
|
|
14497
|
+
out.push(` ${G("\u2713")} ${l.level.padEnd(7)} ${l.displayPath} ${D(`(${formatBytes(l.bytes)}${l.truncated ? ", truncated" : ""})`)}`);
|
|
14498
|
+
}
|
|
14499
|
+
if (report.context.skipped.length > 0) {
|
|
14500
|
+
out.push(` ${D("skipped:")}`);
|
|
14501
|
+
for (const s of report.context.skipped.slice(0, 5)) {
|
|
14502
|
+
out.push(` ${Y("!")} ${s.level}:${s.fileName} ${s.reason}${s.message ? ` \xB7 ${s.message}` : ""}`);
|
|
14503
|
+
}
|
|
14504
|
+
}
|
|
14505
|
+
out.push("");
|
|
14506
|
+
out.push(B("Permissions / Network:"));
|
|
14507
|
+
out.push(` profile: ${report.permissions.defaultProfile} \xB7 allowed ${report.permissions.allowedProfiles.join(", ")} \xB7 rules ${report.permissions.ruleCount} \xB7 custom profiles ${report.permissions.customProfileCount}`);
|
|
14508
|
+
const np = report.networkPolicy;
|
|
14509
|
+
out.push(` networkPolicy: ${np.enabled ? G("enabled") : D("disabled")} \xB7 default ${np.defaultAction} \xB7 allow ${np.allowDomains} domain(s)/${np.allowPorts} port(s) \xB7 deny ${np.denyDomains} domain(s)/${np.denyPorts} port(s) \xB7 private ${np.allowPrivateNetwork ? "allow" : "block/confirm"}`);
|
|
14510
|
+
const overrides = Object.entries(np.toolOverrides).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
14511
|
+
if (overrides) out.push(` tool overrides: ${overrides}`);
|
|
14512
|
+
out.push("");
|
|
14513
|
+
out.push(B("Hooks / Plugins:"));
|
|
14514
|
+
out.push(` hooks: ${report.hooks.enabled ? G("enabled") : D("disabled")} \xB7 total ${report.hooks.total} \xB7 project ${report.hooks.project} \xB7 pending trust ${report.hooks.pendingTrust} \xB7 disabled ${report.hooks.disabled}`);
|
|
14515
|
+
out.push(` plugins: installed ${report.plugins.installed} \xB7 active ${report.plugins.active} \xB7 disabled ${report.plugins.disabled} \xB7 untrusted ${report.plugins.untrusted} \xB7 invalid ${report.plugins.invalid}`);
|
|
14516
|
+
out.push(` plugin assets: ${report.plugins.skillDirs} skill dir(s), ${report.plugins.commandDirs} command dir(s), ${report.plugins.agentDirs} agent dir(s), ${report.plugins.mcpServers} MCP server(s)`);
|
|
14517
|
+
if (report.plugins.entries.length > 0) {
|
|
14518
|
+
for (const p of report.plugins.entries.slice(0, 5)) {
|
|
14519
|
+
const state2 = p.valid ? `${p.enabled ? "enabled" : "disabled"} \xB7 ${p.trusted ? "trusted" : "untrusted"}` : `invalid \xB7 ${p.error ?? ""}`;
|
|
14520
|
+
out.push(` ${p.valid ? G("\u2713") : R("\u2717")} ${p.name}@${p.version} ${D(state2)}`);
|
|
14521
|
+
}
|
|
14522
|
+
}
|
|
14523
|
+
out.push("");
|
|
14524
|
+
out.push(B("MCP Servers:"));
|
|
14525
|
+
out.push(` global configured: ${report.mcp.configured} \xB7 project .mcp.json: ${report.mcp.projectConfigExists ? "yes" : "no"} \xB7 mcpEnabled: ${report.mcp.enabled ? "true" : "false"}`);
|
|
14526
|
+
if (report.mcp.statuses.length === 0) out.push(` ${D("(no connected manager status in this mode)")}`);
|
|
14527
|
+
for (const s of report.mcp.statuses) {
|
|
14528
|
+
const state2 = s.connected ? `${G("connected")} \xB7 ${s.serverName} \xB7 ${s.toolCount} tools` : `${R("disconnected")}${s.error ? D(` \xB7 ${s.error}`) : ""}`;
|
|
14529
|
+
out.push(` ${s.connected ? G("\u2713") : R("\u2717")} ${s.serverId.padEnd(16)} ${state2}`);
|
|
14530
|
+
}
|
|
14531
|
+
out.push("");
|
|
14532
|
+
out.push(B("Config Files:"));
|
|
14533
|
+
for (const f of report.files) {
|
|
14534
|
+
const extra = f.exists && f.sizeBytes !== null ? ` ${D(`(${formatBytes(f.sizeBytes)})`)}` : "";
|
|
14535
|
+
out.push(` ${f.exists ? G("\u2713") : D("\u2013")} ${f.label.padEnd(16)} ${f.exists ? f.path : D("(not found)")}${extra}`);
|
|
14536
|
+
}
|
|
14537
|
+
out.push("");
|
|
14538
|
+
out.push(B("Recent Crashes (last 5):"));
|
|
14539
|
+
if (report.recentCrashes.length === 0) out.push(` ${D("(none - clean!)")}`);
|
|
14540
|
+
for (const c of report.recentCrashes) {
|
|
14541
|
+
out.push(` ${R("\u2717")} ${c.timestamp} ${Y(c.kind)}`);
|
|
14542
|
+
out.push(` ${D(c.message)}`);
|
|
14543
|
+
out.push(` ${D(c.file)}`);
|
|
14544
|
+
}
|
|
14545
|
+
out.push("");
|
|
14546
|
+
const ts = report.toolStats;
|
|
14547
|
+
out.push(B("Tool Usage:"));
|
|
14548
|
+
out.push(` total: ${ts.totalCalls} calls \xB7 ${ts.totalFailures} failures (${ts.totalCalls ? (ts.totalFailures * 100 / ts.totalCalls).toFixed(1) : "0.0"}%)`);
|
|
14549
|
+
if (ts.topUsed.length > 0) {
|
|
14550
|
+
out.push(` ${D("top used:")}`);
|
|
14551
|
+
for (const t of ts.topUsed) out.push(` ${t.name.padEnd(20)} ${String(t.calls).padStart(6)} calls \xB7 avg ${t.calls ? (t.totalDurationMs / t.calls).toFixed(0) : "0"}ms`);
|
|
14552
|
+
}
|
|
14553
|
+
if (ts.topFailing.length > 0) {
|
|
14554
|
+
out.push(` ${D("top failing:")}`);
|
|
14555
|
+
for (const t of ts.topFailing) out.push(` ${R(t.name.padEnd(20))} ${t.failures}/${t.calls} (${(t.failures * 100 / Math.max(1, t.calls)).toFixed(1)}%) ${D(t.lastFailureMessage ?? "")}`.slice(0, 200));
|
|
14556
|
+
}
|
|
14557
|
+
out.push("");
|
|
14558
|
+
const dirAnnotations = {
|
|
14559
|
+
models: "semantic search model -> /index semantic-clear",
|
|
14560
|
+
index: "symbol index -> /index clear",
|
|
14561
|
+
history: "conversation history",
|
|
14562
|
+
logs: "crash logs",
|
|
14563
|
+
"memory-index": "chat memory index -> /memory index-clear",
|
|
14564
|
+
plugins: "installed package plugins"
|
|
14565
|
+
};
|
|
14566
|
+
out.push(B("Disk Usage (~/.aicli):"));
|
|
14567
|
+
out.push(` total: ${formatBytes(report.diskUsage.totalBytes)}`);
|
|
14568
|
+
for (const e of report.diskUsage.entries.slice(0, 10)) {
|
|
14569
|
+
const note = dirAnnotations[e.name];
|
|
14570
|
+
out.push(` ${e.name.padEnd(18)} ${formatBytes(e.bytes)}${note ? ` ${D(`\xB7 ${note}`)}` : ""}`);
|
|
14571
|
+
}
|
|
14572
|
+
out.push("");
|
|
14573
|
+
out.push(G("\u2713 Health check complete"));
|
|
14574
|
+
out.push("");
|
|
14575
|
+
return out.join("\n");
|
|
14576
|
+
}
|
|
14577
|
+
|
|
14235
14578
|
// src/hub/presets.ts
|
|
14236
14579
|
var PRESETS = [
|
|
14237
14580
|
{
|
|
@@ -14419,7 +14762,7 @@ function resolveRoleProviders(roles, lookup, defaultProvider, defaultModel, avai
|
|
|
14419
14762
|
}
|
|
14420
14763
|
|
|
14421
14764
|
// src/hub/persist.ts
|
|
14422
|
-
import { join as
|
|
14765
|
+
import { join as join22 } from "path";
|
|
14423
14766
|
function discussionToMessages(state2) {
|
|
14424
14767
|
const out = [];
|
|
14425
14768
|
const t0 = state2.messages[0]?.timestamp ?? /* @__PURE__ */ new Date();
|
|
@@ -14457,7 +14800,7 @@ async function persistDiscussion(state2, config, defaultProvider, defaultModel)
|
|
|
14457
14800
|
session.title = `[Hub] ${state2.topic.slice(0, 48)}`.replace(/\n/g, " ");
|
|
14458
14801
|
session.titleAiGenerated = true;
|
|
14459
14802
|
await sm.save();
|
|
14460
|
-
return { id: session.id, path:
|
|
14803
|
+
return { id: session.id, path: join22(config.getHistoryDir(), `${session.id}.json`) };
|
|
14461
14804
|
}
|
|
14462
14805
|
|
|
14463
14806
|
// src/web/session-handler.ts
|
|
@@ -15174,7 +15517,7 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
|
|
|
15174
15517
|
this.send({ type: "response_done", content, usage });
|
|
15175
15518
|
if (pendingTeeSave && isCleanDocumentBody(content)) {
|
|
15176
15519
|
try {
|
|
15177
|
-
|
|
15520
|
+
mkdirSync13(dirname7(pendingTeeSave), { recursive: true });
|
|
15178
15521
|
const bodyToSave = stripOuterCodeFence(content);
|
|
15179
15522
|
atomicWriteFileSync(pendingTeeSave, bodyToSave);
|
|
15180
15523
|
undoStack.push(pendingTeeSave, `save_last_response (deferred): ${pendingTeeSave}`);
|
|
@@ -15350,7 +15693,7 @@ ${summaryContent}`,
|
|
|
15350
15693
|
let isError = false;
|
|
15351
15694
|
let summary;
|
|
15352
15695
|
try {
|
|
15353
|
-
|
|
15696
|
+
mkdirSync13(dirname7(saveToFile), { recursive: true });
|
|
15354
15697
|
fileStream = createWriteStream(saveToFile);
|
|
15355
15698
|
const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
|
|
15356
15699
|
const teeExtraMessages = extraMessages.length > 0 ? [...extraMessages, { role: "user", content: TEE_FINAL_USER_NUDGE }] : [{ role: "user", content: TEE_FINAL_USER_NUDGE }];
|
|
@@ -16039,9 +16382,9 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
16039
16382
|
let modifiedFiles = 0;
|
|
16040
16383
|
const diffLines2 = [];
|
|
16041
16384
|
for (const [filePath, { earliest }] of fileMap) {
|
|
16042
|
-
const currentContent =
|
|
16385
|
+
const currentContent = existsSync28(filePath) ? (() => {
|
|
16043
16386
|
try {
|
|
16044
|
-
return
|
|
16387
|
+
return readFileSync21(filePath, "utf-8");
|
|
16045
16388
|
} catch {
|
|
16046
16389
|
return null;
|
|
16047
16390
|
}
|
|
@@ -16557,7 +16900,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
16557
16900
|
case "test": {
|
|
16558
16901
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
16559
16902
|
try {
|
|
16560
|
-
const { executeTests } = await import("./run-tests-
|
|
16903
|
+
const { executeTests } = await import("./run-tests-O76JIBCW.js");
|
|
16561
16904
|
const argStr = args.join(" ").trim();
|
|
16562
16905
|
let testArgs = {};
|
|
16563
16906
|
if (argStr) {
|
|
@@ -16574,9 +16917,9 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
16574
16917
|
// ── /init ───────────────────────────────────────────────────────
|
|
16575
16918
|
case "init": {
|
|
16576
16919
|
const cwd = process.cwd();
|
|
16577
|
-
const targetPath =
|
|
16920
|
+
const targetPath = join23(cwd, "AICLI.md");
|
|
16578
16921
|
const force = args.includes("--force");
|
|
16579
|
-
if (
|
|
16922
|
+
if (existsSync28(targetPath) && !force) {
|
|
16580
16923
|
this.send({ type: "info", message: `AICLI.md already exists at ${targetPath}
|
|
16581
16924
|
Use /init --force to overwrite.` });
|
|
16582
16925
|
break;
|
|
@@ -16586,7 +16929,7 @@ Use /init --force to overwrite.` });
|
|
|
16586
16929
|
const projectInfo = scanProject(cwd);
|
|
16587
16930
|
const prompt = buildInitPrompt(projectInfo, cwd);
|
|
16588
16931
|
const content = await this.chatOnce(prompt, { temperature: 0.3, maxTokens: 4096 });
|
|
16589
|
-
|
|
16932
|
+
writeFileSync3(targetPath, content, "utf-8");
|
|
16590
16933
|
this.send({ type: "info", message: `\u2713 Generated: ${targetPath} (${content.length} chars)
|
|
16591
16934
|
Use /context reload to load it.` });
|
|
16592
16935
|
} catch (err) {
|
|
@@ -16596,53 +16939,13 @@ Use /context reload to load it.` });
|
|
|
16596
16939
|
}
|
|
16597
16940
|
// ── /doctor ─────────────────────────────────────────────────────
|
|
16598
16941
|
case "doctor": {
|
|
16599
|
-
const
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
}
|
|
16607
|
-
lines.push("");
|
|
16608
|
-
const configDir = this.config.getConfigDir();
|
|
16609
|
-
lines.push("**Config Files:**");
|
|
16610
|
-
lines.push(` Dir: ${configDir}`);
|
|
16611
|
-
const checkFile = (label, filePath) => {
|
|
16612
|
-
const exists = existsSync26(filePath);
|
|
16613
|
-
let extra = "";
|
|
16614
|
-
if (exists) {
|
|
16615
|
-
try {
|
|
16616
|
-
extra = ` (${statSync9(filePath).size} bytes)`;
|
|
16617
|
-
} catch {
|
|
16618
|
-
}
|
|
16619
|
-
}
|
|
16620
|
-
lines.push(` ${exists ? "\u2713" : "\u2013"} ${label.padEnd(14)} ${exists ? filePath + extra : "(not found)"}`);
|
|
16621
|
-
};
|
|
16622
|
-
checkFile("config.json", join21(configDir, "config.json"));
|
|
16623
|
-
checkFile("memory.md", join21(configDir, MEMORY_FILE_NAME));
|
|
16624
|
-
checkFile("dev-state.md", join21(configDir, "dev-state.md"));
|
|
16625
|
-
lines.push("");
|
|
16626
|
-
if (this.mcpManager) {
|
|
16627
|
-
lines.push("**MCP Servers:**");
|
|
16628
|
-
const statuses = this.mcpManager.getStatus();
|
|
16629
|
-
if (statuses.length === 0) {
|
|
16630
|
-
lines.push(" (no servers configured)");
|
|
16631
|
-
} else {
|
|
16632
|
-
for (const s of statuses) {
|
|
16633
|
-
const state2 = s.connected ? `connected \xB7 ${s.serverName} \xB7 ${s.toolCount} tools` : `disconnected${s.error ? ` \xB7 ${s.error}` : ""}`;
|
|
16634
|
-
lines.push(` ${s.connected ? "\u2713" : "\u2717"} ${s.serverId.padEnd(16)} ${state2}`);
|
|
16635
|
-
}
|
|
16636
|
-
}
|
|
16637
|
-
lines.push("");
|
|
16638
|
-
}
|
|
16639
|
-
lines.push("**Current Session:**");
|
|
16640
|
-
lines.push(` Provider: ${this.currentProvider}`);
|
|
16641
|
-
lines.push(` Model: ${this.currentModel}`);
|
|
16642
|
-
lines.push(` Version: ${VERSION}`);
|
|
16643
|
-
lines.push("");
|
|
16644
|
-
lines.push("\u2713 Health check complete");
|
|
16645
|
-
this.send({ type: "info", message: lines.join("\n") });
|
|
16942
|
+
const report = buildDoctorReport({
|
|
16943
|
+
config: this.config,
|
|
16944
|
+
providers: this.providers,
|
|
16945
|
+
cwd: process.cwd(),
|
|
16946
|
+
mcpStatuses: this.mcpManager?.getStatus() ?? []
|
|
16947
|
+
});
|
|
16948
|
+
this.send({ type: "info", message: formatDoctorReport(report, false) });
|
|
16646
16949
|
break;
|
|
16647
16950
|
}
|
|
16648
16951
|
// ── /about ──────────────────────────────────────────────────────
|
|
@@ -16809,11 +17112,11 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
|
|
|
16809
17112
|
break;
|
|
16810
17113
|
}
|
|
16811
17114
|
const dirPath = resolve10(sub);
|
|
16812
|
-
if (!
|
|
17115
|
+
if (!existsSync28(dirPath)) {
|
|
16813
17116
|
this.send({ type: "error", message: `Directory not found: ${dirPath}` });
|
|
16814
17117
|
break;
|
|
16815
17118
|
}
|
|
16816
|
-
if (!
|
|
17119
|
+
if (!statSync11(dirPath).isDirectory()) {
|
|
16817
17120
|
this.send({ type: "error", message: `Not a directory: ${dirPath}` });
|
|
16818
17121
|
break;
|
|
16819
17122
|
}
|
|
@@ -16825,14 +17128,14 @@ It will be included in AI context for subsequent messages.` });
|
|
|
16825
17128
|
// ── /commands ───────────────────────────────────────────────────
|
|
16826
17129
|
case "commands": {
|
|
16827
17130
|
const configDir = this.config.getConfigDir();
|
|
16828
|
-
const commandsDir =
|
|
16829
|
-
if (!
|
|
17131
|
+
const commandsDir = join23(configDir, CUSTOM_COMMANDS_DIR_NAME);
|
|
17132
|
+
if (!existsSync28(commandsDir)) {
|
|
16830
17133
|
this.send({ type: "info", message: `No custom commands directory.
|
|
16831
17134
|
Create: ${commandsDir}/ with .md files.` });
|
|
16832
17135
|
break;
|
|
16833
17136
|
}
|
|
16834
17137
|
try {
|
|
16835
|
-
const files =
|
|
17138
|
+
const files = readdirSync13(commandsDir).filter((f) => f.endsWith(".md"));
|
|
16836
17139
|
if (files.length === 0) {
|
|
16837
17140
|
this.send({ type: "info", message: `No custom commands found in ${commandsDir}
|
|
16838
17141
|
Add .md files to create commands.` });
|
|
@@ -16852,7 +17155,7 @@ Add .md files to create commands.` });
|
|
|
16852
17155
|
// ── /plugins / /plugin ──────────────────────────────────────────
|
|
16853
17156
|
case "plugins": {
|
|
16854
17157
|
const configDir = this.config.getConfigDir();
|
|
16855
|
-
const pluginsDir =
|
|
17158
|
+
const pluginsDir = join23(configDir, PLUGINS_DIR_NAME);
|
|
16856
17159
|
const pluginTools = this.toolRegistry.listPluginTools();
|
|
16857
17160
|
const pluginPackages = listInstalledPlugins(configDir);
|
|
16858
17161
|
const lines = [`\u{1F50C} **Plugins:**`, `Dir: ${pluginsDir}`, ""];
|
|
@@ -17134,7 +17437,7 @@ ${entry.content}`;
|
|
|
17134
17437
|
const configDir = this.config.getConfigDir();
|
|
17135
17438
|
try {
|
|
17136
17439
|
atomicWriteFileSync(memoryStorePath(configDir), "");
|
|
17137
|
-
atomicWriteFileSync(
|
|
17440
|
+
atomicWriteFileSync(join23(configDir, MEMORY_FILE_NAME), "");
|
|
17138
17441
|
this.send({ type: "info", message: "\u{1F5D1}\uFE0F Persistent memory cleared." });
|
|
17139
17442
|
this.sendMemoryEntries();
|
|
17140
17443
|
} catch (err) {
|
|
@@ -17416,8 +17719,8 @@ async function setupProxy(configProxy) {
|
|
|
17416
17719
|
}
|
|
17417
17720
|
|
|
17418
17721
|
// src/web/auth.ts
|
|
17419
|
-
import { existsSync as
|
|
17420
|
-
import { join as
|
|
17722
|
+
import { existsSync as existsSync29, readFileSync as readFileSync22, writeFileSync as writeFileSync4, mkdirSync as mkdirSync14, readdirSync as readdirSync14, copyFileSync } from "fs";
|
|
17723
|
+
import { join as join24 } from "path";
|
|
17421
17724
|
import { createHmac, randomBytes, timingSafeEqual, pbkdf2Sync } from "crypto";
|
|
17422
17725
|
var USERS_FILE = "users.json";
|
|
17423
17726
|
var TOKEN_EXPIRY_HOURS = 24;
|
|
@@ -17432,7 +17735,7 @@ var AuthManager = class {
|
|
|
17432
17735
|
db;
|
|
17433
17736
|
constructor(baseDir) {
|
|
17434
17737
|
this.baseDir = baseDir;
|
|
17435
|
-
this.usersFile =
|
|
17738
|
+
this.usersFile = join24(baseDir, USERS_FILE);
|
|
17436
17739
|
this.db = this.loadOrCreate();
|
|
17437
17740
|
}
|
|
17438
17741
|
// ── Public API ─────────────────────────────────────────────────
|
|
@@ -17461,9 +17764,9 @@ var AuthManager = class {
|
|
|
17461
17764
|
}
|
|
17462
17765
|
const salt = randomBytes(16).toString("hex");
|
|
17463
17766
|
const passwordHash = this.hashPassword(password, salt);
|
|
17464
|
-
const dataDir =
|
|
17465
|
-
const fullDataDir =
|
|
17466
|
-
|
|
17767
|
+
const dataDir = join24(USERS_DIR, username);
|
|
17768
|
+
const fullDataDir = join24(this.baseDir, dataDir);
|
|
17769
|
+
mkdirSync14(join24(fullDataDir, "history"), { recursive: true });
|
|
17467
17770
|
const user = {
|
|
17468
17771
|
username,
|
|
17469
17772
|
passwordHash,
|
|
@@ -17578,7 +17881,7 @@ var AuthManager = class {
|
|
|
17578
17881
|
getUserDataDir(username) {
|
|
17579
17882
|
const user = this.db.users.find((u) => u.username === username);
|
|
17580
17883
|
if (!user) throw new Error(`User not found: ${username}`);
|
|
17581
|
-
return
|
|
17884
|
+
return join24(this.baseDir, user.dataDir);
|
|
17582
17885
|
}
|
|
17583
17886
|
/** List all usernames */
|
|
17584
17887
|
listUsers() {
|
|
@@ -17614,30 +17917,30 @@ var AuthManager = class {
|
|
|
17614
17917
|
const err = this.register(username, password);
|
|
17615
17918
|
if (err) return err;
|
|
17616
17919
|
const userDir = this.getUserDataDir(username);
|
|
17617
|
-
const globalConfig =
|
|
17618
|
-
if (
|
|
17920
|
+
const globalConfig = join24(this.baseDir, "config.json");
|
|
17921
|
+
if (existsSync29(globalConfig)) {
|
|
17619
17922
|
try {
|
|
17620
|
-
const content =
|
|
17621
|
-
|
|
17923
|
+
const content = readFileSync22(globalConfig, "utf-8");
|
|
17924
|
+
writeFileSync4(join24(userDir, "config.json"), content, "utf-8");
|
|
17622
17925
|
} catch {
|
|
17623
17926
|
}
|
|
17624
17927
|
}
|
|
17625
|
-
const globalMemory =
|
|
17626
|
-
if (
|
|
17928
|
+
const globalMemory = join24(this.baseDir, "memory.md");
|
|
17929
|
+
if (existsSync29(globalMemory)) {
|
|
17627
17930
|
try {
|
|
17628
|
-
const content =
|
|
17629
|
-
|
|
17931
|
+
const content = readFileSync22(globalMemory, "utf-8");
|
|
17932
|
+
writeFileSync4(join24(userDir, "memory.md"), content, "utf-8");
|
|
17630
17933
|
} catch {
|
|
17631
17934
|
}
|
|
17632
17935
|
}
|
|
17633
|
-
const globalHistory =
|
|
17634
|
-
if (
|
|
17936
|
+
const globalHistory = join24(this.baseDir, "history");
|
|
17937
|
+
if (existsSync29(globalHistory)) {
|
|
17635
17938
|
try {
|
|
17636
|
-
const files =
|
|
17637
|
-
const userHistory =
|
|
17939
|
+
const files = readdirSync14(globalHistory).filter((f) => f.endsWith(".json"));
|
|
17940
|
+
const userHistory = join24(userDir, "history");
|
|
17638
17941
|
for (const f of files) {
|
|
17639
17942
|
try {
|
|
17640
|
-
copyFileSync(
|
|
17943
|
+
copyFileSync(join24(globalHistory, f), join24(userHistory, f));
|
|
17641
17944
|
} catch {
|
|
17642
17945
|
}
|
|
17643
17946
|
}
|
|
@@ -17648,9 +17951,9 @@ var AuthManager = class {
|
|
|
17648
17951
|
}
|
|
17649
17952
|
// ── Private methods ────────────────────────────────────────────
|
|
17650
17953
|
loadOrCreate() {
|
|
17651
|
-
if (
|
|
17954
|
+
if (existsSync29(this.usersFile)) {
|
|
17652
17955
|
try {
|
|
17653
|
-
return JSON.parse(
|
|
17956
|
+
return JSON.parse(readFileSync22(this.usersFile, "utf-8"));
|
|
17654
17957
|
} catch {
|
|
17655
17958
|
}
|
|
17656
17959
|
}
|
|
@@ -17666,7 +17969,7 @@ var AuthManager = class {
|
|
|
17666
17969
|
this.saveDB(this.db);
|
|
17667
17970
|
}
|
|
17668
17971
|
saveDB(db) {
|
|
17669
|
-
|
|
17972
|
+
mkdirSync14(this.baseDir, { recursive: true });
|
|
17670
17973
|
atomicWriteFileSync(this.usersFile, JSON.stringify(db, null, 2));
|
|
17671
17974
|
}
|
|
17672
17975
|
/** Legacy hash — kept only for migrating old users (v0.2.x) */
|
|
@@ -17769,8 +18072,8 @@ async function startWebServer(options = {}) {
|
|
|
17769
18072
|
}
|
|
17770
18073
|
}
|
|
17771
18074
|
let skillManager = null;
|
|
17772
|
-
const skillsDir =
|
|
17773
|
-
if (
|
|
18075
|
+
const skillsDir = join25(config.getConfigDir(), SKILLS_DIR_NAME);
|
|
18076
|
+
if (existsSync30(skillsDir)) {
|
|
17774
18077
|
skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
|
|
17775
18078
|
skillManager.loadSkills(pluginAssets.skillDirs);
|
|
17776
18079
|
const count = skillManager.listSkills().length;
|
|
@@ -17841,18 +18144,18 @@ async function startWebServer(options = {}) {
|
|
|
17841
18144
|
next();
|
|
17842
18145
|
};
|
|
17843
18146
|
const moduleDir = getModuleDir();
|
|
17844
|
-
let clientDir =
|
|
17845
|
-
if (!
|
|
17846
|
-
clientDir =
|
|
18147
|
+
let clientDir = join25(moduleDir, "web", "client");
|
|
18148
|
+
if (!existsSync30(clientDir)) {
|
|
18149
|
+
clientDir = join25(moduleDir, "client");
|
|
17847
18150
|
}
|
|
17848
|
-
if (!
|
|
17849
|
-
clientDir =
|
|
18151
|
+
if (!existsSync30(clientDir)) {
|
|
18152
|
+
clientDir = join25(moduleDir, "..", "..", "src", "web", "client");
|
|
17850
18153
|
}
|
|
17851
|
-
if (!
|
|
17852
|
-
clientDir =
|
|
18154
|
+
if (!existsSync30(clientDir)) {
|
|
18155
|
+
clientDir = join25(process.cwd(), "src", "web", "client");
|
|
17853
18156
|
}
|
|
17854
18157
|
console.log(` Static files: ${clientDir}`);
|
|
17855
|
-
app.use("/vendor", express.static(
|
|
18158
|
+
app.use("/vendor", express.static(join25(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
|
|
17856
18159
|
app.use(express.static(clientDir));
|
|
17857
18160
|
app.get("/api/status", (_req, res) => {
|
|
17858
18161
|
res.json({
|
|
@@ -17919,7 +18222,7 @@ async function startWebServer(options = {}) {
|
|
|
17919
18222
|
app.get("/api/files", requireAuth, (req, res) => {
|
|
17920
18223
|
const cwd = process.cwd();
|
|
17921
18224
|
const prefix = req.query.prefix || "";
|
|
17922
|
-
const targetDir =
|
|
18225
|
+
const targetDir = join25(cwd, prefix);
|
|
17923
18226
|
try {
|
|
17924
18227
|
const canonicalTarget = realpathSync(resolve11(targetDir));
|
|
17925
18228
|
const canonicalCwd = realpathSync(resolve11(cwd));
|
|
@@ -17933,10 +18236,10 @@ async function startWebServer(options = {}) {
|
|
|
17933
18236
|
}
|
|
17934
18237
|
try {
|
|
17935
18238
|
const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", "__pycache__", ".next", ".nuxt", "coverage", ".cache"]);
|
|
17936
|
-
const entries =
|
|
18239
|
+
const entries = readdirSync15(targetDir, { withFileTypes: true });
|
|
17937
18240
|
const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
|
|
17938
18241
|
name: e.name,
|
|
17939
|
-
path: relative4(cwd,
|
|
18242
|
+
path: relative4(cwd, join25(targetDir, e.name)).replace(/\\/g, "/"),
|
|
17940
18243
|
isDir: e.isDirectory()
|
|
17941
18244
|
}));
|
|
17942
18245
|
res.json({ files });
|
|
@@ -17972,8 +18275,8 @@ async function startWebServer(options = {}) {
|
|
|
17972
18275
|
try {
|
|
17973
18276
|
const authUser = req._authUser;
|
|
17974
18277
|
const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
|
|
17975
|
-
const filePath =
|
|
17976
|
-
if (!
|
|
18278
|
+
const filePath = join25(histDir, `${id}.json`);
|
|
18279
|
+
if (!existsSync30(filePath)) {
|
|
17977
18280
|
res.status(404).json({ error: "Session not found" });
|
|
17978
18281
|
return;
|
|
17979
18282
|
}
|
|
@@ -17988,7 +18291,7 @@ async function startWebServer(options = {}) {
|
|
|
17988
18291
|
res.status(404).json({ error: "Session not found" });
|
|
17989
18292
|
return;
|
|
17990
18293
|
}
|
|
17991
|
-
const data = JSON.parse(
|
|
18294
|
+
const data = JSON.parse(readFileSync23(filePath, "utf-8"));
|
|
17992
18295
|
res.json({ session: data });
|
|
17993
18296
|
} catch (err) {
|
|
17994
18297
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -18001,7 +18304,7 @@ async function startWebServer(options = {}) {
|
|
|
18001
18304
|
return;
|
|
18002
18305
|
}
|
|
18003
18306
|
const cwd = process.cwd();
|
|
18004
|
-
const fullPath = resolve11(
|
|
18307
|
+
const fullPath = resolve11(join25(cwd, filePath));
|
|
18005
18308
|
try {
|
|
18006
18309
|
const canonicalFull = realpathSync(fullPath);
|
|
18007
18310
|
const canonicalCwd = realpathSync(resolve11(cwd));
|
|
@@ -18014,12 +18317,12 @@ async function startWebServer(options = {}) {
|
|
|
18014
18317
|
return;
|
|
18015
18318
|
}
|
|
18016
18319
|
try {
|
|
18017
|
-
const stat =
|
|
18320
|
+
const stat = statSync12(fullPath);
|
|
18018
18321
|
if (stat.size > 512 * 1024) {
|
|
18019
18322
|
res.json({ error: `File too large (${(stat.size / 1024).toFixed(0)} KB, max 512 KB)` });
|
|
18020
18323
|
return;
|
|
18021
18324
|
}
|
|
18022
|
-
const content =
|
|
18325
|
+
const content = readFileSync23(fullPath, "utf-8");
|
|
18023
18326
|
res.json({ content, size: stat.size });
|
|
18024
18327
|
} catch {
|
|
18025
18328
|
res.json({ error: "Cannot read file" });
|
|
@@ -18274,17 +18577,17 @@ function resolveProjectMcpPath() {
|
|
|
18274
18577
|
const cwd = process.cwd();
|
|
18275
18578
|
const gitRoot = getGitRoot(cwd);
|
|
18276
18579
|
const projectRoot = gitRoot ?? cwd;
|
|
18277
|
-
const configPath =
|
|
18278
|
-
return
|
|
18580
|
+
const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18581
|
+
return existsSync30(configPath) ? configPath : null;
|
|
18279
18582
|
}
|
|
18280
18583
|
function loadProjectMcpConfig() {
|
|
18281
18584
|
const cwd = process.cwd();
|
|
18282
18585
|
const gitRoot = getGitRoot(cwd);
|
|
18283
18586
|
const projectRoot = gitRoot ?? cwd;
|
|
18284
|
-
const configPath =
|
|
18285
|
-
if (!
|
|
18587
|
+
const configPath = join25(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18588
|
+
if (!existsSync30(configPath)) return null;
|
|
18286
18589
|
try {
|
|
18287
|
-
const raw = JSON.parse(
|
|
18590
|
+
const raw = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
18288
18591
|
return raw.mcpServers ?? raw;
|
|
18289
18592
|
} catch {
|
|
18290
18593
|
return null;
|